aboutsummaryrefslogtreecommitdiff
path: root/sanitizers/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'sanitizers/src/test')
-rw-r--r--sanitizers/src/test/java/com/example/BUILD.bazel159
-rw-r--r--sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java8
-rw-r--r--sanitizers/src/test/java/com/example/DisabledHooksTest.java110
-rw-r--r--sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java31
-rw-r--r--sanitizers/src/test/java/com/example/LdapDnInjection.java15
-rw-r--r--sanitizers/src/test/java/com/example/LdapSearchInjection.java15
-rw-r--r--sanitizers/src/test/java/com/example/ReflectiveCall.java4
-rw-r--r--sanitizers/src/test/java/com/example/ScriptEngineInjection.java171
-rw-r--r--sanitizers/src/test/java/com/example/SsrfHttpClient.java39
-rw-r--r--sanitizers/src/test/java/com/example/SsrfSocketConnect.java (renamed from sanitizers/src/test/java/com/example/ldap/MockInitialContextFactory.java)19
-rw-r--r--sanitizers/src/test/java/com/example/SsrfSocketConnectToHost.java46
-rw-r--r--sanitizers/src/test/java/com/example/SsrfUrlConnection.java33
-rw-r--r--sanitizers/src/test/java/com/example/StackOverflowRegexInjection.java51
-rw-r--r--sanitizers/src/test/java/com/example/XPathInjection.java53
-rw-r--r--sanitizers/src/test/java/com/example/el/BUILD.bazel15
-rw-r--r--sanitizers/src/test/java/com/example/el/InsecureEmailValidator.java (renamed from sanitizers/src/test/java/com/example/InsecureEmailValidator.java)2
-rw-r--r--sanitizers/src/test/java/com/example/el/UserData.java41
17 files changed, 740 insertions, 72 deletions
diff --git a/sanitizers/src/test/java/com/example/BUILD.bazel b/sanitizers/src/test/java/com/example/BUILD.bazel
index 5d2e1ca5..ea0a7f82 100644
--- a/sanitizers/src/test/java/com/example/BUILD.bazel
+++ b/sanitizers/src/test/java/com/example/BUILD.bazel
@@ -6,7 +6,10 @@ java_fuzz_target_test(
srcs = [
"ObjectInputStreamDeserialization.java",
],
- expected_findings = ["java.lang.ExceptionInInitializerError"],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
+ "java.lang.ExceptionInInitializerError",
+ ],
target_class = "com.example.ObjectInputStreamDeserialization",
)
@@ -15,7 +18,10 @@ java_fuzz_target_test(
srcs = [
"ReflectiveCall.java",
],
- expected_findings = ["java.lang.ExceptionInInitializerError"],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
+ "java.lang.ExceptionInInitializerError",
+ ],
target_class = "com.example.ReflectiveCall",
)
@@ -24,25 +30,30 @@ java_fuzz_target_test(
srcs = [
"LibraryLoad.java",
],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
+ ],
target_class = "com.example.LibraryLoad",
# loading of native libraries is very slow on macos,
# especially using Java 17
target_compatible_with = SKIP_ON_MACOS,
+ # The reproducer doesn't contain the sanitizer and thus runs into an ordinary ignored
+ # UnsatisfiedLinkError.
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
name = "ExpressionLanguageInjection",
srcs = [
"ExpressionLanguageInjection.java",
- "InsecureEmailValidator.java",
],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh"],
target_class = "com.example.ExpressionLanguageInjection",
+ # The reproducer can't find jaz.Zer and thus doesn't crash.
+ verify_crash_reproducer = False,
deps = [
- "@maven//:javax_el_javax_el_api",
+ "//sanitizers/src/test/java/com/example/el:ExpressionLanguageExample",
"@maven//:javax_validation_validation_api",
- "@maven//:javax_xml_bind_jaxb_api",
- "@maven//:org_glassfish_javax_el",
- "@maven//:org_hibernate_hibernate_validator",
],
)
@@ -51,7 +62,9 @@ java_fuzz_target_test(
srcs = [
"OsCommandInjectionProcessBuilder.java",
],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical"],
target_class = "com.example.OsCommandInjectionProcessBuilder",
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
@@ -59,17 +72,22 @@ java_fuzz_target_test(
srcs = [
"OsCommandInjectionRuntimeExec.java",
],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical"],
target_class = "com.example.OsCommandInjectionRuntimeExec",
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
name = "LdapSearchInjection",
srcs = [
"LdapSearchInjection.java",
- "ldap/MockInitialContextFactory.java",
"ldap/MockLdapContext.java",
],
- expected_findings = ["javax.naming.directory.InvalidSearchFilterException"],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical",
+ # The crashing input encoded by the replayer does not have valid syntax, but no hook.
+ "javax.naming.directory.InvalidSearchFilterException",
+ ],
target_class = "com.example.LdapSearchInjection",
deps = [
"@maven//:com_unboundid_unboundid_ldapsdk",
@@ -80,10 +98,13 @@ java_fuzz_target_test(
name = "LdapDnInjection",
srcs = [
"LdapDnInjection.java",
- "ldap/MockInitialContextFactory.java",
"ldap/MockLdapContext.java",
],
- expected_findings = ["javax.naming.NamingException"],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical",
+ # The crashing input encoded by the reproducer does not have valid syntax, but no hook.
+ "javax.naming.NamingException",
+ ],
target_class = "com.example.LdapDnInjection",
deps = [
"@maven//:com_unboundid_unboundid_ldapsdk",
@@ -93,7 +114,9 @@ java_fuzz_target_test(
java_fuzz_target_test(
name = "RegexInsecureQuoteInjection",
srcs = ["RegexInsecureQuoteInjection.java"],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow"],
target_class = "com.example.RegexInsecureQuoteInjection",
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
@@ -101,7 +124,9 @@ java_fuzz_target_test(
srcs = [
"RegexCanonEqInjection.java",
],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow"],
target_class = "com.example.RegexCanonEqInjection",
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
@@ -109,19 +134,40 @@ java_fuzz_target_test(
srcs = [
"ClassLoaderLoadClass.java",
],
- expected_findings = ["java.lang.ExceptionInInitializerError"],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
+ # Reproducer does not find the honeypot library and doesn't have the hook.
+ "java.lang.ExceptionInInitializerError",
+ ],
target_class = "com.example.ClassLoaderLoadClass",
)
java_fuzz_target_test(
name = "RegexRoadblocks",
srcs = ["RegexRoadblocks.java"],
+ allowed_findings = ["com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow"],
fuzzer_args = [
# Limit the number of runs to verify that the regex roadblocks are
# cleared quickly.
"-runs=22000",
],
target_class = "com.example.RegexRoadblocks",
+ verify_crash_reproducer = False,
+)
+
+# Catching StackOverflowErrors doesn't work reliably across all systems and JDK versions.
+# It may lead to a native crash before we can handle the exception in Java, therefore the
+# test is set to manual execution.
+java_fuzz_target_test(
+ name = "StackOverflowRegexInjection",
+ srcs = ["StackOverflowRegexInjection.java"],
+ allowed_findings = ["java.util.regex.PatternSyntaxException"],
+ fuzzer_args = [
+ "-runs=1",
+ ],
+ tags = ["manual"],
+ target_class = "com.example.StackOverflowRegexInjection",
+ verify_crash_reproducer = False,
)
java_fuzz_target_test(
@@ -129,7 +175,7 @@ java_fuzz_target_test(
srcs = [
"SqlInjection.java",
],
- expected_findings = [
+ allowed_findings = [
"com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
"org.h2.jdbc.JdbcSQLSyntaxErrorException",
],
@@ -138,3 +184,90 @@ java_fuzz_target_test(
"@maven//:com_h2database_h2",
],
)
+
+java_test(
+ name = "DisabledHooksTest",
+ size = "small",
+ srcs = [
+ "DisabledHooksTest.java",
+ ],
+ test_class = "com.example.DisabledHooksTest",
+ deps = [
+ "//src/main/java/com/code_intelligence/jazzer/api",
+ "//src/main/java/com/code_intelligence/jazzer/api:hooks",
+ ],
+)
+
+java_fuzz_target_test(
+ name = "XPathInjection",
+ srcs = [
+ "XPathInjection.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh",
+ ],
+ target_class = "com.example.XPathInjection",
+ # Fuzz target catches the syntax exception triggered by the reproducer without the sanitizer.
+ verify_crash_reproducer = False,
+)
+
+java_fuzz_target_test(
+ name = "SsrfSocketConnect",
+ srcs = [
+ "SsrfSocketConnect.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium",
+ ],
+ target_class = "com.example.SsrfSocketConnect",
+ verify_crash_reproducer = False,
+)
+
+java_fuzz_target_test(
+ name = "SsrfSocketConnectToHost",
+ srcs = [
+ "SsrfSocketConnectToHost.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium",
+ ],
+ target_class = "com.example.SsrfSocketConnectToHost",
+ verify_crash_reproducer = False,
+)
+
+java_fuzz_target_test(
+ name = "SsrfUrlConnection",
+ srcs = [
+ "SsrfUrlConnection.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium",
+ ],
+ target_class = "com.example.SsrfUrlConnection",
+ verify_crash_reproducer = False,
+)
+
+java_fuzz_target_test(
+ name = "SsrfHttpClient",
+ srcs = [
+ "SsrfHttpClient.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium",
+ ],
+ tags = ["no-jdk8"],
+ target_class = "com.example.SsrfHttpClient",
+ verify_crash_reproducer = False,
+)
+
+java_fuzz_target_test(
+ name = "ScriptEngineInjection",
+ srcs = [
+ "ScriptEngineInjection.java",
+ ],
+ allowed_findings = [
+ "com.code_intelligence.jazzer.api.FuzzerSecurityIssueCritical",
+ ],
+ target_class = "com.example.ScriptEngineInjection",
+ verify_crash_reproducer = False,
+)
diff --git a/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java b/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java
index c3fa47ac..207f29cd 100644
--- a/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java
+++ b/sanitizers/src/test/java/com/example/ClassLoaderLoadClass.java
@@ -22,9 +22,11 @@ public class ClassLoaderLoadClass {
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) {
+ ClassLoaderLoadClass.class.getClassLoader().loadClass(input).newInstance();
+ // TODO(khaled): this fails to reproduce the finding. It seems that this is related to not
+ // throwing a hard-to-catch error when not running in the fuzzing mode.
+ // ClassLoaderLoadClass.class.getClassLoader().loadClass(input).getConstructor().newInstance();
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ignored) {
}
}
}
diff --git a/sanitizers/src/test/java/com/example/DisabledHooksTest.java b/sanitizers/src/test/java/com/example/DisabledHooksTest.java
new file mode 100644
index 00000000..763cd637
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/DisabledHooksTest.java
@@ -0,0 +1,110 @@
+// Copyright 2022 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.FuzzerSecurityIssueHigh;
+import java.io.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Base64;
+import org.junit.After;
+import org.junit.Test;
+
+public class DisabledHooksTest {
+ public static void triggerReflectiveCallSanitizer() {
+ try {
+ Class.forName("jaz.Zer").newInstance();
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ignored) {
+ }
+ }
+
+ public static void triggerExpressionLanguageInjectionSanitizer() throws Throwable {
+ try {
+ Class.forName("jaz.Zer").getMethod("el").invoke(null);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException ignore) {
+ }
+ }
+
+ public static void triggerDeserializationSanitizer() {
+ byte[] data =
+ Base64.getDecoder().decode("rO0ABXNyAAdqYXouWmVyAAAAAAAAACoCAAFCAAlzYW5pdGl6ZXJ4cAEK");
+ try {
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
+ System.out.println(ois.readObject());
+ } catch (IOException | ClassNotFoundException ignore) {
+ }
+ }
+
+ @After
+ public void resetDisabledHooksProperty() {
+ System.clearProperty("jazzer.disabled_hooks");
+ }
+
+ @Test(expected = FuzzerSecurityIssueHigh.class)
+ public void enableReflectiveCallSanitizer() {
+ triggerReflectiveCallSanitizer();
+ }
+
+ @Test(expected = FuzzerSecurityIssueHigh.class)
+ public void enableDeserializationSanitizer() {
+ triggerDeserializationSanitizer();
+ }
+
+ @Test(expected = FuzzerSecurityIssueHigh.class)
+ public void enableExpressionLanguageInjectionSanitizer() throws Throwable {
+ triggerExpressionLanguageInjectionSanitizer();
+ }
+
+ @Test
+ public void disableReflectiveCallSanitizer() {
+ System.setProperty(
+ "jazzer.disabled_hooks", "com.code_intelligence.jazzer.sanitizers.ReflectiveCall");
+ triggerReflectiveCallSanitizer();
+ }
+
+ @Test
+ public void disableDeserializationSanitizer() {
+ System.setProperty(
+ "jazzer.disabled_hooks", "com.code_intelligence.jazzer.sanitizers.Deserialization");
+ triggerDeserializationSanitizer();
+ }
+
+ @Test
+ public void disableExpressionLanguageSanitizer() throws Throwable {
+ System.setProperty("jazzer.disabled_hooks",
+ "com.code_intelligence.jazzer.sanitizers.ExpressionLanguageInjection");
+ triggerExpressionLanguageInjectionSanitizer();
+ }
+
+ @Test(expected = FuzzerSecurityIssueHigh.class)
+ public void disableReflectiveCallAndEnableDeserialization() {
+ System.setProperty(
+ "jazzer.disabled_hooks", "com.code_intelligence.jazzer.sanitizers.ReflectiveCall");
+ triggerReflectiveCallSanitizer();
+ triggerDeserializationSanitizer();
+ }
+
+ @Test
+ public void disableAllSanitizers() throws Throwable {
+ System.setProperty("jazzer.disabled_hooks",
+ "com.code_intelligence.jazzer.sanitizers.ReflectiveCall,"
+ + "com.code_intelligence.jazzer.sanitizers.Deserialization,"
+ + "com.code_intelligence.jazzer.sanitizers.ExpressionLanguageInjection");
+ triggerReflectiveCallSanitizer();
+ triggerExpressionLanguageInjectionSanitizer();
+ triggerDeserializationSanitizer();
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java b/sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java
index e26a9117..7d0192ab 100644
--- a/sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java
+++ b/sanitizers/src/test/java/com/example/ExpressionLanguageInjection.java
@@ -15,33 +15,20 @@
package com.example;
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.validation.*;
-
-class UserData {
- public UserData(String email) {
- this.email = email;
- }
-
- @ValidEmailConstraint private String email;
-}
-
-@Constraint(validatedBy = InsecureEmailValidator.class)
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@interface ValidEmailConstraint {
- String message() default "Invalid email address";
- Class<?>[] groups() default {};
- Class<? extends Payload>[] payload() default {};
-}
+import com.example.el.UserData;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import javax.validation.Validation;
+import javax.validation.Validator;
public class ExpressionLanguageInjection {
final private static Validator validator =
Validation.buildDefaultValidatorFactory().getValidator();
+ public static void fuzzerInitialize() {
+ LogManager.getLogManager().getLogger("").setLevel(Level.SEVERE);
+ }
+
public static void fuzzerTestOneInput(FuzzedDataProvider data) {
UserData uncheckedUserData = new UserData(data.consumeRemainingAsString());
validator.validate(uncheckedUserData);
diff --git a/sanitizers/src/test/java/com/example/LdapDnInjection.java b/sanitizers/src/test/java/com/example/LdapDnInjection.java
index 911db1dc..2fdf4a0c 100644
--- a/sanitizers/src/test/java/com/example/LdapDnInjection.java
+++ b/sanitizers/src/test/java/com/example/LdapDnInjection.java
@@ -15,20 +15,13 @@
package com.example;
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
-import java.util.Hashtable;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.directory.InitialDirContext;
+import com.example.ldap.MockLdapContext;
+import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
+@SuppressWarnings("BanJNDI")
public class LdapDnInjection {
- private static InitialDirContext ctx;
-
- public static void fuzzerInitialize() throws NamingException {
- Hashtable<String, String> env = new Hashtable<>();
- env.put(Context.INITIAL_CONTEXT_FACTORY, "com.example.ldap.MockInitialContextFactory");
- ctx = new InitialDirContext(env);
- }
+ private static final DirContext ctx = new MockLdapContext();
public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) throws Exception {
// Externally provided DN input needs to be escaped properly
diff --git a/sanitizers/src/test/java/com/example/LdapSearchInjection.java b/sanitizers/src/test/java/com/example/LdapSearchInjection.java
index b3dfee74..4ac84931 100644
--- a/sanitizers/src/test/java/com/example/LdapSearchInjection.java
+++ b/sanitizers/src/test/java/com/example/LdapSearchInjection.java
@@ -15,20 +15,13 @@
package com.example;
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
-import java.util.Hashtable;
-import javax.naming.Context;
-import javax.naming.NamingException;
+import com.example.ldap.MockLdapContext;
import javax.naming.directory.SearchControls;
-import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+@SuppressWarnings("BanJNDI")
public class LdapSearchInjection {
- private static InitialLdapContext ctx;
-
- public static void fuzzerInitialize() throws NamingException {
- Hashtable<String, String> env = new Hashtable<>();
- env.put(Context.INITIAL_CONTEXT_FACTORY, "com.example.ldap.MockInitialContextFactory");
- ctx = new InitialLdapContext(env, null);
- }
+ private static final LdapContext ctx = new MockLdapContext();
public static void fuzzerTestOneInput(FuzzedDataProvider fuzzedDataProvider) throws Exception {
// Externally provided LDAP query input needs to be escaped properly
diff --git a/sanitizers/src/test/java/com/example/ReflectiveCall.java b/sanitizers/src/test/java/com/example/ReflectiveCall.java
index e6b62b45..d7b3e46c 100644
--- a/sanitizers/src/test/java/com/example/ReflectiveCall.java
+++ b/sanitizers/src/test/java/com/example/ReflectiveCall.java
@@ -22,8 +22,8 @@ public class ReflectiveCall {
if (input.startsWith("@")) {
String className = input.substring(1);
try {
- Class.forName(className);
- } catch (ClassNotFoundException ignored) {
+ Class.forName(className).newInstance();
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ignored) {
}
}
}
diff --git a/sanitizers/src/test/java/com/example/ScriptEngineInjection.java b/sanitizers/src/test/java/com/example/ScriptEngineInjection.java
new file mode 100644
index 00000000..631b7ab8
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/ScriptEngineInjection.java
@@ -0,0 +1,171 @@
+// Copyright 2023 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.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.util.List;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class ScriptEngineInjection {
+ private final static ScriptEngine engine = new DummyScriptEngine();
+ private final static ScriptContext context = new DummyScriptContext();
+
+ private static void insecureScriptEval(String input) throws Exception {
+ engine.eval(new StringReader(input), context);
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Exception {
+ try {
+ insecureScriptEval(data.consumeRemainingAsAsciiString());
+ } catch (Exception ignored) {
+ }
+ }
+
+ private static class DummyScriptEngine implements ScriptEngine {
+ @Override
+ public Bindings createBindings() {
+ return null;
+ }
+
+ @Override
+ public Object eval(String script) {
+ return null;
+ }
+
+ @Override
+ public Object eval(Reader reader) {
+ return null;
+ }
+
+ @Override
+ public Object eval(String script, ScriptContext context) {
+ return null;
+ }
+
+ @Override
+ public Object eval(Reader reader, ScriptContext context) {
+ return null;
+ }
+
+ @Override
+ public Object eval(String script, Bindings n) {
+ return null;
+ }
+
+ @Override
+ public Object eval(Reader reader, Bindings n) {
+ return null;
+ }
+
+ @Override
+ public Object get(String key) {
+ return null;
+ }
+
+ @Override
+ public Bindings getBindings(int scope) {
+ return null;
+ }
+
+ @Override
+ public ScriptContext getContext() {
+ return null;
+ }
+
+ @Override
+ public ScriptEngineFactory getFactory() {
+ return null;
+ }
+
+ @Override
+ public void put(String key, Object value) {}
+
+ @Override
+ public void setBindings(Bindings bindings, int scope) {}
+
+ @Override
+ public void setContext(ScriptContext context) {}
+
+ public DummyScriptEngine() {}
+ }
+
+ private static class DummyScriptContext implements ScriptContext {
+ @Override
+ public void setBindings(Bindings bindings, int scope) {}
+
+ @Override
+ public Bindings getBindings(int scope) {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object value, int scope) {}
+
+ @Override
+ public Object getAttribute(String name, int scope) {
+ return null;
+ }
+
+ @Override
+ public Object removeAttribute(String name, int scope) {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public int getAttributesScope(String name) {
+ return 0;
+ }
+
+ @Override
+ public Writer getWriter() {
+ return null;
+ }
+
+ @Override
+ public Writer getErrorWriter() {
+ return null;
+ }
+
+ @Override
+ public void setWriter(Writer writer) {}
+
+ @Override
+ public void setErrorWriter(Writer writer) {}
+
+ @Override
+ public Reader getReader() {
+ return null;
+ }
+
+ @Override
+ public void setReader(Reader reader) {}
+
+ @Override
+ public List<Integer> getScopes() {
+ return null;
+ }
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/SsrfHttpClient.java b/sanitizers/src/test/java/com/example/SsrfHttpClient.java
new file mode 100644
index 00000000..6da561a9
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/SsrfHttpClient.java
@@ -0,0 +1,39 @@
+// Copyright 2023 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.io.IOException;
+import java.net.*;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+
+public class SsrfHttpClient {
+ private static final HttpClient CLIENT =
+ HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data)
+ throws IOException, InterruptedException {
+ String hostname = data.consumeString(15);
+ URI uri;
+ try {
+ uri = URI.create("https://" + hostname);
+ HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
+ CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
+ } catch (IllegalArgumentException ignored) {
+ }
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/ldap/MockInitialContextFactory.java b/sanitizers/src/test/java/com/example/SsrfSocketConnect.java
index b674f5c5..f1d7a59b 100644
--- a/sanitizers/src/test/java/com/example/ldap/MockInitialContextFactory.java
+++ b/sanitizers/src/test/java/com/example/SsrfSocketConnect.java
@@ -1,4 +1,4 @@
-// Copyright 2021 Code Intelligence GmbH
+// Copyright 2023 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.
@@ -12,15 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.example.ldap;
+package com.example;
-import java.util.Hashtable;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import java.net.Socket;
-public class MockInitialContextFactory implements InitialContextFactory {
- public Context getInitialContext(Hashtable environment) {
- return new MockLdapContext();
+public class SsrfSocketConnect {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Exception {
+ String hostname = data.consumeString(15);
+ try (Socket s = new Socket(hostname, 80)) {
+ s.getInetAddress();
+ }
}
}
diff --git a/sanitizers/src/test/java/com/example/SsrfSocketConnectToHost.java b/sanitizers/src/test/java/com/example/SsrfSocketConnectToHost.java
new file mode 100644
index 00000000..3e60e503
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/SsrfSocketConnectToHost.java
@@ -0,0 +1,46 @@
+// Copyright 2023 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.BugDetectors;
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+import com.code_intelligence.jazzer.api.Jazzer;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+public class SsrfSocketConnectToHost {
+ // We don't actually care about establishing a connection and thus choose the lowest possible
+ // timeout.
+ private static final int CONNECTION_TIMEOUT_MS = 1;
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Exception {
+ String host = data.consumeAsciiString(15);
+ int port = data.consumeInt(1, 65535);
+
+ try (AutoCloseable ignored = BugDetectors.allowNetworkConnections()) {
+ // Verify that policies nest properly.
+ try (AutoCloseable ignored1 = BugDetectors.allowNetworkConnections(
+ (String h, Integer p) -> h.equals("localhost"))) {
+ try (AutoCloseable ignored2 = BugDetectors.allowNetworkConnections()) {
+ }
+ try (Socket s = new Socket()) {
+ s.connect(new InetSocketAddress(host, port), CONNECTION_TIMEOUT_MS);
+ } catch (IOException ignored3) {
+ }
+ }
+ }
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/SsrfUrlConnection.java b/sanitizers/src/test/java/com/example/SsrfUrlConnection.java
new file mode 100644
index 00000000..8ea940a1
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/SsrfUrlConnection.java
@@ -0,0 +1,33 @@
+// Copyright 2023 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.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class SsrfUrlConnection {
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Exception {
+ String hostname = data.consumeString(15);
+ try {
+ URL url = new URL("https://" + hostname);
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestMethod("GET");
+ con.getInputStream();
+ } catch (IOException | IllegalArgumentException ignored) {
+ }
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/StackOverflowRegexInjection.java b/sanitizers/src/test/java/com/example/StackOverflowRegexInjection.java
new file mode 100644
index 00000000..92dfcf38
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/StackOverflowRegexInjection.java
@@ -0,0 +1,51 @@
+// Copyright 2022 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.util.regex.Pattern;
+
+/**
+ * Compiling a regex pattern can lead to stack overflows and thus is caught
+ * in the constructor of {@link java.util.regex.Pattern} and rethrown as a
+ * {@link java.util.regex.PatternSyntaxException}.
+ * The {@link com.code_intelligence.jazzer.sanitizers.RegexInjection} sanitizer
+ * uses this exception to detect injections and would incorrectly report a
+ * finding. Exceptions caused by stack overflows should not be handled in the
+ * hook as it's very unlikely that the fuzzer generates a pattern causing a
+ * stack overflow before it generates an invalid one.
+ */
+@SuppressWarnings({"ReplaceOnLiteralHasNoEffect", "ResultOfMethodCallIgnored"})
+public class StackOverflowRegexInjection {
+ public static void fuzzerTestOneInput(FuzzedDataProvider ignored) {
+ // load regex classes by using them beforehand,
+ // otherwise initialization would cause other issues.
+ Pattern.compile("\n").matcher("some string").replaceAll("\\\\n");
+
+ generatePatternSyntaxException();
+ }
+
+ @SuppressWarnings("InfiniteRecursion")
+ private static void generatePatternSyntaxException() {
+ // try-catch on every level to not unwind the stack
+ try {
+ // generate stack overflow
+ generatePatternSyntaxException();
+ } catch (StackOverflowError e) {
+ // invoke regex injection hook
+ "some sting".replaceAll("\n", "\\\\n");
+ }
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/XPathInjection.java b/sanitizers/src/test/java/com/example/XPathInjection.java
new file mode 100644
index 00000000..e8fe22a0
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/XPathInjection.java
@@ -0,0 +1,53 @@
+// Copyright 2022 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.io.*;
+import javax.xml.parsers.*;
+import javax.xml.xpath.*;
+import org.w3c.dom.Document;
+import org.xml.sax.*;
+
+public class XPathInjection {
+ static Document doc = null;
+ static XPath xpath = null;
+
+ public static void fuzzerInitialize() throws Exception {
+ String xmlFile = "<user name=\"user\" pass=\"pass\"></user>";
+
+ DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+ domFactory.setNamespaceAware(true);
+ DocumentBuilder builder = domFactory.newDocumentBuilder();
+ doc = builder.parse(new InputSource(new StringReader(xmlFile)));
+
+ XPathFactory xpathFactory = XPathFactory.newInstance();
+ xpath = xpathFactory.newXPath();
+ }
+
+ public static void unsafeEval(String user, String pass) {
+ if (user != null && pass != null) {
+ String expression = "/user[@name='" + user + "' and @pass='" + pass + "']";
+ try {
+ xpath.evaluate(expression, doc, XPathConstants.BOOLEAN);
+ } catch (XPathExpressionException e) {
+ }
+ }
+ }
+
+ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+ unsafeEval(data.consumeString(20), data.consumeRemainingAsString());
+ }
+}
diff --git a/sanitizers/src/test/java/com/example/el/BUILD.bazel b/sanitizers/src/test/java/com/example/el/BUILD.bazel
new file mode 100644
index 00000000..bf12a48b
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/el/BUILD.bazel
@@ -0,0 +1,15 @@
+java_library(
+ name = "ExpressionLanguageExample",
+ srcs = [
+ "InsecureEmailValidator.java",
+ "UserData.java",
+ ],
+ visibility = ["//sanitizers/src/test/java/com/example:__pkg__"],
+ deps = [
+ "@maven//:javax_el_javax_el_api",
+ "@maven//:javax_validation_validation_api",
+ "@maven//:javax_xml_bind_jaxb_api",
+ "@maven//:org_glassfish_javax_el",
+ "@maven//:org_hibernate_hibernate_validator",
+ ],
+)
diff --git a/sanitizers/src/test/java/com/example/InsecureEmailValidator.java b/sanitizers/src/test/java/com/example/el/InsecureEmailValidator.java
index d61e888d..e10b082e 100644
--- a/sanitizers/src/test/java/com/example/InsecureEmailValidator.java
+++ b/sanitizers/src/test/java/com/example/el/InsecureEmailValidator.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.example;
+package com.example.el;
import static java.lang.String.format;
diff --git a/sanitizers/src/test/java/com/example/el/UserData.java b/sanitizers/src/test/java/com/example/el/UserData.java
new file mode 100644
index 00000000..305e78ee
--- /dev/null
+++ b/sanitizers/src/test/java/com/example/el/UserData.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 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.el;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+public class UserData {
+ public UserData(String email) {
+ this.email = email;
+ }
+
+ @ValidEmailConstraint private String email;
+}
+
+@Constraint(validatedBy = InsecureEmailValidator.class)
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@interface ValidEmailConstraint {
+ String message() default "Invalid email address";
+ Class<?>[] groups() default {};
+ Class<? extends Payload>[] payload() default {};
+}