浅析CVE-2015-3636
来源:互联网 发布:网络电影播放器排行榜 编辑:程序博客网 时间:2024/05/21 09:55
//weibo: @少仲
0x0 漏洞信息
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-3636
0x1 漏洞描述
CVE-2015-3636漏洞是Linux kernel的ping套接字上存在的一个Use-After-Free漏洞.
0x2 代码分析
在调用connect连接用socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP)创建的套接字对象前,代码如下:
int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags){struct sock *sk = sock->sk;if (addr_len < sizeof(uaddr->sa_family))return -EINVAL;if (uaddr->sa_family == AF_UNSPEC)return sk->sk_prot->disconnect(sk, flags);if (!inet_sk(sk)->inet_num && inet_autobind(sk))return -EAGAIN;return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len);}
当sa_family == AF_UNSPEC的情况下,调用disconnect函数取决于protocol的类型.比如ICMP套接字.
int udp_disconnect(struct sock *sk, int flags){struct inet_sock *inet = inet_sk(sk);sk->sk_state = TCP_CLOSE;inet->inet_daddr = 0;inet->inet_dport = 0;sock_rps_reset_rxhash(sk);sk->sk_bound_dev_if = 0;if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))inet_reset_saddr(sk);if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) {sk->sk_prot->unhash(sk);inet->inet_sport = 0;}sk_dst_reset(sk);return 0;}
可以看到调用了sk_prot->unhash(sk)函数.
static void ping_v4_unhash(struct sock *sk){struct inet_sock *isk = inet_sk(sk);pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);if (sk_hashed(sk)) {write_lock_bh(&ping_table.lock);hlist_nulls_del(&sk->sk_nulls_node);sock_put(sk);isk->inet_num = 0;isk->inet_sport = 0;sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);write_unlock_bh(&ping_table.lock);}}
通过这段代码,可以看出.如果sk_hashed,它会删除sk_nulls_node在hlist当中的存储.那么我们看下都删除的代码
static inline void __hlist_nulls_del(struct hlist_nulls_node *n){struct hlist_nulls_node *next = n->next;struct hlist_nulls_node **pprev = n->pprev;*pprev = next;if (!is_a_nulls(next))next->pprev = pprev;}static inline void hlist_nulls_del(struct hlist_nulls_node *n){__hlist_nulls_del(n);n->pprev = LIST_POISON2;}
在hlist_nulls_del被调用后,会调用sock_put函数.
static inline void sock_put(struct sock *sk){if (atomic_dec_and_test(&sk->sk_refcnt))sk_free(sk);}
我们可以看到,当sk->sk_nulls_node开始删除的时候,n->pprev的值变成了LIST_POISON2.而这个值在(32位 and 64位)系统中被定义成了0x200200.这段地址可以被攻击者mmap到用户空间.当connect函数被调用第二次的时候,socket对象从hlist当中删除,但是它仍然是hashed类型,因为他取决于第一次connect时的sk->sk_node.因此会再次进入if条件下,再次删除sk->sk_nulls_node.
当执行到*pprev=next时,由于之前的值为0x200200,如果它没有被map到用户空间,则会产生一个页面错误,因此导致内核的panic.(如果要避免crash的情况出现,就需要在第二次连接ICMP socket之前,把它mmap到用户空间.)
每次进入if条件下,都要判断sock的对象的引用计数是否为0.如果为0的话就会被free掉.也就是说比如一个套接字对象被第二次连接时,它的引用计数变成0,因此内核会释放掉它.但是当文件描述符的句柄在用户程序中,并且和内核中的socket对象相关,则容易出现UAF的问题.
0x3 如何利用
当调用close函数释放socket对象时,会触发inet_release函数
int inet_release(struct socket *sock){struct sock *sk = sock->sk;if (sk) {long timeout;sock_rps_reset_flow(sk);ip_mc_drop_socket(sk);timeout = 0;if (sock_flag(sk, SOCK_LINGER) &&!(current->flags & PF_EXITING))timeout = sk->sk_lingertime;sock->sk = NULL;sk->sk_prot->close(sk, timeout);}return 0;}
当内核调用inet_release函数来释放socket对象时,会调用sk_prot->close函数.而sk_proto是sk_common结构中的一个成员变量.它的类型又包含了TCP,UDP,PING等.当0x200200这段地址没有被map的情况下,会造成内核的crash.如果映射一块内存出来就不会crash掉.所以利用的方法就是想办法覆盖掉sk的内存空间,然后使它指向自己的函数,然后提权.
0x4 伪Poc
void exp_func(){struct sockaddr_in addr = {0};int ret = 0;void* map_addr = NULL;map_addr = mmap(,,,,,);int sockfd = socket(AF_INET,SOCK_DGRAM,IPPROTO_ICMP);addr.sin_family = AF_INET;ret = connect(sockfd,&addr,sizof(sockaddr_in));addr.sin_family = AF_UNSPEC;ret = connect(sockfd,&addr,sizof(sockaddr_in));addr.sin_family = AF_UNSPEC;ret = connect(sockfd,&addr,sizof(sockaddr_in));......}
工作原因还是不放出完整的代码了,但是根据大体思路和逆向出来的代码,已经可以确定是这样的.第一次连接时,必须要把sa_family设置成AF_INET类型来保证sk是hashed类型,否则无法进入if条件下.另外要校验一下/proc/sys/net/ipv4/ping_group_range的权限才能使用.
0x5 漏洞修复
static __inline__ void sk_nulls_node_init(struct hlist_nulls_node *node){node->pprev = NULL;}
- 浅析CVE-2015-3636
- CVE-2015-3636
- CVE-2015-3636
- 浅析CVE-2012-4220
- 浅析CVE-2009-2692
- 浅析CVE-2012-0056
- 浅析CVE-2014-0196
- 浅析CVE-2013-6282
- 影响所有Nexus手机的漏洞,浅析CVE-2015-1805
- CVE-2015-1641浅析-word类型混淆漏洞
- CVE-2015-2545浅析-word释放重引用漏洞
- CVE-2015-2425浅析-Internet Explorer释放重引用漏洞
- 浅析CVE-2011-3874(zergRush)
- 浅析cve-2011-1823(Gingerbreak)
- Android 最新漏洞CVE-2015-3636
- CVE-2017-5375&CVE-2017-5400&CVE-2016-9079浅析-firefox中的JIT喷射
- CVE-2015-0235
- CVE-2015-3090
- 一步一步在ubuntu上安装即时通讯服务器-Openfire
- poj 2387 Til the Cows Come Home
- 重复子串问题(五):求最长回文字符子串
- 动态规划专题之zoj1013
- B. Berland National Library
- 浅析CVE-2015-3636
- Ubuntu 安装mysql和简单操作
- CS224d Problem set 2作业
- 如何实时查看linux下的日志
- uva 673 Parentheses Balance
- 1078. Hashing (25)
- The Roatin Games poj
- 一笔画问题 NYOJ
- Java字符串题目--删除给定字符串中出现次数最少的字符