Skip to content

Commit

Permalink
fuzz: extend fuzzing coverage
Browse files Browse the repository at this point in the history
Some notes:
* libinjection: according to libinjection/libinjection#44,
it seems NULL characters are valid in the input string;
* RTP: `rtp_get_stream_type()` is called only for RTP packets; if you
want to tell RTP from RTCP you should use `is_rtp_or_rtcp()`;
* TLS: unnecessary check; we already make the same check just above, at
the beginning of the `while` loop
  • Loading branch information
IvanNardi committed Jul 10, 2023
1 parent 859d9ea commit b1b59b9
Show file tree
Hide file tree
Showing 18 changed files with 208 additions and 55 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
/fuzz/fuzz_ds_libcache
/fuzz/fuzz_ds_tree
/fuzz/fuzz_ds_ptree
/fuzz/fuzz_ds_hash
/fuzz/fuzz_ds_ahocorasick
/fuzz/fuzz_libinjection
/fuzz/fuzz_tls_certificate
Expand Down
17 changes: 16 additions & 1 deletion fuzz/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ bin_PROGRAMS = fuzz_process_packet fuzz_ndpi_reader fuzz_ndpi_reader_alloc_fail
#Alghoritms
bin_PROGRAMS += fuzz_alg_bins fuzz_alg_hll fuzz_alg_hw_rsi_outliers_da fuzz_alg_jitter fuzz_alg_ses_des fuzz_alg_crc32_md5 fuzz_alg_bytestream
#Data structures
bin_PROGRAMS += fuzz_ds_patricia fuzz_ds_ahocorasick fuzz_ds_libcache fuzz_ds_tree fuzz_ds_ptree
bin_PROGRAMS += fuzz_ds_patricia fuzz_ds_ahocorasick fuzz_ds_libcache fuzz_ds_tree fuzz_ds_ptree fuzz_ds_hash
#Third party
bin_PROGRAMS += fuzz_libinjection
#Internal crypto
Expand Down Expand Up @@ -294,6 +294,21 @@ fuzz_ds_ptree_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \
$(fuzz_ds_ptree_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@

fuzz_ds_hash_SOURCES = fuzz_ds_hash.cpp fuzz_common_code.c
fuzz_ds_hash_CXXFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS) -DENABLE_MEM_ALLOC_FAILURES
fuzz_ds_hash_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS)
fuzz_ds_hash_LDADD = ../src/lib/libndpi.a $(ADDITIONAL_LIBS)
fuzz_ds_hash_LDFLAGS = $(LIBS)
if HAS_FUZZLDFLAGS
fuzz_ds_hash_CXXFLAGS += $(LIB_FUZZING_ENGINE)
fuzz_ds_hash_CFLAGS += $(LIB_FUZZING_ENGINE)
fuzz_ds_hash_LDFLAGS += $(LIB_FUZZING_ENGINE)
endif
# force usage of CXX for linker
fuzz_ds_hash_LINK=$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXX) @NDPI_CFLAGS@ $(AM_CXXFLAGS) $(CXXFLAGS) \
$(fuzz_ds_hash_LDFLAGS) @NDPI_LDFLAGS@ $(LDFLAGS) -o $@

fuzz_libinjection_SOURCES = fuzz_libinjection.c
fuzz_libinjection_CFLAGS = @NDPI_CFLAGS@ $(CXXFLAGS)
fuzz_libinjection_LDADD = ../src/lib/libndpi.a $(ADDITIONAL_LIBS)
Expand Down
10 changes: 8 additions & 2 deletions fuzz/fuzz_alg_hw_rsi_outliers_da.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
u_int8_t additive_seeasonal;
double alpha, beta, gamma, forecast, confidence_band;
float significance;
u_int32_t *values;
u_int32_t *values, predict_periods;
u_int32_t prediction;
bool *outliers;

/* Use the same (integral) dataset to peform: RSI, Data analysis, HW and outliers */
/* Use the same (integral) dataset to peform: RSI, Data analysis, HW, outliers
and linear regression */

/* Just to have some data */
if(fuzzed_data.remaining_bytes() < 1024)
Expand Down Expand Up @@ -57,6 +59,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
max_series_len = fuzzed_data.ConsumeIntegral<u_int16_t>();
a = ndpi_alloc_data_analysis(max_series_len);

