aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2024-10-31 21:20:26 +0100
committerLuca Deri <deri@ntop.org>2024-10-31 21:20:46 +0100
commit412ca8700fc53da705c6aa386c736a400279a614 (patch)
tree39ada41ae2b12ea7abf4e1243a4ae5f73d8bf3c3 /src
parentbcc1874e581de9d59514248a27f525cb56a0ec31 (diff)
Added HTTP credentials extraction
Diffstat (limited to 'src')
-rw-r--r--src/include/ndpi_api.h1
-rw-r--r--src/include/ndpi_typedefs.h3
-rw-r--r--src/lib/ndpi_main.c11
-rw-r--r--src/lib/ndpi_utils.c13
-rw-r--r--src/lib/protocols/http.c74
5 files changed, 91 insertions, 11 deletions
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h
index d304ceb5d..ae5679e71 100644
--- a/src/include/ndpi_api.h
+++ b/src/include/ndpi_api.h
@@ -109,6 +109,7 @@ extern "C" {
void * ndpi_calloc(unsigned long count, size_t size);
void * ndpi_realloc(void *ptr, size_t old_size, size_t new_size);
char * ndpi_strdup(const char *s);
+ char * ndpi_strndup(const char *s, size_t size);
void ndpi_free(void *ptr);
void * ndpi_flow_malloc(size_t size);
void ndpi_flow_free(void *ptr);
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 4dfddc5f0..dc3f110ce 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1349,12 +1349,13 @@ struct ndpi_flow_struct {
struct {
ndpi_http_method method;
u_int8_t request_version; /* 0=1.0 and 1=1.1. Create an enum for this? */
- u_int8_t websocket:1, _pad:7;
+ u_int8_t websocket:1, request_header_observed:1, first_payload_after_header_observed:1, is_form:1, _pad:4;
u_int16_t response_status_code; /* 200, 404, etc. */
char *url, *content_type /* response */, *request_content_type /* e.g. for POST */, *user_agent, *server;
char *detected_os; /* Via HTTP/QUIC User-Agent */
char *nat_ip; /* Via HTTP X-Forwarded-For */
char *filename; /* Via HTTP Content-Disposition */
+ char *username, *password;
} http;
ndpi_multimedia_flow_type flow_multimedia_type;
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 98873e959..700016378 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -6762,6 +6762,12 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
if(flow->http.filename)
ndpi_free(flow->http.filename);
+ if(flow->http.username)
+ ndpi_free(flow->http.username);
+
+ if(flow->http.password)
+ ndpi_free(flow->http.password);
+
if(flow->kerberos_buf.pktbuf)
ndpi_free(flow->kerberos_buf.pktbuf);
@@ -9333,6 +9339,8 @@ void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_str,
if((packet->payload[a] == 0x0d) && (packet->payload[a+1] == 0x0a)) {
/* If end of line char sequence CR+NL "\r\n", process line */
+ flow->http.request_header_observed = 1;
+
if(((a + 3) < packet->payload_packet_len)
&& (packet->payload[a+2] == 0x0d)
&& (packet->payload[a+3] == 0x0a)) {
@@ -9401,8 +9409,7 @@ void ndpi_parse_packet_line_info_any(struct ndpi_detection_module_struct *ndpi_s
for(a = 0; a < end; a++) {
if(packet->payload[a] == 0x0a) {
- packet->line[packet->parsed_lines].len = (u_int16_t)(
- ((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr));
+ packet->line[packet->parsed_lines].len = (u_int16_t)(((size_t) &packet->payload[a]) - ((size_t) packet->line[packet->parsed_lines].ptr));
if(a > 0 && packet->payload[a - 1] == 0x0d)
packet->line[packet->parsed_lines].len--;
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 86aee7c7f..782f85f16 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -3885,3 +3885,16 @@ const char* ndpi_print_os_hint(u_int8_t os_hint) {
return("Unknown");
}
+
+/* ************************************************************** */
+
+char* ndpi_strndup(const char *s, size_t size) {
+ char *ret = (char*)ndpi_malloc(size+1);
+
+ if(ret == NULL) return(NULL);
+
+ memcpy(ret, s, size);
+ ret[size] = '\0';
+
+ return(ret);
+}
diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c
index cb146fcc0..1c468165c 100644
--- a/src/lib/protocols/http.c
+++ b/src/lib/protocols/http.c
@@ -108,7 +108,7 @@ static void ndpi_analyze_content_signature(struct ndpi_detection_module_struct *
- ndpi_search_portable_executable
- ndpi_search_shellscript
*/
-
+
if((flow->initial_binary_bytes_len >= 2) && (flow->initial_binary_bytes[0] == 0x4D) && (flow->initial_binary_bytes[1] == 0x5A))
set_risk = 1, msg = "Found DOS/Windows Exe"; /* Win executable */
else if((flow->initial_binary_bytes_len >= 4) && (flow->initial_binary_bytes[0] == 0x7F) && (flow->initial_binary_bytes[1] == 'E')
@@ -224,12 +224,11 @@ static void ndpi_validate_http_content(struct ndpi_detection_module_struct *ndpi
len = packet->payload_packet_len - (double_ret - packet->payload);
- if(ndpi_strnstr((const char *)packet->content_line.ptr, "text/", packet->content_line.len)
+ if(flow->http.is_form
+ || ndpi_strnstr((const char *)packet->content_line.ptr, "text/", packet->content_line.len)
|| ndpi_strnstr((const char *)packet->content_line.ptr, "/json", packet->content_line.len)
- || ndpi_strnstr((const char *)packet->content_line.ptr, "x-www-form-urlencoded", packet->content_line.len)
) {
/* This is supposed to be a human-readeable text file */
-
packet->http_check_content = 1;
if(len >= 8 /* 4 chars for \r\n\r\n and at least 4 charts for content guess */) {
@@ -462,6 +461,7 @@ static void setHttpUserAgent(struct ndpi_flow_struct *flow, char *ua) {
else if(!strcmp(ua, "Windows NT 6.2")) ua = "Windows 8";
else if(!strcmp(ua, "Windows NT 6.3")) ua = "Windows 8.1";
else if(!strcmp(ua, "Windows NT 10.0")) ua = "Windows 10";
+ else if(!strcmp(ua, "Windows NT 11.0")) ua = "Windows 11";
/* Good reference for future implementations:
* https://github.com/ua-parser/uap-core/blob/master/regexes.yaml */
@@ -641,6 +641,42 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp
flow->http.user_agent && strstr(flow->http.user_agent, "Valve/Steam HTTP Client")) {
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_STEAM, master_protocol, NDPI_CONFIDENCE_DPI);
}
+
+
+ if(flow->http.request_header_observed) {
+ if(flow->http.first_payload_after_header_observed == 0) {
+ /* Skip the last part of the HTTP request */
+ flow->http.first_payload_after_header_observed = 1;
+ } else if(flow->http.is_form && (packet->payload_packet_len > 0)) {
+ /* Response payload */
+ char *dup = ndpi_strndup((const char *)packet->payload, packet->payload_packet_len);
+
+ if(dup) {
+ char *key, *value, *tmp;
+
+ key = strtok_r(dup, "=", &tmp);
+
+ while((key != NULL)
+ && ((flow->http.username == NULL) || (flow->http.password == NULL))) {
+ value = strtok_r(NULL, "&", &tmp);
+
+ if(!value)
+ break;
+
+ if((strcmp(key, "user") == 0) || (strcmp(key, "username") == 0)) {
+ if(!flow->http.username) flow->http.username = ndpi_strdup(value);
+ } else if((strcmp(key, "pwd") == 0) || (strcmp(key, "password") == 0)) {
+ if(!flow->http.password) flow->http.password = ndpi_strdup(value);
+ ndpi_set_risk(flow, NDPI_CLEAR_TEXT_CREDENTIALS, "Found password");
+ }
+
+ key = strtok_r(NULL, "=", &tmp);
+ }
+
+ ndpi_free(dup);
+ }
+ }
+ }
}
/* ************************************************************* */
@@ -986,13 +1022,32 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
}
if(packet->authorization_line.ptr != NULL) {
+ const char *a = NULL, *b = NULL;
+
NDPI_LOG_DBG2(ndpi_struct, "Authorization line found %.*s\n",
packet->authorization_line.len, packet->authorization_line.ptr);
- if(ndpi_strncasestr((const char*)packet->authorization_line.ptr,
- "Basic", packet->authorization_line.len)
- || ndpi_strncasestr((const char*)packet->authorization_line.ptr,
- "Digest", packet->authorization_line.len)) {
+ if((a = ndpi_strncasestr((const char*)packet->authorization_line.ptr,
+ "Basic", packet->authorization_line.len))
+ || (b = ndpi_strncasestr((const char*)packet->authorization_line.ptr,
+ "Digest", packet->authorization_line.len))) {
+ size_t content_len;
+ u_int len = b ? 7 : 6;
+ u_char *content = ndpi_base64_decode((const u_char*)&packet->authorization_line.ptr[len],
+ packet->authorization_line.len - len, &content_len);
+
+ if(content != NULL) {
+ char *double_dot = strchr((char*)content, ':');
+
+ if(double_dot) {
+ double_dot[0] = '\0';
+ flow->http.username = ndpi_strdup((char*)content);
+ flow->http.password = ndpi_strdup(&double_dot[1]);
+ }
+
+ ndpi_free(content);
+ }
+
ndpi_set_risk(flow, NDPI_CLEAR_TEXT_CREDENTIALS,
"Found credentials in HTTP Auth Line");
}
@@ -1013,6 +1068,9 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_
packet->content_line.len);
flow->http.request_content_type[packet->content_line.len] = '\0';
}
+
+ if(ndpi_strnstr(flow->http.request_content_type, "x-www-form-urlencoded", packet->content_line.len))
+ flow->http.is_form = 1;
}
} else {
/* Response */