├── LocalCommandInjection.ql ├── README.md ├── 3star-ptr-indirection-level.ql ├── getuid-geteuid-comparison.ql ├── helidon-rce.ql ├── log4j-injection.ql └── razor-template.ql /LocalCommandInjection.ql: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # codeql-queries 2 | My CodeQL queries collection 3 | -------------------------------------------------------------------------------- /3star-ptr-indirection-level.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | from AssignExpr a, int level 4 | where a.getLValue().getType().getPointerIndirectionLevel() = level and level > 2 5 | select a, "Assigment using a pointer indirection level of '"+ level + "'. Possible Three Star Programmer detected." 6 | -------------------------------------------------------------------------------- /getuid-geteuid-comparison.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | // Define a class for the `geteuid` function 4 | class GetEuidFunction extends Function { 5 | GetEuidFunction() { 6 | this.hasName("geteuid") 7 | } 8 | } 9 | 10 | // Define a class for the `getuid` function 11 | class GetUidFunction extends Function { 12 | GetUidFunction() { 13 | this.hasName("getuid") 14 | } 15 | } 16 | 17 | // Define a class for the `getgid` function 18 | class GetGidFunction extends Function { 19 | GetGidFunction() { 20 | this.hasName("getgid") 21 | } 22 | } 23 | 24 | // Define a class for the `getegid` function 25 | class GetEgidFunction extends Function { 26 | GetEgidFunction() { 27 | this.hasName("getegid") 28 | } 29 | } 30 | 31 | from FunctionCall call, Function target, ComparisonOperation comparison 32 | where 33 | ( 34 | (call.getTarget() = target and target instanceof GetEuidFunction) or 35 | (call.getTarget() = target and target instanceof GetUidFunction) 36 | ) and 37 | call.getParent() = comparison and 38 | not exists(FunctionCall prohibitedCall | 39 | prohibitedCall.getParent() = comparison and 40 | ( 41 | prohibitedCall.getTarget() instanceof GetGidFunction or 42 | prohibitedCall.getTarget() instanceof GetEgidFunction 43 | ) 44 | ) 45 | select call, "Call to " + target.getName() + " detected inside a comparison without calls to getgid or getegid." 46 | -------------------------------------------------------------------------------- /helidon-rce.ql: -------------------------------------------------------------------------------- 1 | import java 2 | import semmle.code.java.dataflow.FlowSources 3 | 4 | class UrlConfigSourceHelidon extends RefType { 5 | UrlConfigSourceHelidon() { 6 | this.hasQualifiedName("io.helidon.config", "UrlConfigSource") 7 | } 8 | } 9 | 10 | class HelidonConfigGenericContent extends MethodAccess { 11 | HelidonConfigGenericContent() { 12 | exists(Method m | m.getDeclaringType() instanceof UrlConfigSourceHelidon and 13 | m.hasName("genericContent") and 14 | m = this.getMethod() 15 | ) 16 | } 17 | } 18 | 19 | 20 | /** 21 | * A taint-tracking configuration for tracking untrusted user input used in log entries. 22 | */ 23 | private class HelidonConfiguration extends TaintTracking::Configuration { 24 | HelidonConfiguration() { this = "Helidon YAML Injection" } 25 | 26 | override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } 27 | 28 | override predicate isSink(DataFlow::Node sink) { 29 | sink.asExpr() = any(HelidonConfigGenericContent c) 30 | } 31 | 32 | override predicate isSanitizer(DataFlow::Node node) { 33 | node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType 34 | } 35 | } 36 | 37 | from HelidonConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink 38 | where cfg.hasFlowPath(source, sink) 39 | select sink.getNode(), source, sink, "$@ flows to call.", source.getNode(), 40 | "User-provided value" 41 | -------------------------------------------------------------------------------- /log4j-injection.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Log4j Injection 3 | * @description Detects log4j calls with user-controlled data. 4 | * @kind path-problem 5 | * @problem.severity error 6 | * @precision high 7 | * @id java/log-injection 8 | * @tags security 9 | * external/cwe/cwe-117 10 | */ 11 | 12 | import java 13 | import DataFlow::PathGraph 14 | import semmle.code.java.dataflow.FlowSources 15 | 16 | class Log4jCall extends MethodAccess { 17 | Log4jCall() { 18 | exists(RefType t, Method m | 19 | t.hasQualifiedName("org.apache.log4j", ["Category", "Logger", "LogBuilder"]) // Log4j v1 20 | or 21 | t.hasQualifiedName("org.apache.logging.log4j", ["Logger", "LogBuilder", "LoggerManager"]) // Log4j v2 or 22 | or 23 | t.hasQualifiedName("org.apache.logging.log4j.core", ["Logger", "LogBuilder", "LoggerManager"]) // Log4j v2 24 | or 25 | t.hasQualifiedName("org.apache.logging.log4j.status", "StatusLogger") // Log4j Status logger 26 | or 27 | t.hasQualifiedName("org.slf4j", ["Logger", "LoggingEventBuilder"]) and // SLF4J Logger is used when Log4j core is on classpath 28 | log4JJarCoreJarFilePresent() 29 | | 30 | ( 31 | m.getDeclaringType().getASourceSupertype*() = t or 32 | m.getDeclaringType().extendsOrImplements*(t) 33 | ) and 34 | m.getReturnType() instanceof VoidType and 35 | this = m.getAReference() 36 | ) 37 | } 38 | 39 | Argument getALogArgument() { result = this.getArgument(_) } 40 | } 41 | 42 | /** 43 | * A taint-tracking configuration for tracking untrusted user input used in log entries. 44 | */ 45 | private class Log4JInjectionConfiguration extends TaintTracking::Configuration { 46 | Log4JInjectionConfiguration() { this = "Log4j Injection" } 47 | 48 | override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } 49 | 50 | override predicate isSink(DataFlow::Node sink) { 51 | sink.asExpr() = any(Log4jCall c).getALogArgument() 52 | } 53 | 54 | override predicate isSanitizer(DataFlow::Node node) { 55 | node.getType() instanceof BoxedType or node.getType() instanceof PrimitiveType 56 | } 57 | } 58 | 59 | predicate log4JJCoreJarFile(JarFile file) { file.getBaseName().matches("%log4j-core%") } 60 | 61 | predicate log4JJarCoreJarFilePresent() { log4JJCoreJarFile(_) } 62 | 63 | from Log4JInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink 64 | where cfg.hasFlowPath(source, sink) 65 | select sink.getNode(), source, sink, "$@ flows to log4j call.", source.getNode(), 66 | "User-provided value" 67 | -------------------------------------------------------------------------------- /razor-template.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Server-Side Template Injection in RazorEngine 3 | * @description User-controlled data may be evaluated, leading to arbitrary code execution. 4 | * @kind path-problem 5 | * @problem.severity error 6 | * @precision high 7 | * @id csharp/razor-injection 8 | * @tags security 9 | */ 10 | 11 | import csharp 12 | import semmle.code.csharp.frameworks.microsoft.AspNetCore 13 | import semmle.code.csharp.dataflow.TaintTracking 14 | import semmle.code.csharp.dataflow.flowsources.Remote 15 | import DataFlow::PathGraph 16 | 17 | class RazorEngineServiceExtensionsClass extends Class { 18 | RazorEngineServiceExtensionsClass() { this.hasQualifiedName("RazorEngine.Templating.RazorEngineServiceExtensions") } 19 | 20 | Method getRunCompileMethod() { 21 | result.getDeclaringType() = this and 22 | result.hasName("RunCompile") 23 | } 24 | 25 | Method getAddTemplateMethod() { 26 | result.getDeclaringType() = this and 27 | result.hasName("AddTemplate") 28 | } 29 | 30 | Method getCompileMethod() { 31 | result.getDeclaringType() = this and 32 | result.hasName("Compile") 33 | } 34 | 35 | Method getCompileRunnerMethod() { 36 | result.getDeclaringType() = this and 37 | result.hasName("CompileRunner") 38 | } 39 | } 40 | 41 | class LoadedTemplateSourceClass extends Class { 42 | LoadedTemplateSourceClass() { this.hasQualifiedName("RazorEngine.Templating.LoadedTemplateSource") } 43 | } 44 | 45 | class RazorEngineClass extends Class { 46 | RazorEngineClass() { this.hasQualifiedName("RazorEngine.Razor") } 47 | 48 | Method getParseMethod() { 49 | result.getDeclaringType() = this and 50 | result.hasName("Parse") 51 | } 52 | 53 | Method getParseManyMethod() { 54 | result.getDeclaringType() = this and 55 | result.hasName("ParseMany") 56 | } 57 | 58 | Method getCompileMethod() { 59 | result.getDeclaringType() = this and 60 | result.hasName("Compile") 61 | } 62 | 63 | Method getCreateTemplateMethod() { 64 | result.getDeclaringType() = this and 65 | result.hasName("CreateTemplate") 66 | } 67 | 68 | Method getCreateTemplatesMethod() { 69 | result.getDeclaringType() = this and 70 | result.hasName("CreateTemplates") 71 | } 72 | 73 | Method getGetTemplateMethod() { 74 | result.getDeclaringType() = this and 75 | result.hasName("GetTemplate") 76 | } 77 | 78 | Method getGetTemplatesMethod() { 79 | result.getDeclaringType() = this and 80 | result.hasName("GetTemplates") 81 | } 82 | 83 | Method getCreateTemplateTypeMethod() { 84 | result.getDeclaringType() = this and 85 | result.hasName("CreateTemplateType") 86 | } 87 | 88 | Method getCreateTemplateTypesMethod() { 89 | result.getDeclaringType() = this and 90 | result.hasName("CreateTemplateTypes") 91 | } 92 | } 93 | 94 | class RazorEngineInjection extends TaintTracking::Configuration { 95 | RazorEngineInjection() { this = "RazorEngineInjection" } 96 | 97 | override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { 98 | succ.asExpr().(ArrayInitializer).getAnElement() = pred.asExpr() 99 | or 100 | exists(AssignableDefinition def | 101 | pred.asExpr() = def.getSource() and 102 | succ.asExpr() = def.getTargetAccess().(ArrayWrite).getQualifier() 103 | ) 104 | or 105 | exists(MethodCall mc | 106 | mc.getQualifiedDeclaration().getReturnType().getQualifiedName().matches("System.Collections.Generic.IEnumerable%") and 107 | succ.asExpr() = mc and 108 | pred.asExpr() = mc.getAnArgument() 109 | ) 110 | } 111 | 112 | override predicate isSource(DataFlow::Node source) { 113 | source instanceof RemoteFlowSource 114 | } 115 | 116 | override predicate isSink(DataFlow::Node sink) { 117 | exists(RazorEngineClass rec, MethodCall mc | 118 | ( 119 | mc.getTarget() = rec.getParseMethod() or 120 | mc.getTarget() = rec.getParseManyMethod() or 121 | mc.getTarget() = rec.getCompileMethod() or 122 | mc.getTarget() = rec.getCreateTemplateMethod() or 123 | mc.getTarget() = rec.getCreateTemplatesMethod() or 124 | mc.getTarget() = rec.getGetTemplateMethod() or 125 | mc.getTarget() = rec.getGetTemplatesMethod() or 126 | mc.getTarget() = rec.getCreateTemplateTypeMethod() or 127 | mc.getTarget() = rec.getCreateTemplateTypesMethod() 128 | ) 129 | and 130 | sink.asExpr() = mc.getArgument(0) 131 | ) 132 | or 133 | exists(RazorEngineServiceExtensionsClass rec, MethodCall mc | 134 | ( 135 | mc.getTarget() = rec.getRunCompileMethod() or 136 | mc.getTarget() = rec.getCompileMethod() or 137 | mc.getTarget() = rec.getAddTemplateMethod() or 138 | mc.getTarget() = rec.getCompileRunnerMethod() 139 | ) 140 | and 141 | sink.asExpr() = mc.getArgumentForName("templateSource") 142 | ) 143 | or 144 | exists(ObjectCreation oc, LoadedTemplateSourceClass t | 145 | oc.getTarget().getDeclaringType() = t and 146 | sink.asExpr() = oc.getArgumentForName("template") 147 | ) 148 | } 149 | } 150 | 151 | from RazorEngineInjection cfg, DataFlow::PathNode source, DataFlow::PathNode sink 152 | where cfg.hasFlowPath(source, sink) 153 | select sink, source, sink, 154 | "Server-Side Template Injection in RazorEngine leads to Remote Code Execution" 155 | --------------------------------------------------------------------------------