diff options
author | Norbert Schneider <norbert.schneider@code-intelligence.com> | 2022-03-01 12:46:52 +0100 |
---|---|---|
committer | Norbert Schneider <mail@bertschneider.de> | 2022-03-03 15:07:33 +0100 |
commit | b2e8a9dca69227f2952ec80020f436789efae887 (patch) | |
tree | 0a0c04f767e5fb57c871dc90d66f6459d828ce7d /sanitizers | |
parent | e966b316e9c44817cad19a5bd59f42b790e33f86 (diff) | |
download | jazzer-api-b2e8a9dca69227f2952ec80020f436789efae887.tar.gz |
Hook ClassLoader methods
Hook all Class.forName and ClassLoader.loadClass methods. Some are
protected or even final but could be used by subclasses.
Diffstat (limited to 'sanitizers')
4 files changed, 64 insertions, 8 deletions
diff --git a/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ReflectiveCall.kt b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ReflectiveCall.kt index 3dfd3ca1..7072cc7d 100644 --- a/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ReflectiveCall.kt +++ b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/ReflectiveCall.kt @@ -17,18 +17,36 @@ package com.code_intelligence.jazzer.sanitizers import com.code_intelligence.jazzer.api.HookType import com.code_intelligence.jazzer.api.Jazzer import com.code_intelligence.jazzer.api.MethodHook +import com.code_intelligence.jazzer.api.MethodHooks import java.lang.invoke.MethodHandle /** - * Detects unsafe reflective calls that lead to attacker-controlled method calls. + * Detects unsafe calls that lead to attacker-controlled class loading. + * + * Guide the fuzzer to load honeypot class via [Class.forName] or [ClassLoader.loadClass]. */ @Suppress("unused_parameter", "unused") object ReflectiveCall { - @MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName") + @MethodHooks( + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Class;"), + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Class;"), + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/String;Z)Ljava/lang/Class;"), + ) @JvmStatic - fun classForNameHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { + fun loadClassHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { val className = args[0] as? String ?: return Jazzer.guideTowardsEquality(className, HONEYPOT_CLASS_NAME, hookId) } + + @MethodHooks( + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.Class", targetMethod = "forName", targetMethodDescriptor = "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;"), + MethodHook(type = HookType.BEFORE, targetClassName = "java.lang.ClassLoader", targetMethod = "loadClass", targetMethodDescriptor = "(Ljava/lang/Module;Ljava/lang/String;)Ljava/lang/Class;"), + ) + @JvmStatic + fun loadClassWithModuleHook(method: MethodHandle?, alwaysNull: Any?, args: Array<Any?>, hookId: Int) { + val className = args[1] as? String ?: return + Jazzer.guideTowardsEquality(className, HONEYPOT_CLASS_NAME, hookId) + } } diff --git a/sanitizers/src/test/java/com/example/BUILD.bazel b/sanitizers/src/test/java/com/example/BUILD.bazel index 7a6064fc..5279fe2e 100644 --- a/sanitizers/src/test/java/com/example/BUILD.bazel +++ b/sanitizers/src/test/java/com/example/BUILD.bazel @@ -78,6 +78,16 @@ java_fuzz_target_test( java_fuzz_target_test( name = "RegexCanonEqInjection", - srcs = ["RegexCanonEqInjection.java"], + srcs = [ + "RegexCanonEqInjection.java", + ], target_class = "com.example.RegexCanonEqInjection", ) + +java_fuzz_target_test( + name = "ClassLoaderLoadClass", + srcs = [ + "ClassLoaderLoadClass.java", + ], + target_class = "com.example.ClassLoaderLoadClass", +) diff --git a/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java b/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java new file mode 100644 index 00000000..c3fa47ac --- /dev/null +++ b/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java @@ -0,0 +1,30 @@ +// Copyright 2021 Code Intelligence GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.example; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import java.lang.reflect.InvocationTargetException; + +public class ClassLoaderLoadClass { + public static void fuzzerTestOneInput(FuzzedDataProvider data) throws InterruptedException { + String input = data.consumeRemainingAsAsciiString(); + try { + // create an instance to trigger class initialization + ClassLoaderLoadClass.class.getClassLoader().loadClass(input).getConstructor().newInstance(); + } catch (ClassNotFoundException | InvocationTargetException | InstantiationException + | IllegalAccessException | NoSuchMethodException ignored) { + } + } +} diff --git a/sanitizers/src/test/java/com/example/ReflectiveCall.java b/sanitizers/src/test/java/com/example/ReflectiveCall.java index 7f85e486..e6b62b45 100644 --- a/sanitizers/src/test/java/com/example/ReflectiveCall.java +++ b/sanitizers/src/test/java/com/example/ReflectiveCall.java @@ -15,7 +15,6 @@ package com.example; import com.code_intelligence.jazzer.api.FuzzedDataProvider; -import java.lang.reflect.InvocationTargetException; public class ReflectiveCall { public static void fuzzerTestOneInput(FuzzedDataProvider data) { @@ -23,9 +22,8 @@ public class ReflectiveCall { if (input.startsWith("@")) { String className = input.substring(1); try { - Class.forName(className).getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException - | NoSuchMethodException | ClassNotFoundException ignored) { + Class.forName(className); + } catch (ClassNotFoundException ignored) { } } } |