diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 3e598d636..e46f25099 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -88,7 +88,11 @@ jobs: params: "--dialect=standard" - fuzzer: shell_tokenizer params: "" - - fuzzer: shi_detector + - fuzzer: shi_detector_string + params: "" + - fuzzer: shi_detector_array + params: "" + - fuzzer: cmdi_detector params: "" - fuzzer: sha256 params: "" @@ -100,7 +104,6 @@ jobs: params: "" - fuzzer: session_fingerprint params: "" - steps: - uses: actions/checkout@v4 with: diff --git a/cmake/objects.cmake b/cmake/objects.cmake index efc8011de..30674a7cf 100644 --- a/cmake/objects.cmake +++ b/cmake/objects.cmake @@ -52,7 +52,9 @@ set(LIBDDWAF_SOURCE ${libddwaf_SOURCE_DIR}/src/condition/sqli_detector.cpp ${libddwaf_SOURCE_DIR}/src/condition/ssrf_detector.cpp ${libddwaf_SOURCE_DIR}/src/condition/scalar_condition.cpp + ${libddwaf_SOURCE_DIR}/src/condition/shi_common.cpp ${libddwaf_SOURCE_DIR}/src/condition/shi_detector.cpp + ${libddwaf_SOURCE_DIR}/src/condition/cmdi_detector.cpp ${libddwaf_SOURCE_DIR}/src/matcher/phrase_match.cpp ${libddwaf_SOURCE_DIR}/src/matcher/regex_match.cpp ${libddwaf_SOURCE_DIR}/src/matcher/is_sqli.cpp diff --git a/fuzzer/cmdi_detector/corpus/corpus-0000 b/fuzzer/cmdi_detector/corpus/corpus-0000 new file mode 100644 index 000000000..a09fc98d0 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0000 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0001 b/fuzzer/cmdi_detector/corpus/corpus-0001 new file mode 100644 index 000000000..aa31b5718 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0001 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0002 b/fuzzer/cmdi_detector/corpus/corpus-0002 new file mode 100644 index 000000000..11d42e054 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0002 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0003 b/fuzzer/cmdi_detector/corpus/corpus-0003 new file mode 100644 index 000000000..b3727e028 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0003 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0004 b/fuzzer/cmdi_detector/corpus/corpus-0004 new file mode 100644 index 000000000..e9c1ad780 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0004 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0005 b/fuzzer/cmdi_detector/corpus/corpus-0005 new file mode 100644 index 000000000..9dbe78455 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0005 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0006 b/fuzzer/cmdi_detector/corpus/corpus-0006 new file mode 100644 index 000000000..ca960770c Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0006 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0007 b/fuzzer/cmdi_detector/corpus/corpus-0007 new file mode 100644 index 000000000..122caaccb Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0007 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0008 b/fuzzer/cmdi_detector/corpus/corpus-0008 new file mode 100644 index 000000000..81a770911 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0008 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0009 b/fuzzer/cmdi_detector/corpus/corpus-0009 new file mode 100644 index 000000000..08eec7461 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0009 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0010 b/fuzzer/cmdi_detector/corpus/corpus-0010 new file mode 100644 index 000000000..89bb7de0b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0010 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0011 b/fuzzer/cmdi_detector/corpus/corpus-0011 new file mode 100644 index 000000000..b6e338c97 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0011 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0012 b/fuzzer/cmdi_detector/corpus/corpus-0012 new file mode 100644 index 000000000..a879b7456 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0012 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0013 b/fuzzer/cmdi_detector/corpus/corpus-0013 new file mode 100644 index 000000000..36a065820 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0013 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0014 b/fuzzer/cmdi_detector/corpus/corpus-0014 new file mode 100644 index 000000000..ba95eae1e Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0014 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0015 b/fuzzer/cmdi_detector/corpus/corpus-0015 new file mode 100644 index 000000000..aa31b5718 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0015 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0016 b/fuzzer/cmdi_detector/corpus/corpus-0016 new file mode 100644 index 000000000..f76354826 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0016 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0017 b/fuzzer/cmdi_detector/corpus/corpus-0017 new file mode 100644 index 000000000..a053f35e4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0017 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0018 b/fuzzer/cmdi_detector/corpus/corpus-0018 new file mode 100644 index 000000000..cbd2a5f60 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0018 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0019 b/fuzzer/cmdi_detector/corpus/corpus-0019 new file mode 100644 index 000000000..f254edc8f Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0019 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0020 b/fuzzer/cmdi_detector/corpus/corpus-0020 new file mode 100644 index 000000000..600ef74c4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0020 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0021 b/fuzzer/cmdi_detector/corpus/corpus-0021 new file mode 100644 index 000000000..bc3698364 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0021 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0022 b/fuzzer/cmdi_detector/corpus/corpus-0022 new file mode 100644 index 000000000..05f3c862d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0022 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0023 b/fuzzer/cmdi_detector/corpus/corpus-0023 new file mode 100644 index 000000000..2920e6b92 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0023 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0024 b/fuzzer/cmdi_detector/corpus/corpus-0024 new file mode 100644 index 000000000..a29b99869 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0024 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0025 b/fuzzer/cmdi_detector/corpus/corpus-0025 new file mode 100644 index 000000000..2b53d6a30 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0025 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0026 b/fuzzer/cmdi_detector/corpus/corpus-0026 new file mode 100644 index 000000000..9b7c67a66 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0026 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0027 b/fuzzer/cmdi_detector/corpus/corpus-0027 new file mode 100644 index 000000000..b80d78f82 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0027 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0028 b/fuzzer/cmdi_detector/corpus/corpus-0028 new file mode 100644 index 000000000..3bbaff395 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0028 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0029 b/fuzzer/cmdi_detector/corpus/corpus-0029 new file mode 100644 index 000000000..a96a742cb Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0029 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0030 b/fuzzer/cmdi_detector/corpus/corpus-0030 new file mode 100644 index 000000000..57c8b6d3b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0030 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0031 b/fuzzer/cmdi_detector/corpus/corpus-0031 new file mode 100644 index 000000000..288efb311 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0031 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0032 b/fuzzer/cmdi_detector/corpus/corpus-0032 new file mode 100644 index 000000000..f61b69e47 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0032 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0033 b/fuzzer/cmdi_detector/corpus/corpus-0033 new file mode 100644 index 000000000..87eb6911f Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0033 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0034 b/fuzzer/cmdi_detector/corpus/corpus-0034 new file mode 100644 index 000000000..5648e0c53 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0034 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0035 b/fuzzer/cmdi_detector/corpus/corpus-0035 new file mode 100644 index 000000000..c1a21f427 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0035 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0036 b/fuzzer/cmdi_detector/corpus/corpus-0036 new file mode 100644 index 000000000..1634e611b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0036 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0037 b/fuzzer/cmdi_detector/corpus/corpus-0037 new file mode 100644 index 000000000..a29c9a998 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0037 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0038 b/fuzzer/cmdi_detector/corpus/corpus-0038 new file mode 100644 index 000000000..f717f5817 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0038 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0039 b/fuzzer/cmdi_detector/corpus/corpus-0039 new file mode 100644 index 000000000..6caffccc6 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0039 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0040 b/fuzzer/cmdi_detector/corpus/corpus-0040 new file mode 100644 index 000000000..05b045232 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0040 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0041 b/fuzzer/cmdi_detector/corpus/corpus-0041 new file mode 100644 index 000000000..e13812135 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0041 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0042 b/fuzzer/cmdi_detector/corpus/corpus-0042 new file mode 100644 index 000000000..02e34620d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0042 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0043 b/fuzzer/cmdi_detector/corpus/corpus-0043 new file mode 100644 index 000000000..baa5d1484 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0043 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0044 b/fuzzer/cmdi_detector/corpus/corpus-0044 new file mode 100644 index 000000000..ec12f6bb4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0044 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0045 b/fuzzer/cmdi_detector/corpus/corpus-0045 new file mode 100644 index 000000000..c28918e14 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0045 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0046 b/fuzzer/cmdi_detector/corpus/corpus-0046 new file mode 100644 index 000000000..8e4e95d5c Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0046 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0047 b/fuzzer/cmdi_detector/corpus/corpus-0047 new file mode 100644 index 000000000..f1e08c255 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0047 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0048 b/fuzzer/cmdi_detector/corpus/corpus-0048 new file mode 100644 index 000000000..39bacbca3 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0048 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0049 b/fuzzer/cmdi_detector/corpus/corpus-0049 new file mode 100644 index 000000000..d8daa2f72 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0049 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0050 b/fuzzer/cmdi_detector/corpus/corpus-0050 new file mode 100644 index 000000000..51048a72d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0050 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0051 b/fuzzer/cmdi_detector/corpus/corpus-0051 new file mode 100644 index 000000000..23f02bb93 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0051 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0052 b/fuzzer/cmdi_detector/corpus/corpus-0052 new file mode 100644 index 000000000..74de0914b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0052 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0053 b/fuzzer/cmdi_detector/corpus/corpus-0053 new file mode 100644 index 000000000..40c20e6f2 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0053 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0054 b/fuzzer/cmdi_detector/corpus/corpus-0054 new file mode 100644 index 000000000..b5fb0c3c5 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0054 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0055 b/fuzzer/cmdi_detector/corpus/corpus-0055 new file mode 100644 index 000000000..3f08c8848 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0055 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0056 b/fuzzer/cmdi_detector/corpus/corpus-0056 new file mode 100644 index 000000000..8a69bce57 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0056 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0057 b/fuzzer/cmdi_detector/corpus/corpus-0057 new file mode 100644 index 000000000..b0db1d199 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0057 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0058 b/fuzzer/cmdi_detector/corpus/corpus-0058 new file mode 100644 index 000000000..b5ae43c2b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0058 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0059 b/fuzzer/cmdi_detector/corpus/corpus-0059 new file mode 100644 index 000000000..e6b7e5322 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0059 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0060 b/fuzzer/cmdi_detector/corpus/corpus-0060 new file mode 100644 index 000000000..001e36d4d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0060 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0061 b/fuzzer/cmdi_detector/corpus/corpus-0061 new file mode 100644 index 000000000..cbafe54ba Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0061 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0062 b/fuzzer/cmdi_detector/corpus/corpus-0062 new file mode 100644 index 000000000..016c6202c Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0062 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0063 b/fuzzer/cmdi_detector/corpus/corpus-0063 new file mode 100644 index 000000000..c822d6027 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0063 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0064 b/fuzzer/cmdi_detector/corpus/corpus-0064 new file mode 100644 index 000000000..cab2a456c Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0064 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0065 b/fuzzer/cmdi_detector/corpus/corpus-0065 new file mode 100644 index 000000000..2ae3915a2 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0065 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0066 b/fuzzer/cmdi_detector/corpus/corpus-0066 new file mode 100644 index 000000000..483b6f5f4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0066 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0067 b/fuzzer/cmdi_detector/corpus/corpus-0067 new file mode 100644 index 000000000..fd4d21758 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0067 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0068 b/fuzzer/cmdi_detector/corpus/corpus-0068 new file mode 100644 index 000000000..94b5d9f53 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0068 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0069 b/fuzzer/cmdi_detector/corpus/corpus-0069 new file mode 100644 index 000000000..121270e77 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0069 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0070 b/fuzzer/cmdi_detector/corpus/corpus-0070 new file mode 100644 index 000000000..721bdd382 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0070 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0071 b/fuzzer/cmdi_detector/corpus/corpus-0071 new file mode 100644 index 000000000..f3200d7a6 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0071 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0072 b/fuzzer/cmdi_detector/corpus/corpus-0072 new file mode 100644 index 000000000..977a5d818 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0072 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0073 b/fuzzer/cmdi_detector/corpus/corpus-0073 new file mode 100644 index 000000000..cd9bbc812 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0073 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0074 b/fuzzer/cmdi_detector/corpus/corpus-0074 new file mode 100644 index 000000000..a81b251ff Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0074 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0075 b/fuzzer/cmdi_detector/corpus/corpus-0075 new file mode 100644 index 000000000..ccccc14cb Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0075 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0076 b/fuzzer/cmdi_detector/corpus/corpus-0076 new file mode 100644 index 000000000..14a483c71 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0076 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0077 b/fuzzer/cmdi_detector/corpus/corpus-0077 new file mode 100644 index 000000000..6854fd216 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0077 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0078 b/fuzzer/cmdi_detector/corpus/corpus-0078 new file mode 100644 index 000000000..9638bae7d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0078 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0079 b/fuzzer/cmdi_detector/corpus/corpus-0079 new file mode 100644 index 000000000..8f0924729 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0079 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0080 b/fuzzer/cmdi_detector/corpus/corpus-0080 new file mode 100644 index 000000000..5f9d1482d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0080 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0081 b/fuzzer/cmdi_detector/corpus/corpus-0081 new file mode 100644 index 000000000..fb6959c12 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0081 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0082 b/fuzzer/cmdi_detector/corpus/corpus-0082 new file mode 100644 index 000000000..fc854cb99 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0082 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0083 b/fuzzer/cmdi_detector/corpus/corpus-0083 new file mode 100644 index 000000000..1bb0a7082 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0083 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0084 b/fuzzer/cmdi_detector/corpus/corpus-0084 new file mode 100644 index 000000000..580f2b1b5 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0084 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0085 b/fuzzer/cmdi_detector/corpus/corpus-0085 new file mode 100644 index 000000000..aa70744bc Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0085 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0086 b/fuzzer/cmdi_detector/corpus/corpus-0086 new file mode 100644 index 000000000..65f3da0bc Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0086 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0087 b/fuzzer/cmdi_detector/corpus/corpus-0087 new file mode 100644 index 000000000..8e4818f41 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0087 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0088 b/fuzzer/cmdi_detector/corpus/corpus-0088 new file mode 100644 index 000000000..c053060f1 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0088 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0089 b/fuzzer/cmdi_detector/corpus/corpus-0089 new file mode 100644 index 000000000..d820d0467 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0089 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0090 b/fuzzer/cmdi_detector/corpus/corpus-0090 new file mode 100644 index 000000000..d48f2f5ad Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0090 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0091 b/fuzzer/cmdi_detector/corpus/corpus-0091 new file mode 100644 index 000000000..23210a0da Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0091 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0092 b/fuzzer/cmdi_detector/corpus/corpus-0092 new file mode 100644 index 000000000..39f17b217 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0092 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0093 b/fuzzer/cmdi_detector/corpus/corpus-0093 new file mode 100644 index 000000000..6f6d87529 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0093 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0094 b/fuzzer/cmdi_detector/corpus/corpus-0094 new file mode 100644 index 000000000..cd50ed071 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0094 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0095 b/fuzzer/cmdi_detector/corpus/corpus-0095 new file mode 100644 index 000000000..9f21b7290 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0095 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0096 b/fuzzer/cmdi_detector/corpus/corpus-0096 new file mode 100644 index 000000000..7162310e4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0096 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0097 b/fuzzer/cmdi_detector/corpus/corpus-0097 new file mode 100644 index 000000000..fcfc17ccd Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0097 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0098 b/fuzzer/cmdi_detector/corpus/corpus-0098 new file mode 100644 index 000000000..5e30587d9 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0098 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0099 b/fuzzer/cmdi_detector/corpus/corpus-0099 new file mode 100644 index 000000000..158581183 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0099 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0100 b/fuzzer/cmdi_detector/corpus/corpus-0100 new file mode 100644 index 000000000..7cab70e6e Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0100 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0101 b/fuzzer/cmdi_detector/corpus/corpus-0101 new file mode 100644 index 000000000..15ea99af8 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0101 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0102 b/fuzzer/cmdi_detector/corpus/corpus-0102 new file mode 100644 index 000000000..522f5c04c Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0102 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0103 b/fuzzer/cmdi_detector/corpus/corpus-0103 new file mode 100644 index 000000000..e7ae3cde6 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0103 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0104 b/fuzzer/cmdi_detector/corpus/corpus-0104 new file mode 100644 index 000000000..efc02afc0 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0104 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0105 b/fuzzer/cmdi_detector/corpus/corpus-0105 new file mode 100644 index 000000000..ff18f0a1f Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0105 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0106 b/fuzzer/cmdi_detector/corpus/corpus-0106 new file mode 100644 index 000000000..db5cd7bf3 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0106 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0107 b/fuzzer/cmdi_detector/corpus/corpus-0107 new file mode 100644 index 000000000..62c3b857e Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0107 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0108 b/fuzzer/cmdi_detector/corpus/corpus-0108 new file mode 100644 index 000000000..255f428a4 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0108 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0109 b/fuzzer/cmdi_detector/corpus/corpus-0109 new file mode 100644 index 000000000..c0697b533 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0109 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0110 b/fuzzer/cmdi_detector/corpus/corpus-0110 new file mode 100644 index 000000000..7bc3da815 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0110 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0111 b/fuzzer/cmdi_detector/corpus/corpus-0111 new file mode 100644 index 000000000..1eba4f8ec Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0111 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0112 b/fuzzer/cmdi_detector/corpus/corpus-0112 new file mode 100644 index 000000000..fbdcfc3c5 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0112 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0113 b/fuzzer/cmdi_detector/corpus/corpus-0113 new file mode 100644 index 000000000..99215394b Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0113 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0114 b/fuzzer/cmdi_detector/corpus/corpus-0114 new file mode 100644 index 000000000..dc9f91f1e Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0114 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0115 b/fuzzer/cmdi_detector/corpus/corpus-0115 new file mode 100644 index 000000000..8e316c102 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0115 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0116 b/fuzzer/cmdi_detector/corpus/corpus-0116 new file mode 100644 index 000000000..f07308515 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0116 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0117 b/fuzzer/cmdi_detector/corpus/corpus-0117 new file mode 100644 index 000000000..54ca7b243 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0117 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0118 b/fuzzer/cmdi_detector/corpus/corpus-0118 new file mode 100644 index 000000000..7cc9e3a3f Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0118 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0119 b/fuzzer/cmdi_detector/corpus/corpus-0119 new file mode 100644 index 000000000..ab2023888 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0119 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0120 b/fuzzer/cmdi_detector/corpus/corpus-0120 new file mode 100644 index 000000000..288ba0583 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0120 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0121 b/fuzzer/cmdi_detector/corpus/corpus-0121 new file mode 100644 index 000000000..860c545fa Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0121 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0122 b/fuzzer/cmdi_detector/corpus/corpus-0122 new file mode 100644 index 000000000..b427a0a3d Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0122 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0123 b/fuzzer/cmdi_detector/corpus/corpus-0123 new file mode 100644 index 000000000..3c52bb735 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0123 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0124 b/fuzzer/cmdi_detector/corpus/corpus-0124 new file mode 100644 index 000000000..e144a8276 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0124 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0125 b/fuzzer/cmdi_detector/corpus/corpus-0125 new file mode 100644 index 000000000..fb5c60591 Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0125 differ diff --git a/fuzzer/cmdi_detector/corpus/corpus-0126 b/fuzzer/cmdi_detector/corpus/corpus-0126 new file mode 100644 index 000000000..135d5f8ec Binary files /dev/null and b/fuzzer/cmdi_detector/corpus/corpus-0126 differ diff --git a/fuzzer/cmdi_detector/src/main.cpp b/fuzzer/cmdi_detector/src/main.cpp new file mode 100644 index 000000000..73c996393 --- /dev/null +++ b/fuzzer/cmdi_detector/src/main.cpp @@ -0,0 +1,212 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include +#include + +#include "condition/cmdi_detector.hpp" + +using namespace ddwaf; +using namespace std::literals; + +extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); + +extern "C" int LLVMFuzzerInitialize(const int * /*argc*/, char *** /*argv*/) +{ + ddwaf::memory::set_local_memory_resource(std::pmr::new_delete_resource()); + return 0; +} + +template std::vector gen_param_def(Args... addresses) +{ + return {{{{std::string{addresses}, get_target_index(addresses)}}}...}; +} + +// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) +std::pair, std::string_view> deserialize( + const uint8_t *data, size_t size) +{ + if (size < sizeof(std::size_t)) { + return {}; + } + + const auto resource_size = *reinterpret_cast(data); + + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < sizeof(std::size_t)) { + return {}; + } + + std::vector resource; + resource.reserve(resource_size); + + for (std::size_t i = 0; i < resource_size; ++i) { + const auto arg_size = *reinterpret_cast(data); + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < arg_size) { + return {}; + } + + std::string_view arg{reinterpret_cast(data), arg_size}; + data += arg_size; + size -= arg_size; + + resource.emplace_back(arg); + } + + if (size < sizeof(std::size_t)) { + return {}; + } + + const auto param_size = *reinterpret_cast(data); + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < param_size) { + return {}; + } + + std::string_view param{reinterpret_cast(data), param_size}; + + return {std::move(resource), param}; +} + +struct serializer { + uint8_t *data; + std::size_t total_size{0}; + + explicit serializer(uint8_t *Data) : data(Data) {} + + void serialize(std::size_t size) + { + memcpy(data, reinterpret_cast(&size), sizeof(std::size_t)); + data += sizeof(std::size_t); + total_size += sizeof(std::size_t); + } + + void serialize(std::string_view str) + { + std::size_t size = str.size(); + serialize(size); + + memcpy(data, str.data(), size); + data += size; + total_size += size; + } + + template + std::size_t serialize(const std::vector &resource, std::string_view param) + requires std::is_same_v || std::is_same_v + { + serialize(resource.size()); + for (const auto &arg : resource) { serialize(arg); } + serialize(param); + + return total_size; + } +}; + +// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) + +extern "C" size_t LLVMFuzzerCustomMutator( + // NOLINTNEXTLINE + uint8_t *Data, size_t Size, [[maybe_unused]] size_t MaxSize, [[maybe_unused]] unsigned int Seed) +{ + static thread_local std::mt19937 rng(Seed); + + // One size_t for array size, another one for the parameter length + MaxSize -= sizeof(std::size_t) * 2; + + // Resource and parameter size limits + auto max_resource_size = 3 * MaxSize / 4; + auto max_resource_string_size = 2 * MaxSize / 4; + auto max_param_size = MaxSize / 4; + + auto [old_resource, param] = deserialize(Data, Size); + + // Compose the resource into a string + std::string resource_str; + for (const auto &arg : old_resource) { + if (!resource_str.empty()) { + resource_str.append(" "); + } + resource_str.append(arg); + } + + // Ensure that the resource doesn't take more than half the remaining buffer + // since the final mutated resource will have to be split into arrays elements + // adding further overheads + std::size_t resource_size = std::min(resource_str.size(), max_resource_string_size); + resource_str.resize(max_resource_string_size); + + // Mutate + auto new_size = LLVMFuzzerMutate( + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast(resource_str.data()), resource_size, resource_str.size()); + resource_str.resize(new_size); + + // Break down the resource into array elements + std::size_t start = 0; + std::size_t total_size = 0; + std::vector new_resource; + for (std::size_t i = 0; i < resource_str.size(); ++i) { + if (ddwaf::isspace(resource_str[i]) && start != i && static_cast(rng() % 2)) { + new_resource.emplace_back(resource_str.substr(start, i - start)); + total_size += sizeof(std::size_t) + new_resource.back().size(); + start = i + 1; + } else if ((i + 1) == resource_str.size()) { + new_resource.emplace_back(resource_str.substr(start)); + total_size += sizeof(std::size_t) + new_resource.back().size(); + } + + if (total_size >= max_resource_size) { + break; + } + } + MaxSize -= total_size; + + std::size_t possible_param_size = + std::min(MaxSize, std::min(max_param_size, resource_str.size())); + auto param_idx = rng() % resource_str.size(); + auto param_size = 1 + rng() % std::min(possible_param_size, (resource_str.size() - param_idx)); + + auto param_buffer = resource_str.substr(param_idx, param_size); + return serializer{Data}.serialize(new_resource, param_buffer); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + auto [resource, param] = deserialize(bytes, size); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object array; + ddwaf_object_map(&root); + + ddwaf_object_array(&array); + for (auto arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_stringl(&tmp, arg.data(), arg.size())); + } + + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_stringl(&tmp, param.data(), param.size())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + (void)cond.eval(cache, store, {}, {}, deadline); + + return 0; +} diff --git a/fuzzer/shi_detector_array/corpus/corpus-0000 b/fuzzer/shi_detector_array/corpus/corpus-0000 new file mode 100644 index 000000000..2121c7f6d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0000 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0001 b/fuzzer/shi_detector_array/corpus/corpus-0001 new file mode 100644 index 000000000..aa31b5718 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0001 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0002 b/fuzzer/shi_detector_array/corpus/corpus-0002 new file mode 100644 index 000000000..a4f6339fe Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0002 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0003 b/fuzzer/shi_detector_array/corpus/corpus-0003 new file mode 100644 index 000000000..6a9a9859e Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0003 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0004 b/fuzzer/shi_detector_array/corpus/corpus-0004 new file mode 100644 index 000000000..505a11ba2 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0004 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0005 b/fuzzer/shi_detector_array/corpus/corpus-0005 new file mode 100644 index 000000000..da59112f0 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0005 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0006 b/fuzzer/shi_detector_array/corpus/corpus-0006 new file mode 100644 index 000000000..ba2bd5440 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0006 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0007 b/fuzzer/shi_detector_array/corpus/corpus-0007 new file mode 100644 index 000000000..b4ae92f80 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0007 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0008 b/fuzzer/shi_detector_array/corpus/corpus-0008 new file mode 100644 index 000000000..2e7e807fb Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0008 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0009 b/fuzzer/shi_detector_array/corpus/corpus-0009 new file mode 100644 index 000000000..745a7365a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0009 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0010 b/fuzzer/shi_detector_array/corpus/corpus-0010 new file mode 100644 index 000000000..836588999 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0010 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0011 b/fuzzer/shi_detector_array/corpus/corpus-0011 new file mode 100644 index 000000000..f018248b8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0011 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0012 b/fuzzer/shi_detector_array/corpus/corpus-0012 new file mode 100644 index 000000000..4b2c8b575 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0012 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0013 b/fuzzer/shi_detector_array/corpus/corpus-0013 new file mode 100644 index 000000000..fbd43a62a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0013 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0014 b/fuzzer/shi_detector_array/corpus/corpus-0014 new file mode 100644 index 000000000..5fbd16743 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0014 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0015 b/fuzzer/shi_detector_array/corpus/corpus-0015 new file mode 100644 index 000000000..aa31b5718 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0015 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0016 b/fuzzer/shi_detector_array/corpus/corpus-0016 new file mode 100644 index 000000000..cc9942655 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0016 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0017 b/fuzzer/shi_detector_array/corpus/corpus-0017 new file mode 100644 index 000000000..8d561e28e Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0017 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0018 b/fuzzer/shi_detector_array/corpus/corpus-0018 new file mode 100644 index 000000000..38fbd5e02 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0018 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0019 b/fuzzer/shi_detector_array/corpus/corpus-0019 new file mode 100644 index 000000000..6c01e8176 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0019 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0020 b/fuzzer/shi_detector_array/corpus/corpus-0020 new file mode 100644 index 000000000..37dde560b Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0020 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0021 b/fuzzer/shi_detector_array/corpus/corpus-0021 new file mode 100644 index 000000000..357e5cab7 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0021 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0022 b/fuzzer/shi_detector_array/corpus/corpus-0022 new file mode 100644 index 000000000..164e0077c Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0022 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0023 b/fuzzer/shi_detector_array/corpus/corpus-0023 new file mode 100644 index 000000000..2908fe016 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0023 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0024 b/fuzzer/shi_detector_array/corpus/corpus-0024 new file mode 100644 index 000000000..59b3425e4 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0024 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0025 b/fuzzer/shi_detector_array/corpus/corpus-0025 new file mode 100644 index 000000000..9087ae031 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0025 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0026 b/fuzzer/shi_detector_array/corpus/corpus-0026 new file mode 100644 index 000000000..af74a2be5 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0026 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0027 b/fuzzer/shi_detector_array/corpus/corpus-0027 new file mode 100644 index 000000000..a6e2f90da Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0027 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0028 b/fuzzer/shi_detector_array/corpus/corpus-0028 new file mode 100644 index 000000000..32f505fbd Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0028 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0029 b/fuzzer/shi_detector_array/corpus/corpus-0029 new file mode 100644 index 000000000..dbb09e5ae Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0029 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0030 b/fuzzer/shi_detector_array/corpus/corpus-0030 new file mode 100644 index 000000000..daa042ff8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0030 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0031 b/fuzzer/shi_detector_array/corpus/corpus-0031 new file mode 100644 index 000000000..0719a6cb0 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0031 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0032 b/fuzzer/shi_detector_array/corpus/corpus-0032 new file mode 100644 index 000000000..c9c570d46 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0032 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0033 b/fuzzer/shi_detector_array/corpus/corpus-0033 new file mode 100644 index 000000000..acebe8b4d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0033 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0034 b/fuzzer/shi_detector_array/corpus/corpus-0034 new file mode 100644 index 000000000..37c10e6eb Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0034 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0035 b/fuzzer/shi_detector_array/corpus/corpus-0035 new file mode 100644 index 000000000..147fd6381 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0035 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0036 b/fuzzer/shi_detector_array/corpus/corpus-0036 new file mode 100644 index 000000000..485d3c0ce Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0036 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0037 b/fuzzer/shi_detector_array/corpus/corpus-0037 new file mode 100644 index 000000000..bb791ffdb Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0037 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0038 b/fuzzer/shi_detector_array/corpus/corpus-0038 new file mode 100644 index 000000000..904b1cff4 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0038 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0039 b/fuzzer/shi_detector_array/corpus/corpus-0039 new file mode 100644 index 000000000..bbc89a696 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0039 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0040 b/fuzzer/shi_detector_array/corpus/corpus-0040 new file mode 100644 index 000000000..a262325d7 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0040 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0041 b/fuzzer/shi_detector_array/corpus/corpus-0041 new file mode 100644 index 000000000..3a29014e5 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0041 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0042 b/fuzzer/shi_detector_array/corpus/corpus-0042 new file mode 100644 index 000000000..eb6e431b1 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0042 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0043 b/fuzzer/shi_detector_array/corpus/corpus-0043 new file mode 100644 index 000000000..8ac1fb1de Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0043 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0044 b/fuzzer/shi_detector_array/corpus/corpus-0044 new file mode 100644 index 000000000..2794296b6 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0044 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0045 b/fuzzer/shi_detector_array/corpus/corpus-0045 new file mode 100644 index 000000000..a5916e89f Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0045 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0046 b/fuzzer/shi_detector_array/corpus/corpus-0046 new file mode 100644 index 000000000..4618f4a1a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0046 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0047 b/fuzzer/shi_detector_array/corpus/corpus-0047 new file mode 100644 index 000000000..af6887afa Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0047 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0048 b/fuzzer/shi_detector_array/corpus/corpus-0048 new file mode 100644 index 000000000..79feb20b8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0048 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0049 b/fuzzer/shi_detector_array/corpus/corpus-0049 new file mode 100644 index 000000000..b75d04089 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0049 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0050 b/fuzzer/shi_detector_array/corpus/corpus-0050 new file mode 100644 index 000000000..2c8247b02 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0050 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0051 b/fuzzer/shi_detector_array/corpus/corpus-0051 new file mode 100644 index 000000000..90ba186fe Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0051 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0052 b/fuzzer/shi_detector_array/corpus/corpus-0052 new file mode 100644 index 000000000..0421aa4b4 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0052 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0053 b/fuzzer/shi_detector_array/corpus/corpus-0053 new file mode 100644 index 000000000..f0783dba9 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0053 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0054 b/fuzzer/shi_detector_array/corpus/corpus-0054 new file mode 100644 index 000000000..79e147992 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0054 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0055 b/fuzzer/shi_detector_array/corpus/corpus-0055 new file mode 100644 index 000000000..99f8d677f Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0055 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0056 b/fuzzer/shi_detector_array/corpus/corpus-0056 new file mode 100644 index 000000000..2027d6477 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0056 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0057 b/fuzzer/shi_detector_array/corpus/corpus-0057 new file mode 100644 index 000000000..68e3fb3be Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0057 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0058 b/fuzzer/shi_detector_array/corpus/corpus-0058 new file mode 100644 index 000000000..c5fc0c66d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0058 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0059 b/fuzzer/shi_detector_array/corpus/corpus-0059 new file mode 100644 index 000000000..350f46649 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0059 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0060 b/fuzzer/shi_detector_array/corpus/corpus-0060 new file mode 100644 index 000000000..80d6cf5bd Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0060 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0061 b/fuzzer/shi_detector_array/corpus/corpus-0061 new file mode 100644 index 000000000..8f7174751 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0061 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0062 b/fuzzer/shi_detector_array/corpus/corpus-0062 new file mode 100644 index 000000000..52b27246f Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0062 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0063 b/fuzzer/shi_detector_array/corpus/corpus-0063 new file mode 100644 index 000000000..e4448f308 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0063 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0064 b/fuzzer/shi_detector_array/corpus/corpus-0064 new file mode 100644 index 000000000..eef03b505 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0064 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0065 b/fuzzer/shi_detector_array/corpus/corpus-0065 new file mode 100644 index 000000000..9b1b8c155 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0065 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0066 b/fuzzer/shi_detector_array/corpus/corpus-0066 new file mode 100644 index 000000000..f0c09390e Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0066 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0067 b/fuzzer/shi_detector_array/corpus/corpus-0067 new file mode 100644 index 000000000..07b5bc82d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0067 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0068 b/fuzzer/shi_detector_array/corpus/corpus-0068 new file mode 100644 index 000000000..9286df6ae Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0068 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0069 b/fuzzer/shi_detector_array/corpus/corpus-0069 new file mode 100644 index 000000000..955b531fa Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0069 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0070 b/fuzzer/shi_detector_array/corpus/corpus-0070 new file mode 100644 index 000000000..9a5bd0e3e Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0070 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0071 b/fuzzer/shi_detector_array/corpus/corpus-0071 new file mode 100644 index 000000000..d17f4eab9 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0071 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0072 b/fuzzer/shi_detector_array/corpus/corpus-0072 new file mode 100644 index 000000000..77159c1f8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0072 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0073 b/fuzzer/shi_detector_array/corpus/corpus-0073 new file mode 100644 index 000000000..0d50c36cd Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0073 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0074 b/fuzzer/shi_detector_array/corpus/corpus-0074 new file mode 100644 index 000000000..2ea92e168 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0074 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0075 b/fuzzer/shi_detector_array/corpus/corpus-0075 new file mode 100644 index 000000000..af2cfcb64 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0075 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0076 b/fuzzer/shi_detector_array/corpus/corpus-0076 new file mode 100644 index 000000000..09c3f3de6 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0076 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0077 b/fuzzer/shi_detector_array/corpus/corpus-0077 new file mode 100644 index 000000000..ee820feb2 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0077 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0078 b/fuzzer/shi_detector_array/corpus/corpus-0078 new file mode 100644 index 000000000..9bc23a314 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0078 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0079 b/fuzzer/shi_detector_array/corpus/corpus-0079 new file mode 100644 index 000000000..88dc82dad Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0079 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0080 b/fuzzer/shi_detector_array/corpus/corpus-0080 new file mode 100644 index 000000000..17d2976bb Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0080 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0081 b/fuzzer/shi_detector_array/corpus/corpus-0081 new file mode 100644 index 000000000..8521f6f63 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0081 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0082 b/fuzzer/shi_detector_array/corpus/corpus-0082 new file mode 100644 index 000000000..a58fbe684 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0082 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0083 b/fuzzer/shi_detector_array/corpus/corpus-0083 new file mode 100644 index 000000000..b9a0f12d7 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0083 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0084 b/fuzzer/shi_detector_array/corpus/corpus-0084 new file mode 100644 index 000000000..580f2b1b5 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0084 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0085 b/fuzzer/shi_detector_array/corpus/corpus-0085 new file mode 100644 index 000000000..9d9cf578a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0085 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0086 b/fuzzer/shi_detector_array/corpus/corpus-0086 new file mode 100644 index 000000000..51c3f7e70 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0086 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0087 b/fuzzer/shi_detector_array/corpus/corpus-0087 new file mode 100644 index 000000000..9c47ea99f Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0087 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0088 b/fuzzer/shi_detector_array/corpus/corpus-0088 new file mode 100644 index 000000000..02ca5032a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0088 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0089 b/fuzzer/shi_detector_array/corpus/corpus-0089 new file mode 100644 index 000000000..05161ab0a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0089 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0090 b/fuzzer/shi_detector_array/corpus/corpus-0090 new file mode 100644 index 000000000..0f73f0c36 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0090 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0091 b/fuzzer/shi_detector_array/corpus/corpus-0091 new file mode 100644 index 000000000..3f5811fd7 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0091 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0092 b/fuzzer/shi_detector_array/corpus/corpus-0092 new file mode 100644 index 000000000..1cdf09916 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0092 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0093 b/fuzzer/shi_detector_array/corpus/corpus-0093 new file mode 100644 index 000000000..1c96e2758 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0093 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0094 b/fuzzer/shi_detector_array/corpus/corpus-0094 new file mode 100644 index 000000000..7ecc88e25 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0094 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0095 b/fuzzer/shi_detector_array/corpus/corpus-0095 new file mode 100644 index 000000000..6f0c2284a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0095 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0096 b/fuzzer/shi_detector_array/corpus/corpus-0096 new file mode 100644 index 000000000..7162310e4 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0096 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0097 b/fuzzer/shi_detector_array/corpus/corpus-0097 new file mode 100644 index 000000000..5af67b571 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0097 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0098 b/fuzzer/shi_detector_array/corpus/corpus-0098 new file mode 100644 index 000000000..ec275bd40 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0098 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0099 b/fuzzer/shi_detector_array/corpus/corpus-0099 new file mode 100644 index 000000000..02690a6aa Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0099 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0100 b/fuzzer/shi_detector_array/corpus/corpus-0100 new file mode 100644 index 000000000..944fdb77f Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0100 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0101 b/fuzzer/shi_detector_array/corpus/corpus-0101 new file mode 100644 index 000000000..15ea99af8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0101 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0102 b/fuzzer/shi_detector_array/corpus/corpus-0102 new file mode 100644 index 000000000..d7e911260 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0102 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0103 b/fuzzer/shi_detector_array/corpus/corpus-0103 new file mode 100644 index 000000000..2d8d4fc08 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0103 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0104 b/fuzzer/shi_detector_array/corpus/corpus-0104 new file mode 100644 index 000000000..57b975f37 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0104 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0105 b/fuzzer/shi_detector_array/corpus/corpus-0105 new file mode 100644 index 000000000..0dae2160e Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0105 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0106 b/fuzzer/shi_detector_array/corpus/corpus-0106 new file mode 100644 index 000000000..c021f09dc Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0106 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0107 b/fuzzer/shi_detector_array/corpus/corpus-0107 new file mode 100644 index 000000000..195cf84bd Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0107 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0108 b/fuzzer/shi_detector_array/corpus/corpus-0108 new file mode 100644 index 000000000..1049547cd Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0108 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0109 b/fuzzer/shi_detector_array/corpus/corpus-0109 new file mode 100644 index 000000000..0b633b28b Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0109 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0110 b/fuzzer/shi_detector_array/corpus/corpus-0110 new file mode 100644 index 000000000..7adc563d5 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0110 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0111 b/fuzzer/shi_detector_array/corpus/corpus-0111 new file mode 100644 index 000000000..871f07253 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0111 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0112 b/fuzzer/shi_detector_array/corpus/corpus-0112 new file mode 100644 index 000000000..9af6fc9fb Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0112 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0113 b/fuzzer/shi_detector_array/corpus/corpus-0113 new file mode 100644 index 000000000..f5ec5d855 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0113 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0114 b/fuzzer/shi_detector_array/corpus/corpus-0114 new file mode 100644 index 000000000..6f103e409 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0114 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0115 b/fuzzer/shi_detector_array/corpus/corpus-0115 new file mode 100644 index 000000000..21688d76a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0115 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0116 b/fuzzer/shi_detector_array/corpus/corpus-0116 new file mode 100644 index 000000000..df91e5b9d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0116 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0117 b/fuzzer/shi_detector_array/corpus/corpus-0117 new file mode 100644 index 000000000..37f83a0d9 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0117 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0118 b/fuzzer/shi_detector_array/corpus/corpus-0118 new file mode 100644 index 000000000..5f991c384 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0118 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0119 b/fuzzer/shi_detector_array/corpus/corpus-0119 new file mode 100644 index 000000000..24373ead2 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0119 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0120 b/fuzzer/shi_detector_array/corpus/corpus-0120 new file mode 100644 index 000000000..a3a7ebb66 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0120 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0121 b/fuzzer/shi_detector_array/corpus/corpus-0121 new file mode 100644 index 000000000..19c44ca1a Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0121 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0122 b/fuzzer/shi_detector_array/corpus/corpus-0122 new file mode 100644 index 000000000..cfd783262 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0122 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0123 b/fuzzer/shi_detector_array/corpus/corpus-0123 new file mode 100644 index 000000000..026e3dcb0 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0123 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0124 b/fuzzer/shi_detector_array/corpus/corpus-0124 new file mode 100644 index 000000000..286bd67a1 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0124 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0125 b/fuzzer/shi_detector_array/corpus/corpus-0125 new file mode 100644 index 000000000..f95244f7d Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0125 differ diff --git a/fuzzer/shi_detector_array/corpus/corpus-0126 b/fuzzer/shi_detector_array/corpus/corpus-0126 new file mode 100644 index 000000000..3f50099f8 Binary files /dev/null and b/fuzzer/shi_detector_array/corpus/corpus-0126 differ diff --git a/fuzzer/shi_detector_array/src/main.cpp b/fuzzer/shi_detector_array/src/main.cpp new file mode 100644 index 000000000..a315caf05 --- /dev/null +++ b/fuzzer/shi_detector_array/src/main.cpp @@ -0,0 +1,212 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include +#include + +#include "condition/shi_detector.hpp" + +using namespace ddwaf; +using namespace std::literals; + +extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); + +extern "C" int LLVMFuzzerInitialize(const int * /*argc*/, char *** /*argv*/) +{ + ddwaf::memory::set_local_memory_resource(std::pmr::new_delete_resource()); + return 0; +} + +template std::vector gen_param_def(Args... addresses) +{ + return {{{{std::string{addresses}, get_target_index(addresses)}}}...}; +} + +// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) +std::pair, std::string_view> deserialize( + const uint8_t *data, size_t size) +{ + if (size < sizeof(std::size_t)) { + return {}; + } + + const auto resource_size = *reinterpret_cast(data); + + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < sizeof(std::size_t)) { + return {}; + } + + std::vector resource; + resource.reserve(resource_size); + + for (std::size_t i = 0; i < resource_size; ++i) { + const auto arg_size = *reinterpret_cast(data); + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < arg_size) { + return {}; + } + + std::string_view arg{reinterpret_cast(data), arg_size}; + data += arg_size; + size -= arg_size; + + resource.emplace_back(arg); + } + + if (size < sizeof(std::size_t)) { + return {}; + } + + const auto param_size = *reinterpret_cast(data); + data += sizeof(std::size_t); + size -= sizeof(std::size_t); + + if (size < param_size) { + return {}; + } + + std::string_view param{reinterpret_cast(data), param_size}; + + return {std::move(resource), param}; +} + +struct serializer { + uint8_t *data; + std::size_t total_size{0}; + + explicit serializer(uint8_t *Data) : data(Data) {} + + void serialize(std::size_t size) + { + memcpy(data, reinterpret_cast(&size), sizeof(std::size_t)); + data += sizeof(std::size_t); + total_size += sizeof(std::size_t); + } + + void serialize(std::string_view str) + { + std::size_t size = str.size(); + serialize(size); + + memcpy(data, str.data(), size); + data += size; + total_size += size; + } + + template + std::size_t serialize(const std::vector &resource, std::string_view param) + requires std::is_same_v || std::is_same_v + { + serialize(resource.size()); + for (const auto &arg : resource) { serialize(arg); } + serialize(param); + + return total_size; + } +}; + +// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) + +extern "C" size_t LLVMFuzzerCustomMutator( + // NOLINTNEXTLINE + uint8_t *Data, size_t Size, [[maybe_unused]] size_t MaxSize, [[maybe_unused]] unsigned int Seed) +{ + static thread_local std::mt19937 rng(Seed); + + // One size_t for array size, another one for the parameter length + MaxSize -= sizeof(std::size_t) * 2; + + // Resource and parameter size limits + auto max_resource_size = 3 * MaxSize / 4; + auto max_resource_string_size = 2 * MaxSize / 4; + auto max_param_size = MaxSize / 4; + + auto [old_resource, param] = deserialize(Data, Size); + + // Compose the resource into a string + std::string resource_str; + for (const auto &arg : old_resource) { + if (!resource_str.empty()) { + resource_str.append(" "); + } + resource_str.append(arg); + } + + // Ensure that the resource doesn't take more than half the remaining buffer + // since the final mutated resource will have to be split into arrays elements + // adding further overheads + std::size_t resource_size = std::min(resource_str.size(), max_resource_string_size); + resource_str.resize(max_resource_string_size); + + // Mutate + auto new_size = LLVMFuzzerMutate( + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast(resource_str.data()), resource_size, resource_str.size()); + resource_str.resize(new_size); + + // Break down the resource into array elements + std::size_t start = 0; + std::size_t total_size = 0; + std::vector new_resource; + for (std::size_t i = 0; i < resource_str.size(); ++i) { + if (ddwaf::isspace(resource_str[i]) && start != i && static_cast(rng() % 2)) { + new_resource.emplace_back(resource_str.substr(start, i - start)); + total_size += sizeof(std::size_t) + new_resource.back().size(); + start = i + 1; + } else if ((i + 1) == resource_str.size()) { + new_resource.emplace_back(resource_str.substr(start)); + total_size += sizeof(std::size_t) + new_resource.back().size(); + } + + if (total_size >= max_resource_size) { + break; + } + } + MaxSize -= total_size; + + std::size_t possible_param_size = + std::min(MaxSize, std::min(max_param_size, resource_str.size())); + auto param_idx = rng() % resource_str.size(); + auto param_size = 1 + rng() % std::min(possible_param_size, (resource_str.size() - param_idx)); + + auto param_buffer = resource_str.substr(param_idx, param_size); + return serializer{Data}.serialize(new_resource, param_buffer); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size) +{ + shi_detector cond{{gen_param_def("server.sys.shell.cmd", "server.request.query")}}; + + auto [resource, param] = deserialize(bytes, size); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object array; + ddwaf_object_map(&root); + + ddwaf_object_array(&array); + for (auto arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_stringl(&tmp, arg.data(), arg.size())); + } + + ddwaf_object_map_add(&root, "server.sys.shell.cmd", &array); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_stringl(&tmp, param.data(), param.size())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + (void)cond.eval(cache, store, {}, {}, deadline); + + return 0; +} diff --git a/fuzzer/shi_detector/corpus/corpus-0000 b/fuzzer/shi_detector_string/corpus/corpus-0000 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0000 rename to fuzzer/shi_detector_string/corpus/corpus-0000 diff --git a/fuzzer/shi_detector/corpus/corpus-0001 b/fuzzer/shi_detector_string/corpus/corpus-0001 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0001 rename to fuzzer/shi_detector_string/corpus/corpus-0001 diff --git a/fuzzer/shi_detector/corpus/corpus-0002 b/fuzzer/shi_detector_string/corpus/corpus-0002 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0002 rename to fuzzer/shi_detector_string/corpus/corpus-0002 diff --git a/fuzzer/shi_detector/corpus/corpus-0003 b/fuzzer/shi_detector_string/corpus/corpus-0003 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0003 rename to fuzzer/shi_detector_string/corpus/corpus-0003 diff --git a/fuzzer/shi_detector/corpus/corpus-0004 b/fuzzer/shi_detector_string/corpus/corpus-0004 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0004 rename to fuzzer/shi_detector_string/corpus/corpus-0004 diff --git a/fuzzer/shi_detector/corpus/corpus-0005 b/fuzzer/shi_detector_string/corpus/corpus-0005 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0005 rename to fuzzer/shi_detector_string/corpus/corpus-0005 diff --git a/fuzzer/shi_detector/corpus/corpus-0006 b/fuzzer/shi_detector_string/corpus/corpus-0006 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0006 rename to fuzzer/shi_detector_string/corpus/corpus-0006 diff --git a/fuzzer/shi_detector/corpus/corpus-0007 b/fuzzer/shi_detector_string/corpus/corpus-0007 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0007 rename to fuzzer/shi_detector_string/corpus/corpus-0007 diff --git a/fuzzer/shi_detector/corpus/corpus-0008 b/fuzzer/shi_detector_string/corpus/corpus-0008 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0008 rename to fuzzer/shi_detector_string/corpus/corpus-0008 diff --git a/fuzzer/shi_detector/corpus/corpus-0009 b/fuzzer/shi_detector_string/corpus/corpus-0009 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0009 rename to fuzzer/shi_detector_string/corpus/corpus-0009 diff --git a/fuzzer/shi_detector/corpus/corpus-0010 b/fuzzer/shi_detector_string/corpus/corpus-0010 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0010 rename to fuzzer/shi_detector_string/corpus/corpus-0010 diff --git a/fuzzer/shi_detector/corpus/corpus-0011 b/fuzzer/shi_detector_string/corpus/corpus-0011 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0011 rename to fuzzer/shi_detector_string/corpus/corpus-0011 diff --git a/fuzzer/shi_detector/corpus/corpus-0012 b/fuzzer/shi_detector_string/corpus/corpus-0012 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0012 rename to fuzzer/shi_detector_string/corpus/corpus-0012 diff --git a/fuzzer/shi_detector/corpus/corpus-0013 b/fuzzer/shi_detector_string/corpus/corpus-0013 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0013 rename to fuzzer/shi_detector_string/corpus/corpus-0013 diff --git a/fuzzer/shi_detector/corpus/corpus-0014 b/fuzzer/shi_detector_string/corpus/corpus-0014 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0014 rename to fuzzer/shi_detector_string/corpus/corpus-0014 diff --git a/fuzzer/shi_detector/corpus/corpus-0015 b/fuzzer/shi_detector_string/corpus/corpus-0015 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0015 rename to fuzzer/shi_detector_string/corpus/corpus-0015 diff --git a/fuzzer/shi_detector/corpus/corpus-0016 b/fuzzer/shi_detector_string/corpus/corpus-0016 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0016 rename to fuzzer/shi_detector_string/corpus/corpus-0016 diff --git a/fuzzer/shi_detector/corpus/corpus-0017 b/fuzzer/shi_detector_string/corpus/corpus-0017 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0017 rename to fuzzer/shi_detector_string/corpus/corpus-0017 diff --git a/fuzzer/shi_detector/corpus/corpus-0018 b/fuzzer/shi_detector_string/corpus/corpus-0018 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0018 rename to fuzzer/shi_detector_string/corpus/corpus-0018 diff --git a/fuzzer/shi_detector/corpus/corpus-0019 b/fuzzer/shi_detector_string/corpus/corpus-0019 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0019 rename to fuzzer/shi_detector_string/corpus/corpus-0019 diff --git a/fuzzer/shi_detector/corpus/corpus-0020 b/fuzzer/shi_detector_string/corpus/corpus-0020 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0020 rename to fuzzer/shi_detector_string/corpus/corpus-0020 diff --git a/fuzzer/shi_detector/corpus/corpus-0021 b/fuzzer/shi_detector_string/corpus/corpus-0021 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0021 rename to fuzzer/shi_detector_string/corpus/corpus-0021 diff --git a/fuzzer/shi_detector/corpus/corpus-0022 b/fuzzer/shi_detector_string/corpus/corpus-0022 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0022 rename to fuzzer/shi_detector_string/corpus/corpus-0022 diff --git a/fuzzer/shi_detector/corpus/corpus-0023 b/fuzzer/shi_detector_string/corpus/corpus-0023 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0023 rename to fuzzer/shi_detector_string/corpus/corpus-0023 diff --git a/fuzzer/shi_detector/corpus/corpus-0024 b/fuzzer/shi_detector_string/corpus/corpus-0024 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0024 rename to fuzzer/shi_detector_string/corpus/corpus-0024 diff --git a/fuzzer/shi_detector/corpus/corpus-0025 b/fuzzer/shi_detector_string/corpus/corpus-0025 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0025 rename to fuzzer/shi_detector_string/corpus/corpus-0025 diff --git a/fuzzer/shi_detector/corpus/corpus-0026 b/fuzzer/shi_detector_string/corpus/corpus-0026 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0026 rename to fuzzer/shi_detector_string/corpus/corpus-0026 diff --git a/fuzzer/shi_detector/corpus/corpus-0027 b/fuzzer/shi_detector_string/corpus/corpus-0027 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0027 rename to fuzzer/shi_detector_string/corpus/corpus-0027 diff --git a/fuzzer/shi_detector/corpus/corpus-0028 b/fuzzer/shi_detector_string/corpus/corpus-0028 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0028 rename to fuzzer/shi_detector_string/corpus/corpus-0028 diff --git a/fuzzer/shi_detector/corpus/corpus-0029 b/fuzzer/shi_detector_string/corpus/corpus-0029 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0029 rename to fuzzer/shi_detector_string/corpus/corpus-0029 diff --git a/fuzzer/shi_detector/corpus/corpus-0030 b/fuzzer/shi_detector_string/corpus/corpus-0030 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0030 rename to fuzzer/shi_detector_string/corpus/corpus-0030 diff --git a/fuzzer/shi_detector/corpus/corpus-0031 b/fuzzer/shi_detector_string/corpus/corpus-0031 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0031 rename to fuzzer/shi_detector_string/corpus/corpus-0031 diff --git a/fuzzer/shi_detector/corpus/corpus-0032 b/fuzzer/shi_detector_string/corpus/corpus-0032 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0032 rename to fuzzer/shi_detector_string/corpus/corpus-0032 diff --git a/fuzzer/shi_detector/corpus/corpus-0033 b/fuzzer/shi_detector_string/corpus/corpus-0033 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0033 rename to fuzzer/shi_detector_string/corpus/corpus-0033 diff --git a/fuzzer/shi_detector/corpus/corpus-0034 b/fuzzer/shi_detector_string/corpus/corpus-0034 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0034 rename to fuzzer/shi_detector_string/corpus/corpus-0034 diff --git a/fuzzer/shi_detector/corpus/corpus-0035 b/fuzzer/shi_detector_string/corpus/corpus-0035 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0035 rename to fuzzer/shi_detector_string/corpus/corpus-0035 diff --git a/fuzzer/shi_detector/corpus/corpus-0036 b/fuzzer/shi_detector_string/corpus/corpus-0036 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0036 rename to fuzzer/shi_detector_string/corpus/corpus-0036 diff --git a/fuzzer/shi_detector/corpus/corpus-0037 b/fuzzer/shi_detector_string/corpus/corpus-0037 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0037 rename to fuzzer/shi_detector_string/corpus/corpus-0037 diff --git a/fuzzer/shi_detector/corpus/corpus-0038 b/fuzzer/shi_detector_string/corpus/corpus-0038 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0038 rename to fuzzer/shi_detector_string/corpus/corpus-0038 diff --git a/fuzzer/shi_detector/corpus/corpus-0039 b/fuzzer/shi_detector_string/corpus/corpus-0039 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0039 rename to fuzzer/shi_detector_string/corpus/corpus-0039 diff --git a/fuzzer/shi_detector/corpus/corpus-0040 b/fuzzer/shi_detector_string/corpus/corpus-0040 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0040 rename to fuzzer/shi_detector_string/corpus/corpus-0040 diff --git a/fuzzer/shi_detector/corpus/corpus-0041 b/fuzzer/shi_detector_string/corpus/corpus-0041 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0041 rename to fuzzer/shi_detector_string/corpus/corpus-0041 diff --git a/fuzzer/shi_detector/corpus/corpus-0042 b/fuzzer/shi_detector_string/corpus/corpus-0042 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0042 rename to fuzzer/shi_detector_string/corpus/corpus-0042 diff --git a/fuzzer/shi_detector/corpus/corpus-0043 b/fuzzer/shi_detector_string/corpus/corpus-0043 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0043 rename to fuzzer/shi_detector_string/corpus/corpus-0043 diff --git a/fuzzer/shi_detector/corpus/corpus-0044 b/fuzzer/shi_detector_string/corpus/corpus-0044 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0044 rename to fuzzer/shi_detector_string/corpus/corpus-0044 diff --git a/fuzzer/shi_detector/corpus/corpus-0045 b/fuzzer/shi_detector_string/corpus/corpus-0045 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0045 rename to fuzzer/shi_detector_string/corpus/corpus-0045 diff --git a/fuzzer/shi_detector/corpus/corpus-0046 b/fuzzer/shi_detector_string/corpus/corpus-0046 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0046 rename to fuzzer/shi_detector_string/corpus/corpus-0046 diff --git a/fuzzer/shi_detector/corpus/corpus-0047 b/fuzzer/shi_detector_string/corpus/corpus-0047 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0047 rename to fuzzer/shi_detector_string/corpus/corpus-0047 diff --git a/fuzzer/shi_detector/corpus/corpus-0048 b/fuzzer/shi_detector_string/corpus/corpus-0048 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0048 rename to fuzzer/shi_detector_string/corpus/corpus-0048 diff --git a/fuzzer/shi_detector/corpus/corpus-0049 b/fuzzer/shi_detector_string/corpus/corpus-0049 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0049 rename to fuzzer/shi_detector_string/corpus/corpus-0049 diff --git a/fuzzer/shi_detector/corpus/corpus-0050 b/fuzzer/shi_detector_string/corpus/corpus-0050 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0050 rename to fuzzer/shi_detector_string/corpus/corpus-0050 diff --git a/fuzzer/shi_detector/corpus/corpus-0051 b/fuzzer/shi_detector_string/corpus/corpus-0051 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0051 rename to fuzzer/shi_detector_string/corpus/corpus-0051 diff --git a/fuzzer/shi_detector/corpus/corpus-0052 b/fuzzer/shi_detector_string/corpus/corpus-0052 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0052 rename to fuzzer/shi_detector_string/corpus/corpus-0052 diff --git a/fuzzer/shi_detector/corpus/corpus-0053 b/fuzzer/shi_detector_string/corpus/corpus-0053 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0053 rename to fuzzer/shi_detector_string/corpus/corpus-0053 diff --git a/fuzzer/shi_detector/corpus/corpus-0054 b/fuzzer/shi_detector_string/corpus/corpus-0054 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0054 rename to fuzzer/shi_detector_string/corpus/corpus-0054 diff --git a/fuzzer/shi_detector/corpus/corpus-0055 b/fuzzer/shi_detector_string/corpus/corpus-0055 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0055 rename to fuzzer/shi_detector_string/corpus/corpus-0055 diff --git a/fuzzer/shi_detector/corpus/corpus-0056 b/fuzzer/shi_detector_string/corpus/corpus-0056 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0056 rename to fuzzer/shi_detector_string/corpus/corpus-0056 diff --git a/fuzzer/shi_detector/corpus/corpus-0057 b/fuzzer/shi_detector_string/corpus/corpus-0057 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0057 rename to fuzzer/shi_detector_string/corpus/corpus-0057 diff --git a/fuzzer/shi_detector/corpus/corpus-0058 b/fuzzer/shi_detector_string/corpus/corpus-0058 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0058 rename to fuzzer/shi_detector_string/corpus/corpus-0058 diff --git a/fuzzer/shi_detector/corpus/corpus-0059 b/fuzzer/shi_detector_string/corpus/corpus-0059 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0059 rename to fuzzer/shi_detector_string/corpus/corpus-0059 diff --git a/fuzzer/shi_detector/corpus/corpus-0060 b/fuzzer/shi_detector_string/corpus/corpus-0060 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0060 rename to fuzzer/shi_detector_string/corpus/corpus-0060 diff --git a/fuzzer/shi_detector/corpus/corpus-0061 b/fuzzer/shi_detector_string/corpus/corpus-0061 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0061 rename to fuzzer/shi_detector_string/corpus/corpus-0061 diff --git a/fuzzer/shi_detector/corpus/corpus-0062 b/fuzzer/shi_detector_string/corpus/corpus-0062 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0062 rename to fuzzer/shi_detector_string/corpus/corpus-0062 diff --git a/fuzzer/shi_detector/corpus/corpus-0063 b/fuzzer/shi_detector_string/corpus/corpus-0063 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0063 rename to fuzzer/shi_detector_string/corpus/corpus-0063 diff --git a/fuzzer/shi_detector/corpus/corpus-0064 b/fuzzer/shi_detector_string/corpus/corpus-0064 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0064 rename to fuzzer/shi_detector_string/corpus/corpus-0064 diff --git a/fuzzer/shi_detector/corpus/corpus-0065 b/fuzzer/shi_detector_string/corpus/corpus-0065 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0065 rename to fuzzer/shi_detector_string/corpus/corpus-0065 diff --git a/fuzzer/shi_detector/corpus/corpus-0066 b/fuzzer/shi_detector_string/corpus/corpus-0066 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0066 rename to fuzzer/shi_detector_string/corpus/corpus-0066 diff --git a/fuzzer/shi_detector/corpus/corpus-0067 b/fuzzer/shi_detector_string/corpus/corpus-0067 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0067 rename to fuzzer/shi_detector_string/corpus/corpus-0067 diff --git a/fuzzer/shi_detector/corpus/corpus-0068 b/fuzzer/shi_detector_string/corpus/corpus-0068 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0068 rename to fuzzer/shi_detector_string/corpus/corpus-0068 diff --git a/fuzzer/shi_detector/corpus/corpus-0069 b/fuzzer/shi_detector_string/corpus/corpus-0069 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0069 rename to fuzzer/shi_detector_string/corpus/corpus-0069 diff --git a/fuzzer/shi_detector/corpus/corpus-0070 b/fuzzer/shi_detector_string/corpus/corpus-0070 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0070 rename to fuzzer/shi_detector_string/corpus/corpus-0070 diff --git a/fuzzer/shi_detector/corpus/corpus-0071 b/fuzzer/shi_detector_string/corpus/corpus-0071 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0071 rename to fuzzer/shi_detector_string/corpus/corpus-0071 diff --git a/fuzzer/shi_detector/corpus/corpus-0072 b/fuzzer/shi_detector_string/corpus/corpus-0072 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0072 rename to fuzzer/shi_detector_string/corpus/corpus-0072 diff --git a/fuzzer/shi_detector/corpus/corpus-0073 b/fuzzer/shi_detector_string/corpus/corpus-0073 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0073 rename to fuzzer/shi_detector_string/corpus/corpus-0073 diff --git a/fuzzer/shi_detector/corpus/corpus-0074 b/fuzzer/shi_detector_string/corpus/corpus-0074 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0074 rename to fuzzer/shi_detector_string/corpus/corpus-0074 diff --git a/fuzzer/shi_detector/corpus/corpus-0075 b/fuzzer/shi_detector_string/corpus/corpus-0075 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0075 rename to fuzzer/shi_detector_string/corpus/corpus-0075 diff --git a/fuzzer/shi_detector/corpus/corpus-0076 b/fuzzer/shi_detector_string/corpus/corpus-0076 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0076 rename to fuzzer/shi_detector_string/corpus/corpus-0076 diff --git a/fuzzer/shi_detector/corpus/corpus-0077 b/fuzzer/shi_detector_string/corpus/corpus-0077 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0077 rename to fuzzer/shi_detector_string/corpus/corpus-0077 diff --git a/fuzzer/shi_detector/corpus/corpus-0078 b/fuzzer/shi_detector_string/corpus/corpus-0078 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0078 rename to fuzzer/shi_detector_string/corpus/corpus-0078 diff --git a/fuzzer/shi_detector/corpus/corpus-0079 b/fuzzer/shi_detector_string/corpus/corpus-0079 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0079 rename to fuzzer/shi_detector_string/corpus/corpus-0079 diff --git a/fuzzer/shi_detector/corpus/corpus-0080 b/fuzzer/shi_detector_string/corpus/corpus-0080 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0080 rename to fuzzer/shi_detector_string/corpus/corpus-0080 diff --git a/fuzzer/shi_detector/corpus/corpus-0081 b/fuzzer/shi_detector_string/corpus/corpus-0081 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0081 rename to fuzzer/shi_detector_string/corpus/corpus-0081 diff --git a/fuzzer/shi_detector/corpus/corpus-0082 b/fuzzer/shi_detector_string/corpus/corpus-0082 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0082 rename to fuzzer/shi_detector_string/corpus/corpus-0082 diff --git a/fuzzer/shi_detector/corpus/corpus-0083 b/fuzzer/shi_detector_string/corpus/corpus-0083 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0083 rename to fuzzer/shi_detector_string/corpus/corpus-0083 diff --git a/fuzzer/shi_detector/corpus/corpus-0084 b/fuzzer/shi_detector_string/corpus/corpus-0084 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0084 rename to fuzzer/shi_detector_string/corpus/corpus-0084 diff --git a/fuzzer/shi_detector/corpus/corpus-0085 b/fuzzer/shi_detector_string/corpus/corpus-0085 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0085 rename to fuzzer/shi_detector_string/corpus/corpus-0085 diff --git a/fuzzer/shi_detector/corpus/corpus-0086 b/fuzzer/shi_detector_string/corpus/corpus-0086 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0086 rename to fuzzer/shi_detector_string/corpus/corpus-0086 diff --git a/fuzzer/shi_detector/corpus/corpus-0087 b/fuzzer/shi_detector_string/corpus/corpus-0087 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0087 rename to fuzzer/shi_detector_string/corpus/corpus-0087 diff --git a/fuzzer/shi_detector/corpus/corpus-0088 b/fuzzer/shi_detector_string/corpus/corpus-0088 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0088 rename to fuzzer/shi_detector_string/corpus/corpus-0088 diff --git a/fuzzer/shi_detector/corpus/corpus-0089 b/fuzzer/shi_detector_string/corpus/corpus-0089 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0089 rename to fuzzer/shi_detector_string/corpus/corpus-0089 diff --git a/fuzzer/shi_detector/corpus/corpus-0090 b/fuzzer/shi_detector_string/corpus/corpus-0090 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0090 rename to fuzzer/shi_detector_string/corpus/corpus-0090 diff --git a/fuzzer/shi_detector/corpus/corpus-0091 b/fuzzer/shi_detector_string/corpus/corpus-0091 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0091 rename to fuzzer/shi_detector_string/corpus/corpus-0091 diff --git a/fuzzer/shi_detector/corpus/corpus-0092 b/fuzzer/shi_detector_string/corpus/corpus-0092 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0092 rename to fuzzer/shi_detector_string/corpus/corpus-0092 diff --git a/fuzzer/shi_detector/corpus/corpus-0093 b/fuzzer/shi_detector_string/corpus/corpus-0093 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0093 rename to fuzzer/shi_detector_string/corpus/corpus-0093 diff --git a/fuzzer/shi_detector/corpus/corpus-0094 b/fuzzer/shi_detector_string/corpus/corpus-0094 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0094 rename to fuzzer/shi_detector_string/corpus/corpus-0094 diff --git a/fuzzer/shi_detector/corpus/corpus-0095 b/fuzzer/shi_detector_string/corpus/corpus-0095 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0095 rename to fuzzer/shi_detector_string/corpus/corpus-0095 diff --git a/fuzzer/shi_detector/corpus/corpus-0096 b/fuzzer/shi_detector_string/corpus/corpus-0096 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0096 rename to fuzzer/shi_detector_string/corpus/corpus-0096 diff --git a/fuzzer/shi_detector/corpus/corpus-0097 b/fuzzer/shi_detector_string/corpus/corpus-0097 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0097 rename to fuzzer/shi_detector_string/corpus/corpus-0097 diff --git a/fuzzer/shi_detector/corpus/corpus-0098 b/fuzzer/shi_detector_string/corpus/corpus-0098 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0098 rename to fuzzer/shi_detector_string/corpus/corpus-0098 diff --git a/fuzzer/shi_detector/corpus/corpus-0099 b/fuzzer/shi_detector_string/corpus/corpus-0099 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0099 rename to fuzzer/shi_detector_string/corpus/corpus-0099 diff --git a/fuzzer/shi_detector/corpus/corpus-0100 b/fuzzer/shi_detector_string/corpus/corpus-0100 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0100 rename to fuzzer/shi_detector_string/corpus/corpus-0100 diff --git a/fuzzer/shi_detector/corpus/corpus-0101 b/fuzzer/shi_detector_string/corpus/corpus-0101 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0101 rename to fuzzer/shi_detector_string/corpus/corpus-0101 diff --git a/fuzzer/shi_detector/corpus/corpus-0102 b/fuzzer/shi_detector_string/corpus/corpus-0102 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0102 rename to fuzzer/shi_detector_string/corpus/corpus-0102 diff --git a/fuzzer/shi_detector/corpus/corpus-0103 b/fuzzer/shi_detector_string/corpus/corpus-0103 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0103 rename to fuzzer/shi_detector_string/corpus/corpus-0103 diff --git a/fuzzer/shi_detector/corpus/corpus-0104 b/fuzzer/shi_detector_string/corpus/corpus-0104 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0104 rename to fuzzer/shi_detector_string/corpus/corpus-0104 diff --git a/fuzzer/shi_detector/corpus/corpus-0105 b/fuzzer/shi_detector_string/corpus/corpus-0105 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0105 rename to fuzzer/shi_detector_string/corpus/corpus-0105 diff --git a/fuzzer/shi_detector/corpus/corpus-0106 b/fuzzer/shi_detector_string/corpus/corpus-0106 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0106 rename to fuzzer/shi_detector_string/corpus/corpus-0106 diff --git a/fuzzer/shi_detector/corpus/corpus-0107 b/fuzzer/shi_detector_string/corpus/corpus-0107 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0107 rename to fuzzer/shi_detector_string/corpus/corpus-0107 diff --git a/fuzzer/shi_detector/corpus/corpus-0108 b/fuzzer/shi_detector_string/corpus/corpus-0108 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0108 rename to fuzzer/shi_detector_string/corpus/corpus-0108 diff --git a/fuzzer/shi_detector/corpus/corpus-0109 b/fuzzer/shi_detector_string/corpus/corpus-0109 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0109 rename to fuzzer/shi_detector_string/corpus/corpus-0109 diff --git a/fuzzer/shi_detector/corpus/corpus-0110 b/fuzzer/shi_detector_string/corpus/corpus-0110 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0110 rename to fuzzer/shi_detector_string/corpus/corpus-0110 diff --git a/fuzzer/shi_detector/corpus/corpus-0111 b/fuzzer/shi_detector_string/corpus/corpus-0111 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0111 rename to fuzzer/shi_detector_string/corpus/corpus-0111 diff --git a/fuzzer/shi_detector/corpus/corpus-0112 b/fuzzer/shi_detector_string/corpus/corpus-0112 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0112 rename to fuzzer/shi_detector_string/corpus/corpus-0112 diff --git a/fuzzer/shi_detector/corpus/corpus-0113 b/fuzzer/shi_detector_string/corpus/corpus-0113 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0113 rename to fuzzer/shi_detector_string/corpus/corpus-0113 diff --git a/fuzzer/shi_detector/corpus/corpus-0114 b/fuzzer/shi_detector_string/corpus/corpus-0114 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0114 rename to fuzzer/shi_detector_string/corpus/corpus-0114 diff --git a/fuzzer/shi_detector/corpus/corpus-0115 b/fuzzer/shi_detector_string/corpus/corpus-0115 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0115 rename to fuzzer/shi_detector_string/corpus/corpus-0115 diff --git a/fuzzer/shi_detector/corpus/corpus-0116 b/fuzzer/shi_detector_string/corpus/corpus-0116 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0116 rename to fuzzer/shi_detector_string/corpus/corpus-0116 diff --git a/fuzzer/shi_detector/corpus/corpus-0117 b/fuzzer/shi_detector_string/corpus/corpus-0117 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0117 rename to fuzzer/shi_detector_string/corpus/corpus-0117 diff --git a/fuzzer/shi_detector/corpus/corpus-0118 b/fuzzer/shi_detector_string/corpus/corpus-0118 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0118 rename to fuzzer/shi_detector_string/corpus/corpus-0118 diff --git a/fuzzer/shi_detector/corpus/corpus-0119 b/fuzzer/shi_detector_string/corpus/corpus-0119 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0119 rename to fuzzer/shi_detector_string/corpus/corpus-0119 diff --git a/fuzzer/shi_detector/corpus/corpus-0120 b/fuzzer/shi_detector_string/corpus/corpus-0120 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0120 rename to fuzzer/shi_detector_string/corpus/corpus-0120 diff --git a/fuzzer/shi_detector/corpus/corpus-0121 b/fuzzer/shi_detector_string/corpus/corpus-0121 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0121 rename to fuzzer/shi_detector_string/corpus/corpus-0121 diff --git a/fuzzer/shi_detector/corpus/corpus-0122 b/fuzzer/shi_detector_string/corpus/corpus-0122 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0122 rename to fuzzer/shi_detector_string/corpus/corpus-0122 diff --git a/fuzzer/shi_detector/corpus/corpus-0123 b/fuzzer/shi_detector_string/corpus/corpus-0123 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0123 rename to fuzzer/shi_detector_string/corpus/corpus-0123 diff --git a/fuzzer/shi_detector/corpus/corpus-0124 b/fuzzer/shi_detector_string/corpus/corpus-0124 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0124 rename to fuzzer/shi_detector_string/corpus/corpus-0124 diff --git a/fuzzer/shi_detector/corpus/corpus-0125 b/fuzzer/shi_detector_string/corpus/corpus-0125 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0125 rename to fuzzer/shi_detector_string/corpus/corpus-0125 diff --git a/fuzzer/shi_detector/corpus/corpus-0126 b/fuzzer/shi_detector_string/corpus/corpus-0126 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0126 rename to fuzzer/shi_detector_string/corpus/corpus-0126 diff --git a/fuzzer/shi_detector/corpus/corpus-0127 b/fuzzer/shi_detector_string/corpus/corpus-0127 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0127 rename to fuzzer/shi_detector_string/corpus/corpus-0127 diff --git a/fuzzer/shi_detector/corpus/corpus-0128 b/fuzzer/shi_detector_string/corpus/corpus-0128 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0128 rename to fuzzer/shi_detector_string/corpus/corpus-0128 diff --git a/fuzzer/shi_detector/corpus/corpus-0129 b/fuzzer/shi_detector_string/corpus/corpus-0129 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0129 rename to fuzzer/shi_detector_string/corpus/corpus-0129 diff --git a/fuzzer/shi_detector/corpus/corpus-0130 b/fuzzer/shi_detector_string/corpus/corpus-0130 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0130 rename to fuzzer/shi_detector_string/corpus/corpus-0130 diff --git a/fuzzer/shi_detector/corpus/corpus-0131 b/fuzzer/shi_detector_string/corpus/corpus-0131 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0131 rename to fuzzer/shi_detector_string/corpus/corpus-0131 diff --git a/fuzzer/shi_detector/corpus/corpus-0132 b/fuzzer/shi_detector_string/corpus/corpus-0132 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0132 rename to fuzzer/shi_detector_string/corpus/corpus-0132 diff --git a/fuzzer/shi_detector/corpus/corpus-0133 b/fuzzer/shi_detector_string/corpus/corpus-0133 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0133 rename to fuzzer/shi_detector_string/corpus/corpus-0133 diff --git a/fuzzer/shi_detector/corpus/corpus-0134 b/fuzzer/shi_detector_string/corpus/corpus-0134 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0134 rename to fuzzer/shi_detector_string/corpus/corpus-0134 diff --git a/fuzzer/shi_detector/corpus/corpus-0135 b/fuzzer/shi_detector_string/corpus/corpus-0135 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0135 rename to fuzzer/shi_detector_string/corpus/corpus-0135 diff --git a/fuzzer/shi_detector/corpus/corpus-0136 b/fuzzer/shi_detector_string/corpus/corpus-0136 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0136 rename to fuzzer/shi_detector_string/corpus/corpus-0136 diff --git a/fuzzer/shi_detector/corpus/corpus-0137 b/fuzzer/shi_detector_string/corpus/corpus-0137 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0137 rename to fuzzer/shi_detector_string/corpus/corpus-0137 diff --git a/fuzzer/shi_detector/corpus/corpus-0138 b/fuzzer/shi_detector_string/corpus/corpus-0138 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0138 rename to fuzzer/shi_detector_string/corpus/corpus-0138 diff --git a/fuzzer/shi_detector/corpus/corpus-0139 b/fuzzer/shi_detector_string/corpus/corpus-0139 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0139 rename to fuzzer/shi_detector_string/corpus/corpus-0139 diff --git a/fuzzer/shi_detector/corpus/corpus-0140 b/fuzzer/shi_detector_string/corpus/corpus-0140 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0140 rename to fuzzer/shi_detector_string/corpus/corpus-0140 diff --git a/fuzzer/shi_detector/corpus/corpus-0141 b/fuzzer/shi_detector_string/corpus/corpus-0141 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0141 rename to fuzzer/shi_detector_string/corpus/corpus-0141 diff --git a/fuzzer/shi_detector/corpus/corpus-0142 b/fuzzer/shi_detector_string/corpus/corpus-0142 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0142 rename to fuzzer/shi_detector_string/corpus/corpus-0142 diff --git a/fuzzer/shi_detector/corpus/corpus-0143 b/fuzzer/shi_detector_string/corpus/corpus-0143 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0143 rename to fuzzer/shi_detector_string/corpus/corpus-0143 diff --git a/fuzzer/shi_detector/corpus/corpus-0144 b/fuzzer/shi_detector_string/corpus/corpus-0144 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0144 rename to fuzzer/shi_detector_string/corpus/corpus-0144 diff --git a/fuzzer/shi_detector/corpus/corpus-0145 b/fuzzer/shi_detector_string/corpus/corpus-0145 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0145 rename to fuzzer/shi_detector_string/corpus/corpus-0145 diff --git a/fuzzer/shi_detector/corpus/corpus-0146 b/fuzzer/shi_detector_string/corpus/corpus-0146 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0146 rename to fuzzer/shi_detector_string/corpus/corpus-0146 diff --git a/fuzzer/shi_detector/corpus/corpus-0147 b/fuzzer/shi_detector_string/corpus/corpus-0147 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0147 rename to fuzzer/shi_detector_string/corpus/corpus-0147 diff --git a/fuzzer/shi_detector/corpus/corpus-0148 b/fuzzer/shi_detector_string/corpus/corpus-0148 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0148 rename to fuzzer/shi_detector_string/corpus/corpus-0148 diff --git a/fuzzer/shi_detector/corpus/corpus-0149 b/fuzzer/shi_detector_string/corpus/corpus-0149 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0149 rename to fuzzer/shi_detector_string/corpus/corpus-0149 diff --git a/fuzzer/shi_detector/corpus/corpus-0150 b/fuzzer/shi_detector_string/corpus/corpus-0150 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0150 rename to fuzzer/shi_detector_string/corpus/corpus-0150 diff --git a/fuzzer/shi_detector/corpus/corpus-0151 b/fuzzer/shi_detector_string/corpus/corpus-0151 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0151 rename to fuzzer/shi_detector_string/corpus/corpus-0151 diff --git a/fuzzer/shi_detector/corpus/corpus-0152 b/fuzzer/shi_detector_string/corpus/corpus-0152 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0152 rename to fuzzer/shi_detector_string/corpus/corpus-0152 diff --git a/fuzzer/shi_detector/corpus/corpus-0153 b/fuzzer/shi_detector_string/corpus/corpus-0153 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0153 rename to fuzzer/shi_detector_string/corpus/corpus-0153 diff --git a/fuzzer/shi_detector/corpus/corpus-0154 b/fuzzer/shi_detector_string/corpus/corpus-0154 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0154 rename to fuzzer/shi_detector_string/corpus/corpus-0154 diff --git a/fuzzer/shi_detector/corpus/corpus-0155 b/fuzzer/shi_detector_string/corpus/corpus-0155 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0155 rename to fuzzer/shi_detector_string/corpus/corpus-0155 diff --git a/fuzzer/shi_detector/corpus/corpus-0156 b/fuzzer/shi_detector_string/corpus/corpus-0156 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0156 rename to fuzzer/shi_detector_string/corpus/corpus-0156 diff --git a/fuzzer/shi_detector/corpus/corpus-0157 b/fuzzer/shi_detector_string/corpus/corpus-0157 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0157 rename to fuzzer/shi_detector_string/corpus/corpus-0157 diff --git a/fuzzer/shi_detector/corpus/corpus-0158 b/fuzzer/shi_detector_string/corpus/corpus-0158 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0158 rename to fuzzer/shi_detector_string/corpus/corpus-0158 diff --git a/fuzzer/shi_detector/corpus/corpus-0159 b/fuzzer/shi_detector_string/corpus/corpus-0159 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0159 rename to fuzzer/shi_detector_string/corpus/corpus-0159 diff --git a/fuzzer/shi_detector/corpus/corpus-0160 b/fuzzer/shi_detector_string/corpus/corpus-0160 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0160 rename to fuzzer/shi_detector_string/corpus/corpus-0160 diff --git a/fuzzer/shi_detector/corpus/corpus-0161 b/fuzzer/shi_detector_string/corpus/corpus-0161 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0161 rename to fuzzer/shi_detector_string/corpus/corpus-0161 diff --git a/fuzzer/shi_detector/corpus/corpus-0162 b/fuzzer/shi_detector_string/corpus/corpus-0162 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0162 rename to fuzzer/shi_detector_string/corpus/corpus-0162 diff --git a/fuzzer/shi_detector/corpus/corpus-0163 b/fuzzer/shi_detector_string/corpus/corpus-0163 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0163 rename to fuzzer/shi_detector_string/corpus/corpus-0163 diff --git a/fuzzer/shi_detector/corpus/corpus-0164 b/fuzzer/shi_detector_string/corpus/corpus-0164 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0164 rename to fuzzer/shi_detector_string/corpus/corpus-0164 diff --git a/fuzzer/shi_detector/corpus/corpus-0165 b/fuzzer/shi_detector_string/corpus/corpus-0165 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0165 rename to fuzzer/shi_detector_string/corpus/corpus-0165 diff --git a/fuzzer/shi_detector/corpus/corpus-0166 b/fuzzer/shi_detector_string/corpus/corpus-0166 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0166 rename to fuzzer/shi_detector_string/corpus/corpus-0166 diff --git a/fuzzer/shi_detector/corpus/corpus-0167 b/fuzzer/shi_detector_string/corpus/corpus-0167 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0167 rename to fuzzer/shi_detector_string/corpus/corpus-0167 diff --git a/fuzzer/shi_detector/corpus/corpus-0168 b/fuzzer/shi_detector_string/corpus/corpus-0168 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0168 rename to fuzzer/shi_detector_string/corpus/corpus-0168 diff --git a/fuzzer/shi_detector/corpus/corpus-0169 b/fuzzer/shi_detector_string/corpus/corpus-0169 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0169 rename to fuzzer/shi_detector_string/corpus/corpus-0169 diff --git a/fuzzer/shi_detector/corpus/corpus-0170 b/fuzzer/shi_detector_string/corpus/corpus-0170 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0170 rename to fuzzer/shi_detector_string/corpus/corpus-0170 diff --git a/fuzzer/shi_detector/corpus/corpus-0171 b/fuzzer/shi_detector_string/corpus/corpus-0171 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0171 rename to fuzzer/shi_detector_string/corpus/corpus-0171 diff --git a/fuzzer/shi_detector/corpus/corpus-0172 b/fuzzer/shi_detector_string/corpus/corpus-0172 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0172 rename to fuzzer/shi_detector_string/corpus/corpus-0172 diff --git a/fuzzer/shi_detector/corpus/corpus-0173 b/fuzzer/shi_detector_string/corpus/corpus-0173 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0173 rename to fuzzer/shi_detector_string/corpus/corpus-0173 diff --git a/fuzzer/shi_detector/corpus/corpus-0174 b/fuzzer/shi_detector_string/corpus/corpus-0174 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0174 rename to fuzzer/shi_detector_string/corpus/corpus-0174 diff --git a/fuzzer/shi_detector/corpus/corpus-0175 b/fuzzer/shi_detector_string/corpus/corpus-0175 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0175 rename to fuzzer/shi_detector_string/corpus/corpus-0175 diff --git a/fuzzer/shi_detector/corpus/corpus-0176 b/fuzzer/shi_detector_string/corpus/corpus-0176 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0176 rename to fuzzer/shi_detector_string/corpus/corpus-0176 diff --git a/fuzzer/shi_detector/corpus/corpus-0177 b/fuzzer/shi_detector_string/corpus/corpus-0177 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0177 rename to fuzzer/shi_detector_string/corpus/corpus-0177 diff --git a/fuzzer/shi_detector/corpus/corpus-0178 b/fuzzer/shi_detector_string/corpus/corpus-0178 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0178 rename to fuzzer/shi_detector_string/corpus/corpus-0178 diff --git a/fuzzer/shi_detector/corpus/corpus-0179 b/fuzzer/shi_detector_string/corpus/corpus-0179 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0179 rename to fuzzer/shi_detector_string/corpus/corpus-0179 diff --git a/fuzzer/shi_detector/corpus/corpus-0180 b/fuzzer/shi_detector_string/corpus/corpus-0180 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0180 rename to fuzzer/shi_detector_string/corpus/corpus-0180 diff --git a/fuzzer/shi_detector/corpus/corpus-0181 b/fuzzer/shi_detector_string/corpus/corpus-0181 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0181 rename to fuzzer/shi_detector_string/corpus/corpus-0181 diff --git a/fuzzer/shi_detector/corpus/corpus-0182 b/fuzzer/shi_detector_string/corpus/corpus-0182 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0182 rename to fuzzer/shi_detector_string/corpus/corpus-0182 diff --git a/fuzzer/shi_detector/corpus/corpus-0183 b/fuzzer/shi_detector_string/corpus/corpus-0183 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0183 rename to fuzzer/shi_detector_string/corpus/corpus-0183 diff --git a/fuzzer/shi_detector/corpus/corpus-0184 b/fuzzer/shi_detector_string/corpus/corpus-0184 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0184 rename to fuzzer/shi_detector_string/corpus/corpus-0184 diff --git a/fuzzer/shi_detector/corpus/corpus-0185 b/fuzzer/shi_detector_string/corpus/corpus-0185 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0185 rename to fuzzer/shi_detector_string/corpus/corpus-0185 diff --git a/fuzzer/shi_detector/corpus/corpus-0186 b/fuzzer/shi_detector_string/corpus/corpus-0186 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0186 rename to fuzzer/shi_detector_string/corpus/corpus-0186 diff --git a/fuzzer/shi_detector/corpus/corpus-0187 b/fuzzer/shi_detector_string/corpus/corpus-0187 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0187 rename to fuzzer/shi_detector_string/corpus/corpus-0187 diff --git a/fuzzer/shi_detector/corpus/corpus-0188 b/fuzzer/shi_detector_string/corpus/corpus-0188 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0188 rename to fuzzer/shi_detector_string/corpus/corpus-0188 diff --git a/fuzzer/shi_detector/corpus/corpus-0189 b/fuzzer/shi_detector_string/corpus/corpus-0189 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0189 rename to fuzzer/shi_detector_string/corpus/corpus-0189 diff --git a/fuzzer/shi_detector/corpus/corpus-0190 b/fuzzer/shi_detector_string/corpus/corpus-0190 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0190 rename to fuzzer/shi_detector_string/corpus/corpus-0190 diff --git a/fuzzer/shi_detector/corpus/corpus-0191 b/fuzzer/shi_detector_string/corpus/corpus-0191 similarity index 100% rename from fuzzer/shi_detector/corpus/corpus-0191 rename to fuzzer/shi_detector_string/corpus/corpus-0191 diff --git a/fuzzer/shi_detector/src/main.cpp b/fuzzer/shi_detector_string/src/main.cpp similarity index 96% rename from fuzzer/shi_detector/src/main.cpp rename to fuzzer/shi_detector_string/src/main.cpp index cce32c4ac..1b4d96d54 100644 --- a/fuzzer/shi_detector/src/main.cpp +++ b/fuzzer/shi_detector_string/src/main.cpp @@ -79,8 +79,8 @@ std::size_t serialize(uint8_t *Data, std::string_view resource, std::string_view } // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) -// NOLINTNEXTLINE extern "C" size_t LLVMFuzzerCustomMutator( + // NOLINTNEXTLINE uint8_t *Data, size_t Size, [[maybe_unused]] size_t MaxSize, [[maybe_unused]] unsigned int Seed) { static thread_local std::random_device dev; @@ -100,8 +100,6 @@ extern "C" size_t LLVMFuzzerCustomMutator( auto param_idx = rng() % new_size; auto param_size = 1 + rng() % (new_size - param_idx); - // std::cout << "max_size: " << MaxSize << ", new_size: " << new_size << ", idx: " << param_idx - // << ", size: " << param_size << '\n'; auto param_buffer = resource_buffer.substr(param_idx, param_size); return serialize(Data, resource_buffer, param_buffer); } diff --git a/src/condition/cmdi_detector.cpp b/src/condition/cmdi_detector.cpp new file mode 100644 index 000000000..8dfd81367 --- /dev/null +++ b/src/condition/cmdi_detector.cpp @@ -0,0 +1,434 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "argument_retriever.hpp" +#include "clock.hpp" +#include "condition/base.hpp" +#include "condition/cmdi_detector.hpp" +#include "condition/shi_common.hpp" +#include "condition/structured_condition.hpp" +#include "ddwaf.h" +#include "exception.hpp" +#include "exclusion/common.hpp" +#include "iterator.hpp" +#include "log.hpp" +#include "platform.hpp" +#include "tokenizer/shell.hpp" +#include "transformer/common/cow_string.hpp" +#include "transformer/lowercase.hpp" +#include "utils.hpp" + +using namespace std::literals; + +namespace ddwaf { +namespace { + +// An iterator which returns the given scalar, so that the match_iterator can be +// used directly with a scalar without the need for a fully-fledged object iterator +class scalar_iterator { +public: + explicit scalar_iterator(const ddwaf_object *obj, const std::span & /*path*/, + const exclusion::object_set_ref & /*exclude*/, const object_limits & /*limits*/) + : current_(obj) + {} + + ~scalar_iterator() = default; + + scalar_iterator(const scalar_iterator &) = default; + scalar_iterator(scalar_iterator &&) noexcept = default; + + scalar_iterator &operator=(const scalar_iterator &) = delete; + scalar_iterator &operator=(scalar_iterator &&) noexcept = delete; + + [[nodiscard]] const ddwaf_object *operator*() { return current_; } + bool operator++() + { + current_ = nullptr; + return false; + } + [[nodiscard]] explicit operator bool() const { return current_ != nullptr; } + [[nodiscard]] static std::vector get_current_path() { return {}; } + +protected: + const ddwaf_object *current_; +}; + +struct opt_spec { + // If set to true, an option will be used to indicate the presence of a + // shell command, for example -c or -Command, otherwise the first non-option + // argument is used + bool requires_command_opt{false}; + // If set to true, the shell command will be immediately present after the + // command option. Note that this can only be true if requires_command_opt + // is also true. + bool command_after_opt{false}; + // Indicates the platform type of the shell, this determines how options + // are interpreted from the command line. + platform shell_platform; + // The possible options hich can be used to indicate that a command is + // present in the call + std::unordered_set command_opt; + // The options which require and argument + std::unordered_set opts_with_arg; +}; + +// Most shells support -c as a way to specify a shell command, however some +// shells such as ksh allow for the first argument to be a shell command +std::unordered_map known_shells{ + // sh could be bash (red-hat) or dash (debian) so we cast a wide net + {"sh", {true, false, platform::linux, {"c"}, {"O", "o", "init-file", "rcfile"}}}, + {"bash", {true, false, platform::linux, {"c"}, {"O", "o", "init-file", "rcfile"}}}, + {"ksh", {false, false, platform::linux, {"c"}, {"o", "T"}}}, + {"rksh", {false, false, platform::linux, {"c"}, {"o", "T"}}}, + {"fish", {true, true, platform::linux, {"c", "command"}, {}}}, + {"zsh", {true, false, platform::linux, {"c"}, {"o"}}}, + {"dash", {true, false, platform::linux, {"c"}, {"o"}}}, + {"ash", {true, false, platform::linux, {"c"}, {"o"}}}, + {"powershell", {true, true, platform::windows, {"command", "commandwithargs"}, {}}}, + {"pwsh", {true, true, platform::windows, {"command", "commandwithargs"}, {}}}, +}; + +std::string_view basename(std::string_view path) +{ + std::size_t idx = std::string_view::npos; + if (system_platform::is(platform::windows)) { + idx = path.find_last_of(R"(\/)"sv); + } else { + idx = path.find_last_of('/'); + } + return idx == std::string_view::npos ? path : path.substr(idx + 1); +} + +std::string_view trim_quotes(std::string_view str) +{ + if (str.size() > 1 && ((str.front() == '"' && str.back() == '"') || + (str.front() == '\'' && str.back() == '\''))) { + str.remove_prefix(1); + str.remove_suffix(1); + } + + return str; +} + +std::string_view trim_whitespaces(std::string_view str) +{ + static const std::string_view whitespaces = " \f\n\r\t\v"; + + if (str.empty()) { + return {}; + } + + auto start = str.find_first_not_of(whitespaces); + if (start == std::string_view::npos) { + return {}; + } + + auto end = str.find_last_not_of(whitespaces); + return str.substr(start, 1 + end - start); +} + +std::size_t object_size(const ddwaf_object &obj) { return static_cast(obj.nbEntries); } + +std::string_view object_at(const ddwaf_object &obj, std::size_t idx) +{ + const ddwaf_object &child = obj.array[idx]; + if (child.type != DDWAF_OBJ_STRING) { + return {}; + } + return {child.stringValue, object_size(child)}; +} + +enum class opt_type { none, short_opt, long_opt, end_opt }; + +inline std::pair split_long_opt_with_arg(std::string_view opt) +{ + // We need at least three characters, e.g.: x=y + if (opt.size() < 3) { + return {opt, {}}; + } + + // Check if the opt has = + auto idx = opt.find('='); + // if the idx is found at the beginning or the end, bail + if (idx == std::string_view::npos || idx == 0 || idx == opt.size() - 1) { + return {opt, {}}; + } + + return {opt.substr(0, idx), trim_quotes(opt.substr(idx + 1, opt.size() - (idx + 1)))}; +} + +// arg must not be empty +inline std::tuple parse_option( + const opt_spec &spec, std::string_view arg) +{ + if (spec.shell_platform == platform::windows && (arg[0] == '-' || arg[0] == '/')) { + arg.remove_prefix(1); + if (arg.starts_with('-')) { + // Powershell in linux allows -- + arg.remove_prefix(1); + } + + return {arg, {}, opt_type::long_opt}; + } + + if (spec.shell_platform == platform::linux) { + if (arg[0] == '-') { + arg.remove_prefix(1); + if (arg.starts_with('-')) { + arg.remove_prefix(1); + if (arg.empty()) { + return {{}, {}, opt_type::end_opt}; + } + + // The long option might have the format x=y + auto [key, value] = split_long_opt_with_arg(arg); + return {key, value, opt_type::long_opt}; + } + return {arg, {}, opt_type::short_opt}; + } + + if (arg[0] == '+') { + arg.remove_prefix(1); + return {arg, {}, opt_type::short_opt}; + } + } + + return {{}, {}, opt_type::none}; +} + +std::string_view find_shell_command(std::string_view executable, const ddwaf_object &exec_args) +{ + // By initialising the cow_string with the underlying data + // contained within the std::string, we ensure a new one won't be + // allocated once the string is modified. + cow_string executable_lc{executable}; + + // Lowercase the executable in windows due to being case insensitivity + if (system_platform::is(platform::windows)) { + if (transformer::lowercase::transform(executable_lc)) { + executable = static_cast(executable_lc); + } + + if (executable.ends_with(".exe")) { + executable.remove_suffix(4); + } + } + + auto shell_it = known_shells.find(basename(executable)); + if (shell_it == known_shells.end()) { + return {}; + } + + // We've found that the current exec command is attempting to run a + // a shell. The shell binary itself might be injected, but also the + // shell command. So we need to identify the command + auto &spec = shell_it->second; + + bool command_opt_found = !spec.requires_command_opt; + for (std::size_t i = 1; i < object_size(exec_args); ++i) { + auto arg = object_at(exec_args, i); + if (arg.empty()) { + continue; + } + + auto [opt, embedded_arg, type] = parse_option(spec, arg); + // For every short_opt, we need to check if it requires an argument + if (type == opt_type::short_opt) { + for (std::size_t j = 0; j < opt.size(); ++j) { + const auto single_opt = opt.substr(j, 1); + // If we're looking for a command opt... + command_opt_found = command_opt_found || spec.command_opt.contains(single_opt); + + // If the shell requires the command immediately after the opt, we + // simply return the next argument + if (spec.command_after_opt && command_opt_found) { + if (i + 1 >= object_size(exec_args)) { + return {}; + } + + return object_at(exec_args, i + 1); + } + + // Check if the option requires an argument + if (spec.opts_with_arg.contains(single_opt)) { + // Skip the next argument + ++i; + } + } + } else if (type == opt_type::long_opt) { + cow_string opt_lc{opt}; + if (spec.shell_platform == platform::windows && + transformer::lowercase::transform(opt_lc)) { + // powershell accepts long options without considering case + opt = static_cast(opt_lc); + } + + // If we're looking for a command opt... + command_opt_found = command_opt_found || spec.command_opt.contains(opt); + + // If the shell requires the command immediately after the opt, we + // simply return the next argument + if (spec.command_after_opt && command_opt_found) { + if (embedded_arg.empty() && i + 1 >= object_size(exec_args)) { + break; + } + + return embedded_arg.empty() ? object_at(exec_args, i + 1) : embedded_arg; + } + + // Check if the option requires an argument + if (spec.opts_with_arg.contains(opt)) { + // Skip the next argument + ++i; + } + } else if (type == opt_type::end_opt) { + // Since we found the end of options, the next argument must be + // the shell invocation, but only if we have found the relevant + // command option (assuming it's required) + if (!command_opt_found || i + 1 >= object_size(exec_args)) { + break; + } + + return object_at(exec_args, i + 1); + } else { + // Once the first non-option argument is reached, it must be the + // shell command, unless the command opt is required and hasn't + // been found + if (!command_opt_found) { + break; + } + + return arg; + } + } + + return {}; +} + +std::optional cmdi_impl(const ddwaf_object &exec_args, + std::vector &resource_tokens, const ddwaf_object ¶ms, + const exclusion::object_set_ref &objects_excluded, const object_limits &limits, + ddwaf::timer &deadline) +{ + const std::string_view executable = trim_whitespaces(object_at(exec_args, 0)); + if (executable.empty()) { + return {}; + } + + // Restrict the executable matches to those with more than one component, + // or rather those not in the PATH + const auto exec_basename = basename(executable); + const bool eval_executable = (exec_basename != executable); + + // Find any associated shell command, if the current executable is a shell + auto shell_command = find_shell_command(exec_basename, exec_args); + + if (shell_command.empty() && !eval_executable) { + // No shell command and we're not evaluating the executable, bail + return std::nullopt; + } + + object::kv_iterator it(¶ms, {}, objects_excluded, limits); + for (; it; ++it) { + if (deadline.expired()) { + throw ddwaf::timeout_exception(); + } + + const ddwaf_object ¶m = *(*it); + if (param.type != DDWAF_OBJ_STRING) { + continue; + } + + if (eval_executable) { + // First check if the entire executable was injected + std::string_view value{param.stringValue, static_cast(param.nbEntries)}; + value = trim_whitespaces(value); + if (executable == value) { + // When the full binary has been injected, we consider it an exploit + // although bear in mind that this can also be a vulnerable-by-design + // application, leading to a false positive + return {{std::string(value), it.get_current_path()}}; + } + } + + if (!shell_command.empty()) { + auto res = find_shi_from_params( + shell_command, resource_tokens, param, objects_excluded, limits, deadline); + if (res.has_value()) { + res->key_path = it.get_current_path(); + return res; + } + } + } + + return std::nullopt; +} + +std::string generate_string_resource(const ddwaf_object &root) +{ + std::string resource; + for (std::size_t i = 0; i < object_size(root); ++i) { + auto child = object_at(root, i); + if (i > 0) { + resource.append(R"( ")"); + resource.append(child); + resource.append(R"(")"); + } else { + resource.append(child); + } + } + return resource; +} + +} // namespace + +cmdi_detector::cmdi_detector(std::vector args, const object_limits &limits) + : base_impl(std::move(args), limits) +{} + +eval_result cmdi_detector::eval_impl(const unary_argument &resource, + const variadic_argument ¶ms, condition_cache &cache, + const exclusion::object_set_ref &objects_excluded, ddwaf::timer &deadline) const +{ + if (resource.value->type != DDWAF_OBJ_ARRAY || resource.value->nbEntries == 0) { + return {}; + } + + std::vector resource_tokens; + for (const auto ¶m : params) { + auto res = cmdi_impl( + *resource.value, resource_tokens, *param.value, objects_excluded, limits_, deadline); + if (res.has_value()) { + std::vector resource_kp{ + resource.key_path.begin(), resource.key_path.end()}; + const bool ephemeral = resource.ephemeral || param.ephemeral; + + auto &[highlight, param_kp] = res.value(); + + DDWAF_TRACE("Target {} matched parameter value {}", param.address, highlight); + + cache.match = condition_match{{{"resource"sv, generate_string_resource(*resource.value), + resource.address, resource_kp}, + {"params"sv, highlight, param.address, param_kp}}, + {std::move(highlight)}, "cmdi_detector"sv, {}, ephemeral}; + + return {true, ephemeral}; + } + } + + return {}; +} +} // namespace ddwaf diff --git a/src/condition/cmdi_detector.hpp b/src/condition/cmdi_detector.hpp new file mode 100644 index 000000000..503e13491 --- /dev/null +++ b/src/condition/cmdi_detector.hpp @@ -0,0 +1,28 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#pragma once + +#include "condition/structured_condition.hpp" + +namespace ddwaf { + +class cmdi_detector : public base_impl { +public: + static constexpr unsigned version = 1; + static constexpr std::array param_names{"resource", "params"}; + + explicit cmdi_detector(std::vector args, const object_limits &limits = {}); + +protected: + [[nodiscard]] eval_result eval_impl(const unary_argument &resource, + const variadic_argument ¶ms, condition_cache &cache, + const exclusion::object_set_ref &objects_excluded, ddwaf::timer &deadline) const; + + friend class base_impl; +}; + +} // namespace ddwaf diff --git a/src/condition/match_iterator.hpp b/src/condition/match_iterator.hpp index 8f5a4ed09..9d4c287a6 100644 --- a/src/condition/match_iterator.hpp +++ b/src/condition/match_iterator.hpp @@ -79,7 +79,7 @@ class match_iterator { protected: ResourceType resource_; - std::string_view current_param_{}; + std::string_view current_param_; std::size_t current_index_{npos}; IteratorType it_; }; diff --git a/src/condition/shi_common.cpp b/src/condition/shi_common.cpp new file mode 100644 index 000000000..d6e7c55bc --- /dev/null +++ b/src/condition/shi_common.cpp @@ -0,0 +1,84 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include "shi_common.hpp" +#include "ddwaf.h" +#include +#include +#include +#include + +using namespace std::literals; + +namespace ddwaf { + +shell_argument_array::shell_argument_array(const ddwaf_object &root) +{ + // Since the type check is performed elsewhere, we don't need to check again + auto argc = static_cast(root.nbEntries); + if (argc == 0) { + return; + } + + // Calculate the final resource length + std::size_t resource_len = 0; + for (std::size_t i = 0; i < argc; ++i) { + const auto &child = root.array[i]; + if (child.type == DDWAF_OBJ_STRING && child.stringValue != nullptr && child.nbEntries > 0) { + // if the string is valid or non-empty, increase the resource + // length + 1 for the extra space when relevant + resource_len += + static_cast(child.nbEntries) + static_cast(i > 0); + } + } + + indices.reserve(argc); + resource.reserve(resource_len); + + std::size_t index = 0; + for (std::size_t i = 0; i < argc; ++i) { + const auto &child = root.array[i]; + if (child.type != DDWAF_OBJ_STRING || child.stringValue == nullptr || + child.nbEntries == 0) { + continue; + } + + const std::string_view str{child.stringValue, static_cast(child.nbEntries)}; + + indices.emplace_back(index, index + str.size() - 1); + + index += str.size() + 1; + + if (!resource.empty()) { + resource.append(" "sv); + } + resource.append(str); + } +} + +std::size_t shell_argument_array::find(std::string_view str, std::size_t start) +{ + while ((start = resource.find(str, start)) != npos) { + auto end = start + str.size() - 1; + // Lower bound returns the first element where the condition is false, + // which must be equivalent to cur < start_pair for the binary search to + // work as expected. The condition will match the first iterator where + // cur.second >= start. + auto res = std::lower_bound(indices.begin(), indices.end(), std::pair{start, 0}, + [](const auto &cur, const auto &start_pair) { return cur.second < start_pair.first; }); + + if (res != indices.end() && res->first <= start && res->second >= end) { + return start; + } + // Otherwise, there's overlap and it's not a valid match. + + // Attempt the next match + start += 1; + } + return npos; +} + +} // namespace ddwaf diff --git a/src/condition/shi_common.hpp b/src/condition/shi_common.hpp new file mode 100644 index 000000000..67280c9b6 --- /dev/null +++ b/src/condition/shi_common.hpp @@ -0,0 +1,98 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. +#include +#include +#include +#include +#include +#include +#include + +#include "argument_retriever.hpp" +#include "clock.hpp" +#include "condition/base.hpp" +#include "condition/match_iterator.hpp" +#include "condition/shi_detector.hpp" +#include "condition/structured_condition.hpp" +#include "ddwaf.h" +#include "exception.hpp" +#include "exclusion/common.hpp" +#include "iterator.hpp" +#include "log.hpp" +#include "tokenizer/shell.hpp" +#include "utils.hpp" + +namespace ddwaf { + +struct shi_result { + std::string value; + std::vector key_path; +}; + +struct shell_argument_array { + static constexpr std::size_t npos = std::string_view::npos; + + explicit shell_argument_array(const ddwaf_object &root); + std::size_t find(std::string_view str, std::size_t start = 0); + [[nodiscard]] bool empty() const { return resource.empty(); } + + std::vector> indices; + std::string resource; +}; + +template +std::optional find_shi_from_params(const ResourceType &resource, + std::vector &resource_tokens, const ddwaf_object ¶ms, + const exclusion::object_set_ref &objects_excluded, const object_limits &limits, + ddwaf::timer &deadline) +{ + match_iterator<2, IteratorType, ResourceType> it(resource, ¶ms, objects_excluded, limits); + for (; it; ++it) { + if (deadline.expired()) { + throw ddwaf::timeout_exception(); + } + + const auto [param, param_index] = *it; + + if (resource_tokens.empty()) { + if constexpr (std::is_same_v) { + shell_tokenizer tokenizer(resource.resource); + resource_tokens = tokenizer.tokenize(); + } else { + shell_tokenizer tokenizer(resource); + resource_tokens = tokenizer.tokenize(); + } + } + + auto end_index = param_index + param.size(); + + // Find first token + std::size_t i = 0; + for (; i < resource_tokens.size(); ++i) { + const auto &token = resource_tokens[i]; + if (end_index >= token.index && param_index < (token.index + token.str.size())) { + break; + } + } + + // Ignore if it's a single token + if ((i + 1) < resource_tokens.size() && resource_tokens[i + 1].index >= end_index) { + continue; + } + + for (; i < resource_tokens.size() && end_index >= resource_tokens[i].index; ++i) { + const auto &token = resource_tokens[i]; + if (token.type == shell_token_type::executable || + token.type == shell_token_type::redirection) { + return {{std::string(param), it.get_current_path()}}; + } + } + } + + return std::nullopt; +} + +} // namespace ddwaf diff --git a/src/condition/shi_detector.cpp b/src/condition/shi_detector.cpp index cca5b191b..cb3057a1c 100644 --- a/src/condition/shi_detector.cpp +++ b/src/condition/shi_detector.cpp @@ -3,7 +3,6 @@ // // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2021 Datadog, Inc. -#include #include #include #include @@ -14,11 +13,10 @@ #include "argument_retriever.hpp" #include "clock.hpp" #include "condition/base.hpp" -#include "condition/match_iterator.hpp" +#include "condition/shi_common.hpp" #include "condition/shi_detector.hpp" #include "condition/structured_condition.hpp" #include "ddwaf.h" -#include "exception.hpp" #include "exclusion/common.hpp" #include "log.hpp" #include "tokenizer/shell.hpp" @@ -28,146 +26,6 @@ using namespace std::literals; namespace ddwaf { -namespace { - -struct shi_result { - std::string value; - std::vector key_path; -}; - -struct shell_argument_array { - static constexpr std::size_t npos = std::string_view::npos; - - explicit shell_argument_array(const ddwaf_object &root) - { - // Since the type check is performed elsewhere, we don't need to check again - auto argc = static_cast(root.nbEntries); - if (argc == 0) { - return; - } - - // Calculate the final resource length - std::size_t resource_len = 0; - for (std::size_t i = 0; i < argc; ++i) { - const auto &child = root.array[i]; - if (child.type == DDWAF_OBJ_STRING && child.stringValue != nullptr && - child.nbEntries > 0) { - // if the string is valid or non-empty, increase the resource - // length + 1 for the extra space when relevant - resource_len += - static_cast(child.nbEntries) + static_cast(i > 0); - } - } - - indices.reserve(argc); - resource.reserve(resource_len); - - std::size_t index = 0; - for (std::size_t i = 0; i < argc; ++i) { - const auto &child = root.array[i]; - if (child.type != DDWAF_OBJ_STRING || child.stringValue == nullptr || - child.nbEntries == 0) { - continue; - } - - const std::string_view str{ - child.stringValue, static_cast(child.nbEntries)}; - - indices.emplace_back(index, index + str.size() - 1); - - index += str.size() + 1; - - if (!resource.empty()) { - resource.append(" "sv); - } - resource.append(str); - } - } - - std::size_t find(std::string_view str, std::size_t start = 0) - { - while ((start = resource.find(str, start)) != npos) { - auto end = start + str.size() - 1; - // Lower bound returns the first element where the condition is false, - // which must be equivalent to cur < start_pair for the binary search to - // work as expected. The condition will match the first iterator where - // cur.second >= start. - auto res = std::lower_bound(indices.begin(), indices.end(), std::pair{start, 0}, - [](const auto &cur, const auto &start_pair) { - return cur.second < start_pair.first; - }); - - if (res != indices.end() && res->first <= start && res->second >= end) { - return start; - } - // Otherwise, there's overlap and it's not a valid match. - - // Attempt the next match - start += 1; - } - return npos; - } - - [[nodiscard]] bool empty() const { return resource.empty(); } - - std::vector> indices; - std::string resource; -}; - -template -std::optional shi_impl(const ResourceType &resource, - std::vector &resource_tokens, const ddwaf_object ¶ms, - const exclusion::object_set_ref &objects_excluded, const object_limits &limits, - ddwaf::timer &deadline) -{ - match_iterator it(resource, ¶ms, objects_excluded, limits); - for (; it; ++it) { - if (deadline.expired()) { - throw ddwaf::timeout_exception(); - } - - const auto [param, param_index] = *it; - - if (resource_tokens.empty()) { - if constexpr (std::is_same_v) { - shell_tokenizer tokenizer(resource.resource); - resource_tokens = tokenizer.tokenize(); - } else { - shell_tokenizer tokenizer(resource); - resource_tokens = tokenizer.tokenize(); - } - } - - auto end_index = param_index + param.size(); - - // Find first token - std::size_t i = 0; - for (; i < resource_tokens.size(); ++i) { - const auto &token = resource_tokens[i]; - if (end_index >= token.index && param_index < (token.index + token.str.size())) { - break; - } - } - - // Ignore if it's a single token - if ((i + 1) < resource_tokens.size() && resource_tokens[i + 1].index >= end_index) { - continue; - } - - for (; i < resource_tokens.size(); ++i) { - const auto &token = resource_tokens[i]; - if (token.type == shell_token_type::executable || - token.type == shell_token_type::redirection) { - return {{std::string(param), it.get_current_path()}}; - } - } - } - - return std::nullopt; -} - -} // namespace - eval_result shi_detector::eval_string(const unary_argument &resource, const variadic_argument ¶ms, condition_cache &cache, const exclusion::object_set_ref &objects_excluded, ddwaf::timer &deadline) const @@ -182,7 +40,7 @@ eval_result shi_detector::eval_string(const unary_argument std::vector resource_tokens; for (const auto ¶m : params) { - auto res = shi_impl( + auto res = find_shi_from_params( resource_sv, resource_tokens, *param.value, objects_excluded, limits_, deadline); if (res.has_value()) { std::vector resource_kp{ @@ -216,8 +74,8 @@ eval_result shi_detector::eval_array(const unary_argument std::vector resource_tokens; for (const auto ¶m : params) { - auto res = - shi_impl(arguments, resource_tokens, *param.value, objects_excluded, limits_, deadline); + auto res = find_shi_from_params( + arguments, resource_tokens, *param.value, objects_excluded, limits_, deadline); if (res.has_value()) { std::vector resource_kp{ resource.key_path.begin(), resource.key_path.end()}; diff --git a/src/condition/shi_detector.hpp b/src/condition/shi_detector.hpp index 179b70ed5..6d0998865 100644 --- a/src/condition/shi_detector.hpp +++ b/src/condition/shi_detector.hpp @@ -19,7 +19,6 @@ class shi_detector : public base_impl { explicit shi_detector(std::vector args, const object_limits &limits = {}); protected: - // TODO support array shell_args [[nodiscard]] eval_result eval_impl(const unary_argument &resource, const variadic_argument ¶ms, condition_cache &cache, const exclusion::object_set_ref &objects_excluded, ddwaf::timer &deadline) const; diff --git a/src/parser/expression_parser.cpp b/src/parser/expression_parser.cpp index 1d0faef5e..7f332f05c 100644 --- a/src/parser/expression_parser.cpp +++ b/src/parser/expression_parser.cpp @@ -11,6 +11,7 @@ #include #include "condition/base.hpp" +#include "condition/cmdi_detector.hpp" #include "condition/exists.hpp" #include "condition/lfi_detector.hpp" #include "condition/scalar_condition.hpp" @@ -178,6 +179,9 @@ std::shared_ptr parse_expression(const parameter::vector &conditions } else if (operator_name == "shi_detector") { conditions.emplace_back(build_versioned_condition( operator_name, version, params, source, transformers, addresses, limits)); + } else if (operator_name == "cmdi_detector") { + conditions.emplace_back(build_versioned_condition( + operator_name, version, params, source, transformers, addresses, limits)); } else if (operator_name == "exists") { auto arguments = parse_arguments(params, source, transformers, addresses, limits); diff --git a/src/platform.hpp b/src/platform.hpp index 339e5da0e..3e5467622 100644 --- a/src/platform.hpp +++ b/src/platform.hpp @@ -14,7 +14,7 @@ enum class platform : uint8_t { unknown = 0, linux, windows, macos }; struct system_platform { static platform current() { return platform_override; } - + static bool is(platform p) { return platform_override == p; } static void override_platform(platform p) { platform_override = p; } static platform platform_override; diff --git a/src/processor/fingerprint.cpp b/src/processor/fingerprint.cpp index 415968287..c6c8d9480 100644 --- a/src/processor/fingerprint.cpp +++ b/src/processor/fingerprint.cpp @@ -83,21 +83,6 @@ struct string_buffer { std::size_t length; }; -std::string str_lowercase(std::string_view str) -{ - auto buffer = std::string{str}; - - // By initialising the cow_string with the underlying data - // contained within the std::string, we ensure a new one won't be - // allocated once the string is modified. - cow_string str_lc{buffer.data(), buffer.size()}; - transformer::lowercase::transform(str_lc); - - str_lc.move(); // move to avoid freeing the string - - return buffer; // NOLINT(clang-analyzer-unix.Malloc) -} - // Return true if the first argument is less than (i.e. is ordered before) the second bool str_casei_cmp(std::string_view left, std::string_view right) { @@ -205,7 +190,15 @@ template struct field_generato struct string_field : field_generator { explicit string_field(std::string_view input) : value(input) {} // NOLINTNEXTLINE(readability-make-member-function-const) - [[nodiscard]] std::string generate() { return str_lowercase(value); } + [[nodiscard]] std::string generate() + { + auto buffer = std::string{value}; + + auto str_lc = cow_string::from_mutable_buffer(buffer.data(), buffer.size()); + transformer::lowercase::transform(str_lc); + + return buffer; // NOLINT(clang-analyzer-unix.Malloc) + } std::string_view value; }; diff --git a/src/transformer/common/cow_string.hpp b/src/transformer/common/cow_string.hpp index 237a2d7cf..5ece827d4 100644 --- a/src/transformer/common/cow_string.hpp +++ b/src/transformer/common/cow_string.hpp @@ -26,10 +26,6 @@ class cow_string { throw std::runtime_error{"cow_string initialised with nullptr"}; } } - - explicit cow_string(char *str, std::size_t length) - : modified_(true), buffer_(str), length_(length) - {} cow_string(const cow_string &) = delete; cow_string &operator=(const cow_string &) = delete; cow_string(cow_string &&other) = delete; @@ -37,12 +33,17 @@ class cow_string { ~cow_string() { - [[likely]] if (modified_) { + [[likely]] if (modified_ && owned_) { // NOLINTNEXTLINE(hicpp-no-malloc,cppcoreguidelines-no-malloc) free(buffer_); } } + static cow_string from_mutable_buffer(char *str, std::size_t length) + { + return cow_string{str, length}; + } + template [[nodiscard]] constexpr T at(std::size_t idx) const { return static_cast(buffer_[idx]); @@ -90,12 +91,13 @@ class cow_string { // Replaces the internal buffer, ownership is transferred void replace_buffer(char *str, std::size_t length) { - [[likely]] if (modified_) { + [[likely]] if (modified_ && owned_) { // NOLINTNEXTLINE(hicpp-no-malloc,cppcoreguidelines-no-malloc) free(buffer_); } modified_ = true; + owned_ = true; buffer_ = str; length_ = length; } @@ -125,6 +127,10 @@ class cow_string { } protected: + explicit cow_string(char *str, std::size_t length) + : modified_(true), owned_(false), buffer_(str), length_(length) + {} + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) void force_copy(std::size_t bytes) { @@ -145,6 +151,7 @@ class cow_string { } bool modified_{false}; + bool owned_{true}; char *buffer_{nullptr}; std::size_t length_; }; diff --git a/tests/unit/condition/cmdi_detector_test.cpp b/tests/unit/condition/cmdi_detector_test.cpp new file mode 100644 index 000000000..5a10b923a --- /dev/null +++ b/tests/unit/condition/cmdi_detector_test.cpp @@ -0,0 +1,871 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include "common/gtest_utils.hpp" +#include "condition/cmdi_detector.hpp" +#include "platform.hpp" + +using namespace ddwaf; +using namespace std::literals; + +namespace { + +template std::vector gen_param_def(Args... addresses) +{ + return {{{{std::string{addresses}, get_target_index(addresses)}}}...}; +} + +std::string generate_resource_string(const std::vector &resource) +{ + std::string resource_str; + for (const auto &arg : resource) { + if (!resource_str.empty()) { + resource_str.append(" \""); + resource_str.append(arg); + resource_str.append("\""); + } else { + resource_str.append(arg); + } + } + return resource_str; +} + +TEST(TestCmdiDetector, InvalidType) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + ddwaf_object tmp; + ddwaf_object root; + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.sys.exec.cmd", ddwaf_object_map(&tmp)); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "whatever")); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome); +} + +TEST(TestCmdiDetector, EmptyResource) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + ddwaf_object tmp; + ddwaf_object root; + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.sys.exec.cmd", ddwaf_object_array(&tmp)); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "whatever")); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome); +} + +TEST(TestCmdiDetector, NoInjection) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string>> samples{ + {{"ls", "-l", "/file/in/repository"}, "whatever"}, + {{"ls", "-l", "/file/in/repository"}, "whatever"}, + {{"long-exec-name", "-l", "/file/in/repository"}, "whatever"}, + {{"/usr/bin/reboot"}, "whatever"}, + {{"/usr/bin/reboot", "-f"}, "whatever"}, + {{"/usr/bin/reboot", "-f"}, "whatever"}, + {{"/usr/bin/reboot", "-f"}, "whatever"}, + {{"/usr/bin/reboot", "-f"}, "whatever"}, + {{"/usr/bin/reboot", "-f"}, "whatever"}, + {{"//usr//bin//reboot"}, "whatever"}, + {{"//usr//bin//reboot", "-f"}, "whatever"}, + {{R"(C:\\Temp\\script.ps1)"}, "whatever"}, + {{R"(C:\Temp\script.ps1)"}, "whatever"}, + {{"C:/bin/powershell.exe"}, "whatever"}, + {{"C:/bin/powershell.exe", "-Command", "ls -l $file ; cat /etc/passwd"}, "whatever"}, + {{"/usr/bin/ash", "-c", "ls -l $file ; cat /etc/passwd"}, "whatever"}, + {{"/usr/bin/ash", "-c", "ls -l ; $(cat $file)"}, "whatever"}, + {{"/usr/bin/ash", "-c", "\n -l ; $(cat $file)"}, "whatever"}, + {{"/usr/bin/psh", "-c", "ls -l ; $(cat $file)"}, "whatever"}, + {{"/usr/bin/bash", "-Command", "\"ls -l ; $(cat $file)\""}, "whatever"}, + {{"/usr/bin/ksh", "getconf PAGESIZE"}, "whatever"}, + {{"/usr/bin/rksh", "cat hello"}, "whatever"}, + {{"/usr/bin/fish", "--command=\"cat hello\""}, "whatever"}, + {{"/usr/bin/fish", "--command='cat hello'"}, "whatever"}, + {{"/usr/bin/fish", "--command=cat hello"}, "whatever"}, + }; + + for (const auto &[resource, param] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome) << param; + EXPECT_FALSE(res.ephemeral); + } +} + +TEST(TestCmdiDetector, NoExecutableInjection) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string>> samples{ + {{"ls", "-l", "/file/in/repository"}, "/usr/bin/ls"}, + {{"ls", "-l", "/file/in/repository"}, "ls"}, + {{"long-exec-name", "-l", "/file/in/repository"}, "long-exec-name"}, + {{"/usr/bin/reboot"}, "reboot"}, + {{"/usr/bin/reboot", "-f"}, "unrelated.exe"}, + {{"/usr/bin/reboot", "-f"}, "/bin/unrelated.exe"}, + {{"/usr/bin/reboot", "-f"}, "/usr"}, + {{"/usr/bin/reboot", "-f"}, "usr"}, + {{"/usr/bin/reboot", "-f"}, "-f"}, + {{"//usr//bin//reboot"}, "usr//bin//reboot"}, + {{"//usr//bin//reboot", "-f"}, "//usr//bin//eboot"}, + {{R"(C:\\Temp\\script.ps1)"}, R"(C:\\Temp\script.ps1)"}, + {{R"(C:\Temp\script.ps1)"}, R"(C:\Temp\script.ps)"}, + {{"C:/bin/powershell.exe"}, ":/bin/powershell.exe"}, + }; + + for (const auto &[resource, param] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome) << param; + EXPECT_FALSE(res.ephemeral); + } +} + +TEST(TestCmdiDetector, NoShellInjection) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string>> samples{ + {{"C:/bin/powershell.exe", "-Command", "ls -l $file ; cat /etc/passwd"}, "-l $file"}, + {{"/usr/bin/ash", "-c", "ls -l $file ; cat /etc/passwd"}, "cat"}, + {{"/usr/bin/ash", "-c", "ls -l ; $(cat $file)"}, "-l"}, + {{"/usr/bin/ash", "-c", "\n -l ; $(cat $file)"}, "\n"}, + {{"/usr/bin/psh", "-c", "ls -l ; $(cat $file)"}, "ls -l"}, + {{"/usr/bin/bash", "-Command", "\"ls -l ; $(cat $file)\""}, "ls -l"}, + {{"/usr/bin/ksh", "getconf PAGESIZE"}, "get"}, + {{"/usr/bin/rksh", "cat hello"}, "hello"}, + {{"/usr/bin/fish", "--command=\"cat hello\""}, "hello"}, + {{"/usr/bin/fish", "--command='cat hello'"}, "hello"}, + {{"/usr/bin/fish", "--command=cat hello"}, "hello"}, + {{"bash", "-c", + "file -b --mime '/tmp/ForumEntr-avec " + "kedge20160204-37527-ctbhbi20160204-37527-tuzome.png'"}, + "file"}, + {{"bash", "file -b --mime '/tmp/ForumEntr-avec " + "kedge20160204-37527-ctbhbi20160204-37527-tuzome.png'"}, + "file -b --mime"}, + {{"/bin/sh", "file -b --mime '/tmp/ForumEntr-avec " + "kedge20160204-37527-ctbhbi20160204-37527-tuzome.png'"}, + "file -e"}, + {{"dash", "echo hello"}, "b"}, + {{"/bin/zsh", "phantomjs /vendor/assets/javascripts/highcharts/highcharts-convert.js " + "-infile /app/tmp/highcharts/json/input.json -outfile " + "/app/tmp/highcharts/png/survey_641_chart.png -width 700 2>&1"}, + "641"}, + {{"/sh", "/usr/bin/generate.sh --margin-bottom 20mm --margin-top 27mm --print-media-type " + "--header-html https://url/blabla-bla --footer-html https://url/blabla-bla " + "https://url/blabla-bla -"}, + "blabla-bla"}, + {{"/bin/fish", "ls -l -r -t"}, "-r -t"}, + }; + + for (const auto &[resource, param] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome) << resource_str; + EXPECT_FALSE(res.ephemeral); + } +} + +TEST(TestCmdiDetector, ExecutableInjectionLinux) +{ + system_platform_override spo{platform::linux}; + + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string, std::string>> samples{ + {{"/usr/bin/reboot"}, "/usr/bin/reboot", "/usr/bin/reboot"}, + {{"/usr/bin/reboot", "-f"}, "/usr/bin/reboot", "/usr/bin/reboot"}, + {{"//usr//bin//reboot"}, "//usr//bin//reboot", "//usr//bin//reboot"}, + {{"//usr//bin//reboot", "-f"}, "//usr//bin//reboot", "//usr//bin//reboot"}, + {{"bin/reboot", "-f"}, "bin/reboot", "bin/reboot"}, + {{"../reboot", "-f"}, "../reboot", "../reboot"}, + {{"/reboot", "-f"}, "/reboot", "/reboot"}, + {{"/bin/../usr/bin/reboot", "-f"}, "/bin/../usr/bin/reboot", "/bin/../usr/bin/reboot"}, + }; + + for (const auto &[resource, param, expected] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << param; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, expected.c_str()); + EXPECT_TRUE(cache.match->args[1].key_path.empty()); + + EXPECT_STR(cache.match->highlights[0], expected.c_str()); + } +} + +TEST(TestCmdiDetector, ExecutableInjectionWindows) +{ + system_platform_override spo{platform::windows}; + + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string, std::string>> samples{ + {{"/usr/bin/reboot"}, "/usr/bin/reboot", "/usr/bin/reboot"}, + {{"/usr/bin/reboot", "-f"}, "/usr/bin/reboot", "/usr/bin/reboot"}, + {{"//usr//bin//reboot"}, "//usr//bin//reboot", "//usr//bin//reboot"}, + {{"//usr//bin//reboot", "-f"}, "//usr//bin//reboot", "//usr//bin//reboot"}, + {{"bin/reboot", "-f"}, "bin/reboot", "bin/reboot"}, + {{"../reboot", "-f"}, "../reboot", "../reboot"}, + {{"/reboot", "-f"}, "/reboot", "/reboot"}, + {{"/bin/../usr/bin/reboot", "-f"}, "/bin/../usr/bin/reboot", "/bin/../usr/bin/reboot"}, + {{R"(C:\\Temp\\script.ps1)"}, R"(C:\\Temp\\script.ps1)", R"(C:\\Temp\\script.ps1)"}, + {{R"(C:\Temp\script.ps1)"}, R"(C:\Temp\script.ps1)", R"(C:\Temp\script.ps1)"}, + {{"C:/bin/powershell.exe"}, "C:/bin/powershell.exe", "C:/bin/powershell.exe"}, + }; + + for (const auto &[resource, param, expected] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << param; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, expected.c_str()); + EXPECT_TRUE(cache.match->args[1].key_path.empty()); + + EXPECT_STR(cache.match->highlights[0], expected.c_str()); + } +} + +TEST(TestCmdiDetector, ExecutableWithSpacesInjection) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string, std::string>> samples{ + {{" /usr/bin/ls ", "-l", "/file/in/repository"}, " /usr/bin/ls ", "/usr/bin/ls"}, + {{" /usr/bin/ls\n", "-l", "/file/in/repository"}, " /usr/bin/ls\n", "/usr/bin/ls"}, + {{"\t/usr/bin/ls\n", "-l", "/file/in/repository"}, "/usr/bin/ls", "/usr/bin/ls"}, + {{"/usr/bin/ls", "-l", "/file/in/repository"}, "\t /usr/bin/ls \n", "/usr/bin/ls"}, + {{" //usr//bin//reboot\t\n"}, "//usr//bin//reboot", "//usr//bin//reboot"}, + {{" /usr/bin/reboot", "-f"}, " /usr/bin/reboot ", "/usr/bin/reboot"}, + {{" /usr/bin/reboot\v", "-f"}, " /usr/bin/reboot ", "/usr/bin/reboot"}, + {{"\r \r /usr/bin/reboot\v", "-f"}, "\v \n /usr/bin/reboot ", "/usr/bin/reboot"}, + }; + + for (const auto &[resource, param, expected] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << param; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, expected.c_str()); + EXPECT_TRUE(cache.match->args[1].key_path.empty()); + + EXPECT_STR(cache.match->highlights[0], expected.c_str()); + } +} + +TEST(TestCmdiDetector, LinuxShellInjection) +{ + system_platform_override spo{platform::linux}; + + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string>> samples{ + {{"sh", "-c", "ls -l"}, "ls -l"}, + {{"/sh", "-c", "ls -l"}, "ls -l"}, + {{"/bin/sh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/sh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/sh", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/sh", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/sh", "-c", "-i", "ls -l"}, "ls -l"}, + + {{"bash", "-c", "ls -l"}, "ls -l"}, + {{"/bash", "-c", "ls -l"}, "ls -l"}, + {{"/bin/bash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "--init-file", "whatever", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "--rcfile", ".bashrc", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-co", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "+o", "errexit", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-o", "errexit", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "+o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "-o", "errexit", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "+O", "extglob", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-O", "extglob", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-cO", "extglob", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "+O", "extglob", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "-O", "extglob", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "-O", "extglob", "--", "ls -l"}, "ls -l"}, + + {{"ksh", "-c", "ls -l"}, "ls -l"}, + {{"/ksh", "-c", "ls -l"}, "ls -l"}, + {{"/bin/ksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "--posix", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "--posix", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "+o", "errexit", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "+o", "errexit", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-T", "007", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "-T", "007", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-co", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-oc", "errexit", "ls -l"}, "ls -l"}, + + {{"rksh", "-c", "ls -l"}, "ls -l"}, + {{"/rksh", "-c", "ls -l"}, "ls -l"}, + {{"/bin/rksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "--posix", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "--posix", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "+o", "errexit", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "+o", "errexit", "--posix", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-T", "007", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "-T", "007", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-co", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-oc", "errexit", "ls -l"}, "ls -l"}, + + {{"fish", "-c", "ls -l"}, "ls -l"}, + {{"/fish", "-c", "ls -l"}, "ls -l"}, + {{"/bin/fish", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "--command", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "--command=ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "--command=\"ls -l\""}, "ls -l"}, + {{"/usr/bin/fish", "--command='ls -l'"}, "ls -l"}, + + {{"zsh", "-c", "ls -l"}, "ls -l"}, + {{"/zsh", "-c", "ls -l"}, "ls -l"}, + {{"/bin/zsh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/zsh", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/zsh", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/zsh", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/zsh", "-c", "-i", "ls -l"}, "ls -l"}, + + {{"dash", "-c", "ls -l"}, "ls -l"}, + {{"/dash", "-c", "ls -l"}, "ls -l"}, + {{"/bin/dash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "+o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-co", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-oc", "errexit", "ls -l"}, "ls -l"}, + + {{"ash", "-c", "ls -l"}, "ls -l"}, + {{"/ash", "-c", "ls -l"}, "ls -l"}, + {{"/bin/ash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-ci", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-ic", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "--", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "-o", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-co", "errexit", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-oc", "errexit", "ls -l"}, "ls -l"}, + + {{"/usr/bin/bash", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "+x", "-i", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/ksh", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/rksh", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/fish", "-c", "ls -l"}, "ls -l"}, + {{"/usr/bin/zsh", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "+x", "ls -l"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+x", "ls -l"}, "ls -l"}, + + // Double quote removal + {{"/usr/bin/bash", "-c", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "+x", "-i", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/ksh", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/rksh", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/fish", "-c", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/zsh", "-c", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "+x", R"("ls -l")"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+x", R"("ls -l")"}, "ls -l"}, + + // Single quote removal + {{"/usr/bin/bash", "-c", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/bash", "-c", "+x", "-i", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/ksh", "-c", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/ksh", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/rksh", "-c", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/rksh", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/fish", "-c", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/zsh", "-c", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/dash", "-c", "+x", R"('ls -l')"}, "ls -l"}, + {{"/usr/bin/ash", "-c", "+x", R"('ls -l')"}, "ls -l"}, + + // Linux powershell.... + {{"powershell", "-Command", "ls -l"}, "ls -l"}, + {{"powershell", "-CommandWithArgs", "ls -l"}, "ls -l"}, + {{"powershell", "/Command", "ls -l"}, "ls -l"}, + {{"powershell", "/CommandWithArgs", "ls -l"}, "ls -l"}, + {{"powershell", "--Command", "ls -l"}, "ls -l"}, + {{"powershell", "--CommandWithArgs", "ls -l"}, "ls -l"}, + {{"powershell", "-command", "ls -l"}, "ls -l"}, + {{"powershell", "-commandwithargs", "ls -l"}, "ls -l"}, + {{"powershell", "/command", "ls -l"}, "ls -l"}, + {{"powershell", "/commandwithargs", "ls -l"}, "ls -l"}, + {{"powershell", "--command", "ls -l"}, "ls -l"}, + {{"powershell", "--commandwithargs", "ls -l"}, "ls -l"}, + + {{"pwsh", "-Command", "ls -l"}, "ls -l"}, + {{"pwsh", "-CommandWithArgs", "ls -l"}, "ls -l"}, + {{"pwsh", "/Command", "ls -l"}, "ls -l"}, + {{"pwsh", "/CommandWithArgs", "ls -l"}, "ls -l"}, + {{"pwsh", "--Command", "ls -l"}, "ls -l"}, + {{"pwsh", "--CommandWithArgs", "ls -l"}, "ls -l"}, + {{"pwsh", "-command", "ls -l"}, "ls -l"}, + {{"pwsh", "-commandwithargs", "ls -l"}, "ls -l"}, + {{"pwsh", "/command", "ls -l"}, "ls -l"}, + {{"pwsh", "/commandwithargs", "ls -l"}, "ls -l"}, + {{"pwsh", "--command", "ls -l"}, "ls -l"}, + {{"pwsh", "--commandwithargs", "ls -l"}, "ls -l"}, + }; + + for (const auto &[resource, param] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << resource_str; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, param.c_str()); + EXPECT_TRUE(cache.match->args[1].key_path.empty()); + + EXPECT_STR(cache.match->highlights[0], param.c_str()); + } +} + +TEST(TestCmdiDetector, WindowsShellInjection) +{ + system_platform_override spo{platform::windows}; + + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + + std::vector, std::string>> samples{ + {{R"(C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C:\WINDOWS\SYSTEM32\WINDOWSPOWERSHELL\V1.0\POWERSHELL.EXE)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C:/windows/system32/WindowsPowerShell/v1.0/powershell.exe)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C:/WINDOWS/SYSTEM32/WINDOWSPOWERSHELL/V1.0/POWERSHELL.EXE)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C:\\WINDOWS\\SYSTEM32\\WINDOWSPOWERSHELL\\V1.0\\POWERSHELL.EXE)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C://windows//system32//WindowsPowerShell//v1.0//powershell.exe)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(C://WINDOWS//SYSTEM32//WINDOWSPOWERSHELL//V1.0//POWERSHELL.EXE)", "-Command", "ls -l"}, + "ls -l"}, + {{R"(powershell.exe)", "-Command", "ls -l"}, "ls -l"}, + {{R"(POWERSHELL.EXE)", "-Command", "ls -l"}, "ls -l"}, + {{R"(powershell)", "-Command", "ls -l"}, "ls -l"}, + {{R"(POWERSHELL)", "-Command", "ls -l"}, "ls -l"}, + + {{R"(powershell.exe)", "-Command", R"("ls -l")"}, "ls -l"}, + {{R"(POWERSHELL.EXE)", "-Command", R"("ls -l")"}, "ls -l"}, + {{R"(powershell)", "-Command", R"("ls -l")"}, "ls -l"}, + {{R"(POWERSHELL)", "-Command", R"("ls -l")"}, "ls -l"}, + + {{R"(powershell.exe)", "-Command", R"("ls -l")"}, R"("ls -l")"}, + {{R"(POWERSHELL.EXE)", "-Command", R"("ls -l")"}, R"("ls -l")"}, + {{R"(powershell)", "-Command", R"("ls -l")"}, R"("ls -l")"}, + {{R"(POWERSHELL)", "-Command", R"("ls -l")"}, R"("ls -l")"}, + + {{R"(powershell.exe)", "-Command", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL.EXE)", "-Command", R"('ls -l')"}, "ls -l"}, + {{R"(powershell)", "-Command", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL)", "-Command", R"('ls -l')"}, "ls -l"}, + + {{R"(powershell.exe)", "-CommandWithArgs", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL.EXE)", "-CommandWithArgs", R"('ls -l')"}, "ls -l"}, + {{R"(powershell)", "-CommandWithArgs", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL)", "-CommandWithArgs", R"('ls -l')"}, "ls -l"}, + + {{R"(powershell.exe)", "/Command", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL.EXE)", "/CommandWithArgs", R"('ls -l')"}, "ls -l"}, + {{R"(powershell)", "/command", R"('ls -l')"}, "ls -l"}, + {{R"(POWERSHELL)", "/commandWithArgs", R"('ls -l')"}, "ls -l"}, + + {{R"(pwsh)", "/Command", R"('ls -l')"}, "ls -l"}, + {{R"(pwSh)", "/commandWithArgs", R"('ls -l')"}, "ls -l"}, + {{R"(PWsh)", "-command", R"('ls -l')"}, "ls -l"}, + {{R"(pwsh)", "-commandWithArgs", R"('ls -l')"}, "ls -l"}, + }; + + for (const auto &[resource, param] : samples) { + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, param.c_str())); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << resource_str; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, param.c_str()); + EXPECT_TRUE(cache.match->args[1].key_path.empty()); + + EXPECT_STR(cache.match->highlights[0], param.c_str()); + } +} + +TEST(TestCmdiDetector, ExecutableInjectionMultipleArguments) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::vector resource{"/usr/bin/halt", "-h"}; + std::unordered_map params{ + {"halt", "bin"}, {"-h", "usr"}, {"executable", "/usr/bin/halt"}}; + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object map; + ddwaf_object_map(&map); + for (const auto &[key, value] : params) { + ddwaf_object_map_add(&map, key.c_str(), ddwaf_object_string(&tmp, value.c_str())); + } + ddwaf_object_map_add(&root, "server.request.query", &map); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << resource[0]; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, "/usr/bin/halt"); + EXPECT_STR(cache.match->args[1].key_path[0], "executable"); + + EXPECT_STR(cache.match->highlights[0], "/usr/bin/halt"); +} + +TEST(TestCmdiDetector, EmptyExecutable) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::vector resource{"", "-h"}; + std::unordered_map params{ + {"halt", "bin"}, {"-h", "usr"}, {"executable", "/usr/bin/halt"}}; + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object map; + ddwaf_object_map(&map); + for (const auto &[key, value] : params) { + ddwaf_object_map_add(&map, key.c_str(), ddwaf_object_string(&tmp, value.c_str())); + } + ddwaf_object_map_add(&root, "server.request.query", &map); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_FALSE(res.outcome) << resource[0]; + EXPECT_FALSE(res.ephemeral); +} + +TEST(TestCmdiDetector, ShellInjectionMultipleArguments) +{ + cmdi_detector cond{{gen_param_def("server.sys.exec.cmd", "server.request.query")}}; + ddwaf_object tmp; + ddwaf_object root; + ddwaf_object_map(&root); + + std::vector resource{"/usr/bin/sh", "-c", "ls -l $file; $(cat /etc/passwd)"}; + std::unordered_map params{ + {"-l $file", "bin"}, {"-h", "usr"}, {"shell", "; $(cat /etc/passwd)"}}; + + std::string resource_str = generate_resource_string(resource); + ddwaf_object array; + ddwaf_object_array(&array); + for (const auto &arg : resource) { + ddwaf_object_array_add(&array, ddwaf_object_string(&tmp, arg.c_str())); + } + ddwaf_object_map_add(&root, "server.sys.exec.cmd", &array); + + ddwaf_object map; + ddwaf_object_map(&map); + for (const auto &[key, value] : params) { + ddwaf_object_map_add(&map, key.c_str(), ddwaf_object_string(&tmp, value.c_str())); + } + ddwaf_object_map_add(&root, "server.request.query", &map); + + object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + condition_cache cache; + auto res = cond.eval(cache, store, {}, {}, deadline); + ASSERT_TRUE(res.outcome) << resource[0]; + EXPECT_FALSE(res.ephemeral); + + EXPECT_TRUE(cache.match); + EXPECT_STRV(cache.match->args[0].address, "server.sys.exec.cmd"); + EXPECT_STR(cache.match->args[0].resolved, resource_str.c_str()); + EXPECT_TRUE(cache.match->args[0].key_path.empty()); + + EXPECT_STRV(cache.match->args[1].address, "server.request.query"); + EXPECT_STR(cache.match->args[1].resolved, "; $(cat /etc/passwd)"); + EXPECT_STR(cache.match->args[1].key_path[0], "shell"); + + EXPECT_STR(cache.match->highlights[0], "; $(cat /etc/passwd)"); +} + +} // namespace diff --git a/tests/unit/condition/shi_detector_array_test.cpp b/tests/unit/condition/shi_detector_array_test.cpp index 8fb113479..62f12f8b5 100644 --- a/tests/unit/condition/shi_detector_array_test.cpp +++ b/tests/unit/condition/shi_detector_array_test.cpp @@ -123,6 +123,10 @@ TEST(TestShiDetectorArray, NoMatchAndFalsePositives) {{"ls", "-l", "-r -t"}, "-r -t"}, {{R"!({ ( $(echo ls) ) })!"}, "ls)"}, {{R"!({ ( $(echo ls) ) } #)!", "cat /etc/passwd"}, "cat /etc/passwd)"}, + {{"ls", "-l $file", "&&", "cat /etc/passwd"}, "-l $file"}, + {{"ls -l $file ; cat /etc/passwd"}, "-l $file"}, + // This should match at some point + {{"time", "ls -l"}, "ls -l"}, }; for (const auto &[resource, param] : samples) { diff --git a/tests/unit/condition/shi_detector_string_test.cpp b/tests/unit/condition/shi_detector_string_test.cpp index 70213ddcf..ab0e543fd 100644 --- a/tests/unit/condition/shi_detector_string_test.cpp +++ b/tests/unit/condition/shi_detector_string_test.cpp @@ -76,6 +76,11 @@ TEST(TestShiDetectorString, NoMatchAndFalsePositives) {R"(ls -l -r -t)", "-r -t"}, {R"!({ ( $(echo ls) ) })!", "ls)"}, {R"!({ ( $(echo ls) ) } # cat /etc/passwd)!", "cat /etc/passwd"}, + {R"!(ls -l file && cat /etc/passwd)!", "-l file"}, + {R"!("ls -l $file ; cat /etc/passwd)!", "-l $file"}, + // This should match at some point + {R"!(time ls -l)!", "ls -l"}, + }; for (const auto &[resource, param] : samples) { diff --git a/tests/unit/transformer/cow_string_test.cpp b/tests/unit/transformer/cow_string_test.cpp index 8d3da0915..39fb7f65b 100644 --- a/tests/unit/transformer/cow_string_test.cpp +++ b/tests/unit/transformer/cow_string_test.cpp @@ -26,6 +26,19 @@ TEST(TestCoWString, ConstRead) EXPECT_NE(str.data(), nullptr); } +TEST(TestCoWString, ConstReadMutableBuffer) +{ + std::string original{"value"}; + auto str = cow_string::from_mutable_buffer(original.data(), original.size()); + EXPECT_TRUE(str.modified()); + + EXPECT_EQ(original.length(), str.length()); + for (size_t i = 0; i < original.length(); ++i) { EXPECT_EQ(original[i], str.at(i)); } + + EXPECT_TRUE(str.modified()); + EXPECT_EQ(str.data(), original.data()); +} + TEST(TestCoWString, NonConstRead) { constexpr std::string_view original = "value"; @@ -39,6 +52,19 @@ TEST(TestCoWString, NonConstRead) EXPECT_NE(str.data(), nullptr); } +TEST(TestCoWString, NonConstReadMutableBuffer) +{ + std::string original{"value"}; + auto str = cow_string::from_mutable_buffer(original.data(), original.size()); + EXPECT_TRUE(str.modified()); + + EXPECT_EQ(original.length(), str.length()); + for (size_t i = 0; i < original.length(); ++i) { EXPECT_EQ(original[i], str[i]); } + + EXPECT_TRUE(str.modified()); + EXPECT_EQ(str.data(), original.data()); +} + TEST(TestCoWString, TruncateUnmodified) { cow_string str("value"); @@ -51,6 +77,21 @@ TEST(TestCoWString, TruncateUnmodified) EXPECT_STREQ(str.data(), "valu"); } +TEST(TestCoWString, TruncateUnmodifiedMutableBuffer) +{ + std::string original{"value"}; + auto str = cow_string::from_mutable_buffer(original.data(), original.size()); + + EXPECT_EQ(str.length(), 5); + EXPECT_TRUE(str.modified()); + + str.truncate(4); + + EXPECT_EQ(str.length(), 4); + EXPECT_STREQ(str.data(), "valu"); + EXPECT_EQ(str.data(), original.data()); +} + TEST(TestCoWString, WriteAndTruncate) { cow_string str("value"); @@ -66,6 +107,24 @@ TEST(TestCoWString, WriteAndTruncate) EXPECT_STREQ(str.data(), "vale"); } +TEST(TestCoWString, WriteAndTruncateMutableBuffer) +{ + std::string original{"value"}; + auto str = cow_string::from_mutable_buffer(original.data(), original.size()); + + EXPECT_EQ(str.length(), 5); + EXPECT_TRUE(str.modified()); + + str[3] = 'e'; + EXPECT_TRUE(str.modified()); + EXPECT_NE(str.data(), nullptr); + + str.truncate(4); + EXPECT_EQ(str.length(), 4); + EXPECT_STREQ(str.data(), "vale"); + EXPECT_EQ(str.data(), original.data()); +} + TEST(TestCoWString, EmptyString) { cow_string str(""); diff --git a/validator/tests/rules/structured/015_cmdi_basic_run_match.yaml b/validator/tests/rules/structured/015_cmdi_basic_run_match.yaml new file mode 100644 index 000000000..efe13dd64 --- /dev/null +++ b/validator/tests/rules/structured/015_cmdi_basic_run_match.yaml @@ -0,0 +1,28 @@ +{ + name: "Basic run with match", + runs: [ + { + persistent-input: { + server.sys.exec.cmd: ["/usr/bin/ls", "-l"], + server.request.query: [ "/usr/bin/ls" ] + }, + rules: [ + { + "rsp-930-005": [ + { + resource: { + address: "server.sys.exec.cmd", + value: /usr/bin/ls "-l" + }, + params: { + address: "server.request.query", + value: "/usr/bin/ls" + } + } + ] + } + ], + code: match + } + ] +} diff --git a/validator/tests/rules/structured/016_cmdi_basic_run_no_match.yaml b/validator/tests/rules/structured/016_cmdi_basic_run_no_match.yaml new file mode 100644 index 000000000..783751785 --- /dev/null +++ b/validator/tests/rules/structured/016_cmdi_basic_run_no_match.yaml @@ -0,0 +1,12 @@ +{ + name: "Basic run without match", + runs: [ + { + persistent-input: { + server.sys.exec.cmd: ["ls", "-l"], + server.request.query: [ "potato" ] + }, + code: ok + } + ] +} diff --git a/validator/tests/rules/structured/017_cmdi_basic_run_match_multiparam.yaml b/validator/tests/rules/structured/017_cmdi_basic_run_match_multiparam.yaml new file mode 100644 index 000000000..2a9ef3304 --- /dev/null +++ b/validator/tests/rules/structured/017_cmdi_basic_run_match_multiparam.yaml @@ -0,0 +1,29 @@ +{ + name: "Basic run with match", + runs: [ + { + persistent-input: { + server.sys.exec.cmd: ["/usr/bin/bash", "-c", "cat $0", "/etc/passwd"], + server.request.query: [ "no", "injection", "here" ], + server.request.body: [ "no", "injection", "before", "cat $0", "or", "after"] + }, + rules: [ + { + "rsp-930-005": [ + { + resource: { + address: "server.sys.exec.cmd", + value: /usr/bin/bash "-c" "cat $0" "/etc/passwd" + }, + params: { + address: "server.request.body", + value: "cat $0" + } + } + ] + } + ], + code: match + } + ] +} diff --git a/validator/tests/rules/structured/ruleset.yaml b/validator/tests/rules/structured/ruleset.yaml index 7212f5e6c..12ecdea65 100644 --- a/validator/tests/rules/structured/ruleset.yaml +++ b/validator/tests/rules/structured/ruleset.yaml @@ -76,3 +76,21 @@ rules: - address: graphql.server.all_resolvers - address: graphql.server.resolver operator: shi_detector@v1 + - id: rsp-930-005 + name: CMDi Exploit detection + tags: + type: cmdi + category: exploit_detection + module: rasp + conditions: + - parameters: + resource: + - address: server.sys.exec.cmd + params: + - address: server.request.query + - address: server.request.body + - address: server.request.path_params + - address: grpc.server.request.message + - address: graphql.server.all_resolvers + - address: graphql.server.resolver + operator: cmdi_detector@v1