/* Init Linear Regression */
predict_periods = fuzzed_data.ConsumeIntegral<u_int8_t>();

/* Calculate! */
for (i = 0; i < num_values; i++) {
if (rc_hw == 0)
Expand All @@ -66,6 +71,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_data_add_value(a, values[i]);
}
ndpi_find_outliers(values, outliers, num_values);
ndpi_predict_linear(values, num_values, predict_periods, &prediction);

/* Data analysis stuff */
ndpi_data_average(a);
Expand Down
31 changes: 28 additions & 3 deletions fuzz/fuzz_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
6 + /* files */
((NDPI_LRUCACHE_MAX + 1) * 5) + /* LRU caches */
2 + 1 + 4 + /* ndpi_set_detection_preferences() */
1 + 3 + 1 + /* Monitoring */
1 + 3 + 1 + 3 + /* Monitoring */
7 + /* Opportunistic tls */
2 + /* Pid */
2 + /* Category */
Expand All @@ -50,6 +50,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

ndpi_info_mod = ndpi_init_detection_module(fuzzed_data.ConsumeIntegral<u_int32_t>());

set_ndpi_debug_function(ndpi_info_mod, NULL);

NDPI_BITMASK_RESET(enabled_bitmask);
for(i = 0; i < NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS ; i++) {
if(fuzzed_data.ConsumeBool())
Expand All @@ -60,6 +62,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_info_mod = NULL;
}

ndpi_set_user_data(ndpi_info_mod, (void *)0xabcdabcd); /* Random pointer */
ndpi_set_user_data(ndpi_info_mod, (void *)0xabcdabcd); /* Twice to trigger overwriting */
ndpi_get_user_data(ndpi_info_mod);

ndpi_set_tls_cert_expire_days(ndpi_info_mod, fuzzed_data.ConsumeIntegral<u_int8_t>());

if(fuzzed_data.ConsumeBool())
Expand Down Expand Up @@ -99,13 +105,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_max_packets_to_process,
fuzzed_data.ConsumeIntegralInRange(0, (1 << 16)));

ndpi_set_detection_preferences(ndpi_info_mod, static_cast<ndpi_detection_preference>(0xFF), 0xFF); /* Invalid preference */

if(fuzzed_data.ConsumeBool()) {
ndpi_set_monitoring_state(ndpi_info_mod, NDPI_PROTOCOL_STUN,
fuzzed_data.ConsumeIntegralInRange(0, (1 << 16)),
fuzzed_data.ConsumeIntegralInRange(0, 7));
ndpi_get_monitoring_state(ndpi_info_mod, NDPI_PROTOCOL_STUN, &num, &num2);
}

random_proto = fuzzed_data.ConsumeIntegralInRange(0, (1 << 16) - 1);
random_value = fuzzed_data.ConsumeIntegralInRange(0,2);
ndpi_set_monitoring_state(ndpi_info_mod, random_proto, random_value, random_value);
ndpi_get_monitoring_state(ndpi_info_mod, random_proto, &num, &num2);

ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP, fuzzed_data.ConsumeBool());
ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP);
ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_IMAP, fuzzed_data.ConsumeBool());
Expand All @@ -128,17 +141,24 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_finalize_initialization(ndpi_info_mod);

/* Random protocol configuration */
pid = fuzzed_data.ConsumeIntegralInRange<u_int16_t>(0, ndpi_get_num_supported_protocols(ndpi_info_mod) + 1);
pid = fuzzed_data.ConsumeIntegralInRange<u_int16_t>(0, NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS + 1); /* + 1 to trigger invalid pid */
protoname = ndpi_get_proto_by_id(ndpi_info_mod, pid);
if (protoname) {
assert(ndpi_get_proto_by_name(ndpi_info_mod, protoname) == pid);
}
ndpi_map_user_proto_id_to_ndpi_id(ndpi_info_mod, pid);
ndpi_map_ndpi_id_to_user_proto_id(ndpi_info_mod, pid);
ndpi_set_proto_breed(ndpi_info_mod, pid, NDPI_PROTOCOL_SAFE);
ndpi_set_proto_category(ndpi_info_mod, pid, NDPI_PROTOCOL_CATEGORY_MEDIA);
ndpi_is_subprotocol_informative(ndpi_info_mod, pid);
ndpi_get_proto_breed(ndpi_info_mod, pid);

