Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is nosql injection possible for Ruby on Rails with Mongoid?

I'm trying to investigate if nosql injection is possible on Ruby on Rails with mongo and mongoid gems.

I did Mongodb's requests using Mongo::Client collections and models with Mongoid::Document inclusion.

I tried to pass some command characters like ' " \ ; { }, but is was sanitaized. Passing GET search?title[$ne]=foo was traited like {"title"=>"{\"$ne\"=>\"foo\"}"}, so it don't seems like any problem here.

Is any nosql injection possible if I use ordinary methods of this technology stack?

like image 580
Adlaran Avatar asked Oct 25 '25 14:10

Adlaran


2 Answers

Common operations including queries and inserts/updates in Mongoid sanitize their inputs, thus most times one does not need to worry about "nosql injection".

However, there are methods that pass commands directly to the database, and in those cases it is important to carefully consider whether unsanitized user input can end up as a database command. For example, if Post is a Mongoid model, one can run the following command to create an infinite loop in a MongoDB server:

Post.all.map_reduce('function(){while(true);}','function(){}').out(inline:1).count

Another example is Database#command method provided by the driver to run arbitrary database commands: http://api.mongodb.com/ruby/current/Mongo/Database.html#command-instance_method. If an application places user input into parameters given to this method, this creates potential for "nosql injection".

Note also that it is not necessary to pass an unexpected command to the database - sometimes unexpected data is sufficient. See, for example, https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS. Assuming the Post model has a body field, passing an arbitrary regular expression from the user could be problematic:

# This might take a while
Post.where('body' => {'$regex' => '((a|a?|a*)*)*$'}).count
like image 85
D. SM Avatar answered Oct 27 '25 05:10

D. SM


Possible, and easily overlooked.

In fact, you are pretty close.
Untrust sources are not just from GET parameters.
Mongoid won't help you with anything; in your example, what prevents the succeeded exploitation is the fact that, in RoR, you can't pass a Hash as a GET parameter.

An unsanitized parameter can come from JSON, like this one for example.

posts = PrivatePost.where({ owner_id: json_params[:owner_id] }).each.to_a

Where json_params[:owner_id] could contains { '$ne': 'the owner' },
which can leak posts to someone else.

Or mess with the operation scope via POST-based API:

Post.where({ _id: json_params[:id] }).delete_all
like image 32
Curious Sam Avatar answered Oct 27 '25 04:10

Curious Sam