回归最本质的信息安全

;

linux内核中使用mmap带来的安全问题

2018年5月4日发布

36,153
0
9

导语:我们会在不同产品中识别漏洞,这也是我们工作的一部分,因此,我们会不定时地检查Linux内核,目的主要是在不同的驱动程序中寻找漏洞。在本例中,我们检查了试图擅自利用mmap()函数的驱动程序。

我们会在不同产品中识别漏洞,这也是我们工作的一部分,因此,我们会不定时地检查Linux内核,目的主要是在不同的驱动程序中寻找漏洞。

在本例中,我们检查了试图擅自利用mmap()函数的驱动程序。

由于在组织中,很少有QA人员会检查其代码,并将安全问题作为其编写的程序一部分。因此,重新实现内核功能的想法很可能会导致错误。

在这种情况下,我们发现并揭示了几个问题,我们发现的具体的bug实际上是一个存在了8年的驱动程序漏洞,可以利用其在最新的内核版本(4.16-rc3)中升级特权。

下面是关于这些漏洞的一个例子。

MMAP处理程序

对于驱动程序来说,实现其自身版本的文件操作功能并不少见;这可以在一个驱动的file_operations结构中进行标识:

fig1-1.png

scsi\sg.c 模块中的 file_operations结构

在搜索了关于这些类型的文件操作的更多信息之后,我们发现了MWR实验室给出的非常有用的指南:内核驱动程序mmap处理程序的使用。虽然指南详细解释了应该如何使用mmap()处理程序,但也强调了这些驱动程序的常见漏洞,包括缺乏输入验证和错误溢出(Integer-Overflows)。有了这些新信息,我们决定在整个内核中搜索可能存在的易受攻击的mmap()处理程序。

在开始搜索之前,我们需要对将要寻找的漏洞进行定义。一个典型的驱动程序应该具备下面两个特点:

  1. 该驱动程序要有一个内部缓冲区,该缓冲区代表与外围设备共享内存区域。

  2. 该驱动程序应该只允许用户访问该缓冲区内的内存范围。

现在,我们再检查一遍用户空间里mmap()函数的原型(从man中获取的):

fig3-1.png

正如我们所看到的,有大量的字段攻击者可以控制,因此开发人员应该执行以下检查,并且同时尽量避免可能的错误溢出,以避开这种陷阱:

1.Region start: 0 <= offset < buffer’s end
2.Region end: buffer’s start <= offset + length <= buffer’s end
3.Region start <= Region End

实际上,由于Linux内核将会对所提供的长度进行查杀,因此最后的检查可以省略。这使得当正在通过第三次检查时,几乎不可能通过前两个检查。

既然我们已经知道如何发现可能存在的漏洞,我们还需要知道在哪里可以找到这些漏洞。该指南指出,remap_pfn_range()是一个重要的函数,因为该函数将把物理内存页映射到用户。

用最简单的方法,对“remap_pfn_range(”进行GREP,来发现一些东西。在试图理清最初的158个结果时,我们可以很好地了解一个普通驱动程序所做的检查,从而更容易发现可能的易受攻击的潜在对象。在将潜在的易受攻击对象名单缩小到6个之后,进一步的调查显示了最有可能的攻击对象:

drivers\gpu\drm\udl\udl_fb.c – udl_fb_mmap()

DisplayLink驱动程序——CVE 2018-8781

内核中的video/drm模块定义了一个默认的mmap()包装器,它调用由特定驱动程序定义的real mmap()处理程序。在我们的例子中,漏洞在内部mmap()里,mmap()是在fb_helper文件操作中被定义的,该文件操作属于“DisplayLink”的“udl”驱动程序。

fig2-1.png

说明:这是一个典型的错误溢出的例子。因为偏移量是无符号的,程序员跳过了check #1,直接check #2。然而,计算“偏移量+大小”可能会处理成低值,从而能够使我们能够在仍然使用非法的“偏移”值的同时绕过检查。

注意:在64位机器上,只有48比特的可访问内存,这意味着如果我们使用一个比较大的“偏移量”来绕过该检查,我们还必须确保“info->fix.smem_start + offset”将环绕式处理到一个有效的可映射的物理地址。

证明

为了验证该漏洞,我们使用了一个Ubuntu 64位虚拟机,并上传了一个模拟的易受攻击的驱动程序。在每个测试中,驱动程序的mmap()处理程序包含了我们想要检查的实现。用户模式代码在易受攻击的驱动程序上对mmap()执行了两个连续调用:

1.length = 0x1000, offset = 0x0 -> sanity check
2.length = 0x1000, offset = 0xFFFFFFFFFFFFFFFF – 0x1000 + 1 -> vulnerability check

当在内核/dev/随机数生成器实现的页面对齐物理地址中设置缓冲区的地址时,输出(在这两种情况下)都是预期的结果:

1.The correct physical page: 0x1531000
2.The previous physical page: 0x1530000

其他检查表明,用户可以从映射的页面中读取和写入,从而给攻击者提供了一个强大的原语,可以用该原语在内核空间中触发代码执行。

信息披露时间:

2018年3月18日——漏洞被披露给Linux内核。

2018年3月18日——Linux发行了一个补丁,并要求我们验证它。

2018年3月18日——我们证实了这一补丁,并发出了“绿灯”继续的信号。

2018年3月21日——为CVE 2018-8781发布了一个官方的Linux补丁。

2018年3月21日——补丁被整合到Linux内核中。

总结

该漏洞允许本地用户访问易受攻击的特权驱动程序,读取并写入敏感的内核内存,从而导致本地特权升级。虽然该漏洞是通过一个简单的搜索找到的,但八年前该漏洞就已经被引入到内核中。通过该事件我们知道,即使是在一个热门的开源项目中,如Linux内核,如果知道在哪里搜索,我们总能找到漏洞。

参考

1.MWR实验室 Mmap 使用指南: https://labs.mwrinfosecurity.com/assets/BlogFiles/mwri-mmap-exploitation-whitepaper-2017-09-18.pdf

2.CVE 2018-8781 patch: https://patchwork.freedesktop.org/patch/211845/

3.NVD – https://nvd.nist.gov/vuln/detail/CVE-2018-8781

本文翻译自:http://t.cn/RuNE3hd如若转载,请注明原文地址: http://www.4hou.com/vulnerable/11299.html

点赞 9
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

鲁班七号

这个人很懒,什么也没留下

发私信

发表评论