首页
社区
课程
招聘
[原创]CVE-2017-8890漏洞分析
发表于: 2018-8-11 16:54 10862

[原创]CVE-2017-8890漏洞分析

2018-8-11 16:54
10862

2017年神洞。一直都想玩玩,前段时间分析了下漏洞原理,尝试着写漏洞利用,奈何一直堆喷不成功。哎,水平还是不够,继续修炼。分析过程就发出来吧。不喜勿喷。看了几个linux网络方面的漏洞,发现linux中用C语言实现面对对象编程真是够有意思的,尤其是找每个对应协议的回调函数时,不太好找,或许对linux网络协议代码还是不够熟悉吧。

基于linux-4.1源码分析

第一步,找出来mc_list第一次被初始化的函数。全局搜索mc_list的引用。

static int inet_create(struct net *net, struct socket *sock, int protocol,

                          int kern)

在inet_create函数中发现:

这里只是初始化为NULL。

为什么会确定就是inet_create函数中第一次被创建,因为inet_create函数是在应用层调用socket函数创建socket对象时走到内核层里要调用的。动态调试看。

看一下inet的值。


将mc_list的地址打印出来。


可以看到当前mc_list指针是NULL,存放mc_list指针的地址为0xffff88003cfce300

开始下内存访问断点。


跑起来,断下来了。如下图:

果然是在调用setsockopt设置组播模式这个过程中访问的。

看一下源码:

果然是对mc_list进行rcu模式的解引用。

继续向下看源码。

Rcu_assign_pointer这个其实rcu模式的拷贝函数。红框中代码就是将iml赋值给inet_mc_list。

单步走看看iml的值。

Sock_kmalloc后,iml的值是0xffff88003c8ad80。继续单步。

将inet->mc_list赋值给Iml->next_rcu,这个时候inet->mc_list仍然是NULL。

继续单步。

即将执行1898行代码了。

单步过后。

已经赋值了。到这里,算是inet->mc_list被第一次赋值了。这个值就是0xffff88003c8a4d0。

看一下inet->mc_list结构体里的数据。

0xa0a02e0就是poc中的组网地址:10.10.2.224/0a:0a:02:e0。

到此,算是找出mc_list对象第一次被赋值。这个对象大小是0x30个字节。

第二步:

Diff 可以找到补丁函数。

net/ipv4/inet_connection_sock.c:707

struct sock *inet_csk_clone_lock(const struct sock *sk,

                                      const struct request_sock *req,

                                      const gfp_t priority)

其实可以通过understand去找这个函数的调用链,在自动生成的过程中,发现找的不完整。故采取动态调试查看调用链。

接下来在inet_csk_clone_lock上下断点。

主要是tcp_v4_syn_recv_sock在tcp_check_req这个函数的调用过程中是属于回调函数,故必须调试查看。查看如下。

先确定从第一步到漏洞函数调用链。

在inet_csk_clone_lock中。

看一下补丁。

这里需要确定newsk了。mc_list是一样的。这里就是sk_clone_lock拷贝的过程。

这里父对象是0xffff88003cfce000,子对象是0xffff88003cfcf000。为什么要确定这两个对象。方便分析为什么poc中要调用accept函数。

第三步:

确定accept函数调用链。

看一下源码。


在队列中查询已经建立的连接,并找出它们对应的sock对象。

Newsk其实就是前面三次握手后sk_clone_lock拷贝产生的子对象。在应用层调用accept函数,可以将这个newsk对象对应的应用层socket句柄返回给用户进行操作。

第四步:

Ok。到此,就剩下释放了。Poc中释放的代码如下:

Poc中写的是先释放子对象后释放父对象。这里就方便了,应为对mc_list下了内存访问断点,直接跑起来就可以看到结果了。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (10)
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2018-8-12 12:44
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
3
稍微瞄了下堆喷核心函数create_heap_spray_sockets()内部逻辑:原来就是在一个for循环中反复执行系统调用fork()创建子进程,由后者逐一调用 socket() 创建套接字。看到 poc中设置套接字选项有2处,其一是在main()(父进程)中的 setsockopt() ;其二是在 do_child_task() (子进程内); 用户空间组播参数 MCAST_JOIN_GROUP 致使在内核空间中分配 ip_mc_socklist 结构体?
应该通过gdb 确定到底是在哪个 setsockopt() 代码路径中的第几个参数非法;有时候,原POC作者为了防止滥用·,会故意留下些许编码错误。
另外,accept() 如果成功,会返回新的socket 文件描述符,因此源码中的304行是在释放新的文件描述符,而315行是在释放由252行的socket()创建的最初socket 文件描述符,从而导致在内核空间中第二次释放 mc_list?
最近刚好也在品味 linux 内核网络栈代码,欢迎一起探讨!
最后于 2018-8-13 11:24 被shayi编辑 ,原因:
2018-8-13 00:28
0
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
4
shayi 稍微瞄了下堆喷核心函数create_heap_spray_sockets()内部逻辑:原来就是在一个for循环中反复执行系统调用fork()创建子进程,由后者逐一调用 socket( ...
通过MCAST_JOIN_GROUP进行对喷。304和315行先释放谁都是可以出发漏洞的,虽然sock对象是不一样的,但是mc_list是一样的。
2018-8-13 13:20
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
5
ID蝴蝶 通过MCAST_JOIN_GROUP进行对喷。304和315行先释放谁都是可以出发漏洞的,虽然sock对象是不一样的,但是mc_list是一样的。
嗯,虽然用户空间中的数据结构不同,但在内核中的实现都是一致的
2018-8-15 11:06
0
雪    币: 187
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
请问是用的哪款思维导图软件?很简洁
2018-8-20 18:10
0
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
7
doctorX 请问是用的哪款思维导图软件?很简洁
maxOS下面的软件,understand。
2018-8-21 17:29
0
雪    币: 16506
活跃值: (6392)
能力值: ( LV13,RANK:923 )
在线值:
发帖
回帖
粉丝
8
想问下你们看函数调用链怎么看的,我都是用grep 一个一个搜的,感觉很麻烦!
2018-10-15 10:20
0
雪    币: 275
活跃值: (254)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
9
楼主,你在第一次free之后调用printf、fork这些这么重的函数,占位很大概率会占错啊;而且你喷的时候选的是ipv4的ip_mc_socklist 对象,这个对象虽然size是ok的,但是后续利用起来很难啊,它的next指针不可控,建议从ipv6协议里面找找类似的对象;
2018-10-15 23:12
0
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
10
wule 楼主,你在第一次free之后调用printf、fork这些这么重的函数,占位很大概率会占错啊;而且你喷的时候选的是ipv4的ip_mc_socklist 对象,这个对象虽然size是ok的,但是后续利 ...
嗯嗯,谢谢大佬指点。
2018-10-16 17:45
0
雪    币: 438
活跃值: (228)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
11
大帅锅 想问下你们看函数调用链怎么看的,我都是用grep 一个一个搜的,感觉很麻烦!
source insight啊。
2018-10-16 17:47
0
游客
登录 | 注册 方可回帖
返回
//