Hi All,
Doing some experiments with the sql_injection.nasl yesterday
showed that it failed to detect a trivially injectable CGI
we
set up. Looking back through the history of the plugin it
appears that the problem was introduced in revision 1.25
when
support for blind injection was added. I've attached a
version
that correctly detects the injection vulnerability (and also
added a generic signature for oracle error messages).
The problem sections are below:
# This breaks detecting a trivially injectable CGI
# if (egrep(string:bres,
pattern:"^HTTP/1\..*200 OK"))
# {
# exit(0);
# }
Many CGIs will always give a 200 response, so this test will
always call the script to exit rather than properly testing
the CGI.
# This breaks detecting a trivially injectable CGI
# for ( i = 0; posreply[i]; i ++ )
# {
# if ( posreply[i] >< res ) {
# exit(0);
# }
# }
This check follows sending a big number as the query string
and terminates unless the script gives you an error. This
is often not true for injectable CGIs - they may simply
ignore
the input and return (for example) a form for you to fill
in.
Neither of these checks were in revision 1.24 and it seems
likely that their addition will lead to many new false
negatives.
Cheers
Rich.
--
Richard Moore, Principal Software Engineer,
Westpoint Ltd,
Albion Wharf, 19 Albion Street, Manchester, M1 5LN, England
Tel: +44 161 237 1028
Fax: +44 161 237 1031
#
# This script was written by John Lampe ... j_lampe bellsouth.net
#
# Initial version of script was based (loosely) on wpoison
by M.Meadele mm bzero.net
# See http://wpoison.sourcef
orge.net
#
# See the Nessus Scripts License for details
#
#
# re-worked Aug 20, 2004 : jwlampe -at- tenablesecurity.com
adds POST checks
# June/July 2005 : jwlampe -at- tenablesecurity.com adds
Blind SQL Injection checks
if(description)
{
script_id(11139);
#script_cve_id("CVE-MAP-NOMATCH");
script_version ("$Revision: 1.26 $");
name["english"] = "wpoison (nasl
version)";
script_name(english:name["english"]);
desc["english"] = "
This script attempts to use SQL injection techniques on CGI
scripts
More info at : http://www.s
ecuritydocs.com/library/2651
Solution : Modify the relevant CGIs so that they properly
escape arguments.
Risk factor : High";
script_description(english:desc["english"]);
summary["english"] = "Some common SQL
injection techniques";
script_summary(english:summary["english"]);
script_category(ACT_GATHER_INFO);
script_copyright(english:"This script is Copyright
(C) 2002 John Lampe...j_lampe bellsouth.net");
family["english"] = "CGI abuses";
family["francais"] = "Abus de CGI";
script_family(english:family["english"],
francais:family["francais"]);
script_dependencie("find_service.nes",
"webmirror.nasl");
script_require_ports("Services/www", 80);
exit(0);
}
#
# The script code starts here
#
include("http_func.inc");
include("http_keepalive.inc");
single_quote = raw_string(0x27);
poison[0] = single_quote + "UNION" +
single_quote;
poison[1] = single_quote;
poison[2] = single_quote + "%22";
poison[3] = "9%2c+9%2c+9";
poison[4] = single_quote + "bad_bad_value";
poison[5] = "bad_bad_value" + single_quote;
poison[6] = single_quote + "+OR+" +
single_quote;
poison[7] = single_quote + "WHERE";
poison[8] = "%3B"; # semicolon
poison[9] = single_quote + "OR";
# methods below from http://www.securiteam.com/securityreviews/5DP0N1P76E.ht
ml
poison[10] = single_quote + " or 1=1--";
poison[11] = " or 1=1--";
poison[12] = single_quote + " or " +
single_quote + "a" + single_quote +
"=" + single_quote + "a";
poison[13] = single_quote + ") or (" +
single_quote + "a" + single_quote +
"=" + single_quote + "a";
# blind sql injection methods that we will pass
# if they are putting the user-supplied variable within
single quotes, then we trick them with this
blinder[0] = single_quote + "+AND+" +
single_quote + "a" + single_quote +
">" + single_quote + "b";
# otherwise, this will work most of the time
blinder[1] = "+AND+1=1";
posreply[0] = "Can't find record in";
posreply[1] = "Column count doesn't match value count
at row";
posreply[2] = "error " + single_quote;
posreply[3] = "Incorrect column name";
posreply[4] = "Incorrect column specifier for
column";
posreply[5] = "Invalid parameter type";
posreply[6] = "Microsoft OLE DB Provider for ODBC
Drivers error";
posreply[7] = "ODBC Microsoft Access Driver";
posreply[8] = "ODBC SQL Server Driver";
posreply[9] = "supplied argument is not a valid MySQL
result";
posreply[10] = "mysql_query()";
posreply[11] = "Unknown table";
posreply[12] = "You have an error in your SQL
syntax";
posreply[13] = "Error Occurred While Processing
Request";
posreply[14] = "Syntax";
posreply[15] = "not a valid MySQL result
resource";
posreply[16] = "unexpected end of SQL command";
posreply[17] = "mySQL error with query";
posreply[18] = "ORA-00936: missing expression";
posreply[19] = "ORA-00933: SQL command not properly
ended";
posreply[20] = "Unclosed quotation mark before the
character string";
posreply[21] = "Incorrect syntax near";
posreply[22] = "PostgreSQL query failed:";
posreply[23] = "not a valid PostgreSQL result";
posreply[24] = "An illegal character has been found in
the statement";
posreply[25] = "[IBM][CLI Driver][DB2/6000]";
posreply[26] = "Unable to connect to PostgreSQL
server:";
posreply[27] = "Can't connect to local";
posreply[28] = "ADODB.Recordset";
posreply[29] = "ORA-";
port = get_http_port(default:80);
if(! get_port_state(port))
exit(0);
unsafe_urls = "";
mywarningcount = blindwarningcount = 0;
name = string("www/", port,
"/cgis");
cgi = get_kb_item(name);
if(! cgi)
exit(0);
# populate two arrays param[] and data[]
everythingrray = split(cgi, sep:" ",
keep:FALSE);
if (everythingrray[0] =~ ".*/$")
{
isdir = 1;
}
else
{
isdir = 0;
}
if (! isdir)
{
vrequest = string(everythingrray[0],"?");
bogus_vrequest =
string(everythingrray[0],"?",rand());
pseudocount = 0;
foreach rrayval (everythingrray)
{
if (pseudocount >= 2)
{
if ("]" >< rrayval)
{
pseudocount--;
tmpf = ereg_replace(pattern:"\[|\]",
string:rrayval, replace:"");
data[pseudocount] = tmpf;
vrequest = string(vrequest,"=",tmpf);
}
else
{
param[pseudocount] = rrayval;
if (pseudocount == 2)
{
vrequest = string(vrequest,rrayval);
}
else
{
vrequest =
string(vrequest,"&",rrayval);
}
}
}
else
{
param[pseudocount] = rrayval;
}
pseudocount++;
}
}
for (z=2; param[z]; z = z + 1)
{
blind = '';
url = vrequest;
req = http_get(item:url, port:port);
res = http_keepalive_send_recv(port:port, data:req);
if ( ( res == NULL ) || (! egrep(string:res,
pattern:"^HTTP/1\..*(200 OK|302)")) )
{
exit(0);
}
res_saved = strstr(res,string("\r\n\r\n"));
req = http_get(item:bogus_vrequest, port:port);
bres = http_keepalive_send_recv(port:port, data:req);
# This breaks detecting a trivially injectable CGI
# if (egrep(string:bres, pattern:"^HTTP/1\..*200
OK"))
# {
# exit(0);
# }
# This breaks detecting a trivially injectable CGI
# for ( i = 0; posreply[i]; i ++ )
# {
# if ( posreply[i] >< res ) {
# exit(0);
# }
# }
for (poo=0; poison[poo]; poo = poo + 1)
{
doblind = 0;
qa = '';
url = string(param[0],"?");
blind = string(param[0],"?");
for (i=2 ; param[i]; i = i + 1)
{
if (i == z)
{
if (blinder[poo])
{
doblind++;
qa =
string(blind,param[i],"=",data[i],"'&quo
t;);
blind = string(blind,param[i],"=",data[i],
blinder[poo]);
}
if (data[i])
{
url =
string(url,param[i],"=",poison[poo]);
}
else
{
url =
string(url,param[i],"=",poison[poo]);
}
}
else
{
if (blinder[poo])
{
qa = string(qa,param[i],"=",data[i]);
blind =
string(blind,param[i],"=",data[i]);
}
if (data[i])
{
url =
string(url,param[i],"=",data[i]);
}
else
{
url =
string(url,param[i],"=");
}
}
if (param[i + 1])
{
url = string(url,"&");
blind = string(blind,"&");
qa = string(qa,"&");
}
}
req = http_get(item:url, port:port);
inbuff = http_keepalive_send_recv(port:port, data:req);
if( inbuff == NULL )
exit(0);
for (mu=0; posreply[mu]; mu = mu + 1)
{
if (posreply[mu] >< inbuff )
{
unsafe_urls = string(unsafe_urls, url,
"\n");
mywarningcount = mywarningcount + 1;
}
}
if (doblind > 0)
{
req_blind = http_get(item:blind, port:port);
inbuff = http_keepalive_send_recv(port:port,
data:req_blind);
if( inbuff == NULL )
exit(0);
buff_body =
strstr(inbuff,string("\r\n\r\n"));
if (buff_body == res_saved)
{
req_qa = http_get(item:qa, port:port);
inbuff = http_keepalive_send_recv(port:port,
data:req_qa);
qa_body =
strstr(inbuff,string("\r\n\r\n"));
if (qa_body != res_saved)
{
blind_urls = string(blind_urls, blind,
"\n");
blindwarningcount = blindwarningcount + 1;
}
}
}
if ( safe_checks() == 0 )
{
# create a POST req
tmppost = split(url, sep:"?",
keep:FALSE);
mypostdata = tmppost[1];
postreq = http_post(item:param[0],
port:port, data:mypostdata);
# Test the POST req
inbuff = http_keepalive_send_recv(port:port,
data:postreq);
if ( inbuff == NULL )
exit(0);
for (mu=0; posreply[mu]; mu = mu + 1)
{
if (posreply[mu] >< inbuff )
{
unsafe_urls =
string(unsafe_urls, url, "\n");
mywarningcount =
mywarningcount + 1;
}
}
if (doblind > 0)
{
# create a blind POST req
tmppost = split(blind,
sep:"?", keep:FALSE);
mypostdata = tmppost[1];
postreq = http_post(item:param[0],
port:port, data:mypostdata);
inbuff =
http_keepalive_send_recv(port:port, data:postreq);
if ( inbuff == NULL )
exit(0);
buff_body =
strstr(inbuff,string("\r\n\r\n"));
if (buff_body == res_saved)
{
qapost = split(blind, sep:"?", keep:FALSE);
qapostdata = tmppost[1];
qareq = http_post(item:param[0], port:port,
data:qapostdata);
qabuff = http_keepalive_send_recv(port:port,
data:qareq);
qa_body =
strstr(qabuff,string("\r\n\r\n"));
if (qa_body != res_saved)
{
blind_urls = string(blind_urls,
blind, "\n");
blindwarningcount =
blindwarningcount + 1;
}
}
}
}
# end the non-safe check
}
}
if (mywarningcount > 0)
{
report = string("
The following URLs seem to be vulnerable to various SQL
injection
techniques : \n\n",
unsafe_urls,
"\n\n
An attacker may exploit this flaws to bypass authentication
or to take the control of the remote database.
Solution : Modify the relevant CGIs so that they properly
escape arguments
Risk factor : High
See also : http://www.securiteam.com/securityreviews/5DP0N1P76E.ht
ml");
security_hole(port:port, data:report);
}
if (blindwarningcount > 0)
{
report = string("
The following URLs seem to be vulnerable to BLIND SQL
injection
techniques : \n\n",
blind_urls,
"\n\n
An attacker may exploit this flaws to bypass authentication
or to take the control of the remote database.
Solution : Modify the relevant CGIs so that they properly
escape arguments
Risk factor : High
See also : http://www.s
ecuritydocs.com/library/2651");
security_hole(port:port, data:report);
}
_______________________________________________
Plugins-writers mailing list
Plugins-writers list.nessus.org
http://mail.nessus.org/mailman/listinfo/plugins-writers
a> |