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
Empty file removed java/lib/github/.gitkeep
Empty file.
48 changes: 48 additions & 0 deletions java/lib/github/BeanManipulation.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
private import semmle.code.java.dataflow.TaintTracking

class SetPropertyMethod extends Method {
SetPropertyMethod() {
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("org.springframework.beans", "PropertyAccessor") and
this.hasName(["setPropertyValue", "setPropertyValues"])
or
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName(["org.apache.commons.beanutils", "org.apache.commons.beanutils2"],
["PropertyUtils", "PropertyUtilsBean"]) and
this.hasName(["setProperty", "setNestedProperty", "setSimpleProperty"])
or
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName(["org.apache.commons.beanutils", "org.apache.commons.beanutils2"],
["BeanUtils", "BeanUtilsBean"]) and
this.hasName(["setProperty", "populate"])
or
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("org.springframework.data.redis.hash", "BeanUtilsHashMapper") and
this.hasName("fromHash")
or
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("org.springframework.beans",
"AbstractNestablePropertyAccessor$PropertyHandler") and
this.hasName("setValue")
or
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("org.springframework.beans",
["AbstractNestablePropertyAccessor", "AbstractPropertyAccessor"]) and
this.hasName(["setPropertyValue", "setPropertyValues"])
}
}

class BeanManipulationSink extends DataFlow::ExprNode {
BeanManipulationSink() {
exists(MethodAccess ma |
ma.getMethod() instanceof SetPropertyMethod and
this.getExpr() = ma.getAnArgument()
)
}
}
22 changes: 11 additions & 11 deletions java/src/CVEs/CVE-2021-44228.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.JndiInjection
import DataFlow::PathGraph
import Log4ShellFlow::PathGraph

