Monday, August 12, 2013

Hacking PHP sessions by running out of memory

The problem

What's wrong with this code snippet?

  /* ... */
  $username = $_POST['username'];
  $password = $_POST['password'];
  $_SESSION['username'] = $username;
  if (scrypt($saved_password, $saved_hash) == scrypt($password, $saved_hash)) {
     $perm = load_permissions_from_db($username);
     $_SESSION['permissions'] = $perm;
  } else {

The problem is that scrypt() might allocate memory and trigger PHP's OOM handler:[1]

    PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 133958362 bytes)

This is the really bad part: PHP will stop execution, but still write out the current $_SESSION data when this happens.

In the above example, this would leave a PHP session sitting around with a 'username' property, but no 'permissions' property. If that were a list of negative permissions, or an empty list got interpretted as full control, that user would have access beyond his normal rights.

Even worse, an attacker could have a session with 'username' set to whatever she wished, even if the password was never correct.

If there is anything earlier in the program that the user could control to allocate memory, she could gradually increase the memory footprint until the scrypt() command hit the OOM condition.


I was hoping to be able to make some kind of "critical section" by disabling the write handler for the session before doing something dangerous and turning it on only after completion. However, on the PHP version I tested against (and according to the documentation) that all has to be set before you begin a session. (It's possible that suhosin is screwing with my attempts to do this.)

In theory even something as simple as $_SESSION['foo'] = bar could trigger the OOM.

You can make your own critical section handler by setting $_SESSION['valid'] = false before updating any session variables, and setting it back to true when you are done. Then on every session_start() you destroy any session that is invalid.

You should also think hard about where a hostile user could cause your PHP app to use a lot of memory. Suhosin does do a good job limiting a lot of $_GET, $_POST, and $_SERVER variables. The more likely culprit would be your processing of some kind of data under user control. If you are, say, analyzing XML under the user's control, they could insert a billion laughs to cause you to run out of memory, and then carefully reduce the size of the input until they get your app to crash in just the right place.

This is also a reminder to practice good session hygiene: session IDs should only be created by the system; when a user logs out, or attempts to log in, her old session should be completely destroyed and her cookie expired.


I asked the PHP team about this and was told:

So there is no bug per se here, security related or normal bug.
Increase or disable the memory limit to solve this problem.

Which seems to miss the point but there you go.


[1] There is no scrypt() in the PHP library right now, but in theory what any scrypt() does is check a password via a method that purposefully uses a lot of memory to make things harder on people brute forcing passwords. There are lots of other functions that could allocate memory, but I chose this one because the irony of using a lot of memory as a security feature can cause other problems here.

Friday, December 14, 2012

Closed Caption Buffer Overflows

I've seen a few times where closed captions make my older Samsung TV reset or even turn right off.  It even works on recordings done via VCR or TiVo.  How far can this be exploited?

Friday, October 26, 2012

uiHz8oGyluCGnzGrRY1ewNZJnq4= is the best password ever

uiHz8oGyluCGnzGrRY1ewNZJnq4= is the best password ever.

If you SHA1 this password, you get 00000966b07716162cb853553994b8096c689ad0.

Hackers who brute-force passwords use five zero's at their beginning to mark them as solved.

Therefore, when hackers find this hash in a list, they will think it's already decrypted.

You will be safe forever!

P.S. Someone pointed out that posting uiHz8oGyluCGnzGrRY1ewNZJnq4= in the title of this blog post makes it no longer secure.  Very well, now JkDn+9q0K5dCAt1FsYpb9gwAJxE= is the best password ever.

Saturday, July 02, 2011

If only Microsoft supported their own hardware on Windows

Register My Microsoft Mouse over the Internet now? Awesome!

Oh, 404 not found. Well, programming websites can be hard.

Let me see if my device is under warranty. Let's go to the warranty page.

Oh, they don't recognize their serial number. (For about a year, Microsoft had a "temporary problem" recognizing the serial number printed on the mouse. Maybe until the warranty ran out.)

Hey, let me try having their ActiveX control identify the device.

Oh, Internet Explorer blocked the ActiveX control because it's unsafe. No option to allow it to run, either.

When a Microsoft Wireless Notebook Optical Mouse 3000 acts funny in Windows:

  • continuously disconnecting and reconnecting,
  • working for anywhere from 2 seconds to 20 seconds, but then breaking,
  • re-installig Intellipoint, will, at best make IPoint.exe crash, or have no effet.
What's the solution? Should both pieces be tossed in the trash? Batteries have been replaced.

Wednesday, May 18, 2011

Security of Bitcoin websites

Bitcoins are a (relatively) new digital currency. Their closest real-world analogue is to cash, since there is no central authority that manages them. Transaction fees within the system are also very very small, less than 0.1% if even that much.

I'm not an expert, but here's a quick primer: you can send coins in your wallet to a valid address, and this transaction is validated by a peer-to-peer network. Addresses can be created at will. Coins are validated via their history, so you can see the addresses of previous transactions involving those coins. For example, I just made up the address 15NhuaukwoUoHWRJijfdrb4iiz6D61mCds; you can see the history of that address here, which is blank right now. (If you give me bitcoins at that address, there is a "receipt" right there. See, bitcoins makes begging on-line seem cool again, just like it was ten years ago.)

Bitcoin's online use also makes a brand-new target for thieves. Instead of breaking into your computer to try and sniff your passwords or selling you off to a zombie net, hackers could directly steal value stored there.

This also applies to websites that handle bitcoins. There is no central body so there is no such thing as PCI Compliance. But websites that allow bitcoins to be transferred to other addresses need to take security very seriously, as if they were handling credit card information or actual cash like a bank.

(Websites that receive payments via Bitcoin do not need to worry as much, but they still should use best practices.)

One example is Mt Gox, a site that facilitates the exchange of different currencies, including US Dollars and Bitcoins. EvilPacket demonstrated a XSS and CSRF attack against the site, which has since been fixed.

One of the more popular source of coins these days are "mining pools," in which lots of people work together to help the peer-to-peer network validate transactions, and are occasionally rewarded with new bitcoins. All these sites have web interfaces. I gave a peek to see if they were vulnerable to some simple attacks.

BTCMine, slush's pool, and MtRed were all safe. (MtRed claims to have fixed a CSRF problem, but if so then it was definitely before I looked, and it seems like it was built right into their framework automatically.)

I incorrectly thought that DeepBit was vulnerable, but the admin pointed out that he already had defenses in place, and when I checked my notes, it turns out he was right all along. Good show there (plus they require email confirmation for changing their destination address).

Bitcoin Pool was vulnerable when I checked. I could change my receiving address blindly, which means it was ripe for a CSRF attack. I dropped an admin a private message in their forum, and didn't get a response. But they seem to have taken action anyway. If you go to now, it fails unless you are using a referrer from their own domain.


As users, the big piece of advice: log out of any website that lets you transmit bitcoins. Log in to those sites only one at a time, and with a separate browser (or even a browser within a VM if you have sufficient amounts of money in play).

As website developers, you need to build secure sites. That's a whole different article.

As a network... well, that's interesting. If one were to perform a widespread theft like this, actions could still be taken against the thieves.

Although you may hear people describe bitcoins as anonymous, the better word is pseudonymous. You can make arbitrary account numbers and receive payment at them, but their use can still be tracked. A theft of a sufficient number of coins would attract the attention of the FBI or similar organization.

At some point, just like with US Dollars, the holders of stolen Bitcoins will want to redeem them for goods or services. Even if they bounce the stolen Bitcoins through thousands of addresses, those can be tracked, since the entire nature of the network is that it is transparent. Eventually a vendor of something physical will acquire some of these coins and be able to provide authorities with some kind of address for the crooks.

Fencing stolen coins is still possible, but actually harder than it would be with, say, a briefcase full of greenbacks.

Tuesday, August 17, 2010

Solving Hangman?

Over on the Wolfram blog a Mathematica user wrote up a hangman game, and found that "jazz" was the hardest word for his AI to guess.

You can read through his post, but he figures that there are so many easy words that guessing some rare letters near the beginning won't cost you that much.

I took that as a challenge and investigated on my own. In turns out to be pretty hard, even if you get 13 wrong guesses to die, to find all possible words.

Instead of his 90,000 word dictionary, I was using the 230,000 word dictionary in /usr/share/dict/words on OpenBSD. To get a good look at the sub-problem, I restricted myself to the 825 words that could be "_ A _ _". I've included those 825 words in the first comment of this post (since I don't know how to get Blogspot to do attachments and am too tired to try it after working on this for a few hours in evening).

