One of my customers had a custom interface built to group periodic posts (think blog categories, even though that is not exact). The former programmer never finished the functionality, and I inherited the project. After completing the required features, I have largely left it alone and that means that I did not perform a complete audit of the existing code.
I received an e-mail today that some “hacker” had learned the login details and was posting junk advertisements for cialis and the like. As any good system administrator would do, I dug out the log files to see what was happening. The bots that were posting (there were two IPs) never touched the login page, but accessed the posting page directly.
We have database entries for the most recent login time on each account, and only one account has been used within the last year. The password on that account is secure, so apart from theft (over an unsecure connection?) there is no way that somebody obtained it.
My first inclination was that they were using stored login cookies, and I took immediate action to limit the length of all login sessions (including the automatic cancelation of any existing session cookies). This was a programatic change since I do not have root access to the server.
Another ten advertisements were posted this evening, so I examined the login requirements again for the posting page. The basic layout of the original code looked like this:
<?php
session_start();
if (!$_SESSION['logged_in']) {
header('Location: login.php');
}
?>
I had beefed it up with session time limiters but overlooked the basic program flow. After the “Location” header, the page continues to build!
In other words, if a bot were to disregard the redirect then it would have a copy of the article submission form to fill in. Submit that back and the PHP page will happily store the information in the database while spewing out another “Location” header for the bot to ignore.
As you might have guessed by now, we had a public link to the posting page.
Always, always, always exit after a redirect.