From 441825919c1437e7a919d22395905734fb9a67f9 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Fri, 22 May 2020 01:13:57 +0530 Subject: [PATCH] Java : add MongoDB injection sinks --- .../Security/CWE/CWE-089/SqlInjectionLib.qll | 29 +++++++++ .../Security/CWE/CWE-089/SqlTaintedLocal.ql | 4 ++ .../CWE-089/semmle/examples/Mongo.java | 25 ++++++++ .../semmle/examples/SqlTaintedLocal.expected | 7 ++ .../security/CWE-089/semmle/examples/options | 1 + .../com/mongodb/BasicDBObject.java | 7 ++ .../stubs/mongodbClient/com/mongodb/DB.java | 8 +++ .../com/mongodb/DBCollection.java | 7 ++ .../mongodbClient/com/mongodb/DBCursor.java | 4 ++ .../mongodbClient/com/mongodb/DBObject.java | 4 ++ .../mongodbClient/com/mongodb/Mongo.java | 10 +++ .../com/mongodb/MongoClient.java | 6 ++ .../com/mongodb/ServerAddress.java | 64 +++++++++++++++++++ .../mongodbClient/com/mongodb/util/JSON.java | 8 +++ .../mongodbClient/org/bson/BSONObject.java | 22 +++++++ 15 files changed, 206 insertions(+) create mode 100644 java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java create mode 100644 java/ql/test/query-tests/security/CWE-089/semmle/examples/options create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/BasicDBObject.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DB.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBCollection.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/MongoClient.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java create mode 100644 java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java create mode 100644 java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java diff --git a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll index cd5c34352d89..71b0133bdd5c 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll +++ b/java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll @@ -4,6 +4,22 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection +/** A sink for MongoDB injection vulnerabilities. */ +class MongoDbInjectionSink extends QueryInjectionSink { + MongoDbInjectionSink() { + exists(MethodAccess call | + call.getMethod().getDeclaringType().hasQualifiedName("com.mongodb", "BasicDBObject") and + call.getMethod().hasName("parse") and + this.asExpr() = call.getArgument(0) + ) + or + exists(CastExpr c | + c.getExpr() = this.asExpr() and + c.getTypeExpr().getType().(RefType).hasQualifiedName("com.mongodb", "DBObject") + ) + } +} + private class QueryInjectionFlowConfig extends TaintTracking::Configuration { QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" } @@ -16,6 +32,10 @@ private class QueryInjectionFlowConfig extends TaintTracking::Configuration { node.getType() instanceof BoxedType or node.getType() instanceof NumberType } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + mongoJsonStep(node1, node2) + } } /** @@ -27,3 +47,12 @@ predicate queryTaintedBy( ) { exists(QueryInjectionFlowConfig conf | conf.hasFlowPath(source, sink) and sink.getNode() = query) } + +predicate mongoJsonStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma | + ma.getMethod().getDeclaringType().hasQualifiedName("com.mongodb.util", "JSON") and + ma.getMethod().hasName("parse") and + ma.getArgument(0) = node1.asExpr() and + ma = node2.asExpr() + ) +} diff --git a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql index f5cb9ca4aae2..c27c69be25de 100644 --- a/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql +++ b/java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql @@ -25,6 +25,10 @@ class LocalUserInputToQueryInjectionFlowConfig extends TaintTracking::Configurat override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + mongoJsonStep(node1, node2) + } } from diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java new file mode 100644 index 000000000000..3a1cfff39f94 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/Mongo.java @@ -0,0 +1,25 @@ +import com.mongodb.MongoClient; +import com.mongodb.DBObject; +import com.mongodb.util.*; +import com.mongodb.ServerAddress; +import com.mongodb.DBCollection; +import com.mongodb.DBCursor; +import com.mongodb.*; + +public class Mongo { + public static void main(String[] args) { + MongoClient mongoClient = new MongoClient(new ServerAddress("localhost", 27017)); + DB db = mongoClient.getDB("mydb"); + DBCollection collection = db.getCollection("test"); + + String name = args[1]; + String stringQuery = "{ 'name' : '" + name + "'}"; + DBObject databaseQuery = (DBObject) JSON.parse(stringQuery); + DBCursor result = collection.find(databaseQuery); + + String json = args[1]; + BasicDBObject bdb = BasicDBObject.parse(json); + DBCursor result2 = collection.find(bdb); + + } +} \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected index b85657f771d8..4ecdc32c2043 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTaintedLocal.expected @@ -1,4 +1,6 @@ edges +| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) | +| Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | | Test.java:29:30:29:42 | args : String[] | Test.java:36:47:36:52 | query1 | | Test.java:29:30:29:42 | args : String[] | Test.java:42:57:42:62 | query2 | | Test.java:29:30:29:42 | args : String[] | Test.java:50:62:50:67 | query3 | @@ -11,6 +13,9 @@ edges | Test.java:214:11:214:14 | args : String[] | Test.java:29:30:29:42 | args : String[] | | Test.java:218:14:218:17 | args : String[] | Test.java:183:33:183:45 | args : String[] | nodes +| Mongo.java:10:29:10:41 | args : String[] | semmle.label | args : String[] | +| Mongo.java:17:45:17:67 | parse(...) | semmle.label | parse(...) | +| Mongo.java:21:49:21:52 | json | semmle.label | json | | Test.java:29:30:29:42 | args : String[] | semmle.label | args : String[] | | Test.java:36:47:36:52 | query1 | semmle.label | query1 | | Test.java:42:57:42:62 | query2 | semmle.label | query2 | @@ -24,6 +29,8 @@ nodes | Test.java:214:11:214:14 | args : String[] | semmle.label | args : String[] | | Test.java:218:14:218:17 | args : String[] | semmle.label | args : String[] | #select +| Mongo.java:17:45:17:67 | parse(...) | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) | Query might include code from $@. | Mongo.java:10:29:10:41 | args | this user input | +| Mongo.java:21:49:21:52 | json | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | Query might include code from $@. | Mongo.java:10:29:10:41 | args | this user input | | Test.java:36:47:36:52 | query1 | Test.java:213:26:213:38 | args : String[] | Test.java:36:47:36:52 | query1 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | | Test.java:42:57:42:62 | query2 | Test.java:213:26:213:38 | args : String[] | Test.java:42:57:42:62 | query2 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | | Test.java:50:62:50:67 | query3 | Test.java:213:26:213:38 | args : String[] | Test.java:50:62:50:67 | query3 | Query might include code from $@. | Test.java:213:26:213:38 | args | this user input | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/options b/java/ql/test/query-tests/security/CWE-089/semmle/examples/options new file mode 100644 index 000000000000..89d52ab90eb2 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/BasicDBObject.java b/java/ql/test/stubs/mongodbClient/com/mongodb/BasicDBObject.java new file mode 100644 index 000000000000..326c0ea4777e --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/BasicDBObject.java @@ -0,0 +1,7 @@ +package com.mongodb; + +public class BasicDBObject implements com.mongodb.DBObject { + public static com.mongodb.BasicDBObject parse(java.lang.String json) { + return null; + } +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/DB.java b/java/ql/test/stubs/mongodbClient/com/mongodb/DB.java new file mode 100644 index 000000000000..6e10d3361d41 --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/DB.java @@ -0,0 +1,8 @@ +package com.mongodb; + +public class DB { + + public com.mongodb.DBCollection getCollection(java.lang.String name) { + return null; + } +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/DBCollection.java b/java/ql/test/stubs/mongodbClient/com/mongodb/DBCollection.java new file mode 100644 index 000000000000..ac5307d70f9b --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/DBCollection.java @@ -0,0 +1,7 @@ +package com.mongodb; + +public class DBCollection { + public com.mongodb.DBCursor find(com.mongodb.DBObject query) { + return null; + } +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java b/java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java new file mode 100644 index 000000000000..dc7ee46f3046 --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java @@ -0,0 +1,4 @@ +package com.mongodb; + +public class DBCursor { +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java b/java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java new file mode 100644 index 000000000000..7cb3c04a3e14 --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java @@ -0,0 +1,4 @@ +package com.mongodb; + +public abstract interface DBObject { +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java b/java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java new file mode 100644 index 000000000000..0c822830b7a7 --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java @@ -0,0 +1,10 @@ + +package com.mongodb; + +public class Mongo { + + public com.mongodb.DB getDB(java.lang.String dbName) { + return null; + } + +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/MongoClient.java b/java/ql/test/stubs/mongodbClient/com/mongodb/MongoClient.java new file mode 100644 index 000000000000..6b9928928e2c --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/MongoClient.java @@ -0,0 +1,6 @@ +package com.mongodb; + +public class MongoClient extends com.mongodb.Mongo { + public MongoClient(com.mongodb.ServerAddress addr) { + } +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java b/java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java new file mode 100644 index 000000000000..2fe39341a17e --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java @@ -0,0 +1,64 @@ +// Failed to get sources. Instead, stub sources have been generated by the disassembler. +// Implementation of methods is unavailable. +package com.mongodb; + +public class ServerAddress implements java.io.Serializable { + + public ServerAddress() { + } + + public ServerAddress(java.lang.String host) { + } + + public ServerAddress(java.net.InetAddress inetAddress) { + } + + public ServerAddress(java.net.InetAddress inetAddress, int port) { + } + + public ServerAddress(java.net.InetSocketAddress inetSocketAddress) { + } + + public ServerAddress(java.lang.String host, int port) { + } + + public boolean equals(java.lang.Object o) { + return false; + } + + public int hashCode() { + return 0; + } + + public java.lang.String getHost() { + return null; + } + + public int getPort() { + return 0; + } + + public java.net.InetSocketAddress getSocketAddress() { + return null; + } + + public java.util.List getSocketAddresses() { + return null; + } + + public java.lang.String toString() { + return null; + } + + public static java.lang.String defaultHost() { + return null; + } + + public static int defaultPort() { + return 0; + } + + public boolean sameHost(java.lang.String hostName) { + return false; + } +} diff --git a/java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java b/java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java new file mode 100644 index 000000000000..3eb6ee6fa9cc --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java @@ -0,0 +1,8 @@ +package com.mongodb.util; + +public class JSON { + + public static java.lang.Object parse(java.lang.String jsonString) { + return null; + } +} diff --git a/java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java b/java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java new file mode 100644 index 000000000000..f703a43c3098 --- /dev/null +++ b/java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java @@ -0,0 +1,22 @@ +package org.bson; + +public abstract interface BSONObject { + + public abstract java.lang.Object put(java.lang.String arg0, java.lang.Object arg1); + + public abstract void putAll(org.bson.BSONObject arg0); + + public abstract void putAll(java.util.Map arg0); + + public abstract java.lang.Object get(java.lang.String arg0); + + public abstract java.util.Map toMap(); + + public abstract java.lang.Object removeField(java.lang.String arg0); + + public abstract boolean containsKey(java.lang.String arg0); + + public abstract boolean containsField(java.lang.String arg0); + + public abstract java.util.Set keySet(); +}