From 2d0a256dc962b00a2871e1292e833cc33f652093 Mon Sep 17 00:00:00 2001 From: you Date: Mon, 3 Jun 2024 09:40:31 +0200 Subject: [PATCH 1/2] Specify multiple http urls to probe with --http-url "/index.html,/index.php" --- src/stack-tcp-core.c | 161 +++++++++++++++++++++++++++++-------------- 1 file changed, 108 insertions(+), 53 deletions(-) diff --git a/src/stack-tcp-core.c b/src/stack-tcp-core.c index 911056de..2de599cd 100644 --- a/src/stack-tcp-core.c +++ b/src/stack-tcp-core.c @@ -380,13 +380,18 @@ tcpcon_set_http_header(struct TCP_ConnectionTable *tcpcon, enum http_field_t what) { UNUSEDPARM(tcpcon); - banner_http.hello_length = http_change_field( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - name, - (const unsigned char *)value, - value_length, - what); + struct ProtocolParserStream *banner_iter = &banner_http; + /* change header on all HTTP banners in the linked-list */ + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_field( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + name, + (const unsigned char *)value, + value_length, + what); + banner_iter = banner_iter->next; + } } @@ -401,25 +406,31 @@ tcpcon_set_parameter(struct TCP_ConnectionTable *tcpcon, const void *value) { struct Banner1 *banner1 = tcpcon->banner1; + struct ProtocolParserStream *banner_iter = &banner_http; if (name_equals(name, "http-payload")) { char lenstr[64]; snprintf(lenstr, sizeof(lenstr), "%u", (unsigned)value_length); - banner_http.hello_length = http_change_requestline( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - (const unsigned char *)value, - value_length, - 3); /* payload*/ - - banner_http.hello_length = http_change_field( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - "Content-Length:", - (const unsigned char *)lenstr, - strlen(lenstr), - http_field_replace); + /* change header on all HTTP banners in the linked-list */ + banner_iter = &banner_http; + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_requestline( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + (const unsigned char *)value, + value_length, + 3); /* payload*/ + + banner_iter->hello_length = http_change_field( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + "Content-Length:", + (const unsigned char *)lenstr, + strlen(lenstr), + http_field_replace); + banner_iter = banner_iter->next; + } return; } @@ -430,23 +441,33 @@ tcpcon_set_parameter(struct TCP_ConnectionTable *tcpcon, * string built into masscan */ if (name_equals(name, "http-user-agent")) { - banner_http.hello_length = http_change_field( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - "User-Agent:", - (const unsigned char *)value, - value_length, - http_field_replace); + /* change header on all HTTP banners in the linked-list */ + banner_iter = &banner_http; + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_field( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + "User-Agent:", + (const unsigned char *)value, + value_length, + http_field_replace); + banner_iter = banner_iter->next; + } return; } if (name_equals(name, "http-host")) { - banner_http.hello_length = http_change_field( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - "Host:", - (const unsigned char *)value, - value_length, - http_field_replace); + /* change header on all HTTP banners in the linked-list */ + banner_iter = &banner_http; + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_field( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + "Host:", + (const unsigned char *)value, + value_length, + http_field_replace); + banner_iter = banner_iter->next; + } return; } @@ -454,30 +475,64 @@ tcpcon_set_parameter(struct TCP_ConnectionTable *tcpcon, * Changes the URL */ if (name_equals(name, "http-method")) { - banner_http.hello_length = http_change_requestline( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - (const unsigned char *)value, - value_length, - 0); /* method*/ + /* change header on all HTTP banners in the linked-list */ + banner_iter = &banner_http; + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_requestline( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + (const unsigned char *)value, + value_length, + 0); /* method*/ + banner_iter = banner_iter->next; + } return; } if (name_equals(name, "http-url")) { - banner_http.hello_length = http_change_requestline( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - (const unsigned char *)value, - value_length, - 1); /* url */ + /* special hack to specify multiple urls separated with "," + * e.g. --http-url "/index.html,/index.php" */ + const char *v = value; + unsigned v_len = 0; + unsigned nb_probes = 0; + struct ProtocolParserStream *banner = &banner_http; + while (v + v_len != value + value_length) { + v_len += 1; + while (v + v_len != value + value_length && v[v_len - 1] != ',' ) { + v_len += 1; + } + if (nb_probes > 0) { + banner->next = MALLOC(sizeof(*banner)); + banner = banner->next; + memcpy(banner, &banner_http, sizeof(banner_http)); + banner->hello = MALLOC(strlen(banner_http.hello) + 1); + banner->hello_length = banner_http.hello_length; + memcpy((char*)banner->hello, banner_http.hello, banner->hello_length); + } + banner->hello_length = http_change_requestline( + (unsigned char**)&banner->hello, + banner->hello_length, + (const unsigned char *)v, + v_len - ((v[v_len - 1] == ',')?1:0), + 1); /* url */ + banner->next = NULL; + nb_probes += 1; + v = v + v_len; + v_len = 0; + } return; } if (name_equals(name, "http-version")) { - banner_http.hello_length = http_change_requestline( - (unsigned char**)&banner_http.hello, - banner_http.hello_length, - (const unsigned char *)value, - value_length, - 2); /* version */ + /* change header on all HTTP banners in the linked-list */ + banner_iter = &banner_http; + while (banner_iter != NULL) { + banner_iter->hello_length = http_change_requestline( + (unsigned char**)&banner_iter->hello, + banner_iter->hello_length, + (const unsigned char *)value, + value_length, + 2); /* version */ + banner_iter = banner_iter->next; + } return; } From a9af461e72b254808eedeaf5d1be71e0f97086bb Mon Sep 17 00:00:00 2001 From: you Date: Mon, 3 Jun 2024 11:15:43 +0200 Subject: [PATCH 2/2] Add TCP probe in output file (XML, greppable) --- src/in-binary.c | 4 +++ src/main-conf.c | 14 ++++++++++ src/masscan.h | 1 + src/out-binary.c | 4 ++- src/out-certs.c | 3 +++ src/out-grepable.c | 8 ++++++ src/out-hostonly.c | 3 +++ src/out-json.c | 26 +++++++++++++----- src/out-ndjson.c | 26 +++++++++++++----- src/out-null.c | 3 +++ src/out-redis.c | 3 +++ src/out-text.c | 33 ++++++++++++++++------- src/out-unicornscan.c | 3 +++ src/out-xml.c | 60 +++++++++++++++++++++++++++++------------- src/output.c | 3 ++- src/output.h | 4 +++ src/proto-banout.c | 41 +++++++++++++++++++++++++++++ src/proto-banout.h | 6 +++++ src/proto-coap.c | 1 + src/proto-dns.c | 2 ++ src/proto-isakmp.c | 1 + src/proto-memcached.c | 1 + src/proto-netbios.c | 1 + src/proto-ntp.c | 1 + src/proto-snmp.c | 1 + src/proto-udp.c | 2 ++ src/proto-zeroaccess.c | 1 + src/stack-tcp-app.c | 4 +++ src/stack-tcp-app.h | 7 +++++ src/stack-tcp-core.c | 11 ++++++++ 30 files changed, 235 insertions(+), 43 deletions(-) diff --git a/src/in-binary.c b/src/in-binary.c index 865a6f99..67044057 100644 --- a/src/in-binary.c +++ b/src/in-binary.c @@ -325,6 +325,7 @@ parse_banner6(struct Output *out, unsigned char *buf, size_t length, record.port, record.app_proto, /* HTTP, SSL, SNMP, etc. */ record.ttl, /* ttl */ + NULL, 0, buf+offset, (unsigned)(length-offset) ); } @@ -364,6 +365,7 @@ parse_banner3(struct Output *out, unsigned char *buf, size_t buf_length) record.port, record.app_proto, 0, /* ttl */ + NULL, 0, buf+12, (unsigned)buf_length-12 ); } @@ -404,6 +406,7 @@ parse_banner4(struct Output *out, unsigned char *buf, size_t buf_length) record.port, record.app_proto, /* HTTP, SSL, SNMP, etc. */ 0, /* ttl */ + NULL, 0, buf+13, (unsigned)buf_length-13 ); } @@ -462,6 +465,7 @@ parse_banner9(struct Output *out, unsigned char *buf, size_t buf_length, record.port, record.app_proto, /* HTTP, SSL, SNMP, etc. */ record.ttl, /* ttl */ + NULL, 0, data, (unsigned)data_length ); } diff --git a/src/main-conf.c b/src/main-conf.c index f0aaa5a1..aae7591b 100644 --- a/src/main-conf.c +++ b/src/main-conf.c @@ -2345,6 +2345,19 @@ static int SET_debug_tcp(struct Masscan *masscan, const char *name, const char * } +static int SET_output_probes(struct Masscan *masscan, const char *name, const char *value) +{ + UNUSEDPARM(name); + if (masscan->echo) { + if (masscan->is_output_probes || masscan->echo_all) + fprintf(masscan->echo, "output-probes = %s\n", masscan->is_output_probes?"true":"false"); + return 0; + } + masscan->is_output_probes = parseBoolean(value); + return CONF_OK; +} + + struct ConfigParameter { const char *name; @@ -2395,6 +2408,7 @@ struct ConfigParameter config_parameters[] = { {"output-noshow", SET_output_noshow, 0, {"noshow",0}}, {"output-show-open",SET_output_show_open, F_BOOL, {"open", "open-only", 0}}, {"output-append", SET_output_append, 0, {"append-output",0}}, + {"output-probes", SET_output_probes, F_BOOL, {0}}, {"rotate", SET_rotate_time, 0, {"output-rotate", "rotate-output", "rotate-time", 0}}, {"rotate-dir", SET_rotate_directory, 0, {"output-rotate-dir", "rotate-directory", 0}}, {"rotate-offset", SET_rotate_offset, 0, {"output-rotate-offset", 0}}, diff --git a/src/masscan.h b/src/masscan.h index c132a911..e8751968 100644 --- a/src/masscan.h +++ b/src/masscan.h @@ -206,6 +206,7 @@ struct Masscan unsigned is_hello_http:1; /* --hello=http, use HTTP on all ports */ unsigned is_scripting:1; /* whether scripting is needed */ unsigned is_capture_servername:1; /* --capture servername */ + unsigned is_output_probes:1; /* --output-probes */ /** Packet template options, such as whether we should add a TCP MSS * value, or remove it from the packet */ diff --git a/src/out-binary.c b/src/out-binary.c index 0c759151..846cd05e 100644 --- a/src/out-binary.c +++ b/src/out-binary.c @@ -217,6 +217,7 @@ static void binary_out_banner_ipv6(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { unsigned char foo[32768]; @@ -294,6 +295,7 @@ static void binary_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { unsigned char foo[32768]; @@ -302,7 +304,7 @@ binary_out_banner(struct Output *out, FILE *fp, time_t timestamp, static const unsigned HeaderLength = 14; if (ip.version == 6) { - binary_out_banner_ipv6(out, fp, timestamp, ip, ip_proto, port, proto, ttl, px, length); + binary_out_banner_ipv6(out, fp, timestamp, ip, ip_proto, port, proto, ttl, probe, probe_length, px, length); return; } diff --git a/src/out-certs.c b/src/out-certs.c index 5e0705ac..4621b0e3 100644 --- a/src/out-certs.c +++ b/src/out-certs.c @@ -51,6 +51,7 @@ cert_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { unsigned i; @@ -63,6 +64,8 @@ cert_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(ttl); UNUSEDPARM(proto); UNUSEDPARM(port); + UNUSEDPARM(probe); + UNUSEDPARM(probe_length); if (length > 5 && memcmp(px, "cert:", 5) == 0) { px += 5; diff --git a/src/out-grepable.c b/src/out-grepable.c index 30d89fc3..b96a77eb 100644 --- a/src/out-grepable.c +++ b/src/out-grepable.c @@ -179,9 +179,11 @@ static void grepable_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { char banner_buffer[MAX_BANNER_LENGTH]; + char probe_buffer[MAX_PROBE_LENGTH]; ipaddress_formatted_t fmt; UNUSEDPARM(ttl); @@ -195,6 +197,12 @@ grepable_out_banner(struct Output *out, FILE *fp, time_t timestamp, fprintf(fp, "\tService: %s", masscan_app_to_string(proto)); + if (out->masscan->is_output_probes) { + normalize_string(probe, probe_length, probe_buffer, sizeof(probe_buffer)); + + fprintf(fp, "\tProbe: %s\n", probe_buffer); + } + normalize_string(px, length, banner_buffer, sizeof(banner_buffer)); fprintf(fp, "\tBanner: %s\n", banner_buffer); diff --git a/src/out-hostonly.c b/src/out-hostonly.c index 9ead76a5..c92ce0c2 100644 --- a/src/out-hostonly.c +++ b/src/out-hostonly.c @@ -46,6 +46,7 @@ static void hostonly_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { /* SYN only - no banner */ ipaddress_formatted_t fmt = ipaddress_fmt(ip); @@ -57,6 +58,8 @@ hostonly_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(ip); UNUSEDPARM(ip_proto); UNUSEDPARM(proto); + UNUSEDPARM(probe); + UNUSEDPARM(probe_length); UNUSEDPARM(px); UNUSEDPARM(length); fprintf(fp, "%s\n", fmt.string); diff --git a/src/out-json.c b/src/out-json.c index 21b2b83d..eb52e40d 100644 --- a/src/out-json.c +++ b/src/out-json.c @@ -1,4 +1,5 @@ #include "output.h" +#include "masscan.h" #include "masscan-app.h" #include "masscan-status.h" #include "util-safefunc.h" @@ -103,6 +104,7 @@ json_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { char banner_buffer[65536]; @@ -121,13 +123,23 @@ json_out_banner(struct Output *out, FILE *fp, time_t timestamp, fprintf(fp, "{ "); fmt = ipaddress_fmt(ip); fprintf(fp, " \"ip\": \"%s\", ", fmt.string); - fprintf(fp, " \"timestamp\": \"%d\", \"ports\": [ {\"port\": %u, \"proto\": \"%s\", \"service\": {\"name\": \"%s\", \"banner\": \"%s\"} } ] ", - (int) timestamp, - port, - name_from_ip_proto(ip_proto), - masscan_app_to_string(proto), - normalize_json_string(px, length, banner_buffer, sizeof(banner_buffer)) - ); + if (out->masscan->is_output_probes) + fprintf(fp, " \"timestamp\": \"%d\", \"ports\": [ {\"port\": %u, \"proto\": \"%s\", \"service\": {\"name\": \"%s\", \"probe\": \"%s\", \"banner\": \"%s\"} } ] ", + (int) timestamp, + port, + name_from_ip_proto(ip_proto), + masscan_app_to_string(proto), + normalize_json_string(probe, probe_length, banner_buffer, sizeof(banner_buffer)), + normalize_json_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); + else + fprintf(fp, " \"timestamp\": \"%d\", \"ports\": [ {\"port\": %u, \"proto\": \"%s\", \"service\": {\"name\": \"%s\", \"banner\": \"%s\"} } ] ", + (int) timestamp, + port, + name_from_ip_proto(ip_proto), + masscan_app_to_string(proto), + normalize_json_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); fprintf(fp, "}\n"); UNUSEDPARM(out); diff --git a/src/out-ndjson.c b/src/out-ndjson.c index de040cf2..3db382ef 100644 --- a/src/out-ndjson.c +++ b/src/out-ndjson.c @@ -1,4 +1,5 @@ #include "output.h" +#include "masscan.h" #include "masscan-app.h" #include "masscan-status.h" #include "util-safefunc.h" @@ -99,6 +100,7 @@ ndjson_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { char banner_buffer[65536]; @@ -110,13 +112,23 @@ ndjson_out_banner(struct Output *out, FILE *fp, time_t timestamp, fprintf(fp, "{"); fmt = ipaddress_fmt(ip); fprintf(fp, "\"ip\":\"%s\",", fmt.string); - fprintf(fp, "\"timestamp\":\"%d\",\"port\":%u,\"proto\":\"%s\",\"rec_type\":\"banner\",\"data\":{\"service_name\":\"%s\",\"banner\":\"%s\"}", - (int) timestamp, - port, - name_from_ip_proto(ip_proto), - masscan_app_to_string(proto), - normalize_ndjson_string(px, length, banner_buffer, sizeof(banner_buffer)) - ); + if (out->masscan->is_output_probes) + fprintf(fp, "\"timestamp\":\"%d\",\"port\":%u,\"proto\":\"%s\",\"rec_type\":\"banner\",\"data\":{\"service_name\":\"%s\", \"probe\": \"%s\", \"banner\":\"%s\"}", + (int) timestamp, + port, + name_from_ip_proto(ip_proto), + masscan_app_to_string(proto), + normalize_ndjson_string(probe, probe_length, banner_buffer, sizeof(banner_buffer)), + normalize_ndjson_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); + else + fprintf(fp, "\"timestamp\":\"%d\",\"port\":%u,\"proto\":\"%s\",\"rec_type\":\"banner\",\"data\":{\"service_name\":\"%s\", \"banner\":\"%s\"}", + (int) timestamp, + port, + name_from_ip_proto(ip_proto), + masscan_app_to_string(proto), + normalize_ndjson_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); // fprintf(fp, "\"timestamp\":\"%d\",\"ports\":[{\"port\":%u,\"proto\":\"%s\",\"service\":{\"name\":\"%s\",\"banner\":\"%s\"}}]", // (int) timestamp, // port, diff --git a/src/out-null.c b/src/out-null.c index 320c11eb..6b9bf6e9 100644 --- a/src/out-null.c +++ b/src/out-null.c @@ -55,6 +55,7 @@ static void null_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { UNUSEDPARM(ttl); @@ -65,6 +66,8 @@ null_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(ip_proto); UNUSEDPARM(port); UNUSEDPARM(proto); + UNUSEDPARM(probe); + UNUSEDPARM(probe_length); UNUSEDPARM(px); UNUSEDPARM(length); diff --git a/src/out-redis.c b/src/out-redis.c index e06ddd1f..db7bc686 100644 --- a/src/out-redis.c +++ b/src/out-redis.c @@ -321,6 +321,7 @@ static void redis_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { UNUSEDPARM(ttl); @@ -331,6 +332,8 @@ redis_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(ip_proto); UNUSEDPARM(port); UNUSEDPARM(proto); + UNUSEDPARM(probe); + UNUSEDPARM(probe_length); UNUSEDPARM(px); UNUSEDPARM(length); diff --git a/src/out-text.c b/src/out-text.c index 1a2856b4..d482f27e 100644 --- a/src/out-text.c +++ b/src/out-text.c @@ -52,24 +52,39 @@ static void text_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { char banner_buffer[MAX_BANNER_LENGTH]; + char probe_buffer[MAX_PROBE_LENGTH]; ipaddress_formatted_t fmt = ipaddress_fmt(ip); UNUSEDPARM(out); UNUSEDPARM(ttl); - fprintf(fp, "%s %s %u %s %u %s %s\n", - "banner", - name_from_ip_proto(ip_proto), - port, - fmt.string, - (unsigned)timestamp, - masscan_app_to_string(proto), - normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) - ); + if (out->masscan->is_output_probes) + fprintf(fp, "%s %s %u %s %u %s %s %s\n", + "banner", + name_from_ip_proto(ip_proto), + port, + fmt.string, + (unsigned)timestamp, + masscan_app_to_string(proto), + normalize_string(probe, probe_length, probe_buffer, sizeof(probe_buffer)), + normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); + else + fprintf(fp, "%s %s %u %s %u %s %s\n", + "banner", + name_from_ip_proto(ip_proto), + port, + fmt.string, + (unsigned)timestamp, + masscan_app_to_string(proto), + normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); + } diff --git a/src/out-unicornscan.c b/src/out-unicornscan.c index 2ba5a1fc..29717678 100644 --- a/src/out-unicornscan.c +++ b/src/out-unicornscan.c @@ -62,6 +62,7 @@ static void unicornscan_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { /* SYN only - no banner */ UNUSEDPARM(out); @@ -72,6 +73,8 @@ unicornscan_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(ip); UNUSEDPARM(ip_proto); UNUSEDPARM(proto); + UNUSEDPARM(probe); + UNUSEDPARM(probe_length); UNUSEDPARM(px); UNUSEDPARM(length); diff --git a/src/out-xml.c b/src/out-xml.c index 72a6581d..43f862d7 100644 --- a/src/out-xml.c +++ b/src/out-xml.c @@ -1,4 +1,5 @@ #include "output.h" +#include "masscan.h" #include "masscan-app.h" #include "masscan-status.h" #include "util-safefunc.h" @@ -96,9 +97,11 @@ xml_out_banner(struct Output *out, FILE *fp, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { char banner_buffer[MAX_BANNER_LENGTH]; + char probe_buffer[MAX_PROBE_LENGTH]; const char *reason; ipaddress_formatted_t fmt = ipaddress_fmt(ip); @@ -109,24 +112,45 @@ xml_out_banner(struct Output *out, FILE *fp, time_t timestamp, UNUSEDPARM(out); - fprintf(fp, "" - "
" - "" - "" - "" - "" - "" - "" - "" - "\r\n", - (unsigned)timestamp, - fmt.string, - name_from_ip_proto(ip_proto), - port, - reason, ttl, - masscan_app_to_string(proto), - normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) - ); + if (out->masscan->is_output_probes) + fprintf(fp, "" + "
" + "" + "" + "" + "" + "" + "" + "" + "\r\n", + (unsigned)timestamp, + fmt.string, + name_from_ip_proto(ip_proto), + port, + reason, ttl, + masscan_app_to_string(proto), + normalize_string(probe, probe_length, probe_buffer, sizeof(probe_buffer)), + normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); + else + fprintf(fp, "" + "
" + "" + "" + "" + "" + "" + "" + "" + "\r\n", + (unsigned)timestamp, + fmt.string, + name_from_ip_proto(ip_proto), + port, + reason, ttl, + masscan_app_to_string(proto), + normalize_string(px, length, banner_buffer, sizeof(banner_buffer)) + ); } /**************************************************************************** diff --git a/src/output.c b/src/output.c index f563a4c9..7799eb10 100644 --- a/src/output.c +++ b/src/output.c @@ -870,6 +870,7 @@ output_report_banner(struct Output *out, time_t now, ipaddress ip, unsigned ip_proto, unsigned port, unsigned proto, unsigned ttl, + unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length) { FILE *fp = out->fp; @@ -932,7 +933,7 @@ output_report_banner(struct Output *out, time_t now, * Now do the actual output, whether it be XML, binary, JSON, ndjson, Redis, * and so on. */ - out->funcs->banner(out, fp, now, ip, ip_proto, port, proto, ttl, px, length); + out->funcs->banner(out, fp, now, ip, ip_proto, port, proto, ttl, probe, probe_length, px, length); } diff --git a/src/output.h b/src/output.h index 722195af..3ef6ab52 100644 --- a/src/output.h +++ b/src/output.h @@ -10,6 +10,7 @@ #include "masscan-app.h" #define MAX_BANNER_LENGTH 8192 +#define MAX_PROBE_LENGTH 8192 struct Masscan; struct Output; @@ -37,6 +38,7 @@ struct OutputType { time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, enum ApplicationProtocol proto, unsigned ttl, + const unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length); }; @@ -174,6 +176,7 @@ typedef void (*OUTPUT_REPORT_BANNER)( struct Output *output, time_t timestamp, ipaddress ip, unsigned ip_proto, unsigned port, unsigned proto, unsigned ttl, + unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length); void output_report_banner( @@ -182,6 +185,7 @@ void output_report_banner( ipaddress ip, unsigned ip_proto, unsigned port, unsigned proto, unsigned ttl, + unsigned char *probe, unsigned probe_length, const unsigned char *px, unsigned length); /** diff --git a/src/proto-banout.c b/src/proto-banout.c index 88c1eda3..38a17b0a 100644 --- a/src/proto-banout.c +++ b/src/proto-banout.c @@ -27,6 +27,9 @@ banout_init(struct BannerOutput *banout) banout->protocol = 0; banout->next = 0; banout->max_length = sizeof(banout->banner); + banout->probe[0] = '\0'; + banout->probe_length = 0; + banout->probe_max_length = sizeof(banout->probe); } /*************************************************************************** @@ -247,6 +250,8 @@ banout_new_proto(struct BannerOutput *banout, unsigned proto) p = CALLOC(1, sizeof(*p)); p->protocol = proto; p->max_length = sizeof(p->banner); + p->probe_length = 0; + p->probe_max_length = sizeof(p->probe); p->next = banout->next; banout->next = p; return p; @@ -359,6 +364,42 @@ banout_append(struct BannerOutput *banout, unsigned proto, } +/*************************************************************************** + ***************************************************************************/ +void +banout_set_probe(struct BannerOutput *banout, unsigned proto, + const void *probe, size_t length) +{ + struct BannerOutput *p; + + if (length == AUTO_LEN) + length = strlen((const char*)probe); + + /* + * Get the matching record for the protocol (e.g. HTML, SSL, etc.). + * If it doesn't already exist, add the protocol object to the linked + * list. + */ + p = banout_find_proto(banout, proto); + if (p == NULL) { + p = banout_new_proto(banout, proto); + } + + + /* + * If the current object isn't big enough, expand it + */ + while (length >= p->probe_max_length) { + p = banout_expand(banout, p); + } + + /* + * Now that we are assured there is enough space, do the copy + */ + memcpy(p->probe, probe, length); + p->probe_length = length; +} + /***************************************************************************** *****************************************************************************/ static const char *b64 = diff --git a/src/proto-banout.h b/src/proto-banout.h index 6c5361c2..b81408f8 100644 --- a/src/proto-banout.h +++ b/src/proto-banout.h @@ -15,6 +15,9 @@ struct BannerBase64; struct BannerOutput { struct BannerOutput *next; unsigned protocol; + unsigned probe_length; + unsigned probe_max_length; + unsigned char probe[200]; unsigned length; unsigned max_length; unsigned char banner[200]; @@ -59,6 +62,9 @@ void banout_append(struct BannerOutput *banout, unsigned proto, const void *px, size_t length); #define AUTO_LEN ((size_t)~0) +void +banout_set_probe(struct BannerOutput *banout, unsigned proto, + const void *probe, size_t length); void banout_printf(struct BannerOutput *banout, unsigned proto, const char *fmt, ...); diff --git a/src/proto-coap.c b/src/proto-coap.c index ea2bfdc3..9ee06a23 100644 --- a/src/proto-coap.c +++ b/src/proto-coap.c @@ -578,6 +578,7 @@ coap_handle_response(struct Output *out, time_t timestamp, ip_them, 17 /*udp*/, parsed->port_src, PROTO_COAP, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_COAP), banout_string_length(banout, PROTO_COAP)); banout_release(banout); diff --git a/src/proto-dns.c b/src/proto-dns.c index 9f391333..865b6fa7 100644 --- a/src/proto-dns.c +++ b/src/proto-dns.c @@ -403,6 +403,7 @@ handle_dns(struct Output *out, time_t timestamp, ip_them, 17, port_them, PROTO_DNS_VERSIONBIND, parsed->ip_ttl, + NULL, 0, (const unsigned char*)reason, (unsigned)strlen(reason)); return 0; @@ -443,6 +444,7 @@ handle_dns(struct Output *out, time_t timestamp, ip_them, 17, port_them, PROTO_DNS_VERSIONBIND, parsed->ip_ttl, + NULL, 0, px + offset, txtlen); return 1; } diff --git a/src/proto-isakmp.c b/src/proto-isakmp.c index b3cd9087..78c87523 100644 --- a/src/proto-isakmp.c +++ b/src/proto-isakmp.c @@ -433,6 +433,7 @@ isakmp_parse(struct Output *out, time_t timestamp, ip_them, 17, port_them, PROTO_ISAKMP, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_ISAKMP), banout_string_length(banout, PROTO_ISAKMP)); diff --git a/src/proto-memcached.c b/src/proto-memcached.c index 68cec957..03bee60b 100644 --- a/src/proto-memcached.c +++ b/src/proto-memcached.c @@ -379,6 +379,7 @@ memcached_udp_parse(struct Output *out, time_t timestamp, ip_them, 17 /*UDP*/, parsed->port_src, PROTO_MEMCACHED, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_MEMCACHED), banout_string_length(banout, PROTO_MEMCACHED)); diff --git a/src/proto-netbios.c b/src/proto-netbios.c index 19174a16..ed4182c9 100644 --- a/src/proto-netbios.c +++ b/src/proto-netbios.c @@ -99,6 +99,7 @@ handle_nbtstat_rr(struct Output *out, time_t timestamp, unsigned ttl, ip_them, 17, port_them, PROTO_NBTSTAT, ttl, + NULL, 0, banner, banner_length); return 0; } diff --git a/src/proto-ntp.c b/src/proto-ntp.c index 72ab04e5..d073a4a6 100644 --- a/src/proto-ntp.c +++ b/src/proto-ntp.c @@ -272,6 +272,7 @@ ntp_handle_response(struct Output *out, time_t timestamp, ip_them, 17, parsed->port_src, PROTO_NTP, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_NTP), banout_string_length(banout, PROTO_NTP)); diff --git a/src/proto-snmp.c b/src/proto-snmp.c index 53a869e2..37046631 100644 --- a/src/proto-snmp.c +++ b/src/proto-snmp.c @@ -574,6 +574,7 @@ handle_snmp(struct Output *out, time_t timestamp, ip_them, 17, parsed->port_src, PROTO_SNMP, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_SNMP), banout_string_length(banout, PROTO_SNMP)); diff --git a/src/proto-udp.c b/src/proto-udp.c index 276b335e..ea17f85e 100644 --- a/src/proto-udp.c +++ b/src/proto-udp.c @@ -44,6 +44,7 @@ default_udp_parse(struct Output *out, time_t timestamp, ip_them, 17, port_them, PROTO_NONE, parsed->ip_ttl, + NULL, 0, px, length); return 0; @@ -126,6 +127,7 @@ handle_udp(struct Output *out, time_t timestamp, port_them, PROTO_NONE, parsed->ip_ttl, + NULL, 0, px + parsed->app_offset, parsed->app_length); } diff --git a/src/proto-zeroaccess.c b/src/proto-zeroaccess.c index f267b886..9ba50338 100644 --- a/src/proto-zeroaccess.c +++ b/src/proto-zeroaccess.c @@ -252,6 +252,7 @@ handle_zeroaccess( struct Output *out, time_t timestamp, ip_them, 17, port_them, PROTO_UDP_ZEROACCESS, parsed->ip_ttl, + NULL, 0, banout_string(banout, PROTO_UDP_ZEROACCESS), banout_string_length(banout, PROTO_UDP_ZEROACCESS)); diff --git a/src/stack-tcp-app.c b/src/stack-tcp-app.c index 4694619a..c8dd23f9 100644 --- a/src/stack-tcp-app.c +++ b/src/stack-tcp-app.c @@ -6,6 +6,7 @@ #include "util-malloc.h" #include "util-logger.h" #include "util-errormsg.h" +#include #include enum { @@ -154,6 +155,9 @@ application_event(struct stack_handle_t *socket, case App_SendFirst: /* This isn't called from the outside, but from one of the * states internally whhen we transmit for the first time */ + banner_set_probe(socket, masscan_string_to_app(stream->name), + stream->hello, stream->hello_length); + if (stream == &banner_ssl || stream == &banner_ssl_12) { /* * Kludge, extreme kludge diff --git a/src/stack-tcp-app.h b/src/stack-tcp-app.h index e33ddef6..7c958d93 100644 --- a/src/stack-tcp-app.h +++ b/src/stack-tcp-app.h @@ -34,6 +34,13 @@ banner_set_sslhello(struct stack_handle_t *socket, bool is_true); void banner_set_small_window(struct stack_handle_t *socket, bool is_true); +void +banner_set_probe( + struct stack_handle_t *socket, + int proto, + const unsigned char *probe, + unsigned probe_length + ); bool banner_is_heartbleed(const struct stack_handle_t *socket); diff --git a/src/stack-tcp-core.c b/src/stack-tcp-core.c index 2de599cd..98e00aec 100644 --- a/src/stack-tcp-core.c +++ b/src/stack-tcp-core.c @@ -70,6 +70,7 @@ #include "pixie-timer.h" #include "stack-queue.h" #include "proto-banner1.h" +#include "proto-banout.h" #include "proto-ssl.h" #include "proto-http.h" #include "proto-smb.h" @@ -872,6 +873,8 @@ banner_flush(struct stack_handle_t *socket) tcb->port_them, banout->protocol & 0x0FFFFFFF, tcb->ttl, + banout->probe, + banout->probe_length, banout->banner, banout->length); } @@ -1617,6 +1620,14 @@ banner_set_small_window(struct stack_handle_t *socket, bool is_true) { tcb->is_small_window = is_true; } +void +banner_set_probe(struct stack_handle_t *socket, int proto, const unsigned char *probe, unsigned probe_length) { + struct TCP_Control_Block *tcb = socket->tcb; + struct BannerOutput *banout = &(tcb->banout); + banout_set_probe(banout, proto, probe, probe_length); + +} + bool banner_is_heartbleed(const struct stack_handle_t *socket) { struct TCP_ConnectionTable *tcpcon = socket->tcpcon;