Skip to content

Commit

Permalink
Version 2.09b: bugfixes and policy improvements
Browse files Browse the repository at this point in the history
  - 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.
  • Loading branch information
spinkham committed Sep 12, 2012
1 parent c9d5b74 commit e48969d
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 53 deletions.
13 changes: 13 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
17 changes: 14 additions & 3 deletions assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,13 @@
'Fetch result: ' + i2.error + '</div>';
}

if (i2.extra.length > 0) add_html += '<div class="comment">Memo: ' + H(i2.extra) + '</div>\n';
if (i2.extra.length > 0) {
add_html += '<div class="comment">Memo: ' + H(i2.extra);
if (i2.sid.length > 0 && i2.sid > 0) {
add_html += ' (sig: ' + i2.sid + ')';
}
add_html += '</div>\n';
}

}

Expand Down Expand Up @@ -922,9 +928,14 @@
'[ <a href="#" onclick="return show_dat(\'' + i.samples[sno].dir + '\', false)">show trace</a> ' +
'<a href="#" onclick="return show_win(\'' + i.samples[sno].dir + '\', false)">+</a> ]</span>\n';

if (i.samples[sno].extra && i.samples[sno].extra.length > 0)
add_html += '<div class="comment">Memo: ' + H(i.samples[sno].extra) + '</div>\n';
if (i.samples[sno].extra && i.samples[sno].extra.length > 0) {
add_html += '<div class="comment">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 += '</div>\n';

}
}

add_html += '</ol></tr></td></table>\n';
Expand Down
5 changes: 5 additions & 0 deletions signatures/apps.sigs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ id:11001; sev:3; content:"<title>phpinfo()</title><meta name="; depth:2048; memo
id:11002; sev:3; content:'<title>phpMyAdmin </title>'; depth:1024; content:'<a href="http://www.phpmyadmin.net" target="_blank" class="logo">'; depth:2048; memo:"phpMyAdmin";

id:11003; sev:3; content:"<title>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</title>"; depth:100; content:"<h1>Apache Server Status for"; depth:25; memo:"Apache mod_status page";

id:11005; sev:3; mime:"text/html"; content:"<title>Server Information</title>"; depth:200; content:"Apache Server Information</h1>"; depth:50; memo:"Apache mod_status page";
11 changes: 9 additions & 2 deletions signatures/files.sigs
Original file line number Diff line number Diff line change
Expand Up @@ -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:"<cross-domain-policy>"; depth:512; memo:"Flash crossdomain file";
id:31009; sev:3; content:"<access-policy>"; depth:512; memo:"Silverlight cross-domain policy";
id:31008; sev:2; content:"<cross-domain-policy>"; depth:512; content:'<allow-access-from domain="*"'; depth:50; memo:"Flash cross-domain policy with wildcard";
id:31009; sev:4; content:"<access-policy>"; depth:512; content:'<domain uri="*"/>'; depth:512; memo:"Silverlight cross-domain policy with wildcard";

# Web.xml config file
id:31010; sev:3; content:"<web-app"; depth:512; memo:"web.xml config file";
Expand All @@ -28,6 +28,13 @@ id:31013; sev:3; content:"0] \"GET /"; depth:1024; memo:"Apache access log";
id:31014; sev:3; content:"[error] [client "; depth:1024; memo:"Apache error log";
id:31015; sev:3; content:"0, GET, /"; depth:1024; memo:"Microsoft IIS access log";

# Generic robots.txt file
id:31016; sev:4; content:"User-agent:"; depth:100; content:"Disallow: /"; memo:"robots.txt file";

# Signatures to detect SQL dumps
id:31101; sev:2; mime:"text/plain"; content:"-- MySQL dump"; depth:1; content:"-- Host"; depth:256; content:"-- Server version"; memo:"MySQL dump database file";
id:31103; sev:2; mime:"text/plain"; content:" phpMyAdmin SQL Dump"; depth:3; content:" version"; content:"CREATE TABLE"; memo:"phpMyAdmin database dump file";

# Source code and scripts
id:32001; sev:3; content:"\nimport java."; depth:512; memo:"Java source";
id:32002; sev:3; content:"\n#include"; depth:512; memo:"C/C++ source";
Expand Down
14 changes: 0 additions & 14 deletions src/analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -2379,12 +2379,6 @@ static void check_for_stuff(struct http_request* req,
}
}

if (inl_strcasestr(sniffbuf, (u8*)"\nDisallow:") ||
inl_strcasestr(sniffbuf, (u8*)"\rDisallow:")) {
problem(PROB_FILE_POI, req, res, (u8*)"robots.txt ruleset", req->pivot, 0);
return;
}

/* Add more directory signatures here... */

if (strstr((char*)sniffbuf, "<A HREF=\"?N=D\">") ||
Expand Down Expand Up @@ -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;
}
}


Expand Down
4 changes: 2 additions & 2 deletions src/checks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; i<req->pivot->misc_cnt; i++) {

/* Store the biggest response time */
Expand Down Expand Up @@ -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;
}
Expand Down
9 changes: 4 additions & 5 deletions src/crawler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1399,12 +1399,11 @@ static u8 dir_404_check(struct http_request* req,
} 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),
Expand Down
22 changes: 13 additions & 9 deletions src/database.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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! */

}
Expand Down Expand Up @@ -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++;
}
}
Expand All @@ -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");
Expand All @@ -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);
Expand Down
8 changes: 7 additions & 1 deletion src/database.h
Original file line number Diff line number Diff line change
Expand Up @@ -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): */
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);

Expand Down
8 changes: 4 additions & 4 deletions src/report.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
15 changes: 3 additions & 12 deletions src/signatures.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/* 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);
/* 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);

if (memo) ck_free(memo);
#endif
}

Expand Down

0 comments on commit e48969d

Please sign in to comment.