The general strategy is to guess the letters that are most likely to appear. Wrong guesses bring you closer to your doom, right guesses give you a lot of information.

If you could perfectly bisect the remaining words with each guess it would only take 10 guesses, but we can't eliminate that many words at each time.

You could go through the letters in their normal order in the English language, but that gets you to J or Z only after about 20 guesses.

Okay, so let's review. We have "_ A _ _". I'm pretending that we got lucky and guessed "A" first, so we have 25 possible letters left to guess, and 13 wrong answers kill us. There are 825 words and here are how many of those words contain each letter:

 1. r 172
 2. e 172
 3. n 170
 4. t 163
 5. l 148
 6. s 136
 7. i 131
 8. m 117
 9. k 116
10. d 107
11. p 102
12. h 101
13. g 91
14. c 89
15. w 88
16. b 88
17. y 84
18. u 82
19. f 61
20. o 54
21. v 41
22. j 29
23. z 28
24. x 9
(q does not appear at all)
Guessing those in order won't work either, as you can see. But we don't need to guess in that order.

The most straightforward way, and the one used at the Wolfram post if I understood it correctly, is to iteratively find the most common letter in the remaining words and guess that one. I think they called this A* back when I was in school. Or was that a greedy algorithm? I can't remember.

Anyway, if you do that, you get this

Guess NumberLetterRemaining Words
So after our 13th wrong answer, we are hanged and still have 8 words left: {bach bawd caph dabb hadj jazz wapp zach}.

However, this isn't necessarily the best order in which to guess letters. There are 24! different orders in which you could guess the letters that aren't A or Q. That would take 1.5*1021 tries to figure out.

Well, what only matters is the first 13 that we guess, and 24C13 is about 2.5 million. That's still a lot, and it may not generalize for other words.

We can do something like minmax algorithm, where we assume that we get the worst possible result from our best possible guesses, looking forward several steps. Looking forward 2, 3, or even 6 steps the very start leaves us off no better. In retrospect this isn't that surprising, since we still have letters pretty well distributed.

However, if we take the 400 best combinations from that 6th step (with word sets ranging in size from 155 to 204) and look forward 5 steps from there, we get some better results. What I called A* above only had us down to 26 word choices, but the best discovery here is down to 24 words. (We guessed D, E, K, L, M, N, P, R, S, T and Y.)

If we take the 32 best solutions we had there (ranging in size from 24 words up to 30 words), and look forward 2 steps, we can get down to 6 possible words. With the additional letters B and F, those words are {gazi hagi jacu jazz waco zach}.

So I can't always win. I didn't test every single combination, but I'm pretty sure that I got close. If I were to spend more than an evening on this, I would try starting with the common results around position 4 or 5 and building trees from there.

I also think that I might be more successful with Mathematica's smaller word list of 90,000 entries. I can't find a good place to download that or a similar corpus (this gets me close, but it looks like a hell of a lot of work to pull out that data). When I find a dictionary of that size I'll try again.

Sunday, August 23, 2009

DC Comics' Spider-Man

Yes, the tag on those pajamas says "DC Super Friends."

Yes, those are Iron Man and Spider-Man you see.

I suspect most parents won't notice stuff like this. It's like some weird bootleg clothes.

Chase does it again

Chase is really eager to get me to sign up for their "triple rewards" program, which has so much fine print I just toss it in the trash. But this recent offer made me reconsider. I wonder if that would last forever. Chase's offer department must not have read many Encyclopedia Brown books.