美文网首页
【linux内核漏洞利用】ret2dir利用方法

【linux内核漏洞利用】ret2dir利用方法

作者: bsauce | 来源:发表于2020-03-23 21:45 被阅读0次

完全参考rtfingc的文章linux kernel pwn 之 ret2dir 学习,附赠文件及源码点这里,原文中给出的kpwn.c文件有错误,现已更正。

目的:利用return-to-direct-mapped memory(ret2dir)攻击技术绕过SMEP,SMAP,PXN,KERNEXEC,UDEREF,KGuard保护。简单来说,通过利用一个核心区域,直接映射系统的一部分或全部物理内存(用户空间内存映射到physmap,内核可直接访问physmap),允许攻击者在内核地址空间内访问用户数据。

防护:排他性页框架所有权机制(exclusive page frame ownership scheme),能以很低的性能损耗缓解ret2dir攻击。

1.Linux x86_64 内存布局

Documentation/x86/x86_64/mm.txt

1-memory_layout.png

可见,physmap区域在0xffff888000000000 - 0xffffc87fffffffff这一段,大小为64TB。物理内存直接映射在该虚拟内存空间某地址处,只要知道该基址,做线性加减就完事了,速度和效率都很高。

2-physmap.png

linux内核的伙伴系统+slub分配器可参考这篇文章,内存分配主要有kmalloc和vmalloc两种方式。

  • vmalloc 请求 页的倍数大小的内存,要保证虚拟地址连续,物理地址不需要连续

  • kmalloc 内存在字节级做分配,要保证 虚拟地址和物理地址都是连续的

kmalloc是slub分配器使用的方式,kmalloc可在physmap上做内存分配操作。例如分配0x200,则对应kmalloc-512,该内存在physmap里面。

2.利用方式

从以上可知,1.physmap和RAM是直接的映射关系;2.可通过kmalloc分配的内存地址找到physmap的基址。

SMAP/SMEP主要是使内核不能直接执行用户态的代码。但用户态分配的内存,会停留在RAM中,这块内存在physmap中也能看到。可通过mmap分配大量的内存,这样找到的概率就会比较大。

早期的physmap可执行,只需在用户态写好shellcode,然后劫持内核后跳到physmap对应位置即可,不用管SMAP/SMEP。后期加上保护策略,physmap不可执行(W^X),但可通过ROP方式进行利用。

利用过程如下:

  1. mmap大量内存(喷射rop chain等,这样用户数据会映射到内核physmap),提高命中概率。
  2. 泄露slab地址,根据内核中的slab地址计算physmap基地址,根据physmap基址搜索映射到内核physmap的用户数据。
  3. 劫持内核执行流到physmap。

3.测试

内核版本:linux-5.0

gcc版本:8.3.0

ubuntu版本:19.04

内核模块见kpwn.c。

功能:

  • add_any:kmalloc任意size,返回地址
  • del_any:传入addr,kfree释放该地址
  • read_any:传入addr,任意地址读
  • write_any:传入addr,任意地址写

利用步骤:

  1. mmap喷射大量内存(这样用户数据会映射到内核physmap)
  2. physmap中找出用户态mmap的内存的地址A
  3. 尝试改写physmap中地址A的内容,在用户态查看是否有变化

(1)mmap内存

qemu给了128M的内存,mmap出64M的内存,以增大命中率(在用户层喷射数据,这样会映射到内核physmap,这样根据physmap基址搜索的时候才更有可能搜到用户数据)。mmap内存都初始化为字符"K"。

// 64M
#define spray_times 32*32
#define mp_size 1024*64  // 64k
void *spray[spray_times];
void heap_srapy(){
    void *mp;
    for(int i=0;i<spray_times;i++){
        if((mp=mmap(NULL,mp_size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0))==MAP_FAILED){
            logs("error","heap spray");
            exit(0);
        }
        memset(mp,'K',mp_size);
        spray[i]=mp;
    }
}

(2)找physmap对应地址

add_any(fd,0x200,buf);找出slab的地址,然后在上面做爆破,一个页一个页读取,直到找出KKKKKKKKKKKKKKKK这个子串的内存。

char *target = "KKKKKKKKKKKKKKKK";
 ...
    u64 addr = slab_addr;
    u64 pos=0;

    u64 addr_to_change=0;
    for(;addr < 0xffffc80000000000;addr+=0x1000){
        memset(buf,0,0x1000);
        read_any(fd,addr,buf,0x1000);
        pos = (u64) memmem(buf,0x1000,target,0x10);
        if(pos){
....
        }
    }

(3)改写尝试

找到可能的physmap地址后,调用write_any写这个地址,看看用户态对应的内存有没有被改变,如果随之改变,则说明两者已经对应上了。

        if(pos){
            addr_to_change = addr + pos - (u64)buf;
            loglx("physmap hit addr",addr);
            loglx("addr to change",addr_to_change);
            write_any(fd,addr_to_change,dirty,0x100);
            u64 *p = check();
            if(p!=NULL){
                logs("userspace","already change");
                break;
            }
        }

4.结果

可以看出,内核首次分配的slab地址是ffff888007b5d800,计算出physmap起始地址是0xffff888007000000,顺着physmap搜到用户喷射的"K"首次出现在0xffff888007030000,把该内核地址处的值改成"A",找到用户空间出现改变的地址是0x7f7535b8f000,打印出来如下图所示。

3-output.png

内核physmap大部分空间都喷射的是"K"。

4-debug.png

参考:

ret2dir: Rethinking Kernel Isolation

ret2dir:Rethinking Kernel Isolation(翻译)

linux 内核 内存管理 slub算法 (一) 原理

linux kernel pwn 之 ret2dir 学习

相关文章

网友评论

      本文标题:【linux内核漏洞利用】ret2dir利用方法

      本文链接:https://www.haomeiwen.com/subject/grvgyhtx.html