Skip to content

Commit f104955

Browse files
committed
feat: add MVEL guidance hook
Hook to guide inputs to MVEL interpreter towards performing OS commands which are detected by the OS command injection sanitizer.
1 parent 9094131 commit f104955

File tree

6 files changed

+110
-3
lines changed

6 files changed

+110
-3
lines changed

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ TEST_MAVEN_ARTIFACTS = [
8989
"org.assertj:assertj-core:3.27.6",
9090
"org.jacoco:org.jacoco.core:0.8.14",
9191
"org.mockito:mockito-core:5.20.0",
92+
"org.mvel:mvel2:2.5.2.Final",
9293
"org.openjdk.jmh:jmh-core:1.37",
9394
"org.openjdk.jmh:jmh-generator-annprocess:1.37",
9495
]

maven_install.json

Lines changed: 42 additions & 2 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": -1638807165,
4-
"__RESOLVED_ARTIFACTS_HASH": -1440417829,
3+
"__INPUT_ARTIFACTS_HASH": 1624596153,
4+
"__RESOLVED_ARTIFACTS_HASH": 1478602772,
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",
@@ -536,6 +536,12 @@
536536
},
537537
"version": "5.20.0"
538538
},
539+
"org.mvel:mvel2": {
540+
"shasums": {
541+
"jar": "77d14116dfad5259aa3c21e177fb5455b2c86f4873f49828fdb6000ebe77660d"
542+
},
543+
"version": "2.5.2.Final"
544+
},
539545
"org.objenesis:objenesis": {
540546
"shasums": {
541547
"jar": "02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb"
@@ -2164,6 +2170,34 @@
21642170
"org.mockito.stubbing",
21652171
"org.mockito.verification"
21662172
],
2173+
"org.mvel:mvel2": [
2174+
"org.mvel2",
2175+
"org.mvel2.asm",
2176+
"org.mvel2.asm.signature",
2177+
"org.mvel2.ast",
2178+
"org.mvel2.compiler",
2179+
"org.mvel2.conversion",
2180+
"org.mvel2.debug",
2181+
"org.mvel2.integration",
2182+
"org.mvel2.integration.impl",
2183+
"org.mvel2.jsr223",
2184+
"org.mvel2.math",
2185+
"org.mvel2.optimizers",
2186+
"org.mvel2.optimizers.dynamic",
2187+
"org.mvel2.optimizers.impl.asm",
2188+
"org.mvel2.optimizers.impl.refl",
2189+
"org.mvel2.optimizers.impl.refl.collection",
2190+
"org.mvel2.optimizers.impl.refl.nodes",
2191+
"org.mvel2.sh",
2192+
"org.mvel2.sh.command.basic",
2193+
"org.mvel2.sh.command.file",
2194+
"org.mvel2.sh.text",
2195+
"org.mvel2.templates",
2196+
"org.mvel2.templates.res",
2197+
"org.mvel2.templates.util",
2198+
"org.mvel2.templates.util.io",
2199+
"org.mvel2.util"
2200+
],
21672201
"org.objenesis:objenesis": [
21682202
"org.objenesis",
21692203
"org.objenesis.instantiator",
@@ -2784,6 +2818,7 @@
27842818
"org.junit.platform:junit-platform-reporting",
27852819
"org.junit.platform:junit-platform-testkit",
27862820
"org.mockito:mockito-core",
2821+
"org.mvel:mvel2",
27872822
"org.objenesis:objenesis",
27882823
"org.openjdk.jmh:jmh-core",
27892824
"org.openjdk.jmh:jmh-generator-annprocess",
@@ -2945,6 +2980,11 @@
29452980
"org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener"
29462981
]
29472982
},
2983+
"org.mvel:mvel2": {
2984+
"javax.script.ScriptEngineFactory": [
2985+
"org.mvel2.jsr223.MvelScriptEngineFactory"
2986+
]
2987+
},
29482988
"org.openjdk.jmh:jmh-generator-annprocess": {
29492989
"javax.annotation.processing.Processor": [
29502990
"org.openjdk.jmh.generators.BenchmarkProcessor"

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ object ExpressionLanguageInjection {
3535
private const val SPRING_EXPRESSION_LANGUAGE_ATTACK = "T($HONEYPOT_CLASS_NAME).el()"
3636
private const val ELPROCESSOR_JEXL_LANGUAGE_ATTACK =
3737
"\"\".getClass().forName(\"$HONEYPOT_CLASS_NAME\").getMethod(\"el\").invoke(null)"
38+
private const val MVEL_ATTACK = "Runtime.getRuntime().exec(\"jazze\")"
3839

3940
init {
4041
require(EXPRESSION_LANGUAGE_ATTACK.length <= 64) {
@@ -46,6 +47,9 @@ object ExpressionLanguageInjection {
4647
require(ELPROCESSOR_JEXL_LANGUAGE_ATTACK.length <= 64) {
4748
"Expression language exploit must fit in a table of recent compares entry (64 bytes)"
4849
}
50+
require(MVEL_ATTACK.length <= 64) {
51+
"MVEL exploit must fit in a table of recent compares entry (64 bytes)"
52+
}
4953
}
5054

5155
@MethodHooks(
@@ -193,4 +197,51 @@ object ExpressionLanguageInjection {
193197
val expr = arguments[0] as? CharSequence ?: return
194198
Jazzer.guideTowardsContainment(expr.toString(), ELPROCESSOR_JEXL_LANGUAGE_ATTACK, hookId)
195199
}
200+
201+
@MethodHook(
202+
type = HookType.BEFORE,
203+
targetClassName = "org.mvel2.MVEL",
204+
targetMethod = "eval",
205+
)
206+
@MethodHook(
207+
type = HookType.BEFORE,
208+
targetClassName = "org.mvel2.MVEL",
209+
targetMethod = "evalToString",
210+
)
211+
@MethodHook(
212+
type = HookType.BEFORE,
213+
targetClassName = "org.mvel2.MVEL",
214+
targetMethod = "evalToBoolean",
215+
)
216+
@MethodHook(
217+
type = HookType.BEFORE,
218+
targetClassName = "org.mvel2.MVEL",
219+
targetMethod = "compileExpression",
220+
)
221+
@MethodHook(
222+
type = HookType.BEFORE,
223+
targetClassName = "org.mvel2.MVEL",
224+
targetMethod = "compileGetExpression",
225+
)
226+
@MethodHook(
227+
type = HookType.BEFORE,
228+
targetClassName = "org.mvel2.MVEL",
229+
targetMethod = "compileSetExpression",
230+
)
231+
@JvmStatic
232+
fun mvelEval(
233+
method: MethodHandle?,
234+
thisObject: Any?,
235+
arguments: Array<Any>,
236+
hookId: Int,
237+
) {
238+
if (arguments.isEmpty()) return
239+
val message =
240+
when (val arg0 = arguments[0]) {
241+
is String -> arg0
242+
is CharArray -> String(arg0)
243+
else -> throw IllegalArgumentException("Unexpected type for arguments[0] in ExpressionLanguageInjection hook")
244+
}
245+
Jazzer.guideTowardsContainment(message, MVEL_ATTACK, hookId)
246+
}
196247
}

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
@@ -27,6 +27,7 @@ java_junit5_test(
2727
"@maven//:org_apache_commons_commons_jexl",
2828
"@maven//:org_junit_jupiter_junit_jupiter_api",
2929
"@maven//:org_junit_jupiter_junit_jupiter_params",
30+
"@maven//:org_mvel_mvel2",
3031
"@maven//:org_springframework_cloud_spring_cloud_function_context",
3132
"@maven//:org_springframework_cloud_spring_cloud_function_core",
3233
],

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ java_fuzz_target_test(
5050
srcs = [
5151
"ExpressionLanguageInjection.java",
5252
],
53-
allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh"],
53+
allowed_findings = [
54+
"com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
55+
"com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical",
56+
],
5457
tags = ["dangerous"],
5558
target_class = "com.example.ExpressionLanguageInjection",
5659
target_method = method,
@@ -66,11 +69,13 @@ java_fuzz_target_test(
6669
"@maven//:javax_validation_validation_api",
6770
"@maven//:org_apache_commons_commons_jexl",
6871
"@maven//:org_junit_jupiter_junit_jupiter_api",
72+
"@maven//:org_mvel_mvel2",
6973
],
7074
) for method in [
7175
"fuzzValidator",
7276
"fuzzEval",
7377
"fuzzJexlExpression",
78+
"fuzzMVELExpression",
7479
]]
7580

7681
java_fuzz_target_test(

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.commons.jexl2.JexlException;
3232
import org.apache.commons.jexl2.MapContext;
3333
import org.junit.jupiter.api.BeforeEach;
34+
import org.mvel2.MVEL;
3435

3536
public class ExpressionLanguageInjection {
3637
private static final Validator validator =
@@ -70,4 +71,12 @@ void fuzzJexlExpression(@NotNull String data) {
7071
} catch (JexlException | StringIndexOutOfBoundsException ignored) {
7172
}
7273
}
74+
75+
@FuzzTest
76+
void fuzzMVELExpression(@NotNull String data) {
77+
try {
78+
MVEL.executeExpression(MVEL.compileExpression(data));
79+
} catch (Throwable ignored) {
80+
}
81+
}
7382
}

0 commit comments

Comments
 (0)