Java: add Android database taint and SQL injection sinks

This commit is contained in:
Arthur Baars
2020-09-23 18:07:16 +02:00
parent d652b95b21
commit 6db4f839cb
2 changed files with 178 additions and 0 deletions

View File

@@ -387,6 +387,17 @@ private predicate taintPreservingQualifierToMethod(Method m) {
stringlist.getTypeArgument(0) instanceof TypeString
)
)
or
m
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") and
// buildQuery(String[] projectionIn, String selection, String groupBy, String having, String sortOrder, String limit)
// buildQuery(String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit)
// buildUnionQuery(String[] subQueries, String sortOrder, String limit)
// buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String[] selectionArgs, String groupBy, String having)
// buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String groupBy, String having)
m.hasName(["buildQuery", "buildUnionQuery", "buildUnionSubQuery"])
}
private class StringReplaceMethod extends Method {
@@ -447,6 +458,20 @@ private predicate argToMethodStep(Expr tracked, MethodAccess sink) {
private predicate taintPreservingArgumentToMethod(Method method) {
method.getDeclaringType() instanceof TypeString and
(method.hasName("format") or method.hasName("formatted") or method.hasName("join"))
or
method.getDeclaringType().hasQualifiedName("android.database", "DatabaseUtils") and
// String[] appendSelectionArgs(String[] originalValues, String[] newValues)
// String concatenateWhere(String a, String b)
method.hasName(["appendSelectionArgs", "concatenateWhere"])
or
method
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") and
// buildQuery(String[] projectionIn, String selection, String groupBy, String having, String sortOrder, String limit)
// buildQuery(String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit)
// buildUnionQuery(String[] subQueries, String sortOrder, String limit)
method.hasName(["buildQuery", "buildUnionQuery"])
}
/**
@@ -560,6 +585,18 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
method.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and
method.hasName("append") and
arg = 0
or
method.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and
(
// static buildQueryString(boolean distinct, String tables, String[] columns, String where, String groupBy, String having, String orderBy, String limit)
method.hasName("buildQueryString") and arg = [1 .. method.getNumberOfParameters()]
or
// buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String[] selectionArgs, String groupBy, String having)
// buildUnionSubQuery(String typeDiscriminatorColumn, String[] unionColumns, Set<String> columnsPresentInTable, int computedColumnsOffset, String typeDiscriminatorValue, String selection, String groupBy, String having)
method.hasName("buildUnionSubQuery") and
arg = [0 .. method.getNumberOfParameters()] and
arg != 3
)
}
/**
@@ -612,6 +649,12 @@ private predicate taintPreservingArgToArg(Method method, int input, int output)
method.getNumberOfParameters() > 1 and
input = method.getNumberOfParameters() - 1 and
output = 0
or
method.getDeclaringType().hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") and
// static appendColumns(StringBuilder s, String[] columns)
method.hasName("appendColumns") and
input = 1 and
output = 0
}
/**
@@ -649,6 +692,17 @@ private predicate taintPreservingArgumentToQualifier(Method method, int arg) {
arg = 0 and
append.getDeclaringType().hasQualifiedName("java.io", "StringWriter")
)
or
method
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") and
// setProjectionMap(Map<String, String> columnMap)
// setTables(String inTables)
// appendWhere(CharSequence inWhere)
// appendWhereStandalone(CharSequence inWhere)
method.hasName(["setProjectionMap", "setTables", "appendWhere", "appendWhereStandalone"]) and
arg = 0
}
/** A comparison or equality test with a constant. */

View File

@@ -90,3 +90,127 @@ private class MongoJsonStep extends AdditionalQueryInjectionTaintStep {
)
}
}
/** A sink for Android database injection vulnerabilities. */
private class AndroidDatabaseUtils extends QueryInjectionSink {
AndroidDatabaseUtils() {
exists(MethodAccess call, Method method |
method = call.getMethod() and
method.getDeclaringType().hasQualifiedName("android.database", "DatabaseUtils") and
(
// (blobFileDescriptor|long|string)ForQuery(SQLiteDatabase db, String query, String[] selectionArgs)
method.hasName(["blobFileDescriptorForQuery", "longForQuery", "stringForQuery"]) and
method.getNumberOfParameters() = 3 and
this.asExpr() = call.getArgument(1)
or
// createDbFromSqlStatements(Context context, String dbName, int dbVersion, String sqlStatements)
method.hasName("createDbFromSqlStatements") and
this.asExpr() = call.getArgument(3)
or
// queryNumEntries(SQLiteDatabase db, String table, String selection)
// queryNumEntries(SQLiteDatabase db, String table, String selection, String[] selectionArgs)
method.hasName("queryNumEntries") and
this.asExpr() = call.getArgument(2)
)
or
method
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.database.sqlite", "SQLiteDatabase") and
(
// compileStatement(String sql)
method.hasName("compileStatement") and
this.asExpr() = call.getArgument(0)
or
// delete(String table, String whereClause, String[] whereArgs)
method.hasName("delete") and
this.asExpr() = call.getArgument(1)
or
// execPerConnectionSQL(String sql, Object[] bindArgs)
// execSQL(String sql)
// execSQL(String sql, Object[] bindArgs)
method.hasName(["execPerConnectionSQL", "execSQL"]) and
this.asExpr() = call.getArgument(0)
or
// query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
// query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)
// query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
// query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
method.hasName("query") and
(
this.asExpr() = call.getArgument([3, 5, 6, 7, 8]) and
method.getNumberOfParameters() = [9, 10]
or
this.asExpr() = call.getArgument([2, 4, 5, 6, 7]) and
method.getNumberOfParameters() = [7, 8]
)
or
// queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)
// queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
method.hasName("queryWithFactory") and
this.asExpr() = call.getArgument([4, 6, 7, 8, 9])
or
// rawQuery(String sql, String[] selectionArgs, CancellationSignal cancellationSignal)
// rawQuery(String sql, String[] selectionArgs)
method.hasName("rawQuery") and
this.asExpr() = call.getArgument(0)
or
// rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal)
// rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable)
method.hasName("rawQueryWithFactory") and
this.asExpr() = call.getArgument(1)
or
// update(String table, ContentValues values, String whereClause, String[] whereArgs)
// updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm)
method.hasName(["update", "updateWithOnConflict"]) and
this.asExpr() = call.getArgument(2)
)
or
method
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.content", "ContentProvider") and
(
// delete(Uri uri, String selection, String[] selectionArgs)
method.hasName("delete") and
this.asExpr() = call.getArgument(1) and
method.getNumberOfParameters() = 3
or
// query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
// query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
method.hasName("query") and
method.getNumberOfParameters() = [5, 6] and
this.asExpr() = call.getArgument(2)
or
// update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
method.hasName("update") and
this.asExpr() = call.getArgument(2) and
method.getNumberOfParameters() = 4
)
or
method
.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("android.database.sqlite", "SQLiteQueryBuilder") and
(
// delete(SQLiteDatabase db, String selection, String[] selectionArgs)
method.hasName("delete") and
(this.asExpr() = call.getArgument(1) or this.asExpr() = call.getQualifier())
or
// insert(SQLiteDatabase db, ContentValues values)
method.hasName("update") and
this.asExpr() = call.getQualifier()
or
// query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder)
// query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit)
// query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit, CancellationSignal cancellationSignal)
method.hasName("query") and
(this.asExpr() = call.getArgument([3, 5, 6, 7, 8]) or this.asExpr() = call.getQualifier())
or
// update(SQLiteDatabase db, ContentValues values, String selection, String[] selectionArgs)
method.hasName("update") and
(this.asExpr() = call.getArgument(2) or this.asExpr() = call.getQualifier())
)
)
}
}