Mongo BSON Injection: Ruby Regexps Strike Again
sakurity.com
sakurity.com
Are they actually broken? One of the first quirks I learned writing Ruby is that you use \A and \z instead of ^ and $.
I know better than to blame security vulnerabilities on "bad programmers" rather than usability problems with a language (or plain old PoLA violations), but changing the meaning of these anchors will be a tough migration, possibly.
Considering that I would venture to say that this is indeed a broken thing since it's a convention that I've only heard about in Ruby. It's a special snowflake in a component that developers use almost exclusively for validation (regex), with a pretty huge gotcha, especially because it appears to function as intended.
I'm not saying that I have a solution, but I can't help be see the parallels.
Anybody interested should have a read through http://pcre.org/pcre.txt. The syntax presented here is used in perl, php, ruby, python, and many others.
Also, nobody ever uses \A without the /m flag. You use ^, it has the same meaning unless you specifically add the /m flag to allow ^ to match at the beginning of any line rather than at the front of the string only. This distinction will only bite developers who just add flags like /msig for every regex, because again they don't understand exactly what every flag actually does.
(and incidentally, that would make changing it easier, you can just request that users specify a flag all the time and deprecate the one without).
It still falls on the developer to understand the exact flavor of regex available in their language. And yet ruby is doing a disservice to anybody coming to their language with existing PCRE knowledge by having syntax that is almost an exact match to PCRE used in many languages... only to find out someday that it's not. Harsh.
So the problem is probably not developer knowledge (note that you got it wrong, too!), but rather that regexps are too hard to get right.
Uhm... No? ^$ have always meant beginning and end of string, not line, unless you turn on a flag. Not by default. You can check PCRE's documentation if you don't believe me. And then, there's Ruby:
irb(main):005:0> "foo\nbar".match /o$/
=> #<MatchData "o">$50,000/day is an expensive lesson!
No, money wasn't being stolen, but the validation error meant that clients' money was being spent and not being tracked. The company had to eat the costs.
As I understand it, the vulnerability is in any ruby application which uses a vulnerable version of the bson gem and which accepts object IDs from user input. You don't have to be using Moped.
The vulnerability is in `bson-ruby`[1] which is written by MongoDB and used by Moped (and thus Mongoid), the official Ruby driver from MongoDB, and Mongo Mapper.
The only thing that _isn't_ vulnerable is Moped's BSON implementation (if reasonably recent), but it was dropped in Moped 2.x.
In reality if your using Mongo with Ruby, your most likely vulnerable, unless you happen to be on Moped 1.x.
[1] https://github.com/mongodb/bson-ruby/blob/84d8acd32ce9067ad6...
> The vulnerability is in `bson-ruby`[1] which is written by MongoDB and used by Moped (and thus Mongoid), the official Ruby driver from MongoDB, and Mongo Mapper.
Then it's in the ruby gem of MongoDB's driver for ruby NOT in MongoDB. The title is still misleading for people who do not code in ruby and therefore are not vulnerable to the apparently ever present ruby BSON bug.
> Mongo BSON Injection
A better title would be Mongo gem BSON Injection
I am not trying to nit-pic I was fairly confused when seeing the title because I don't code in ruby and was 99% sure Mongo's core was C not ruby.
/A-z/ includes "[]^_`" [1]
Now go search github [2] and see the +1k repos that have this bug in their parsing of base64
Sources: [1]: http://wtfjs.com/2014/01/29/regular-expression-and-slash
[2]: https://github.com/search?utf8=%E2%9C%93&q=INVALID_BASE64_RE...
I didn't understand it at first, but the key difference is `A-z` vs. `A-Za-z`.
This is the buggy code:
!!str.match(/^[0-9a-f]{24}$/i)
That regex is trying to do three different things: validate the length is 24, validate the string contains alphanums, and ensure the matching is pinned from start to finish.I prefer code that makes the validation steps explicit and simpler:
str.length==24 && str!~/[^0-9a-z]/iI once had an idea to invite open source developers to remotely pair with me for a day on something (a bug fix, some feature they are working on, whatever)... I would record the session, do an introduction to the problem, and then edit the session down to about an hour or an hour and a half. I think it would be fascinating (if a lot of work).
Maybe some day...
Thanks for clarifying.
I also wonder how many vulnerabilities result just from Rubyists favoring cutesy APIs (or "DSLs," as they call them) that while making for great demos, hide the often times unignorable, crucial details of what they do from their users.
gem "moped", "~> 2.0.5"