Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I worked on a big name project that had this same problem, which we found because users had begun exploiting it. The problem was caused when a user would intentionally prevent the recovery_code from submitting with the rest of the form, which resulted in recovery_code being nil, which resulted in "SELECT something FROM users WHERE recovery_code IS NULL AND email = targeted_email" hitting the database. This wouldn't work if you'd requested a password reset code and not yet used it, but everyone else was vulnerable. Sounds like something similar happened here.

EDIT: Updated explanation of problem because I originally explained it wrong (required omission of the value on submission, not just a blank value).



Yet another example of why allowing nullable values anywhere is a bad idea.


How did the string go from "" to nil automagically?


I explained it incorrectly. It actually wasn't as simple as leaving the recovery code blank, because as you note, that would result in an empty string. What they did was delete the recovery_code element from the form entirely and then submit. It was a Rails project, so when the application requested params[:recovery_code], it would get back nil, since Ruby gives nil when you request a key that doesn't exist in a hash. If you left the box blank, you wouldn't hit the bug, because "" != NULL.


It wasn't the case here, but Oracle effectively treats empty string and null as the same value.


In a similar vain MS SQL Server ignores trailing spaces when performing string comparisons, which can lead to odd bugs where the data layer considers things to be equal when other layers don't.

Similarly most RDBMSs are case insensitive by default while most programming languages are not, which again can lead to problems where different layers in an application disagree about string equality.

It isn't at all unlikely that bugs in naive code (caused by people not being concious and careful of these sorts of differences) can allow attackers to cause useful information to leak.


Bad database constraints obviously.


For this to happen, wouldn't it mean that recovery codes never expired?


No, the recovery codes did expire. I don't remember exactly how the system was checking expirations, but it was obviously not in a way that precluded this attack, though I agree there are several possible ways to check expirations that would've done so. Most likely, the application ignored expiration dates when set to NULL instead of complaining about the invalidity.

Anyone who did not have an active password reset token could have their password reset, because it was selecting users based on their username/email and the user not having an active password reset token (token reset to NULL upon successful password reset, so it wasn't just users who had never reset a password, but also any user who had redeemed their most recent password reset request (obviously, this included practically all users)).


This would not happen with normal use of a modern framework.


Not sure how you're defining "modern", but it did happen with Ruby on Rails 2.x. I bet I could recreate it in a Rails 4 app.

Yes, there are things that could've been done to prevent this bug from happening, like using Rails's validation mechanisms to reject any POST that didn't contain the field, but that's not really the point. The point is that simple, subtle bugs can and do sneak into production codebases, and more-exhaustive-than-usual testing is needed for anything used to control account access like password resets.


Rails isn't modern. I assume though that at least it does support validation, which is exactly the point. Building a bunch of tests in order to avoid college-level development practices would be a waste. Tests are valuable, but as an additional level of protection on top of good - or just regular - practices.


What are some examples of a modern framework?


Laravel and Yii are my favorites in PHP. Both borrowed concepts from Rails, but brought in the maturity of older PHP frameworks.


> maturity of older PHP frameworks.

I mean Laravel is somewhat good. But there wasn't a real mature PHP Framework in the past. Especially not as mature than Rails, Django.


> Rails isn't modern.

You are using a drastically different version of modern than normal English usage. Where's that Scotsman when you need him?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: