Removing Entropy From PHP Session IDs
35 posts remaining…
Samy is awesome. If you missed his preso at Blackhat and DefCon, you missed out. You should try to get the DVD just to hear him. It’s hilarious. I’m not just saying that because he was using me as a fake case study or anything, it really was hilarious. Anyway, we got to talking and it occurred to me that it wasn’t super easy to automate his PHP session ID attack because it requires some social engineering to get the IP address of the user that you want to hijack. Well, after thinking I think I came up with a way around that in some cases.
There are a ton of sites these days that use load-balancers in front of them. There’s a few ways they can be installed - completely transparent or acting more like a proxy. The proxy is the more common setup but it has one pretty huge negative side-effect, all the IP addresses come to the server as just one - the internal IP of the load balancer. Normally that’s not a huge deal because the load-balancer does the logging or it sets some custom HTTP header that is properly logged. But PHP doesn’t know about any of that - it’s dumb. It’ll take whatever value it sees as the IP address and apply it to the session ID algorithm. So now instead of having to guess the entire IP space of the Internet, you now have to just guess RFC1918 - and probably realistically a much smaller slice of that in most cases.
Although that setup is pretty common, there is still one drawback. For Samy’s exploit to work you need to know when someone logged in (down to the second, preferably) to remove enough entropy to make it worthwhile to attack. So this still isn’t easily turned into an automated exploit, but we’re slowly but surely getting there.



August 13th, 2010 at 1:08 am
i’m pretty sure the modules that support the original ip in a header will set the ip before php gets it.
http://httpd.apache.org/docs/2.3/mod/mod_remoteip.html for example.
It updates the information in apache, probably in the early handlers such as the post read request handler, which (I haven’t checked) should be before php gets its hands on any connection data.
August 13th, 2010 at 5:59 am
@Gavin - if that one module is used, perhaps. I’d hazard a guess that the percent of sites that use that module compared to having load balancers as a whole is tiny. Most of the time I see people just modifying Apache to log the additional HTTP header (if anything at all - because in a lot of cases they’re ignoring their logs entirely).
August 16th, 2010 at 9:10 am
Can you link the algo?
I didn’t get the session_id / IP relation :S
August 16th, 2010 at 10:40 am
@fmachs - the session comes down to being a hash of this line of code from PHP’s session.c:
spprintf(&buf, 0, “%.15s%ld%ld%0.8F”,
remote_addr ? remote_addr : “”,
tv.tv_sec,
(long int)tv.tv_usec,
php_combined_lcg(TSRMLS_C) * 10);
You can find some more info on all of it in my presentation at http://samy.pl/bh10/
August 28th, 2010 at 10:04 am
Wouldn’t the use of entropy from /dev/urandom via PHP’s session.entropy_length setting to read even 32 bytes mitigate this attack?
August 28th, 2010 at 10:07 am
@Ilia - yes, but how many sites are you aware of that change how many bytes of entropy are used in their random session ID generation source code? Although it’s possible, no one is going to do it statistically speaking. It would require a patch to PHP to be meaningful and would only help people who upgraded.
August 29th, 2010 at 8:22 am
Admittedly few people know about this feature, but it is there. To make it’s usage more common we probably should revise the default PHP config to use, however the source code of PHP does not actually need to be patched. Distros (which is how most people get their PHPs) could simply revise the the configuration defaults to read 32 or more bytes.
Having security articles such as yours and Samy’s mention it as a solution, would be of great help too