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 += '
\n';
+ if (i2.extra.length > 0) {
+ 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 += '\n';
+ if (i.samples[sno].extra && i.samples[sno].extra.length > 0) {
+ 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:"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
}