diff --git a/ChangeLog b/ChangeLog index 0355fde..610b355 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Version 2.09b: + + - Fixed a crash that could be triggered during 404 fingerprint failures + + - Signature IDs for detected issues are now stored in the report + JSON files. + + - Added mod_status, mod_info, MySQL dump, phpMyAdmin SQL dump and + robots.txt signatures. + + - Improved the Flash and Silverlight crossdomain policy signatures to + only warn about them when they use wildcards. + Version 2.08b: - Added Host header XSS testing. diff --git a/Makefile b/Makefile index b824797..5d135b3 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ # PROGNAME = skipfish -VERSION = 2.08b +VERSION = 2.09b SRCDIR = src SFILES = http_client.c database.c crawler.c analysis.c report.c \ diff --git a/assets/index.html b/assets/index.html index ce036f9..e4d1a27 100644 --- a/assets/index.html +++ b/assets/index.html @@ -707,7 +707,13 @@ function load_issues() { 'Fetch result: ' + i2.error + ''; } - if (i2.extra.length > 0) add_html += '
Memo: ' + H(i2.extra) + '
\n'; + if (i2.extra.length > 0) { + add_html += '
Memo: ' + H(i2.extra); + if (i2.sid.length > 0 && i2.sid > 0) { + add_html += ' (sig: ' + i2.sid + ')'; + } + add_html += '
\n'; + } } @@ -922,9 +928,14 @@ function load_issue_summaries() { '[ show trace ' + '+ ]\n'; - if (i.samples[sno].extra && i.samples[sno].extra.length > 0) - add_html += '
Memo: ' + H(i.samples[sno].extra) + '
\n'; + if (i.samples[sno].extra && i.samples[sno].extra.length > 0) { + add_html += '
Memo: ' + H(i.samples[sno].extra); + if (i.samples[sno].sid && i.samples[sno].sid > 0) { + add_html += ' (sig: ' + i.samples[sno].sid + ')'; + } + add_html += '
\n'; + } } add_html += '\n'; diff --git a/signatures/apps.sigs b/signatures/apps.sigs index 663855f..05f34f6 100644 --- a/signatures/apps.sigs +++ b/signatures/apps.sigs @@ -11,3 +11,8 @@ id:11001; sev:3; content:"phpinfo()'; depth:2048; memo:"phpMyAdmin"; id:11003; sev:3; content:"Parallels Plesk Panel"; depth:1024; content:'action="/login_up.php3" method="post"'; memo:"Plesk administrative interface"; + +# Reference: http://httpd.apache.org/docs/2.2/mod/mod_status.html +id:11004; sev:3; mime:"text/html"; content:"<title>Apache Status"; depth:100; content:"

Apache Server Status for"; depth:25; memo:"Apache mod_status page"; + +id:11005; sev:3; mime:"text/html"; content:"Server Information"; depth:200; content:"Apache Server Information

