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下了内存访问断点,直接跑起来就可以看到结果了。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!