
CVE-2021-42008 is a Slab-Out-Of-Bounds Write vulnerability in the Linux 6pack driver, caused by a lack of size validation checks in the decode_data function. Malicious input from a process with CAP_NET_ADMIN capabilities may lead to an overflow of the Cooked_buf field in the Sixpack structure, resulting in kernel memory corruption. If exploited correctly, this could lead to root privilege escalation. In this article, after analyzing the vulnerability, we will exploit it using kernel exploitation techniques to bypass all modern kernel protections, and then we will evaluate other methods to achieve privilege escalation.
Overview
6pack is a transport protocol for data exchange between PCs and TNCs (Terminal Node Controllers) over serial lines. It serves as an alternative to the KISS protocol for networking via AX.25. AX.25 is a data link layer protocol widely used in amateur packet radio networks (and some satellites, such as 3CAT2).
The vulnerability we are going to exploit was introduced by commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and was added to the 6pack driver in 2005. It was discovered by Syzbot and was recently fixed by commit 19d1532a18765a0c1fc7321cac2. Every kernel version prior to 5.13.13 is affected.
As mentioned in the introduction, the vulnerability is caused by a lack of size validation checks in the decode_data() function. Malicious input received from a process with CAP_NET_ADMIN capabilities through the Sixpack channel may cause the decode_data() function to be called multiple times by Sixpack_decode(). The malicious input is then decoded and stored in the cooked_buf buffer within the sixpack structure. The variable rx_count_cooked is used as an index in cooked_buf, which essentially determines the offset for writing the decoded bytes. The problem is that if decode_data() is called multiple times, the rx_count_cooked variable will increment repeatedly until it exceeds the size of cooked_buf, which can hold a maximum of 400 bytes. This could lead to a Slab-Out-Of-Bounds Write vulnerability, which, if exploited correctly, could lead to root access.
To exploit this vulnerability, we will target one of the latest versions of Debian 11. You can download it here. The vulnerability is designed and tested against kernel 5.10.0-8-amd64. All modern protections such as KASLR, SMEP, SMAP, PTI, CONFIG_SLAB_FREELIST_RANDOM, CONFIG_SLAB_FREELIST_HARDENED, CONFIG_HARDENED_USERCOPY, etc., are enabled.
Analyzing the Vulnerable Driver
In modern Linux distributions, 6pack is typically compiled as a loadable kernel module. By setting the line discipline of the tty to N_6PACK, the module can be loaded into the kernel. To do this, we can simply create a ptmx/pts pair, which are the master and slave ends of a pty, and set the line discipline of the slave end to N_6PACK:
#define N_6PACK 7
int open_ptmx(void) {
int ptmx;
ptmx = getpt();
if (ptmx < 0) {
perror("[X] open_ptmx()");
exit(1);
}
grantpt(ptmx);
unlockpt(ptmx);
return ptmx;
}
int open_pts(int fd) {
int pts;
pts = open(ptsname(fd), 0, 0);
if (pts < 0) {
perror("[X] open_pts()");
exit(1);
}
return pts;
}
void set_line_discipline(int fd, int ldisc) {
if (ioctl(fd, TIOCSETD, &ldisc) < 0) // [2]
{
perror("[X] ioctl() TIOCSETD");
exit(1);
}
}
int init_sixpack() {
int ptmx, pts;
ptmx = open_ptmx();
pts = open_pts(ptmx);
set_line_discipline(pts, N_6PACK); // [1]
return ptmx;
}