"; depth:50; memo:"Apache mod_status page"; diff --git a/signatures/files.sigs b/signatures/files.sigs index 1deca5d..bd9e5a8 100644 --- a/signatures/files.sigs +++ b/signatures/files.sigs @@ -13,8 +13,8 @@ id:31006; sev:3; content:"Provider="; content:";Password="; depth:512; memo:"ODB id:31007; sev:3; content:"Driver="; content:";Pwd="; depth:512; memo:"ODBC connect string"; # Typical crossdomain / access policy files -id:31008; sev:3; content:""; depth:512; memo:"Flash crossdomain file"; -id:31009; sev:3; content:""; depth:512; memo:"Silverlight cross-domain policy"; +id:31008; sev:2; content:""; depth:512; content:'"; depth:512; content:''; depth:512; memo:"Silverlight cross-domain policy with wildcard"; # Web.xml config file id:31010; sev:3; content:"pivot, 0); - return; - } - /* Add more directory signatures here... */ if (strstr((char*)sniffbuf, "") || @@ -2471,14 +2465,6 @@ static void check_for_stuff(struct http_request* req, return; } - /* Three very lame rules follow; help improve. */ - - if (inl_strcasestr(res->payload, (u8*)"\nCREATE TABLE") || - inl_strcasestr(res->payload, (u8*)"\nSELECT * FROM") || - inl_strcasestr(res->payload, (u8*)"\nDROP TABLE")) { - problem(PROB_FILE_POI, req, res, (u8*)"SQL script", req->pivot, 0); - return; - } } diff --git a/src/checks.c b/src/checks.c index 18d332c..c5cc7d1 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1856,8 +1856,6 @@ static u8 param_behavior_check(struct http_request* req, DEBUG_MISC_CALLBACK(req, res); - req->pivot->state = PSTATE_PAR_CHECK; - for (i=0; ipivot->misc_cnt; i++) { /* Store the biggest response time */ @@ -1911,7 +1909,9 @@ static u8 param_behavior_check(struct http_request* req, req->pivot->res_varies = 1; problem(PROB_VARIES, req, res, 0, req->pivot, 0); } + return 0; } + req->pivot->state = PSTATE_PAR_CHECK; return 0; } diff --git a/src/crawler.c b/src/crawler.c index 6541a33..09ad419 100644 --- a/src/crawler.c +++ b/src/crawler.c @@ -1399,12 +1399,11 @@ bad_404: } else { if (req->pivot->type != PIVOT_SERV) { - /* todo(niels) improve behavior by adding a new pivot */ - n = req_copy(RPREQ(req), req->pivot, 1); - replace_slash(n, NULL); - maybe_add_pivot(n, NULL, 2); + req->pivot->type = PIVOT_PATHINFO; - destroy_request(n); + replace_slash(req->pivot->req, NULL); + + /* XXX Update request */ } else problem(PROB_404_FAIL, RPREQ(req), RPRES(req), diff --git a/src/database.c b/src/database.c index 50b1cc3..21afba8 100644 --- a/src/database.c +++ b/src/database.c @@ -406,9 +406,6 @@ void maybe_add_pivot(struct http_request* req, struct http_response* res, } - /* Store a reference in our the callers request struct. */ - req->pivot = cur; - /* At this point, 'cur' points to a newly created or existing node for the path element. If this element is parametric, make sure that its value is on the 'try' list. */ @@ -542,10 +539,6 @@ void maybe_add_pivot(struct http_request* req, struct http_response* res, } - /* Set the request pivot, if not set already */ - if(!req->pivot) - req->pivot = cur; - /* Done, at last! */ } @@ -599,6 +592,7 @@ void remove_issue(struct pivot_desc *pv, u32 type) { tmp[cnt].extra = pv->issue[i].extra; tmp[cnt].req = pv->issue[i].req; tmp[cnt].res = pv->issue[i].res; + tmp[cnt].sid = pv->issue[i].sid; cnt++; } } @@ -609,11 +603,20 @@ void remove_issue(struct pivot_desc *pv, u32 type) { } -/* Registers a problem, if not duplicate (res, extra may be NULL): */ - void problem(u32 type, struct http_request* req, struct http_response* res, u8* extra, struct pivot_desc* pv, u8 allow_dup) { + /* Small wrapper for all those problem() calls that do not need to + specify a sid */ + register_problem(type, 0, req, res, extra, pv, allow_dup); + +} + +/* Registers a problem, if not duplicate (res, extra may be NULL): */ +void register_problem(u32 type, u32 sid, struct http_request* req, + struct http_response* res, u8* extra, + struct pivot_desc* pv, u8 allow_dup) { + u32 i; if (pv->type == PIVOT_NONE) FATAL("Uninitialized pivot point"); @@ -637,6 +640,7 @@ void problem(u32 type, struct http_request* req, struct http_response* res, pv->issue[pv->issue_cnt].extra = extra ? ck_strdup(extra) : NULL; pv->issue[pv->issue_cnt].req = req_copy(req, pv, 1); pv->issue[pv->issue_cnt].res = res_copy(res); + pv->issue[pv->issue_cnt].sid = sid; #ifndef LOG_STDERR u8* url = serialize_path(req, 1, 1); diff --git a/src/database.h b/src/database.h index 412517c..5783374 100644 --- a/src/database.h +++ b/src/database.h @@ -452,13 +452,19 @@ struct pstruct pstructs[] = { struct issue_desc { u32 type; /* PROB_* */ u8* extra; /* Problem-specific string */ - u32 sid; /* Signature ID, if any */ + u32 sid; /* Source ID, if any */ struct http_request* req; /* HTTP request sent */ struct http_response* res; /* HTTP response seen */ }; -/* Register a problem, if not duplicate (res, extra may be NULL): */ + +/* Register a problem, if not duplicate (res, extra may be NULL): */ +void register_problem(u32 type, u32 sid, struct http_request* req, + struct http_response* res, u8* extra, + struct pivot_desc* pv, u8 allow_dup); + +/* Wrapper for register_problem */ void problem(u32 type, struct http_request* req, struct http_response* res, u8* extra, struct pivot_desc* pv, u8 allow_dup); diff --git a/src/report.c b/src/report.c index 23ccaf5..e2027d2 100644 --- a/src/report.c +++ b/src/report.c @@ -605,8 +605,8 @@ static void output_crawl_tree(struct pivot_desc* pv) { u8 tmp[32]; sprintf((char*)tmp, "i%u", i); - fprintf(f, " { 'severity': %u, 'type': %u, 'extra': '%s', ", - PSEV(pv->issue[i].type) - 1, pv->issue[i].type, + fprintf(f, " { 'severity': %u, 'type': %u, 'sid': '%d', 'extra': '%s', ", + PSEV(pv->issue[i].type) - 1, pv->issue[i].type, pv->issue[i].sid, pv->issue[i].extra ? js_escape(pv->issue[i].extra, 0) : (u8*)""); describe_res(f, pv->issue[i].res); @@ -744,9 +744,9 @@ static void output_summary_views() { save_req_res(i_samp[i].i[c]->req, i_samp[i].i[c]->res, 0); if (chdir("..")) PFATAL("chdir unexpectedly fails!"); fprintf(f, " { 'url': '%s', ", js_escape(p, 0)); - fprintf(f, "'extra': '%s', 'dir': '%s/%s' }%s\n", + fprintf(f, "'extra': '%s', 'sid': '%d', 'dir': '%s/%s' }%s\n", i_samp[i].i[c]->extra ? js_escape(i_samp[i].i[c]->extra, 0) : - (u8*)"", tmp, tmp2, + (u8*)"", i_samp[i].i[c]->sid, tmp, tmp2, (c == use_samp - 1) ? " ]" : ","); ck_free(p); } diff --git a/src/signatures.c b/src/signatures.c index 9a95da8..fcb92b1 100644 --- a/src/signatures.c +++ b/src/signatures.c @@ -495,20 +495,11 @@ void signature_problem(struct signature *sig, #ifdef _SIGNATURE_TEST DEBUG("signature_problem() called for %d (%s)\n", sig->id, sig->memo); #else - u8* memo = NULL; - /* Each signature is supposed to have a memo: testing just in case */ - if (sig->memo) { - u32 len = strlen((char*)sig->memo); - memo = ck_alloc(len + 15); /* of which 5 for the ID */ - snprintf((char*)memo, len + 14, "%s (sig: %u)", (char*)sig->memo, sig->id); - } + /* Register the problem, together with the sid */ + register_problem((sig->prob ? sig->prob : sig_serv[sig->severity]), sig->id, + req, res, (sig->memo ? sig->memo : (u8*)""), req->pivot, 0); - /* Todo: update issue_desc and add the ID in it */ - problem((sig->prob ? sig->prob : sig_serv[sig->severity]), req, res, - (memo ? memo : (u8*)""), req->pivot, 0); - - if (memo) ck_free(memo); #endif }