From 3ad06ca2c6d7f65b9ce467c298ec53730fbdc52d Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Mon, 1 Mar 2021 18:04:53 +0100 Subject: Rewrite the example fuzz targets to use SecurityBug and assert Also split up JsonSanitizerFuzzer into four individual fuzzers. --- examples/BUILD.bazel | 43 ++++++++++++++++++--- .../src/main/java/com/example/ExampleFuzzer.java | 3 +- .../com/example/ExampleValueProfileFuzzer.java | 3 +- .../java/com/example/JsonSanitizerCrashFuzzer.java | 30 +++++++++++++++ .../com/example/JsonSanitizerDenylistFuzzer.java | 45 ++++++++++++++++++++++ .../main/java/com/example/JsonSanitizerFuzzer.java | 41 -------------------- .../example/JsonSanitizerIdempotenceFuzzer.java | 34 ++++++++++++++++ .../com/example/JsonSanitizerValidJsonFuzzer.java | 42 ++++++++++++++++++++ 8 files changed, 192 insertions(+), 49 deletions(-) create mode 100644 examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java create mode 100644 examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java delete mode 100644 examples/src/main/java/com/example/JsonSanitizerFuzzer.java create mode 100644 examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java create mode 100644 examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java (limited to 'examples') diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index 6304bc7f..39392796 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -70,11 +70,44 @@ java_fuzz_target_test( ) java_fuzz_target_test( - name = "JsonSanitizerFuzzer", + name = "JsonSanitizerCrashFuzzer", srcs = [ - "src/main/java/com/example/JsonSanitizerFuzzer.java", + "src/main/java/com/example/JsonSanitizerCrashFuzzer.java", ], - target_class = "com.example.JsonSanitizerFuzzer", + target_class = "com.example.JsonSanitizerCrashFuzzer", + deps = [ + "@maven//:com_mikesamuel_json_sanitizer", + ], +) + +java_fuzz_target_test( + name = "JsonSanitizerDenylistFuzzer", + srcs = [ + "src/main/java/com/example/JsonSanitizerDenylistFuzzer.java", + ], + target_class = "com.example.JsonSanitizerDenylistFuzzer", + deps = [ + "@maven//:com_mikesamuel_json_sanitizer", + ], +) + +java_fuzz_target_test( + name = "JsonSanitizerIdempotenceFuzzer", + srcs = [ + "src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java", + ], + target_class = "com.example.JsonSanitizerIdempotenceFuzzer", + deps = [ + "@maven//:com_mikesamuel_json_sanitizer", + ], +) + +java_fuzz_target_test( + name = "JsonSanitizerValidJsonFuzzer", + srcs = [ + "src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java", + ], + target_class = "com.example.JsonSanitizerValidJsonFuzzer", deps = [ "@maven//:com_google_code_gson_gson", "@maven//:com_mikesamuel_json_sanitizer", @@ -131,11 +164,9 @@ java_binary( ":ExampleFuzzer_target_deploy.jar", ":ExampleValueProfileFuzzer_target_deploy.jar", ":FastJsonFuzzer_target_deploy.jar", - ":GifImageParserFuzzer_target_deploy.jar", ":JacksonCborFuzzer_target_deploy.jar", ":JpegImageParserFuzzer_target_deploy.jar", - ":JsonSanitizerFuzzer_target_deploy.jar", - ":TiffImageParserFuzzer_target_deploy.jar", + ":JsonSanitizerDenylistFuzzer_target_deploy.jar", ], visibility = ["//visibility:public"], ) diff --git a/examples/src/main/java/com/example/ExampleFuzzer.java b/examples/src/main/java/com/example/ExampleFuzzer.java index b41f9c77..073d924a 100644 --- a/examples/src/main/java/com/example/ExampleFuzzer.java +++ b/examples/src/main/java/com/example/ExampleFuzzer.java @@ -15,6 +15,7 @@ package com.example; import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium; import java.security.SecureRandom; public class ExampleFuzzer { @@ -34,6 +35,6 @@ public class ExampleFuzzer { } private static void mustNeverBeCalled() { - throw new IllegalStateException("mustNeverBeCalled has been called"); + throw new FuzzerSecurityIssueMedium("mustNeverBeCalled has been called"); } } diff --git a/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java index 1200c560..acc023a2 100644 --- a/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java +++ b/examples/src/main/java/com/example/ExampleValueProfileFuzzer.java @@ -15,6 +15,7 @@ package com.example; import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; import java.util.Base64; public class ExampleValueProfileFuzzer { @@ -47,6 +48,6 @@ public class ExampleValueProfileFuzzer { } private static void mustNeverBeCalled() { - throw new IllegalStateException("mustNeverBeCalled has been called"); + throw new FuzzerSecurityIssueLow("mustNeverBeCalled has been called"); } } diff --git a/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.java new file mode 100644 index 00000000..05ac4611 --- /dev/null +++ b/examples/src/main/java/com/example/JsonSanitizerCrashFuzzer.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 com.google.json.JsonSanitizer; + +public class JsonSanitizerCrashFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + try { + JsonSanitizer.sanitize(input, 10); + } catch (ArrayIndexOutOfBoundsException ignored) { + // ArrayIndexOutOfBoundsException is expected if nesting depth is + // exceeded. + } + } +} diff --git a/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java new file mode 100644 index 00000000..e715b1d9 --- /dev/null +++ b/examples/src/main/java/com/example/JsonSanitizerDenylistFuzzer.java @@ -0,0 +1,45 @@ +// 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 com.code_intelligence.jazzer.api.FuzzerSecurityIssueHigh; +import com.code_intelligence.jazzer.api.FuzzerSecurityIssueMedium; +import com.google.json.JsonSanitizer; + +public class JsonSanitizerDenylistFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + String validJson; + try { + validJson = JsonSanitizer.sanitize(input, 10); + } catch (Exception e) { + return; + } + + // Check for forbidden substrings. As these would enable Cross-Site Scripting, treat every + // finding as a high severity vulnerability. + assert !validJson.contains("") : new FuzzerSecurityIssueHigh("Output contains ]]>"); + + // Check for more forbidden substrings. As these would not directly enable Cross-Site Scripting + // in general, but may impact script execution on the embedding page, treat each finding as a + // medium severity vulnerability. + assert !validJson.contains("") || validJson.contains("")) { - System.out.println(validJson); - throw new IllegalStateException("Output contains forbidden substring"); - } - } -} diff --git a/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java new file mode 100644 index 00000000..111d3de2 --- /dev/null +++ b/examples/src/main/java/com/example/JsonSanitizerIdempotenceFuzzer.java @@ -0,0 +1,34 @@ +// 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 com.google.json.JsonSanitizer; + +public class JsonSanitizerIdempotenceFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + String validJson; + try { + validJson = JsonSanitizer.sanitize(input, 10); + } catch (Exception e) { + return; + } + + // Ensure that sanitizing twice does not give different output (idempotence). Since failure to + // be idempotent is not a security issue in itself, fail with a regular AssertionError. + assert JsonSanitizer.sanitize(validJson).equals(validJson) : "Not idempotent"; + } +} diff --git a/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java b/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java new file mode 100644 index 00000000..f82381cb --- /dev/null +++ b/examples/src/main/java/com/example/JsonSanitizerValidJsonFuzzer.java @@ -0,0 +1,42 @@ +// 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 com.code_intelligence.jazzer.api.FuzzerSecurityIssueLow; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.json.JsonSanitizer; + +public class JsonSanitizerValidJsonFuzzer { + public static void fuzzerTestOneInput(FuzzedDataProvider data) { + String input = data.consumeRemainingAsString(); + String validJson; + try { + validJson = JsonSanitizer.sanitize(input, 10); + } catch (Exception e) { + return; + } + + // Check that the output is valid JSON. Invalid JSON may crash other parts of the application + // that trust the output of the sanitizer. + try { + Gson gson = new Gson(); + gson.fromJson(validJson, JsonElement.class); + } catch (Exception e) { + throw new FuzzerSecurityIssueLow("Not idempotent", e); + } + } +} -- cgit v1.2.3