1
1
/**
2
- * @name Injection in JavaScript Engine
2
+ * @name Injection in Java Script Engine
3
3
* @description Evaluation of a user-controlled malicious JavaScript or Java expression in
4
- * JavaScript Engine may lead to remote code execution.
4
+ * Java Script Engine may lead to remote code execution.
5
5
* @kind path-problem
6
6
* @problem.severity error
7
7
* @precision high
@@ -14,31 +14,62 @@ import java
14
14
import semmle.code.java.dataflow.FlowSources
15
15
import DataFlow:: PathGraph
16
16
17
+ /** A method of ScriptEngine that allows code injection. */
17
18
class ScriptEngineMethod extends Method {
18
19
ScriptEngineMethod ( ) {
19
20
this .getDeclaringType ( ) .getASupertype * ( ) .hasQualifiedName ( "javax.script" , "ScriptEngine" ) and
20
21
this .hasName ( "eval" )
22
+ or
23
+ this .getDeclaringType ( ) .getASupertype * ( ) .hasQualifiedName ( "javax.script" , "Compilable" ) and
24
+ this .hasName ( "compile" )
25
+ or
26
+ this .getDeclaringType ( ) .getASupertype * ( ) .hasQualifiedName ( "javax.script" , "ScriptEngineFactory" ) and
27
+ this .hasName ( [ "getProgram" , "getMethodCallSyntax" ] )
21
28
}
22
29
}
23
30
24
- /** The context class `org.mozilla.javascript.Context` of Rhino JavaScript Engine. */
31
+ /** The context class `org.mozilla.javascript.Context` of Rhino Java Script Engine. */
25
32
class RhinoContext extends RefType {
26
33
RhinoContext ( ) { this .hasQualifiedName ( "org.mozilla.javascript" , "Context" ) }
27
34
}
28
35
29
- /**
30
- * A method that evaluates a Rhino expression.
31
- */
36
+ /** A method that evaluates a Rhino expression with `org.mozilla.javascript.Context`. */
32
37
class RhinoEvaluateExpressionMethod extends Method {
33
38
RhinoEvaluateExpressionMethod ( ) {
34
39
this .getDeclaringType ( ) .getAnAncestor * ( ) instanceof RhinoContext and
35
- (
36
- hasName ( "evaluateString" ) or
37
- hasName ( "evaluateReader" )
38
- )
40
+ this .hasName ( [
41
+ "evaluateString" , "evaluateReader" , "compileFunction" , "compileReader" , "compileString"
42
+ ] )
39
43
}
40
44
}
41
45
46
+ /**
47
+ * A method that compiles a Rhino expression with
48
+ * `org.mozilla.javascript.optimizer.ClassCompiler`.
49
+ */
50
+ class RhinoCompileClassMethod extends Method {
51
+ RhinoCompileClassMethod ( ) {
52
+ this .getDeclaringType ( )
53
+ .getASupertype * ( )
54
+ .hasQualifiedName ( "org.mozilla.javascript.optimizer" , "ClassCompiler" ) and
55
+ this .hasName ( "compileToClassFiles" )
56
+ }
57
+ }
58
+
59
+ /**
60
+ * A method that defines a Java class from a Rhino expression with
61
+ * `org.mozilla.javascript.GeneratedClassLoader`.
62
+ */
63
+ class RhinoDefineClassMethod extends Method {
64
+ RhinoDefineClassMethod ( ) {
65
+ this .getDeclaringType ( )
66
+ .getASupertype * ( )
67
+ .hasQualifiedName ( "org.mozilla.javascript" , "GeneratedClassLoader" ) and
68
+ this .hasName ( "defineClass" )
69
+ }
70
+ }
71
+
72
+ /** Holds if `ma` is a method access of `ScriptEngineMethod`. */
42
73
predicate scriptEngine ( MethodAccess ma , Expr sink ) {
43
74
exists ( Method m | m = ma .getMethod ( ) |
44
75
m instanceof ScriptEngineMethod and
@@ -47,11 +78,17 @@ predicate scriptEngine(MethodAccess ma, Expr sink) {
47
78
}
48
79
49
80
/**
50
- * Holds if `ma` has Rhino code injection vulnerabilities .
81
+ * Holds if a Rhino expression evaluation method has the code injection vulnerability .
51
82
*/
52
83
predicate evaluateRhinoExpression ( MethodAccess ma , Expr sink ) {
53
84
exists ( RhinoEvaluateExpressionMethod m | m = ma .getMethod ( ) |
54
- sink = ma .getArgument ( 1 ) and // The second argument is the JavaScript or Java input
85
+ (
86
+ sink = ma .getArgument ( 1 ) and // The second argument is the JavaScript or Java input
87
+ not ma .getMethod ( ) .getName ( ) = "compileReader"
88
+ or
89
+ sink = ma .getArgument ( 0 ) and // The first argument is the input reader
90
+ ma .getMethod ( ) .getName ( ) = "compileReader"
91
+ ) and
55
92
not exists ( MethodAccess ca |
56
93
(
57
94
ca .getMethod ( ) .hasName ( "initSafeStandardObjects" ) // safe mode
@@ -63,15 +100,34 @@ predicate evaluateRhinoExpression(MethodAccess ma, Expr sink) {
63
100
)
64
101
}
65
102
103
+ /**
104
+ * Holds if a Rhino expression compilation method has the code injection vulnerability.
105
+ */
106
+ predicate compileScript ( MethodAccess ma , Expr sink ) {
107
+ exists ( RhinoCompileClassMethod m | m = ma .getMethod ( ) | sink = ma .getArgument ( 0 ) )
108
+ }
109
+
110
+ /**
111
+ * Holds if a Rhino class loading method has the code injection vulnerability.
112
+ */
113
+ predicate defineClass ( MethodAccess ma , Expr sink ) {
114
+ exists ( RhinoDefineClassMethod m | m = ma .getMethod ( ) | sink = ma .getArgument ( 1 ) )
115
+ }
116
+
117
+ /** A sink of script injection. */
66
118
class ScriptInjectionSink extends DataFlow:: ExprNode {
67
119
ScriptInjectionSink ( ) {
68
120
scriptEngine ( _, this .getExpr ( ) ) or
69
- evaluateRhinoExpression ( _, this .getExpr ( ) )
121
+ evaluateRhinoExpression ( _, this .getExpr ( ) ) or
122
+ compileScript ( _, this .getExpr ( ) ) or
123
+ defineClass ( _, this .getExpr ( ) )
70
124
}
71
125
72
126
MethodAccess getMethodAccess ( ) {
73
127
scriptEngine ( result , this .getExpr ( ) ) or
74
- evaluateRhinoExpression ( result , this .getExpr ( ) )
128
+ evaluateRhinoExpression ( result , this .getExpr ( ) ) or
129
+ compileScript ( result , this .getExpr ( ) ) or
130
+ defineClass ( result , this .getExpr ( ) )
75
131
}
76
132
}
77
133
@@ -90,4 +146,4 @@ class ScriptInjectionConfiguration extends TaintTracking::Configuration {
90
146
from DataFlow:: PathNode source , DataFlow:: PathNode sink , ScriptInjectionConfiguration conf
91
147
where conf .hasFlowPath ( source , sink )
92
148
select sink .getNode ( ) .( ScriptInjectionSink ) .getMethodAccess ( ) , source , sink ,
93
- "JavaScript Engine evaluate $@." , source .getNode ( ) , "user input"
149
+ "Java Script Engine evaluate $@." , source .getNode ( ) , "user input"
0 commit comments