Merge pull request #3542 from porcupineyhairs/mongoJava

Java : add MongoDB injection sinks
This commit is contained in:
Anders Schack-Mulligen
2020-09-01 16:19:17 +02:00
committed by GitHub
15 changed files with 206 additions and 0 deletions

View File

@@ -4,6 +4,22 @@ import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.QueryInjection 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 { private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" } QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
@@ -16,6 +32,10 @@ private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
node.getType() instanceof BoxedType or node.getType() instanceof BoxedType or
node.getType() instanceof NumberType 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) 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()
)
}

View File

@@ -25,6 +25,10 @@ class LocalUserInputToQueryInjectionFlowConfig extends TaintTracking::Configurat
override predicate isSanitizer(DataFlow::Node node) { override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
} }
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
mongoJsonStep(node1, node2)
}
} }
from from

View File

@@ -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);
}
}

View File

@@ -1,4 +1,6 @@
edges 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: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:42:57:42:62 | query2 |
| Test.java:29:30:29:42 | args : String[] | Test.java:50:62:50:67 | query3 | | 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: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[] | | Test.java:218:14:218:17 | args : String[] | Test.java:183:33:183:45 | args : String[] |
nodes 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:29:30:29:42 | args : String[] | semmle.label | args : String[] |
| Test.java:36:47:36:52 | query1 | semmle.label | query1 | | Test.java:36:47:36:52 | query1 | semmle.label | query1 |
| Test.java:42:57:42:62 | query2 | semmle.label | query2 | | 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:214:11:214:14 | args : String[] | semmle.label | args : String[] |
| Test.java:218:14:218:17 | args : String[] | semmle.label | args : String[] | | Test.java:218:14:218:17 | args : String[] | semmle.label | args : String[] |
#select #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: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: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 | | 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 |

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient

View File

@@ -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;
}
}

View File

@@ -0,0 +1,8 @@
package com.mongodb;
public class DB {
public com.mongodb.DBCollection getCollection(java.lang.String name) {
return null;
}
}

View File

@@ -0,0 +1,7 @@
package com.mongodb;
public class DBCollection {
public com.mongodb.DBCursor find(com.mongodb.DBObject query) {
return null;
}
}

View File

@@ -0,0 +1,4 @@
package com.mongodb;
public class DBCursor {
}

View File

@@ -0,0 +1,4 @@
package com.mongodb;
public abstract interface DBObject {
}

View File

@@ -0,0 +1,10 @@
package com.mongodb;
public class Mongo {
public com.mongodb.DB getDB(java.lang.String dbName) {
return null;
}
}

View File

@@ -0,0 +1,6 @@
package com.mongodb;
public class MongoClient extends com.mongodb.Mongo {
public MongoClient(com.mongodb.ServerAddress addr) {
}
}

View File

@@ -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<java.net.InetSocketAddress> 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;
}
}

View File

@@ -0,0 +1,8 @@
package com.mongodb.util;
public class JSON {
public static java.lang.Object parse(java.lang.String jsonString) {
return null;
}
}

View File

@@ -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<java.lang.String> keySet();
}