Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions java/ql/src/Security/CWE/CWE-089/SqlInjectionLib.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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" }

Expand All @@ -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)
}
}

/**
Expand All @@ -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()
)
}
4 changes: 4 additions & 0 deletions java/ql/src/Security/CWE/CWE-089/SqlTaintedLocal.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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);

}
}
Original file line number Diff line number Diff line change
@@ -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 |
Expand All @@ -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 |
Expand All @@ -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 |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/mongodbClient
Original file line number Diff line number Diff line change
@@ -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;
}
}
8 changes: 8 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/DB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mongodb;

public class DB {

public com.mongodb.DBCollection getCollection(java.lang.String name) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.mongodb;

public class DBCollection {
public com.mongodb.DBCursor find(com.mongodb.DBObject query) {
return null;
}
}
4 changes: 4 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/DBCursor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.mongodb;

public class DBCursor {
}
4 changes: 4 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/DBObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.mongodb;

public abstract interface DBObject {
}
10 changes: 10 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/Mongo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

package com.mongodb;

public class Mongo {

public com.mongodb.DB getDB(java.lang.String dbName) {
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.mongodb;

public class MongoClient extends com.mongodb.Mongo {
public MongoClient(com.mongodb.ServerAddress addr) {
}
}
64 changes: 64 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/ServerAddress.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
8 changes: 8 additions & 0 deletions java/ql/test/stubs/mongodbClient/com/mongodb/util/JSON.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mongodb.util;

public class JSON {

public static java.lang.Object parse(java.lang.String jsonString) {
return null;
}
}
22 changes: 22 additions & 0 deletions java/ql/test/stubs/mongodbClient/org/bson/BSONObject.java
Original file line number Diff line number Diff line change
@@ -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();
}