diff options
-rw-r--r-- | .github/workflows/cifuzz.yml | 2 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | fuzz/Makefile.am | 38 | ||||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/q046.bin | bin | 0 -> 1324 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/q050.bin | bin | 0 -> 1319 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection.bin | bin | 0 -> 1219 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection_b.bin | bin | 0 -> 1219 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v1_doq.bin | bin | 0 -> 1210 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_first_fragment.bin | bin | 0 -> 1190 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_second_fragment.bin | bin | 0 -> 1190 bytes | |||
-rw-r--r-- | fuzz/corpus/fuzz_quic_get_crypto_data/v2.bin | bin | 0 -> 1210 bytes | |||
-rw-r--r-- | fuzz/fuzz_quic_get_crypto_data.c | 136 | ||||
-rw-r--r-- | src/lib/protocols/quic.c | 35 |
13 files changed, 194 insertions, 19 deletions
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index c74c81096..a4b7ddbe9 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -18,7 +18,7 @@ jobs: uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'ndpi' - fuzz-seconds: 600 + fuzz-seconds: 900 dry-run: false sanitizer: ${{ matrix.sanitizer }} - name: Check Crash (fails when a crash is detected) diff --git a/.gitignore b/.gitignore index 21f2a04d2..4565885d2 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,8 @@ /fuzz/fuzz_ndpi_reader_with_main /fuzz/fuzz_process_packet /fuzz/fuzz_process_packet_with_main +/fuzz/fuzz_quic_get_crypto_data +/fuzz/fuzz_quic_get_crypto_data_with_main /influxdb/Makefile /install-sh /libndpi.pc diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index ed680892b..2e80ec205 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = fuzz_process_packet fuzz_process_packet_with_main fuzz_ndpi_reader fuzz_ndpi_reader_with_main +bin_PROGRAMS = fuzz_process_packet fuzz_process_packet_with_main fuzz_ndpi_reader fuzz_ndpi_reader_with_main fuzz_quic_get_crypto_data fuzz_quic_get_crypto_data_with_main fuzz_process_packet_SOURCES = fuzz_process_packet.c fuzz_process_packet_CFLAGS = @@ -44,9 +44,45 @@ fuzz_ndpi_reader_with_main_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ $(fuzz_ndpi_reader_with_main_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ +fuzz_quic_get_crypto_data_SOURCES = fuzz_quic_get_crypto_data.c +fuzz_quic_get_crypto_data_CFLAGS = -I../example/ +fuzz_quic_get_crypto_data_LDADD = ../example/libndpiReader.a ../src/lib/libndpi.a +fuzz_quic_get_crypto_data_LDFLAGS = $(PCAP_LIB) $(ADDITIONAL_LIBS) $(LIBS) +if HAS_FUZZLDFLAGS +fuzz_quic_get_crypto_data_CFLAGS += $(LIB_FUZZING_ENGINE) +fuzz_quic_get_crypto_data_LDFLAGS += $(LIB_FUZZING_ENGINE) +endif +# force usage of CXX for linker +fuzz_quic_get_crypto_data_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(fuzz_quic_get_crypto_data_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ + +fuzz_quic_get_crypto_data_with_main_SOURCES = fuzz_quic_get_crypto_data.c +fuzz_quic_get_crypto_data_with_main_CFLAGS = -I../example/ -DBUILD_MAIN +fuzz_quic_get_crypto_data_with_main_LDADD = ../src/lib/libndpi.a +fuzz_quic_get_crypto_data_with_main_LDFLAGS = ../example/libndpiReader.a $(PCAP_LIB) $(ADDITIONAL_LIBS) $(LIBS) +# force usage of CXX for linker +fuzz_quic_get_crypto_data_with_main_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(fuzz_quic_get_crypto_data_with_main_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@ + + # required for Google oss-fuzz # see https://github.com/google/oss-fuzz/tree/master/projects/ndpi testpcaps := $(wildcard ../tests/pcap/*.pcap*) fuzz_ndpi_reader_seed_corpus.zip: $(testpcaps) zip -r fuzz_ndpi_reader_seed_corpus.zip $(testpcaps) + +files_corpus_fuzz_quic_get_crypto_data := $(wildcard corpus/fuzz_quic_get_crypto_data/*) + +fuzz_quic_get_crypto_data_seed_corpus.zip: $(files_corpus_fuzz_quic_get_crypto_data) + zip -r fuzz_quic_get_crypto_data_seed_corpus.zip $(files_corpus_fuzz_quic_get_crypto_data) + +corpus: fuzz_quic_get_crypto_data_seed_corpus.zip + +distdir: + find . -type d | xargs -I'{}' mkdir -p '$(distdir)/{}' + find . -type f -name '*.c' \ + -o -name '*.am' \ + -o -name '*.bin' | xargs -I'{}' cp '{}' '$(distdir)/{}' diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/q046.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/q046.bin Binary files differnew file mode 100644 index 000000000..679ef8245 --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/q046.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/q050.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/q050.bin Binary files differnew file mode 100644 index 000000000..e91a15d41 --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/q050.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection.bin Binary files differnew file mode 100644 index 000000000..6f7e2253e --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection_b.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection_b.bin Binary files differnew file mode 100644 index 000000000..258979432 --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_chaos_protection_b.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v1_doq.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_doq.bin Binary files differnew file mode 100644 index 000000000..e1c7d9cbb --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_doq.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_first_fragment.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_first_fragment.bin Binary files differnew file mode 100644 index 000000000..d865a5578 --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_first_fragment.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_second_fragment.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_second_fragment.bin Binary files differnew file mode 100644 index 000000000..59aa1fd6e --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v1_only_second_fragment.bin diff --git a/fuzz/corpus/fuzz_quic_get_crypto_data/v2.bin b/fuzz/corpus/fuzz_quic_get_crypto_data/v2.bin Binary files differnew file mode 100644 index 000000000..86e5d2bc4 --- /dev/null +++ b/fuzz/corpus/fuzz_quic_get_crypto_data/v2.bin diff --git a/fuzz/fuzz_quic_get_crypto_data.c b/fuzz/fuzz_quic_get_crypto_data.c new file mode 100644 index 000000000..3e16446cd --- /dev/null +++ b/fuzz/fuzz_quic_get_crypto_data.c @@ -0,0 +1,136 @@ +#include "ndpi_api.h" + +#include <stdint.h> +#include <stdio.h> + +struct ndpi_detection_module_struct *ndpi_info_mod = NULL; +struct ndpi_flow_struct *flow = NULL; + +extern const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + uint32_t version, + u_int8_t *clear_payload, uint32_t clear_payload_len, + uint64_t *crypto_data_len); +extern void process_tls(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const u_int8_t *crypto_data, uint32_t crypto_data_len, + uint32_t version); +extern void process_chlo(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const u_int8_t *crypto_data, uint32_t crypto_data_len); +extern int is_version_with_tls(uint32_t version); + + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const u_int8_t *crypto_data; + uint64_t crypto_data_len; + u_int32_t first_int, version = 0; + + if(ndpi_info_mod == NULL) { + ndpi_info_mod = ndpi_init_detection_module(ndpi_enable_ja3_plus); + NDPI_PROTOCOL_BITMASK all; + NDPI_BITMASK_SET_ALL(all); + ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &all); +#if 0 + NDPI_PROTOCOL_BITMASK debug_bitmask; + NDPI_BITMASK_SET_ALL(debug_bitmask); + ndpi_set_log_level(ndpi_info_mod, 4); + ndpi_set_debug_bitmask(ndpi_info_mod, debug_bitmask); +#endif + ndpi_finalize_initialization(ndpi_info_mod); + + flow = ndpi_calloc(1, SIZEOF_FLOW_STRUCT); + } + + if(Size < 4) + return 0; + + first_int = ntohl(*(u_int32_t *)Data); + if((first_int % 4) == 0) + version = 0x00000001; /* v1 */ + else if((first_int % 4) == 1) + version = 0x51303530; /* Q050 */ + else if((first_int % 4) == 2) + version = 0x51303436; /* Q046 */ + else if((first_int % 4) == 3) + version = 0x709A50C4; /* v2 */ + + memset(flow, '\0', sizeof(*flow)); + flow->detected_protocol_stack[0] = NDPI_PROTOCOL_QUIC; + flow->l4_proto = IPPROTO_UDP; + + crypto_data = get_crypto_data(ndpi_info_mod, flow, version, (u_int8_t *)Data + 4, Size - 4, &crypto_data_len); + + if(crypto_data) { + if(!is_version_with_tls(version)) { + process_chlo(ndpi_info_mod, flow, crypto_data, crypto_data_len); + } else { + process_tls(ndpi_info_mod, flow, crypto_data, crypto_data_len, version); + } + } + + ndpi_free_flow_data(flow); + + return 0; +} + +#ifdef BUILD_MAIN +int main(int argc, char ** argv) +{ + FILE * data_file; + long data_file_size; + uint8_t * data_buffer; + int test_retval; + + if (argc != 2) { + fprintf(stderr, "usage: %s: [data-file]\n", + (argc > 0 ? argv[0] : "fuzz_quic_get_crypto_data")); + return 1; + } + + data_file = fopen(argv[1], "r"); + if (data_file == NULL) { + perror("fopen failed"); + return 1; + } + + if (fseek(data_file, 0, SEEK_END) != 0) { + perror("fseek(SEEK_END) failed"); + fclose(data_file); + return 1; + } + + data_file_size = ftell(data_file); + if (data_file_size < 0) { + perror("ftell failed"); + fclose(data_file); + return 1; + } + + if (fseek(data_file, 0, SEEK_SET) != 0) { + perror("fseek(0, SEEK_SET) failed"); + fclose(data_file); + return 1; + } + + data_buffer = malloc(data_file_size); + if (data_buffer == NULL) { + perror("malloc failed"); + fclose(data_file); + return 1; + } + + if (fread(data_buffer, sizeof(*data_buffer), data_file_size, data_file) != (size_t)data_file_size) { + perror("fread failed"); + fclose(data_file); + free(data_buffer); + return 1; + } + + test_retval = LLVMFuzzerTestOneInput(data_buffer, data_file_size); + fclose(data_file); + free(data_buffer); + + return test_retval; +} +#endif diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index 433bc0261..7f405b433 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -172,7 +172,7 @@ static int is_version_with_encrypted_header(uint32_t version) ((version & 0xFFFFFF00) == 0x51303500) /* Q05X */ || ((version & 0xFFFFFF00) == 0x54303500) /* T05X */; } -static int is_version_with_tls(uint32_t version) +int is_version_with_tls(uint32_t version) { return is_version_quic(version) || ((version & 0xFFFFFF00) == 0x54303500) /* T05X */; @@ -1126,11 +1126,11 @@ static const uint8_t *get_reassembled_crypto_data(struct ndpi_detection_module_s return NULL; } -static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - uint32_t version, - u_int8_t *clear_payload, uint32_t clear_payload_len, - uint64_t *crypto_data_len) +const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + uint32_t version, + u_int8_t *clear_payload, uint32_t clear_payload_len, + uint64_t *crypto_data_len) { const u_int8_t *crypto_data = NULL; uint32_t counter; @@ -1222,12 +1222,12 @@ static const uint8_t *get_crypto_data(struct ndpi_detection_module_struct *ndpi_ case 0x06: NDPI_LOG_DBG2(ndpi_struct, "CRYPTO frame\n"); counter += 1; - if(counter > clear_payload_len || - counter + quic_len_buffer_still_required(clear_payload[counter]) > clear_payload_len) + if(counter >= clear_payload_len || + counter + quic_len_buffer_still_required(clear_payload[counter]) >= clear_payload_len) return NULL; counter += quic_len(&clear_payload[counter], &frag_offset); - if(counter > clear_payload_len || - counter + quic_len_buffer_still_required(clear_payload[counter]) > clear_payload_len) + if(counter >= clear_payload_len || + counter + quic_len_buffer_still_required(clear_payload[counter]) >= clear_payload_len) return NULL; counter += quic_len(&clear_payload[counter], &frag_len); if(frag_len + counter > clear_payload_len) { @@ -1306,10 +1306,11 @@ static uint8_t *get_clear_payload(struct ndpi_detection_module_struct *ndpi_stru return clear_payload; } -static void process_tls(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - const u_int8_t *crypto_data, uint32_t crypto_data_len, - uint32_t version) + +void process_tls(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const u_int8_t *crypto_data, uint32_t crypto_data_len, + uint32_t version) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; @@ -1341,9 +1342,9 @@ static void process_tls(struct ndpi_detection_module_struct *ndpi_struct, ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DOH_DOT, NDPI_PROTOCOL_QUIC, NDPI_CONFIDENCE_DPI); } } -static void process_chlo(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - const u_int8_t *crypto_data, uint32_t crypto_data_len) +void process_chlo(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + const u_int8_t *crypto_data, uint32_t crypto_data_len) { const uint8_t *tag; uint32_t i; |