最近一段时间在研究linux kernel的漏洞利用,我们以CVE-2017-8890为例探索了linux kernel的提权过程.
0x00 测试环境
linux kernel 版本:4.10.6 x86_64
调试环境:qemu + linux kernel + busybox + gdb
kernel 防护机制: no smep, no smap,no KASLR
主机:Ubuntu 16.04
测试环境我们使用qemu运行linux kernel + busybox的最小化系统,并在Ubuntu主机上通过gdb远程调试linux kernel,十分便捷。同时,我们为了方便,关闭了内核的SMEP/SMAP、KASLR防护机制。
0x01 漏洞原理
CVE-2017-8890是启明星辰ADLab去年披露的linux kernel double free漏洞,取名Phoenix Talon,可影响几乎所有Linux kernel 2.5.69 ~ Linux kernel 4.11的内核版本、对应的发行版本以及相关国产系统。我们简单介绍下该漏洞的原理。
我们在socket编程中服务端创建socket时会在内核创建一个inet_sock结构体, 暂时称其为sock1:
struct inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct sock sk;
........
__be32 inet_saddr;
__s16 uc_ttl;
__u16 cmsg_flags;
__be16 inet_sport;
__u16 inet_id;
..........
__be32 mc_addr;
struct ip_mc_socklist __rcu *mc_list;
struct inet_cork_full cork;
};
当服务端调用accept函数接收外来连接的时候会创建一个新的inet_sock结构体, 称为sock2。sock2对象会从sock1对象复制一份ip_mc_socklist指针,其结构体如下:
struct ip_mc_socklist {
struct ip_mc_socklist __rcu *next_rcu;
struct ip_mreqn multi;
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
struct ip_sf_socklist __rcu *sflist;
struct rcu_head rcu;
};
此时在内核中存在两个不同inet_sock对象,但它们的mc_list指针却指向同一个ip_mc_socklist对象。此后,当服务端close socket的时候,内核会free对应的inet_sock对象sock1,并同时释放mc_list指针指向的那个ip_mc_socklist对象。但是服务端在关闭accept创建的inet_sock对象sock2时,会再次释放同一个mc_list对象,造成double free漏洞。
该漏洞的原理比较简单,就是在复制对象的时候将指针也一同复制了一份,造成两个指针指向同一对象。因此,漏洞修复也比较简单,直接在复制对象的时候将mc_list指针置为NULL即可。