NoSQL MEANS No SECURITY? Philipp Krenn @xeraa

DEVELOPER

https://db-engines.com/en/ranking

Injections

JavaScript Injection HTTP://WWW.KALZUMEUS.COM/2010/09/22/SECURITY-LESSONS-LEARNED-FROM-THE-DIASPORA-LAUNCH/ def self.search(query) Person.all(‘$where’ => “function() { return this.diaspora_handle.match(/^#{query}/i) || this.profile.first_name.match(/^#{query}/i) || this.profile.last_name.match(/^#{query}/i); }”) end

Problem JS Evaluation $where db.eval() db.runCommand( { mapReduce: db.collection.group()

Solution JS Evaluation —noscripting OR security.javascriptEnabled: false

Saarbrücker Cybersicherheits-Studenten entdecken bis zu 40.000 ungesicherte Datenbanken im Internet — http://www.uni-saarland.de/nc/aktuelles/artikel/nr/12173.html, Feb 2015

Massive ransomware attack takes out 27,000 MongoDB servers — http://www.techrepublic.com/article/massive-ransomware-attacktakes-out-27000-mongodb-servers/, Jan 2017

https://twitter.com/ashu_barot/ status/1129081068819058688

Bound to all interfaces by default?

Authentication enabled by default?

Authentication & Authorization

Enable auth=true

<3.0 MONGODB CHALLENGE RESPONSE (MONGODB-CR)

=3.0 IETF RFC 5802 (SCRAM-SHA-1) >=4.0 SCRAM-SHA-256

SCRAM-SHA-1 CONFIGURABLE iterationCount SALT PER USER INSTEAD OF SERVER SHA-1 INSTEAD OF MD5 SERVER AUTHENTICATES AGAINST THE CLIENT AS WELL

Predefined Roles read / readAnyDatabase readWrite / readWriteAnyDatabase dbAdmin / dbAdminAnyDatabase userAdmin / userAdminAnyDatabase dbOwner BACKUP, RESTORE, CLUSTER MANAGEMENT,…

$ mongod —noauth —port 27017 —dbpath test/ —logpath testlog $ mongo localhost/admin > db.createUser({ user: “philipp”, pwd: “password”, roles: [ { role: “root”, db: “admin” } ] }) > db.system.users.find() > exit

$ mongod —auth —port 27017 —dbpath test/ —logpath testlog $ mongo localhost/admin > show dbs > exit

$ mongo localhost/admin -u philipp -p —authenticationDatabase admin > show dbs > db.createUser({ user: “alice”, pwd: “password”, roles: [ { role: “read”, db: “testA” }, { role: “readWrite”, db: “testB” } ] }) > db.system.users.find() > exit

$ > > > > > > > > mongo localhost/testA -u alice -p —authenticationDatabase admin db.test.insert({ foo: “bar” }) db.test.find() use testB db.test.insert({ foo: “bar” }) db.test.find() use testC db.test.find() exit

=3.0 SSL INCLUDED (ALMOST) EVERYWHERE

Research shows 75% of ‘open’ Redis servers infected — https://www.incapsula.com/blog/report-75-of-open-redis-serversare-infected.html, May 2018

Let’s crack Redis for fun and no profit at all given I’m the developer of this thing — http://antirez.com/news/96, Nov 2015

Bound to all interfaces by default?

Protected Mode

=3.2.0 ANSWER LOCAL QUERIES RESPOND WITH AN ERROR FOR REMOTE

Authentication & Authorization

tiny layer of authentication that is optionally turned on — http://redis.io/topics/security

AUTH <password> COMMAND PLAIN-TEXT PASSWORD IN REDIS.CONF NO (BUILT-IN) SSL OR RATE LIMITS

Hiding Commands

SET IN REDIS.CONF RESET AFTER RESTART

rename-command CONFIG mysecretconfigname

rename-command CONFIG “”

While it would be a very strange use case, the application should avoid composing the body of the Lua script using strings obtained from untrusted sources. — http://redis.io/topics/security

Redis EVAL command allows execution of Lua scripts, and such feature should be allowed by default since is a fundamental Redis feature. — http://antirez.com/news/118, Jun 2018

Redis Lua scripting: several security vulnerabilities fixed — http://antirez.com/news/119, Jun 2018

Future

REDIS 6 ACL & TLS HTTP://ANTIREZ.COM/NEWS/118, JUN 2018

Bound to all interfaces by default?

Authentication enabled by default?

Broadcasting on the local subnet?

Running as root?

Scripting

ELASTICSEARCH HTTPS://WWW.ELASTIC.CO/COMMUNITY/SECURITY CVE-2014-3120 CVE-2014-6439 CVE-2015-1427 CVE-2015-3337 CVE-2015-4165 CVE-2015-5377 CVE-2015-5531 CVE-2018-3826 (6.8): (4.3): (6.8): (4.3): (3.3): (5.1): (5.0): (X.X): Dynamic scripting CORS misconfiguration Groovy sandbox escape Directory traversal File modifications RCE related to Groovy Directory traversal Disclosure flaw

ELASTICSEARCH HTTPS://WWW.ELASTIC.CO/COMMUNITY/SECURITY CVE-2014-3120 CVE-2014-6439 CVE-2015-1427 CVE-2015-3337 CVE-2015-4165 CVE-2015-5377 CVE-2015-5531 CVE-2018-3826 (6.8): (4.3): (6.8): (4.3): (3.3): (5.1): (5.0): (X.X): Dynamic scripting CORS misconfiguration Groovy sandbox escape Directory traversal File modifications RCE related to Groovy Directory traversal Disclosure flaw

Painless

HIRED DEVELOPER 1 YEAR DEVELOPMENT

Why build a brand new language when there are already so many to choose from? — https://www.elastic.co/blog/painless-a-new-scripting-language

Goal SECURE & PERFORMANT

POST posts/doc/1/_update { “script”: { “lang”: “painless”, “source”: “”” if(ctx._source.details.containsKey(“plus_ones”)) { ctx._source.details.plus_ones++; } else { ctx._source.details.plus_ones = 1; } “”” } }

Removed GROOVY, PYTHON, JAVASCRIPT IN 6.0

Authentication & Authorization

$ curl yellow yellow yellow yellow -XGET ‘http://67.205.153.88:9200/_cat/indices’ open goal12 5 1 9397 0 27mb 27mb open please_read 5 1 1 0 4.9kb 4.9kb open un-webhose 5 1 2294 1 25.4mb 25.4mb open goal11 5 1 4828 0 13.3mb 13.3mb

$ curl -XGET ‘http://67.205.153.88:9200/please_read/_search?pretty’ { “took” : 1, “timed_out” : false, “_shards” : { “total” : 5, “successful” : 5, “failed” : 0 }, “hits” : { “total” : 1, “max_score” : 1.0, “hits” : [ { “_index” : “please_read”, “_type” : “info”, “_id” : “AVm3qmXeus_FduwRD54v”, “_score” : 1.0, “_source” : { “Info” : “Your DB is Backed up at our servers, to restore send 0.5 BTC to the Bitcoin Address then send an email with your server ip”, “Bitcoin Address” : “12JNfaS2Gzic2vqzGMvDEo38MQSX1kDQrx”, “Email” : “elasticsearch@mail2tor.com” } } ] } }

Conclusion

Injections Are Still a Thing

Enable Security by Default

Be Creative — Or Not

Custom Scripting Can Make Sense

Security Takes Time

Thanks! QUESTIONS? Philipp Krenn @xeraa