Skip to content

Commit f47d1ba

Browse files
author
Florian Gläßer
committed
feat: add jexl expression guidance hook
1 parent b510b50 commit f47d1ba

File tree

6 files changed

+71
-7
lines changed

6 files changed

+71
-7
lines changed

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ TEST_MAVEN_ARTIFACTS = [
8585
"jakarta.validation:jakarta.validation-api:3.0.2",
8686
"javax.persistence:javax.persistence-api:2.2",
8787
"junit:junit:4.13.2",
88+
"org.apache.commons:commons-jexl:2.1.1",
8889
"org.assertj:assertj-core:3.27.6",
8990
"org.jacoco:org.jacoco.core:0.8.14",
9091
"org.mockito:mockito-core:5.20.0",

maven_install.json

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
3-
"__INPUT_ARTIFACTS_HASH": 109726797,
4-
"__RESOLVED_ARTIFACTS_HASH": -368514076,
3+
"__INPUT_ARTIFACTS_HASH": 1855151744,
4+
"__RESOLVED_ARTIFACTS_HASH": 1869254491,
55
"conflict_resolution": {
66
"com.google.code.gson:gson:2.8.6": "com.google.code.gson:gson:2.8.9",
77
"com.google.j2objc:j2objc-annotations:2.8": "com.google.j2objc:j2objc-annotations:3.1",
@@ -166,9 +166,9 @@
166166
},
167167
"commons-logging:commons-logging": {
168168
"shasums": {
169-
"jar": "e94af49749384c11f5aa50e8d0f5fe679be771295b52030338d32843c980351e"
169+
"jar": "ce6f913cad1f0db3aad70186d65c5bc7ffcc9a99e3fe8e0b137312819f7c362f"
170170
},
171-
"version": "1.0.4"
171+
"version": "1.1.1"
172172
},
173173
"io.github.classgraph:classgraph": {
174174
"shasums": {
@@ -266,6 +266,12 @@
266266
},
267267
"version": "1.0-alpha2"
268268
},
269+
"org.apache.commons:commons-jexl": {
270+
"shasums": {
271+
"jar": "03c9a9fae5da78ce52c0bf24467cc37355b7e23196dff4839e2c0ff018a01306"
272+
},
273+
"version": "2.1.1"
274+
},
269275
"org.apache.commons:commons-lang3": {
270276
"shasums": {
271277
"jar": "4ee380259c068d1dbe9e84ab52186f2acd65de067ec09beff731fca1697fdb16"
@@ -733,6 +739,9 @@
733739
"junit:junit": [
734740
"org.hamcrest:hamcrest-core"
735741
],
742+
"org.apache.commons:commons-jexl": [
743+
"commons-logging:commons-logging"
744+
],
736745
"org.apache.commons:commons-text": [
737746
"org.apache.commons:commons-lang3"
738747
],
@@ -1478,6 +1487,14 @@
14781487
"org.apache.commons.imaging.internal",
14791488
"org.apache.commons.imaging.palette"
14801489
],
1490+
"org.apache.commons:commons-jexl": [
1491+
"org.apache.commons.jexl2",
1492+
"org.apache.commons.jexl2.internal",
1493+
"org.apache.commons.jexl2.internal.introspection",
1494+
"org.apache.commons.jexl2.introspection",
1495+
"org.apache.commons.jexl2.parser",
1496+
"org.apache.commons.jexl2.scripting"
1497+
],
14811498
"org.apache.commons:commons-lang3": [
14821499
"org.apache.commons.lang3",
14831500
"org.apache.commons.lang3.arch",
@@ -2722,6 +2739,7 @@
27222739
"net.jodah:typetools",
27232740
"net.sf.jopt-simple:jopt-simple",
27242741
"org.apache.commons:commons-imaging",
2742+
"org.apache.commons:commons-jexl",
27252743
"org.apache.commons:commons-lang3",
27262744
"org.apache.commons:commons-math3",
27272745
"org.apache.commons:commons-text",
@@ -2831,6 +2849,11 @@
28312849
"reactor.core.scheduler.ReactorBlockHoundIntegration"
28322850
]
28332851
},
2852+
"org.apache.commons:commons-jexl": {
2853+
"javax.script.ScriptEngineFactory": [
2854+
"org.apache.commons.jexl2.scripting.JexlScriptEngineFactory"
2855+
]
2856+
},
28342857
"org.apache.logging.log4j:log4j-api": {
28352858
"org.apache.logging.log4j.util.PropertySource": [
28362859
"org.apache.logging.log4j.util.EnvironmentPropertySource",

sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ExpressionLanguageInjection.kt

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ object ExpressionLanguageInjection {
3333
private const val EXPRESSION_LANGUAGE_ATTACK =
3434
"\${Byte.class.forName(\"$HONEYPOT_CLASS_NAME\").getMethod(\"el\").invoke(null)}"
3535
private const val SPRING_EXPRESSION_LANGUAGE_ATTACK = "T($HONEYPOT_CLASS_NAME).el()"
36-
private const val ELPROCESSOR_LANGUAGE_ATTACK =
36+
private const val ELPROCESSOR_JEXL_LANGUAGE_ATTACK =
3737
"\"\".getClass().forName(\"$HONEYPOT_CLASS_NAME\").getMethod(\"el\").invoke(null)"
3838

3939
init {
@@ -43,7 +43,7 @@ object ExpressionLanguageInjection {
4343
require(SPRING_EXPRESSION_LANGUAGE_ATTACK.length <= 64) {
4444
"Expression language exploit must fit in a table of recent compares entry (64 bytes)"
4545
}
46-
require(ELPROCESSOR_LANGUAGE_ATTACK.length <= 64) {
46+
require(ELPROCESSOR_JEXL_LANGUAGE_ATTACK.length <= 64) {
4747
"Expression language exploit must fit in a table of recent compares entry (64 bytes)"
4848
}
4949
}
@@ -108,7 +108,7 @@ object ExpressionLanguageInjection {
108108
return
109109
}
110110
val message = arguments[0] as String
111-
Jazzer.guideTowardsContainment(message, ELPROCESSOR_LANGUAGE_ATTACK, hookId)
111+
Jazzer.guideTowardsContainment(message, ELPROCESSOR_JEXL_LANGUAGE_ATTACK, hookId)
112112
}
113113

114114
// With default configurations the argument to
@@ -171,4 +171,28 @@ object ExpressionLanguageInjection {
171171
val expr = arguments[0] as? String ?: return
172172
Jazzer.guideTowardsContainment(expr, SPRING_EXPRESSION_LANGUAGE_ATTACK, hookId)
173173
}
174+
175+
@MethodHooks(
176+
MethodHook(
177+
type = HookType.BEFORE,
178+
targetClassName = "org.apache.commons.jexl2.JexlEngine",
179+
targetMethod = "createExpression",
180+
),
181+
MethodHook(
182+
type = HookType.BEFORE,
183+
targetClassName = "org.apache.commons.jexl2.JexlEngine",
184+
targetMethod = "createScript",
185+
),
186+
)
187+
@JvmStatic
188+
fun hookJexlExpression(
189+
method: MethodHandle?,
190+
thisObject: Any?,
191+
arguments: Array<Any>,
192+
hookId: Int,
193+
) {
194+
if (arguments.isEmpty()) return
195+
val expr = arguments[0] as? String ?: return
196+
Jazzer.guideTowardsContainment(expr, ELPROCESSOR_JEXL_LANGUAGE_ATTACK, hookId)
197+
}
174198
}

sanitizers/src/test/java/com/code_intelligence/jazzer/sanitizers/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ java_junit5_test(
2424
"@maven//:javax_el_javax_el_api",
2525
"@maven//:javax_persistence_javax_persistence_api",
2626
"@maven//:javax_validation_validation_api",
27+
"@maven//:org_apache_commons_commons_jexl",
2728
"@maven//:org_junit_jupiter_junit_jupiter_api",
2829
"@maven//:org_junit_jupiter_junit_jupiter_params",
2930
"@maven//:org_springframework_cloud_spring_cloud_function_context",

sanitizers/src/test/java/com/example/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,13 @@ java_fuzz_target_test(
6464
"//sanitizers/src/test/java/com/example/el:ExpressionLanguageExample",
6565
"@maven//:javax_el_javax_el_api",
6666
"@maven//:javax_validation_validation_api",
67+
"@maven//:org_apache_commons_commons_jexl",
6768
"@maven//:org_junit_jupiter_junit_jupiter_api",
6869
],
6970
) for method in [
7071
"fuzzValidator",
7172
"fuzzEval",
73+
"fuzzJexlExpression",
7274
]]
7375

7476
java_fuzz_target_test(

sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javax.el.ELProcessor;
2626
import javax.validation.Validation;
2727
import javax.validation.Validator;
28+
import org.apache.commons.jexl2.*;
2829
import org.junit.jupiter.api.BeforeEach;
2930

3031
public class ExpressionLanguageInjection {
@@ -53,4 +54,16 @@ void fuzzEval(@NotNull String data) {
5354
| ArithmeticException ignored) {
5455
}
5556
}
57+
58+
@FuzzTest
59+
void fuzzJexlExpression(@NotNull String data) {
60+
JexlEngine jexl = new JexlEngine();
61+
JexlContext context = new MapContext();
62+
63+
try {
64+
Expression expr = jexl.createExpression(data);
65+
expr.evaluate(context);
66+
} catch (JexlException | StringIndexOutOfBoundsException ignored) {
67+
}
68+
}
5669
}

0 commit comments

Comments
 (0)