poc 分析

首先在补丁函数 inet_csk_clone_lock,sys_accept,ip_mc_leave_src 处下断点,执行poc,首先断在了inet_csk_clone_lock函数处,当前函数调用链sys_connect->......->tcp_v4_rcv->tcp_check_req->tcp_v4_syn_recv_sock->tcp_create_openreq_child->inet_csk_clone_lock,可以确定这个函数在建立连接,三次握手时使用,因为补丁是把inet_sk(newsk)->mc_list = NULL,因此先确定当前sk状态

然后进入inet_csk_clone_lock函数,断在struct sock *newsk = sk_clone_lock(sk, priority);,sk_clone_lock函数处,查看复制后的newsk的状态

复制后newsk与sk存在相同的mc_list 指针。

为什么要加入多播组

只有加入多播组,内核才会为多播创建相应的ip_mc_socklist对象,inet_sock中mc_list才会是一个有效的对象的指针。

poc触发原理

这个漏洞根据补丁可以知道是因为inet_sock->mc_list不为NULL导致,而且这个补丁存在于一个复制sock功能的函数inet_csk_clone_lock中,这样导致两个对象里面有一个同样的指针指向同一个对象,这样在free的时候会产生double free。

1,要使mc_list指针有效,必须将socket加入组播

2,要执行一次通过inet_csk_clone_lock复制一次inet_sock,使复制前后的两个sock存在相同的mc_list指针。

3,accept的时候会将复制一份socket,并返回socket对应的fd,newsocket->sk = newsock。

这样便完成了两个fd对应同一个mc_list,对应如下关系:

  • fd1->file1->socket->sk->mc_list
  • fd2->file2->newsocket->newsock->mc_list

如果按照这个理论,这里可以做到通过多次执行connect,accept ,可以做到多次free(mc_list)。

heap spary

可以根据前面分析确定被double free的对象是ip_mc_socklist。

obj size : 0x30,因此从kmalloc-64的slab中分配。

寻找合适的堆喷对象,对象的大小必须在(32,64]范围内,而且我们要控制func,next_rcu指针,因此,前8个字节字节必须可控,但是像sendmsg等这些函数前48个字节内容不可控,因此不符合要求

根据函数调用链找到这样一条sock_kmalloc路径。

执行语句如下

        int count = IP_SFBLOCK;

        if (psl)
            count += psl->sl_max;
        newpsl = sock_kmalloc(sk, IP_SFLSIZE(count), GFP_KERNEL);
-------------------------------------------------------------------------------
        #define IP_SFLSIZE(count)    (sizeof(struct ip_sf_socklist) + \
    (count) * sizeof(__be32))

这样计算下来,size大小刚好为64byte。

控制pc

setsockopt 堆喷路径选择

udp_setsockopt属于udp_prot,也就是需要udp(dgram)类型的socket。

sys_setsockopt (level != SOL_SOCKET)->[sock->ops->setsockopt]->sock_common_setsockopt->
udp_setsockopt->ip_setsockopt (level == SOL_IP)->do_ip_setsockopt->ip_mc_source ()

喷射成功后的mc_list对象


next_rcu指向了用户空间的一块内存地址,这样就可以在用户空间布置 fake ip_mc_socklist(shellcode) 提权。

但是这里堆喷成功率很低,而且前8个字节虽然可以利用,但是用户不可控,正在学习新的喷射方法去增加喷射成功率,使对象内需要的指针可控。

userfaultfd+setxattr

preView