|
| 1 | +/** |
| 2 | + * @name Load 3rd party classes or code ('unsafe reflection') without signature check |
| 3 | + * @description Load classes or code from 3rd party package without checking the |
| 4 | + * package signature but only rely on package name. |
| 5 | + * This makes it susceptible to package namespace squatting |
| 6 | + * potentially leading to arbitrary code execution. |
| 7 | + * @kind path-problem |
| 8 | + * @problem.severity error |
| 9 | + * @precision high |
| 10 | + * @id java/unsafe-reflection |
| 11 | + * @tags security |
| 12 | + * experimental |
| 13 | + * external/cwe/cwe-470 |
| 14 | + */ |
| 15 | + |
| 16 | +import java |
| 17 | +import semmle.code.java.dataflow.DataFlow |
| 18 | +import semmle.code.java.dataflow.TaintTracking |
| 19 | + |
| 20 | +predicate doesPackageContextLeadToInvokeMethod( |
| 21 | + DataFlow::Node sinkPackageContext, MethodAccess maInvoke |
| 22 | + |
| 23 | +) |
| 24 | +{ |
| 25 | + exists( |
| 26 | + MethodAccess maGetClassLoader, |
| 27 | + MethodAccess maLoadClass, |
| 28 | + MethodAccess maGetMethod | |
| 29 | + maGetClassLoader.getCallee().getName() = "getClassLoader" and |
| 30 | + maGetClassLoader.getQualifier() = sinkPackageContext.asExpr() and |
| 31 | + maLoadClass.getCallee().getName() = "loadClass" and |
| 32 | + maLoadClass.getQualifier() = maGetClassLoader and |
| 33 | + // check for arbitray code execution |
| 34 | + maGetMethod.getCallee().getName() = "getMethod" and |
| 35 | + maGetMethod.getQualifier() = maLoadClass and |
| 36 | + maInvoke.getCallee().getName() = "invoke" and |
| 37 | + maInvoke.getQualifier() = maGetMethod |
| 38 | + ) |
| 39 | +} |
| 40 | + |
| 41 | +predicate isSignaturesChecked(MethodAccess maCreatePackageContext) |
| 42 | +{ |
| 43 | + exists( |
| 44 | + MethodAccess maCheckSignatures | |
| 45 | + maCheckSignatures.getCallee().getDeclaringType().getQualifiedName() = "android.content.pm.PackageManager" and |
| 46 | + maCheckSignatures.getCallee().getName() = "checkSignatures" and |
| 47 | + //maCheckSignatures.getArgument(0).toString() = maCreatePackageContext.getArgument(0).toString() |
| 48 | + TaintTracking::localTaint( |
| 49 | + DataFlow::exprNode(maCheckSignatures.getArgument(0)), |
| 50 | + DataFlow::exprNode(maCreatePackageContext.getArgument(0))) |
| 51 | + ) |
| 52 | +} |
| 53 | + |
| 54 | +from |
| 55 | + MethodAccess maCreatePackageContext, |
| 56 | + LocalVariableDeclExpr lvdePackageContext, |
| 57 | + DataFlow::Node sinkPackageContext, |
| 58 | + MethodAccess maInvoke |
| 59 | +where |
| 60 | + maCreatePackageContext.getCallee().getDeclaringType().getQualifiedName() = "android.content.ContextWrapper" and |
| 61 | + maCreatePackageContext.getCallee().getName() = "createPackageContext" and |
| 62 | + |
| 63 | + not isSignaturesChecked(maCreatePackageContext) and |
| 64 | + |
| 65 | + lvdePackageContext.getEnclosingStmt() = maCreatePackageContext.getEnclosingStmt() and |
| 66 | + TaintTracking::localTaint(DataFlow::exprNode(lvdePackageContext.getAnAccess()), sinkPackageContext) and |
| 67 | + |
| 68 | + doesPackageContextLeadToInvokeMethod(sinkPackageContext, maInvoke) |
| 69 | +select |
| 70 | + lvdePackageContext, |
| 71 | + sinkPackageContext, |
| 72 | + maInvoke, |
| 73 | + maCreatePackageContext.getArgument(0) |
| 74 | + |
0 commit comments