aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2019-11-01 23:05:11 +0100
committerLuca Deri <deri@ntop.org>2019-11-01 23:05:11 +0100
commita3a85106a1eb59bc87cafa06796ea404f450eda9 (patch)
treec63578d2056850b58de3accc858a29bc11717720
parent75302a10bd24556e0a0f50b0de905ad4c46ad8c7 (diff)
Implemented SQL Injection and XSS attack detection
-rw-r--r--example/ndpiReader.c23
-rw-r--r--src/include/ndpi_api.h2
-rw-r--r--src/include/ndpi_typedefs.h6
-rw-r--r--src/lib/ndpi_utils.c163
-rw-r--r--tests/pcap/WebattackSQLinj.pcapbin0 -> 31536 bytes
-rw-r--r--tests/pcap/WebattackXSS.pcapbin0 -> 4871156 bytes
6 files changed, 182 insertions, 12 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 268fea160..f70ebd785 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -998,6 +998,23 @@ static char* is_unsafe_cipher(ndpi_cipher_weakness c) {
/* ********************************** */
+char* printUrlRisk(ndpi_url_risk risk) {
+ switch(risk) {
+ case ndpi_url_no_problem:
+ return("");
+ break;
+ case ndpi_url_possible_xss:
+ return(" ** XSS **");
+ break;
+ case ndpi_url_possible_sql_injection:
+ return(" ** SQL Injection **");
+ break;
+ }
+
+ return("");
+}
+/* ********************************** */
+
/**
* @brief Print the flow
*/
@@ -1143,8 +1160,10 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
}
if(flow->http.url[0] != '\0')
- fprintf(out, "[URL: %s][StatusCode: %u][ContentType: %s][UserAgent: %s]",
- flow->http.url, flow->http.response_status_code,
+ fprintf(out, "[URL: %s%s][StatusCode: %u][ContentType: %s][UserAgent: %s]",
+ flow->http.url,
+ printUrlRisk(ndpi_validate_url(flow->http.url)),
+ flow->http.response_status_code,
flow->http.content_type, flow->http.user_agent);
if(flow->ssh_tls.ssl_version != 0) fprintf(out, "[%s]", ndpi_ssl_version2str(flow->ssh_tls.ssl_version, &known_tls));
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h
index a1c33b36e..6228a6123 100644
--- a/src/include/ndpi_api.h
+++ b/src/include/ndpi_api.h
@@ -940,6 +940,8 @@ extern "C" {
const char* ndpi_data_ratio2str(float ratio);
void ndpi_data_print_window_values(struct ndpi_analyze_struct *s); /* debug */
+
+ ndpi_url_risk ndpi_validate_url(char *url);
#ifdef __cplusplus
}
#endif
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 04e439221..057fa2527 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -42,6 +42,12 @@ typedef enum {
ndpi_l4_proto_tcp_and_udp,
} ndpi_l4_proto_info;
+typedef enum {
+ ndpi_url_no_problem = 0,
+ ndpi_url_possible_xss,
+ ndpi_url_possible_sql_injection
+ } ndpi_url_risk;
+
/* NDPI_VISIT */
typedef enum {
ndpi_preorder,
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index f11f074cd..a8c73e67e 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -759,11 +759,11 @@ void ndpi_user_pwd_payload_copy(u_int8_t *dest, u_int dest_len,
u_int offset,
const u_int8_t *src, u_int src_len) {
u_int i, j=0, k = dest_len-1;
-
+
for(i=offset; (i<src_len) && (j<=k); i++) {
if((j == k) || (src[i] < ' '))
break;
-
+
dest[j++] = src[i];
}
@@ -857,7 +857,7 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
u_int32_t src_v4, u_int32_t dst_v4,
struct ndpi_in6_addr *src_v6, struct ndpi_in6_addr *dst_v6,
u_int16_t src_port, u_int16_t dst_port,
- ndpi_protocol l7_protocol,
+ ndpi_protocol l7_protocol,
ndpi_serializer *serializer) {
char buf[64], src_name[32], dst_name[32];
@@ -976,7 +976,7 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_start_of_block(serializer, "http");
if(flow->host_server_name[0] != '\0')
ndpi_serialize_string_string(serializer, "hostname", (const char*)flow->host_server_name);
- ndpi_serialize_string_string(serializer, "url", flow->http.url);
+ ndpi_serialize_string_string(serializer, "url", flow->http.url);
ndpi_serialize_string_uint32(serializer, "code", flow->http.response_status_code);
ndpi_serialize_string_string(serializer, "content_type", flow->http.content_type);
ndpi_serialize_string_string(serializer, "user_agent", flow->http.user_agent);
@@ -989,28 +989,28 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
-
+
case NDPI_PROTOCOL_MAIL_POP:
ndpi_serialize_start_of_block(serializer, "pop");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
-
+
case NDPI_PROTOCOL_MAIL_SMTP:
ndpi_serialize_start_of_block(serializer, "smtp");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
-
+
case NDPI_PROTOCOL_FTP_CONTROL:
ndpi_serialize_start_of_block(serializer, "ftp");
ndpi_serialize_string_string(serializer, "user", flow->protos.ftp_imap_pop_smtp.username);
ndpi_serialize_string_string(serializer, "password", flow->protos.ftp_imap_pop_smtp.password);
ndpi_serialize_end_of_block(serializer);
break;
-
+
case NDPI_PROTOCOL_SSH:
ndpi_serialize_start_of_block(serializer, "ssh");
ndpi_serialize_string_string(serializer, "client_signature", flow->protos.ssh.client_signature);
@@ -1041,7 +1041,7 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_string_string(serializer, "issuer", flow->protos.stun_ssl.ssl.server_organization);
if(before) {
- strftime(notBefore, sizeof(notBefore), "%F %T", before);
+ strftime(notBefore, sizeof(notBefore), "%F %T", before);
ndpi_serialize_string_string(serializer, "notbefore", notBefore);
}
@@ -1061,7 +1061,7 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_string_string(serializer, "fingerprint", buf);
}
-
+
ndpi_serialize_end_of_block(serializer);
}
}
@@ -1072,3 +1072,146 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct,
}
/* ********************************** */
+
+/*
+ /dv/vulnerabilities/xss_r/?name=%3Cscript%3Econsole.log%28%27JUL2D3WXHEGWRAFJE2PI7OS71Z4Z8RFUHXGNFLUFYVP6M3OL55%27%29%3Bconsole.log%28document.cookie%29%3B%3C%2Fscript%3E
+ /dv/vulnerabilities/sqli/?id=1%27+and+1%3D1+union+select+null%2C+table_name+from+information_schema.tables%23&Submit=Submit
+*/
+
+/* https://www.rosettacode.org/wiki/URL_decoding#C */
+static int ishex(int x) {
+ return(x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F');
+}
+
+/* ********************************** */
+
+static int ndpi_url_decode(const char *s, char *out) {
+ char *o;
+ const char *end = s + strlen(s);
+ int c;
+
+ for(o = out; s <= end; o++) {
+ c = *s++;
+ if(c == '+') c = ' ';
+ else if(c == '%' && (!ishex(*s++)||
+ !ishex(*s++)||
+ !sscanf(s - 2, "%2x", &c)))
+ return(-1);
+
+ if(out) *o = c;
+ }
+
+ return(o - out);
+}
+
+/* ********************************** */
+
+/* #define URL_CHECK_DEBUG 1 */
+
+static int find_occurrency(char *str, char *what) {
+ char *found = strstr(str, what);
+ u_int len;
+
+#ifdef URL_CHECK_DEBUG
+ printf("%s() [%s][%s]\n", __FUNCTION__, str, what);
+#endif
+
+ if(!found) return(0);
+
+ len = strlen(what);
+
+ if((found[len] != '\0') && (found[len] != ' ')
+ && ((found == str) || (found[-1] == ' ')))
+ return(1);
+ else
+ return(find_occurrency(&found[len], what));
+}
+
+/* ********************************** */
+
+static int ndpi_check_tokens(char* query, char* keywords[]) {
+#ifdef URL_CHECK_DEBUG
+ printf("%s() [%s]\n", __FUNCTION__, query);
+#endif
+
+ for(int i=0; keywords[i] != NULL; i++) {
+ if(find_occurrency(query, keywords[i]) > 0)
+ return(1);
+ }
+
+ return(0);
+}
+
+/* ********************************** */
+
+static int ndpi_is_sql_injection(char* query) {
+ char* sql_keywords[] = { "select", "from", "where", "any", "all", "join", "inner", "left", "right", "full",
+ "table", "alter", "create", "delete", "union", "update", "drop", "group", "order",
+ "limit", "primary", "column", NULL };
+ return(ndpi_check_tokens(query, sql_keywords));
+}
+
+/* ********************************** */
+
+static int ndpi_is_xss_injection(char* query) {
+ char* js_keywords[] = { "<script>", "console.", "log.", NULL };
+ return(ndpi_check_tokens(query, js_keywords));
+}
+
+/* ********************************** */
+
+ndpi_url_risk ndpi_validate_url(char *url) {
+ char *orig_str = NULL, *str = NULL, *question_mark = strchr(url, '?');
+ ndpi_url_risk rc = ndpi_url_no_problem;
+
+ if(question_mark) {
+ char *tmp;
+
+ orig_str = str = ndpi_strdup(&question_mark[1]); /* Skip ? */
+
+ if(!str) goto validate_rc;
+
+ str = strtok_r(str, "&", &tmp);
+
+ while(str != NULL) {
+ char *value = strchr(str, '=');
+ char *decoded;
+
+ if(!value)
+ break;
+ else
+ value = &value[1];
+
+ if(value[0] != '\0') {
+ if(!(decoded = (char*)ndpi_malloc(strlen(value)+1)))
+ break;
+
+ if(ndpi_url_decode(value, decoded) < 0) {
+ /* Invalid string */
+ } else if(decoded[0] != '\0') {
+ /* Valid string */
+
+ if(ndpi_is_xss_injection(decoded))
+ rc = ndpi_url_possible_xss;
+ else if(ndpi_is_sql_injection(decoded))
+ rc = ndpi_url_possible_sql_injection;
+
+#ifdef URL_CHECK_DEBUG
+ printf("=>> [rc: %u] %s\n", rc, decoded);
+#endif
+ }
+
+ ndpi_free(decoded);
+
+ if(rc != ndpi_url_no_problem)
+ break;
+ }
+
+ str = strtok_r(NULL, "&", &tmp);
+ }
+ }
+
+ validate_rc:
+ if(orig_str) ndpi_free(orig_str);
+ return(rc);
+}
diff --git a/tests/pcap/WebattackSQLinj.pcap b/tests/pcap/WebattackSQLinj.pcap
new file mode 100644
index 000000000..f63da5f80
--- /dev/null
+++ b/tests/pcap/WebattackSQLinj.pcap
Binary files differ
diff --git a/tests/pcap/WebattackXSS.pcap b/tests/pcap/WebattackXSS.pcap
new file mode 100644
index 000000000..8fc8a89e8
--- /dev/null
+++ b/tests/pcap/WebattackXSS.pcap
Binary files differ