class Log4ShellConfig extends TaintTracking::Configuration {
Log4ShellConfig() { this = "Log4ShellConfig" }
private module Log4ShellConfig implements DataFlow::ConfigSig {
int fieldFlowBranchLimit() { result = 9 }

override int fieldFlowBranchLimit() { result = 9 }

override predicate isSource(DataFlow::Node source) {
predicate isSource(DataFlow::Node source) {
exists(Method m, Parameter p |
m.getParameter(0) = p and
p = source.asParameter() and
Expand All @@ -28,9 +26,9 @@ class Log4ShellConfig extends TaintTracking::Configuration {
)
}

override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }

override predicate isSanitizer(DataFlow::Node n) {
predicate isBarrier(DataFlow::Node n) {
exists(string s | n.getLocation().getFile().getBaseName() = s |
s.matches("%Appender.java") and not s = "AbstractOutputStreamAppender.java"
or
Expand All @@ -41,6 +39,8 @@ class Log4ShellConfig extends TaintTracking::Configuration {
}
}

from Log4ShellConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink
where conf.hasFlowPath(source, sink)
select sink, source, sink, "log4shell"
module Log4ShellFlow = TaintTracking::Global<Log4ShellConfig>;

from Log4ShellFlow::PathNode source, Log4ShellFlow::PathNode sink
where Log4ShellFlow::flowPath(source, sink)
select sink, source, sink, "Log4shell"
45 changes: 45 additions & 0 deletions java/src/CVEs/CVE-2022-22965.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @name Spring4Shell
* @description ClassLoader Manipulation in Spring Beans
* @kind path-problem
* @problem.severity error
* @precision high
* @id githubsecuritylab/spring4shell
* @tags security
*/

import java
import semmle.code.java.dataflow.FlowSources
import Spring4ShellFlow::PathGraph
import github.BeanManipulation

private module Spring4ShellConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
source.asExpr().getEnclosingCallable().getDeclaringType().hasName("WebUtils")
}

predicate isSink(DataFlow::Node sink) { sink instanceof BeanManipulationSink }

predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(ConstructorCall ma |
ma.getConstructor().getDeclaringType().getASourceSupertype*().hasName("MutablePropertyValues") and
n1.asExpr() = ma.getAnArgument() and
n2.(DataFlow::PostUpdateNode).getPreUpdateNode() = DataFlow::getInstanceArgument(ma)
)
}

predicate isBarrier(DataFlow::Node n) {
n.getLocation().getFile().getRelativePath().matches(["%test%", "%mock%"])
or
exists(MethodAccess ma |
ma.getMethod().hasName("toString") and DataFlow::getInstanceArgument(ma) = n
)
}
}

module Spring4ShellFlow = TaintTracking::Global<Spring4ShellConfig>;

from Spring4ShellFlow::PathNode source, Spring4ShellFlow::PathNode sink
where Spring4ShellFlow::flowPath(source, sink)
select sink, source, sink, "Bean Manipulation at $@.", sink.getNode(), "user input"
20 changes: 9 additions & 11 deletions java/src/CVEs/CVE-2022-33980.ql
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import DataFlow
import DataFlow::PathGraph
import ACCInjectionFlow::PathGraph

class InterpolatorConfig extends TaintTracking::Configuration {
InterpolatorConfig() { this = "InterpolatorConfig" }
private module ACCInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma, Method m | ma.getMethod() = m and ma.getAnArgument() = sink.asExpr() |
m.getName() = ["addProperty", "setProperty"] and
m.getDeclaringType()
Expand All @@ -38,6 +34,8 @@ class InterpolatorConfig extends TaintTracking::Configuration {
}
}

from DataFlow::PathNode source, DataFlow::PathNode sink, InterpolatorConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "injection from $@.", source.getNode(), "this user input"
module ACCInjectionFlow = TaintTracking::Global<ACCInjectionConfig>;

from ACCInjectionFlow::PathNode source, ACCInjectionFlow::PathNode sink
where ACCInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Script injection"
20 changes: 9 additions & 11 deletions java/src/CVEs/CVE-2022-42889.ql
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import DataFlow
import DataFlow::PathGraph
import ACTInjectionFlow::PathGraph

class InterpolatorConfig extends TaintTracking::Configuration {
InterpolatorConfig() { this = "InterpolatorConfig" }
private module ACTInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma, Method m | ma.getMethod() = m and ma.getAnArgument() = sink.asExpr() |
m.getName() = "replace" and
m.getDeclaringType()
Expand All @@ -34,6 +30,8 @@ class InterpolatorConfig extends TaintTracking::Configuration {
}
}

from DataFlow::PathNode source, DataFlow::PathNode sink, InterpolatorConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "injection from $@.", source.getNode(), "this user input"
module ACTInjectionFlow = TaintTracking::Global<ACTInjectionConfig>;

from ACTInjectionFlow::PathNode source, ACTInjectionFlow::PathNode sink
where ACTInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Script injection"
69 changes: 69 additions & 0 deletions java/src/security/CWE-022/UnsafeURICheck.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* @name Unsafe URI Check
* @description Checking a URL against an allow/block list in Java may be unsafe.
* @kind path-problem
* @problem.severity error
* @precision high
* @id githubsecuritylab/unsafe-uri-check
* @tags security
* external/cwe/cwe-22
*/

import java
import semmle.code.java.dataflow.FlowSources
import UnsafeURICheckFlow::PathGraph

// Reference: https://mail-archives.apache.org/mod_mbox/ambari-user/202102.mbox/%3CCAEJYuxEQZ_aPwJdAaSxPu-Dva%3Dhc7zZUx3-pzBORbd23g%2BGH1A%40mail.gmail.com%3E
class ServletFilterInterface extends Interface {
ServletFilterInterface() { this.hasQualifiedName("javax.servlet", "Filter") }
}

class ServletRequestInterface extends Interface {
ServletRequestInterface() { this.hasQualifiedName("javax.servlet.http", "HttpServletRequest") }
}

class GetRequestURIMethodAccess extends MethodAccess {
GetRequestURIMethodAccess() {
this.getMethod().getName() = "getRequestURI" and
this.getMethod().getDeclaringType() instanceof ServletRequestInterface
}
}

private module UnsafeURICheckConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(GetRequestURIMethodAccess ma |
ma.getEnclosingCallable().getDeclaringType().getASourceSupertype*() instanceof
ServletFilterInterface and
source.asExpr() = ma
)
}

predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
// java.util.regex.Pattern.matcher("aaaaab");
ma.getMethod().getName() = "matcher" and
ma.getMethod().getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and
sink.asExpr() = ma.getArgument(0)
or
// java.util.regex.Pattern.matches("a*b", "aaaaab");
ma.getMethod().getName() = "matches" and
ma.getMethod().getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and
sink.asExpr() = ma.getArgument(1)
or
ma.getMethod().getName() = "matches" and
ma.getMethod().getDeclaringType() instanceof TypeString and
sink.asExpr() = ma.getQualifier()
or
ma.getMethod().getName() = ["startsWith", "endsWith"] and
ma.getMethod().getDeclaringType() instanceof TypeString and
not ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "/" and
sink.asExpr() = ma.getQualifier()
)
}
}

