Hi, today I’ll do a quick preamble article about NoSQL Injection, more specifically on MongoDB. I found an interesting way to call the $where operator when you’re in an NoSQL injection inside a field.
Current techniques
Normally, you are not supposed to be able to call the $where operator since it is a top-level operator that shouldn’t be put inside a field. The general exploitation way is to use other operator, such as $ne (not equal) to bypass authentication if the password is directly sent in the query, or use $regex and so on to get information about the NoSQL objects.
SSJS
MongoDB implements a way to execute server-side javascript for its $where operator. It previously used spidermonkey (the same JS engine as Firefox) but switched to V8.
When it was still on spidermonkey, remote code execution was easy since NativeHelper was present, an security researcher named agix made an interesting article about that.
Getting SSJS with a NoSQL injection
To get JavaScript execution, I will use $elemMatch, which takes multiple queries. It is supposed to avoid the $where operator, but as you can see, $where will get parsed (and not executed) before. Knowing that, you’ll be able to execute JavaScript, without the database context by using assert:
{"field": {"$elemMatch": {"$where": "return a;};assert.neq('a','a',Object.keys(this));//"}}
Doing this will print all the keys in “this”, as long as you have the error messages.
You won’t have the database context (this.db) so you won’t be able to do database queries directly, but since it is running in V8, we can imagine an attack directly on the JavaScript engine (OOB, use-after-free, type confusion, …) to get RCE. If I’m able to do that, I’ll do an article on here about that.
Once again, I’m not sure if I should consider that as a 0day, but well, let’s wait and see. Thanks for reading!