ndpi_get_proto_by_name(ndpi_info_mod, NULL); /* Error */
ndpi_get_proto_by_name(ndpi_info_mod, "foo"); /* Invalid protocol */

/* Custom category configuration */
cat = fuzzed_data.ConsumeIntegralInRange(static_cast<int>(NDPI_PROTOCOL_CATEGORY_CUSTOM_1),
static_cast<int>(NDPI_PROTOCOL_CATEGORY_CUSTOM_5 + 1)); /* + 1 to trigger invalid cat */
static_cast<int>(NDPI_PROTOCOL_NUM_CATEGORIES + 1)); /* + 1 to trigger invalid cat */
ndpi_category_set_name(ndpi_info_mod, static_cast<ndpi_protocol_category_t>(cat), catname);
ndpi_is_custom_category(static_cast<ndpi_protocol_category_t>(cat));
ndpi_category_get_name(ndpi_info_mod, static_cast<ndpi_protocol_category_t>(cat));
Expand Down Expand Up @@ -190,6 +210,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_find_ipv4_category_userdata(ndpi_info_mod, flow.c_address.v4);

ndpi_search_tcp_or_udp_raw(ndpi_info_mod, NULL, 0, ntohl(flow.c_address.v4), ntohl(flow.s_address.v4));

ndpi_guess_undetected_protocol_v4(ndpi_info_mod, bool_value ? &flow : NULL,
flow.l4_proto,
flow.c_address.v4, flow.c_port,
flow.s_address.v4, flow.s_port);
}
/* Another "strange" function: fuzz it here, for lack of a better alternative */
ndpi_search_tcp_or_udp(ndpi_info_mod, &flow);
Expand Down
2 changes: 2 additions & 0 deletions fuzz/fuzz_ds_ahocorasick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
else
mc = NULL;

ac_automata_enable_debug(0);

a = ac_automata_init(mc);
a2 = ndpi_init_automa();

Expand Down
63 changes: 63 additions & 0 deletions fuzz/fuzz_ds_hash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "ndpi_api.h"
#include "fuzz_common_code.h"

#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include "fuzzer/FuzzedDataProvider.h"