module UnsafeURICheckFlow = TaintTracking::Global<UnsafeURICheckConfig>;

from UnsafeURICheckFlow::PathNode source, UnsafeURICheckFlow::PathNode sink
where UnsafeURICheckFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Unsafe URI check"
57 changes: 57 additions & 0 deletions java/src/security/CWE-094/GroovyCodeInjection.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @name Code Injection
* @description Code Injection may allow attackers to
* execute arbitrary code.
* @kind path-problem
* @problem.severity error
* @precision high
* @id githubsecuritylab/code-injection
* @tags security
* external/cwe/cwe-94
*/

import java
import semmle.code.java.dataflow.FlowSources
import GroovyCodeInjectionFlow::PathGraph

class ParseClassMethod extends Method {
ParseClassMethod() {
this.getDeclaringType()
.getASourceSupertype*()
.hasQualifiedName("groovy.lang", "GroovyClassLoader") and
this.hasName("parseClass") and
(
this.getParameterType(0).(RefType).hasQualifiedName("java.lang", "String") or
this.getParameterType(0).(RefType).hasQualifiedName("java.io", "InputStream") or
this.getParameterType(0).(RefType).hasQualifiedName("java.io", "Reader")
)
or
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("groovy.lang", "GroovyShell") and
(this.hasName("parse") or this.hasName("evaluate")) and
(
this.getParameterType(0).(RefType).hasQualifiedName("java.lang", "String") or
this.getParameterType(0).(RefType).hasQualifiedName("java.io", "Reader")
)
}
}

class GroovyCodeInjectionSink extends DataFlow::ExprNode {
GroovyCodeInjectionSink() {
exists(MethodAccess ma |
ma.getMethod() instanceof ParseClassMethod and
this.getExpr() = ma.getArgument(0)
)
}
}

private module GroovyCodeInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

predicate isSink(DataFlow::Node sink) { sink instanceof GroovyCodeInjectionSink }
}

module GroovyCodeInjectionFlow = TaintTracking::Global<GroovyCodeInjectionConfig>;

from GroovyCodeInjectionFlow::PathNode source, GroovyCodeInjectionFlow::PathNode sink
where GroovyCodeInjectionFlow::flowPath(source, sink)
select sink, source, sink, "Groovy code injection at $@.", sink.getNode(), "user input"
63 changes: 63 additions & 0 deletions java/src/security/CWE-094/RhinoScriptInjection.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @name Rhino Script Injection
* @kind path-problem
* @problem.severity error
* @precision high
* @id githubsecuritylab/rhino-script-injection
* @tags security
* external/cwe/cwe-094
*/

import java
import semmle.code.java.dataflow.FlowSources
import RhinoInjectionFlow::PathGraph

class RhinoContextType extends Class {
RhinoContextType() { hasQualifiedName("org.mozilla.javascript", "Context") }
}

class CompileMethod extends Method {
CompileMethod() {
this.getDeclaringType() instanceof RhinoContextType and
this.hasName(["compileFunction", "compileReader"])
}
}

class EvaluateMethod extends Method {
EvaluateMethod() {
this.getDeclaringType() instanceof RhinoContextType and
this.hasName(["evaluateString", "evaluateReader"])
}
}

class CompileScriptMethod extends Method {
CompileScriptMethod() {
this.getDeclaringType() instanceof RhinoContextType and
this.hasName("compileScript")
}
}

class RhinoInjectionSink extends DataFlow::ExprNode {
RhinoInjectionSink() {
exists(MethodAccess ma |
(ma.getMethod() instanceof CompileMethod or ma.getMethod() instanceof EvaluateMethod) and
this.getExpr() = ma.getArgument(1)
or
ma.getMethod() instanceof CompileScriptMethod and
this.getExpr() = ma.getArgument(0)
)
}
}

private module RhinoInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

predicate isSink(DataFlow::Node sink) { sink instanceof RhinoInjectionSink }
}

module RhinoInjectionFlow = TaintTracking::Global<RhinoInjectionConfig>;

from RhinoInjectionFlow::PathNode source, RhinoInjectionFlow::PathNode sink
where RhinoInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Rhino script injection from $@.", source.getNode(),
"this user input"
Loading