|
13 | 13 | */ |
14 | 14 |
|
15 | 15 | import java |
16 | | -import semmle.code.java.dataflow.FlowSources |
17 | | -import semmle.code.java.dataflow.TaintTracking |
| 16 | +import semmle.code.java.security.RegexInjectionQuery |
18 | 17 | import DataFlow::PathGraph |
19 | 18 |
|
20 | | -/** |
21 | | - * A data flow sink for untrusted user input used to construct regular expressions. |
22 | | - */ |
23 | | -class RegexSink extends DataFlow::ExprNode { |
24 | | - RegexSink() { |
25 | | - exists(MethodAccess ma, Method m | m = ma.getMethod() | |
26 | | - ( |
27 | | - m.getDeclaringType() instanceof TypeString and |
28 | | - ( |
29 | | - ma.getArgument(0) = this.asExpr() and |
30 | | - // TODO: confirm if more/less than the below need to be handled |
31 | | - m.hasName(["matches", "split", "replaceFirst", "replaceAll"]) |
32 | | - ) |
33 | | - or |
34 | | - // TODO: review Java Pattern API |
35 | | - m.getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and |
36 | | - ( |
37 | | - ma.getArgument(0) = this.asExpr() and |
38 | | - // TODO: confirm if more/less than the below need to be handled |
39 | | - m.hasName(["compile", "matches"]) |
40 | | - ) |
41 | | - or |
42 | | - // TODO: read docs about regex APIs in Java |
43 | | - m.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "RegExUtils") and |
44 | | - ( |
45 | | - ma.getArgument(1) = this.asExpr() and |
46 | | - m.getParameterType(1) instanceof TypeString and |
47 | | - // TODO: confirm if more/less than the below need to be handled |
48 | | - m.hasName([ |
49 | | - "removeAll", "removeFirst", "removePattern", "replaceAll", "replaceFirst", |
50 | | - "replacePattern" |
51 | | - ]) |
52 | | - ) |
53 | | - ) |
54 | | - ) |
55 | | - } |
56 | | -} |
57 | | - |
58 | | -// TODO: is this abstract class needed? Are there pre-existing sanitizer classes that can be used instead? |
59 | | -abstract class Sanitizer extends DataFlow::ExprNode { } |
60 | | - |
61 | | -/** |
62 | | - * A call to a function whose name suggests that it escapes regular |
63 | | - * expression meta-characters. |
64 | | - */ |
65 | | -class RegExpSanitizationCall extends Sanitizer { |
66 | | - RegExpSanitizationCall() { |
67 | | - exists(string calleeName, string sanitize, string regexp | |
68 | | - calleeName = this.asExpr().(Call).getCallee().getName() and |
69 | | - sanitize = "(?:escape|saniti[sz]e)" and // TODO: confirm this is sufficient |
70 | | - regexp = "regexp?" // TODO: confirm this is sufficient |
71 | | - | |
72 | | - calleeName |
73 | | - .regexpMatch("(?i)(" + sanitize + ".*" + regexp + ".*)" + "|(" + regexp + ".*" + sanitize + |
74 | | - ".*)") // TODO: confirm this is sufficient |
75 | | - ) |
76 | | - } |
77 | | -} |
78 | | - |
79 | | -/** |
80 | | - * A taint-tracking configuration for untrusted user input used to construct regular expressions. |
81 | | - */ |
82 | | -class RegexInjectionConfiguration extends TaintTracking::Configuration { |
83 | | - RegexInjectionConfiguration() { this = "RegexInjectionConfiguration" } |
84 | | - |
85 | | - override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } |
86 | | - |
87 | | - override predicate isSink(DataFlow::Node sink) { sink instanceof RegexSink } |
88 | | - |
89 | | - override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } |
90 | | -} |
91 | | - |
92 | 19 | from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c |
93 | 20 | where c.hasFlowPath(source, sink) |
94 | 21 | select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", |
95 | 22 | source.getNode(), "user-provided value" |
96 | | -// from MethodAccess ma |
97 | | -// where |
98 | | -// // ma.getMethod().hasName("startsWith") and // graphhopper |
99 | | -// // ma.getFile().getBaseName() = "NavigateResource.java" // graphhopper |
100 | | -// // ma.getMethod().hasName("substring") and // jfinal |
101 | | -// // ma.getFile().getBaseName() = "FileManager.java" // jfinal |
102 | | -// ma.getMethod().hasName("startsWith") and // roller |
103 | | -// ma.getFile().getBaseName() = "PageServlet.java" // roller (or RegexUtil.java) |
104 | | -// ProteinArraySignificanceTestJSON.java or MockRKeys.java for cbioportal |
105 | | -// select ma, "method access" |
0 commit comments