本篇主要是记录一下CVE-2017-7533是什么类型的漏洞,漏洞原理是什么,以及如何触发,又是如何被patch的。进一步,编译源码刷机(此步骤耗时最为长久),在pixel2上复现。此外,进一步思考如果想要从poc到exploit进一步需要做哪些事情?
欢迎对这个漏洞感兴趣的同学一起交流学习~
根据对该CVE的描述信息[1]我们可以知道,这是一个在linux kernel中fsnotify中的race condition漏洞。攻击者可以利用inotify_handle_event和vfs_rename同时执行,实现本地提权或者DoS。
Race condition in the fsnotify implementation in the Linux kernel through 4.12.4 allows local users to gain privileges or cause a denial of service (memory corruption) via a crafted application that leverages simultaneous execution of the inotify_handle_event and vfs_rename functions.
根据redhat mail[2]中对该漏洞的描述,这个漏洞由于race condition会溢出下一个slab的数据。摘录漏洞的触发过程如下图所示。
linux kernel 4.4相关代码:
inotify_event_info 结构体:
在上图中,和漏洞相关的关键点有三个:
问题在于2和3之间,如果file_name被修改了,就可以造成heap overflow。而事实上,由于内核中有大量的线程在同时运行,file_name是可以通过sys_rename系统调用来修改的。
由于overflow的是kmalloc申请的buffer之后的内存,因此需要有效的控制该内存才可以DoS或者是提权。
根据redhat mailist[2],影响的linux kernel version:v3.14-rc1 - v4.12。 对于Android而言,根据Android security bulletin[3],影响的patch level: before 2017-12-01。
CVE-2017-7533这个漏洞的patch影响kernel 3.12-rc4到4.12。因此,nexus6p上是实现不了了,看了一下msm中angler的branch kernel都是3.10的。因此,在pixel 2 android 8.1 kernel 4.4上测试。通过git checkout 4.4.56-g594d847d09a1切换到对应的kernel版本。
分析漏洞原理时,我们已经明白了需要使用两个thread来触发漏洞:一个触发inotify_handle_event,一个触发sys_rename。hardenedlinux有该漏洞的POC[4]。
该POC中,main函数中的notify_thread_func线程,使用inotify机制监控test_dir/f文件的打开、关闭 访问行为。如果触发了该行为,调用handle_events函数,从inotify实例中read 所有的inofity_event事件,遍历时间判断当前触发事件的event->name是否为"b",如果是,则成功触发。
main函数中的trigger_rename_open线程中又开启了两个线程,callrename和openclose。callrename线程中构造longname "bbbb321032103210xxxxxxxx",并开始循环,循环调用两次rename系统调用,修改test_dir/f为longname再修改回来。
callrename线程比较简单,开始循环,循环打开test_dir/f,用于触发用户态中inotify_handle_event的监听事件,从而触发内核中的inotify_handle_event函数,从而竞争触发heap overflow。
漏洞触发的时候:
监听事件触发的时候read的buffer中是inotify_event结构体,其中len代表了name+padding的长度。
但是在内核中,inotify_handle_event中的event是inotify_event_info结构体,其中name_len就是代表name的长度。这个特别容易混淆。
因此,在漏洞触发时,虽然file_name已经被修改,但是内核中inotify_event_info的name_len依然还是1,name则是longname了。经过测试,用户态read的buffer中,inotify_event结构体的name似乎是根据内核中的name_len来获取的(纯属猜测),因此是漏洞触发时,用户态获取的name是b。
poc运行后,输出: 图中已经检测到了event->name是b,
修改了kernel源码,在strcpy处加入pr_err 查看log:
编译内核后查看,dmesg信息:
可以看到,file_name已经被rename成了longname,strcpy给event->name成功溢出了。
该漏洞在linux kernel中的patch[5]如下所示,新增加了name_snapshot结构体,并增加了dentry中name的take和release的方法。原先对dentry中name的操作都要先获取一个快照(snap)再操作。
以fsnotify.c为例:
为什么漏洞在inotify_handle_event()却要patch fsnotify(..., file_name)呢?
看了一会儿源码发现inotify_handle_event()的触发链如下:fsnotify(...,file_name)->send_to_group(... ,file_name)->group->ops->handle_event(..., file_name, cookie)
。
根据ops的定义const struct fsnotify_ops *ops;
,查看该结构体:
因此, group->ops->handle_event(..., file_name, cookie)是会调用inotify_handle_event()的。
patch了之后,fsnotify(..., file_name)中的file_name是snap的name,即使调用sys_rename使得dentry中的name改变了,但是fsnotify拿到的name依然没变,inotify_handle_event中也就不会发生对溢出了。
通过patch,我们可以更加清晰的发现,由于原先inotify_handle_event的file_name 实际上是一个指向dentry中name的一个指针,在race condition时就会发生问题。漏洞的本质是传入参数的改变,那么patch 自然也应该在上层函数中patch了。
写到这里,如何从poc到exp呢?其实目前我还不清楚。
既然是kmalloc发生了溢出,那么思路就是利用溢出后的数据来覆盖后面一个obj中的指针啊什么的来控制PC指针。所以溢出后面的数据是一个obj吗?如果是,这个obj可以控制吗?内核堆的管理方式又是什么样子的呢?如何查看内核堆中的数据呢?
最后,内核中这样由于竞争导致的问题肯定还有,如何发现呢?
带着这样的问题,继续上路吧。
[1] b49K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0N6X3g2Q4x3X3g2E0K9i4c8J5k6g2)9J5k6h3!0J5k6#2)9J5c8X3y4Y4K9g2)9J5k6r3u0A6L8W2)9J5c8X3y4$3k6h3&6S2L8h3g2Q4x3X3g2U0k6$3W2Q4x3@1k6F1j5h3#2W2i4K6y4p5b7#2k6q4i4K6u0V1x3U0l9I4y4#2)9J5k6o6M7#2x3K6x3`. [2] 7b5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6k6h3y4D9K9i4y4@1M7#2)9J5k6h3!0J5k6#2)9J5c8X3!0K6M7#2)9J5k6s2y4W2j5#2)9J5c8U0t1H3x3e0N6Q4x3V1k6I4x3#2)9J5c8U0t1@1x3l9`.`. [3] 8beK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3X3g2S2L8X3c8J5L8$3W2V1i4K6u0W2j5$3!0E0i4K6u0r3M7$3g2U0N6i4u0A6N6s2W2Q4x3V1k6T1N6h3I4D9k6i4c8A6L8W2)9J5c8U0t1H3x3e0N6Q4x3X3b7I4x3W2)9J5k6o6l9I4 [4] 928K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Z5j5i4u0V1k6h3&6W2k6r3I4A6L8Y4g2^5i4K6u0r3L8$3k6X3k6h3&6K6K9i4k6W2i4K6g2X3M7r3!0U0i4K6u0r3N6s2u0W2k6g2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8V1y4h3c8g2)9J5k6o6t1H3x3e0N6Q4x3X3b7%4y4e0x3K6 [5] a0eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Q4x3X3g2C8k6i4u0F1k6h3I4Q4x3X3g2G2M7X3N6Q4x3V1k6H3N6h3u0Q4x3V1k6K6j5$3#2Q4x3V1k6D9K9h3&6#2P5q4)9J5c8X3E0W2M7X3&6W2L8q4)9J5c8X3N6A6N6q4)9J5c8Y4c8G2M7Y4k6S2L8r3c8K6i4K6u0r3L8r3W2F1N6i4S2Q4x3X3g2Y4K9i4c8Q4x3V1k6U0L8$3#2E0K9i4c8Q4x3V1k6Q4x3@1k6A6k6q4)9K6c8o6b7&6k6o6x3I4j5K6u0X3x3K6R3&6j5h3y4X3k6e0R3K6y4o6p5%4x3o6R3K6k6e0p5J5x3o6R3@1x3U0u0T1y4o6l9&6x3h3y4V1z5b7`.`.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-1-11 19:30
被kanxue编辑
,原因: