From 86f5b94657ef07f848bb95d51f489893907e31c7 Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Fri, 10 Dec 2021 16:07:03 +0100 Subject: Add a sanitizer for javax.naming.Context#lookup --- sanitizers/sanitizers.bzl | 3 +- .../jazzer/sanitizers/BUILD.bazel | 1 + .../jazzer/sanitizers/NamingContextLookup.kt | 98 ++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/NamingContextLookup.kt diff --git a/sanitizers/sanitizers.bzl b/sanitizers/sanitizers.bzl index 488d4bd8..8bdea7a9 100644 --- a/sanitizers/sanitizers.bzl +++ b/sanitizers/sanitizers.bzl @@ -16,8 +16,9 @@ _sanitizer_package_prefix = "com.code_intelligence.jazzer.sanitizers." _sanitizer_class_names = [ "Deserialization", - "ReflectiveCall", "ExpressionLanguageInjection", + "NamingContextLookup", + "ReflectiveCall", ] SANITIZER_CLASSES = [_sanitizer_package_prefix + class_name for class_name in _sanitizer_class_names] diff --git a/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/BUILD.bazel b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/BUILD.bazel index 5905c132..65480653 100644 --- a/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/BUILD.bazel +++ b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/BUILD.bazel @@ -5,6 +5,7 @@ kt_jvm_library( srcs = [ "Deserialization.kt", "ExpressionLanguageInjection.kt", + "NamingContextLookup.kt", "ReflectiveCall.kt", "Utils.kt", ], diff --git a/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/NamingContextLookup.kt b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/NamingContextLookup.kt new file mode 100644 index 00000000..7728e2d8 --- /dev/null +++ b/sanitizers/src/main/java/com/code_intelligence/jazzer/sanitizers/NamingContextLookup.kt @@ -0,0 +1,98 @@ +// 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.code_intelligence.jazzer.sanitizers + +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical +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 + +object NamingContextLookup { + + // The particular URL g.co is used here since it is: + // - short, which makes it easier for the fuzzer to incorporate into the input; + // - valid, which means that a `lookup` call on it could actually result in RCE; + // - highly reputable, which makes it very unlikely that it would ever host an actual exploit. + private const val LDAP_MARKER = "ldap://g.co/" + private const val RMI_MARKER = "rmi://g.co/" + + @MethodHooks( + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.Context", + targetMethod = "lookup", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialContext", + targetMethod = "lookup", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialDirContext", + targetMethod = "lookup", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialLdapContext", + targetMethod = "lookup", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.Context", + targetMethod = "lookupLink", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialContext", + targetMethod = "lookupLink", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialDirContext", + targetMethod = "lookupLink", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + MethodHook( + type = HookType.BEFORE, + targetClassName = "javax.naming.InitialLdapContext", + targetMethod = "lookupLink", + targetMethodDescriptor = "(Ljava/lang/String;)Ljava/lang/Object;", + ), + ) + @JvmStatic + fun lookupHook(method: MethodHandle?, thisObject: Any?, args: Array, hookId: Int) { + val name = args[0] as String + if (name.startsWith(RMI_MARKER) || name.startsWith(LDAP_MARKER)) { + Jazzer.reportFindingFromHook( + FuzzerSecurityIssueCritical( + """Remote JNDI Lookup +JNDI lookups with attacker-controlled remote URLs can, depending on the JDK +version, lead to remote code execution or the exfiltration of information.""" + ) + ) + } + Jazzer.guideTowardsEquality(name, RMI_MARKER, hookId) + Jazzer.guideTowardsEquality(name, LDAP_MARKER, 31 * hookId) + } +} -- cgit v1.2.3