extern "C" void cleanup_func(ndpi_str_hash *h) {
/* Nothing to do */
return;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fuzzed_data(data, size);
u_int16_t i, rc, num_iteration, data_len, is_added = 0;
std::vector<char>value_added;
void *value;
ndpi_str_hash *h = NULL;

/* Just to have some data */
if (fuzzed_data.remaining_bytes() < 1024)
return -1;

/* To allow memory allocation failures */
fuzz_set_alloc_callbacks_and_seed(size);

if (fuzzed_data.ConsumeBool())
ndpi_hash_init(&h);
else
ndpi_hash_init(NULL);

num_iteration = fuzzed_data.ConsumeIntegral<u_int8_t>();
for (i = 0; i < num_iteration; i++) {

data_len = fuzzed_data.ConsumeIntegralInRange(0, 127);
std::vector<char>data = fuzzed_data.ConsumeBytes<char>(data_len);

rc = ndpi_hash_add_entry(&h, data.data(), data.size(), &i);
/* Keep one random entry really added */
if (rc == 0 && fuzzed_data.ConsumeBool()) {
value_added = data;
is_added = 1;
}
}

/* "Random" search */
num_iteration = fuzzed_data.ConsumeIntegral<u_int8_t>();
for (i = 0; i < num_iteration; i++) {
data_len = fuzzed_data.ConsumeIntegralInRange(0, 127);
std::vector<char>data = fuzzed_data.ConsumeBytes<char>(data_len);

ndpi_hash_find_entry(h, data.data(), data.size(), &value);
}
/* Search of an added entry */
if (is_added) {
ndpi_hash_find_entry(h, value_added.data(), value_added.size(), &value);
}

ndpi_hash_free(&h, cleanup_func);

return 0;
}
4 changes: 2 additions & 2 deletions fuzz/fuzz_ds_patricia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(fuzzed_data.remaining_bytes() > 4) {
std::vector<u_int8_t>data = fuzzed_data.ConsumeBytes<u_int8_t>(4);
ip = data.data();
ip_len = fuzzed_data.ConsumeIntegralInRange(0, 32);
ip_len = fuzzed_data.ConsumeIntegralInRange(0, 33); /* 33 to force error */
ndpi_fill_prefix_v4(&prefix, (struct in_addr *)ip, ip_len, 32);
node = ndpi_patricia_lookup(p, &prefix);
/* Keep one random node really added */
Expand All @@ -71,7 +71,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(fuzzed_data.remaining_bytes() > 16) {
std::vector<u_int8_t>data = fuzzed_data.ConsumeBytes<u_int8_t>(16);
ip = data.data();
ip_len = fuzzed_data.ConsumeIntegralInRange(0, 128);
ip_len = fuzzed_data.ConsumeIntegralInRange(0, 129); /* 129 to force error */
ndpi_fill_prefix_v6(&prefix, (const struct in6_addr *)ip, ip_len, 128);
node = ndpi_patricia_lookup(p, &prefix);
/* Keep one random node really added */
Expand Down
26 changes: 7 additions & 19 deletions fuzz/fuzz_libinjection.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,24 @@
#include "../src/lib/third_party/include/libinjection_sqli.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
char *query;
struct libinjection_sqli_state state;

/* No memory allocations involved */

/* Libinjection: it wants null-terminated string */

query = malloc(size + 1);
if (!query)
return 0;
memcpy(query, data, size);
query[size] = '\0';


libinjection_sqli_init(&state, query, strlen(query), 0); /* Default: FLAG_QUOTE_NONE | FLAG_SQL_ANSI */
libinjection_sqli_init(&state, (char *)data, size, 0); /* Default: FLAG_QUOTE_NONE | FLAG_SQL_ANSI */
libinjection_is_sqli(&state);
libinjection_sqli_init(&state, query, strlen(query), FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI);
libinjection_sqli_init(&state, (char *)data, size, FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI);
libinjection_is_sqli(&state);
libinjection_sqli_init(&state, query, strlen(query), FLAG_QUOTE_DOUBLE | FLAG_SQL_ANSI);
libinjection_sqli_init(&state, (char *)data, size, FLAG_QUOTE_DOUBLE | FLAG_SQL_ANSI);
libinjection_is_sqli(&state);
libinjection_sqli_init(&state, query, strlen(query), FLAG_QUOTE_NONE | FLAG_SQL_MYSQL);
libinjection_sqli_init(&state, (char *)data, size, FLAG_QUOTE_NONE | FLAG_SQL_MYSQL);
libinjection_is_sqli(&state);
libinjection_sqli_init(&state, query, strlen(query), FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL);
libinjection_sqli_init(&state, (char *)data, size, FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL);
libinjection_is_sqli(&state);
libinjection_sqli_init(&state, query, strlen(query), FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL);
libinjection_sqli_init(&state, (char *)data, size, FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL);
libinjection_is_sqli(&state);

libinjection_xss(query, strlen(query));

free(query);
libinjection_xss((char *)data, size);

libinjection_version();

Expand Down
5 changes: 5 additions & 0 deletions fuzz/fuzz_ndpi_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
ndpi_load_malicious_ja3_file(workflow->ndpi_struct, "ja3_fingerprints.csv");
ndpi_load_malicious_sha1_file(workflow->ndpi_struct, "sha1_fingerprints.csv");

ndpi_set_detection_preferences(workflow->ndpi_struct, ndpi_pref_enable_tls_block_dissection, 0 /* unused */);

ndpi_set_monitoring_state(workflow->ndpi_struct, NDPI_PROTOCOL_STUN,
10, NDPI_MONITORING_STUN_SUBCLASSIFIED);

memset(workflow->stats.protocol_counter, 0,
sizeof(workflow->stats.protocol_counter));
memset(workflow->stats.protocol_counter_bytes, 0,
Expand Down
Loading

0 comments on commit b1b59b9

Please sign in to comment.