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.
Comments
Submitted by garrettw on
Yeah, I always thought that was a bit counter-intuitive, that you’d have to die(); after sending a Location header (I mean, who wouldn’t want to?)—but since the header() function can be used for things you wouldn’t want to follow with die(), the only alternative would be a modification to PHP itself: header() would have to check if it’s doing a redirect or not, and automatically die(); if it is.
Or they could just make a separate redirect() function for sending that header, like ASP.NET has Response.Redirect().
When I read the title of this post, I assumed it was going to be about hacking Windows admin accounts.
Submitted by Chris on
There is a good reason for it to not die. If I wanted to make a pretty error page for broken web browsers (ie. very old ones) then I could generate that after the header() function call.
Most of the time, the most extravagant that I do is a message that says “You need to go /here/ instead.”
Hacking Windows administrative accounts is old hat.
Oh, and I do have the NoRedirect extension installed on Firefox to use while debugging. It can be useful to see output during a “Location” redirect.
Submitted by garrettw on
[quote=Chris]If I wanted to make a pretty error page for broken web browsers
That’s interesting; I didn’t know there were browsers that don’t use Location headers properly.
[quote=Chris]Hacking Windows administrative accounts is old hat.
I know, I still thought that’s what it was going to be about.