ENPM809V
Linux Kernel Security Part 2
Agenda
- Kernel API's Worth Taking a Look
- Privilege Escalation
- Escaping Seccomp
- Writing Kernel Shellcode
Kernel API's Worth
Looking At
What have we learned last class?
- How kernel modules work and how they are compiled
- How they are loaded in
- How we can interact with them
What have we learned last class?
- Character Devices
- Very basics on Interrupts
- Threading
- And much much more...
But the kernel has vulnerabilities too...
- Memory Corruption is still a thing...
- Stack/Heap Overflows
- Race Conditions
- And many many more...
Interesting API Calls...
- copy_from_user(kernel_address, userspace_address, length);
- Copies data from userspace into a buffer in the kernel space.
- What happens if we don't do proper bounds checking?
- What happens if we copy in too much data?
- Copies data from userspace into a buffer in the kernel space.
-
copy_to_user(userspace_address, kernel_address, length);- copies data from kernel and sends it back to userspace
- What if we are able to send arbitrary data back to the user?
- copies data from kernel and sends it back to userspace
Interesting API Calls...
- There are other ways that data can be exchanged (but don't recommend)
- get_user_pages_fast((unsigned long)user_ptr, 1, 1, &page);
- Fast access to a userspace page from the kernel
- mmap - high performing shared buffers
- get_user_pages_fast((unsigned long)user_ptr, 1, 1, &page);
static int my_mmap(struct file *filp, struct vm_area_struct *vma) {
unsigned long pfn = virt_to_phys(kernel_buffer) >> PAGE_SHIFT;
return remap_pfn_range(vma, vma->vm_start, pfn,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}int fd = open("/dev/mydevice", O_RDWR);
char *mapped = mmap(NULL, length, PROT_READ
| PROT_WRITE, MAP_SHARED, fd, 0);
strcpy(mapped, "hello from user space");Interesting API Calls...

Our First Privilege Escalation
Let's Review Interacting with The Kernel
- System Calls
- Can be triggered at userspace
- Very Difficult to modify without recompiling the kernel
Let's Review Interacting with The Kernel
-
Input/Output Control provides a much more flexible interface.
-
From kernel space:
static long device_ioctl(struct file *filp, unsigned int ioctl_num, unsigned long ioctl_param) -
From user space:
-
-
Useful for setting and querying non-stream data (i.e., webcam resolution settings as opposed to webcam video stream).
int fd = open("/dev/pwn-college", 0);
ioctl(fd, COMMAND_CODE, &custom_data_structure);Let's Review Interacting with The Kernel
- One interaction mode is to handler read() and write() for your module's exposed file.
- From kernel space:
- From user space:
- Useful for modules that deal with streams (i.e., a stream of
- audio or video data).
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
static ssize_t device_write(struct file *filp, const char *buf, size_t len, loff_t *off)fd = open("/dev/pwn-college", 0)
read(fd, buffer, 128);Why Is This Important?
Can Be A Vector for Exploitation

from pwn.college - baby_kernel2.0 challenge
What if contains something else?


from pwn.college
How can we modify the cred structure?
- Credentials should be immutable, but can be replaced
-
struct cred * prepare_kernel_cred(struct task_struct *reference_task_struct)- Creates a cred structure with the credentials of a particular task
- commit_creds(struct cred *)
- Commits the credentials to the current task.
How can we modify the cred structure?
- What if we pass NULL to prepare_kernel_creds?
- It gives the creds struct of the root process!
- What if we commit this?
- We become root!
commit_creds(prepare_kernel_creds(NULL))
Let's Practice This
Bypassing Seccomp (Again)
What have we learned?
- Seccomp is a system call that restricts user space programs from making certain system calls
- If we do not properly utilize seccomp, we can bypass it with injection
- Children only inherit seccomp rules if seccomp is called before the fork
- Otherwise it is not possible to bypass
Except...
- There is a way to disable it from the kernel!
- Let's look back at the task_struct. There is more in here.

Except...
- Under task_struct->thread_info, there is a flags field.
- One of the bits is TIF_SECCOMP (this determines if SECCOMP is enabled/disabled)

Except...


Note: this is as of kernel version 5.4
Except...


https://elixir.bootlin.com/linux/v5.4/source/arch/x86/include/asm/thread_info.h
https://elixir.bootlin.com/linux/v5.4/source/include/linux/sched.h#L624 - task struct
Where does it get checked?

https://elixir.bootlin.com/linux/v5.4/source/arch/x86/entry/vsyscall/vsyscall_64.c
Where does it get checked?


This is where the filtering happens and ensure whether the system call actually happens.
https://elixir.bootlin.com/linux/v5.4/source/include/linux/seccomp.h#L35
https://elixir.bootlin.com/linux/v5.4/source/kernel/seccomp.c#L920
How do we get around this?
- We need to set the TIF_SECCOMP bit in task_struct->thread_info.flags to 0.
- We do this by setting the following:
current->thread_info.flags &= ~(1 << TIF_SECCOMP)- Current is the task struct that we are currently working in. This is stored in the gs register (important for shellcoding later)
- Plan of attack
- Access current->thread_info.flags via the gs register
- clear the TIF_SECCOMP bit
- Win!
- Only issue is that our children will still be seccomped (if enabled)
- We do this by setting the following:
Writing Kernel Shellcode
How did we do this before?
/* push b'/flag\x00' */
mov rax, 0x101010101010101
push rax
mov rax, 0x101010101010101 ^ 0x67616c662f
xor [rsp], rax
/* call open('rsp', 'O_RDONLY', 'rdx') */
push 2 /* 2 */
pop rax
mov rdi, rsp
xor esi, esi /* O_RDONLY */
syscall
/* call sendfile(1, 'rax', 0, 0x7fffffff) */
mov r10d, 0x7fffffff
mov rsi, rax
push 40 /* 0x28 */
pop rax
push 1
pop rdi
cdq /* rdx=0 */
syscall
Whether we used shellcraft to help us or not, we ended up making lots of system calls to get our desired behavior.
Why?
- Always accessible
- Gave us deep functionality
- Gave us enough to execute something else
Not the case for the Kernel!!!
- Syscalls are userspace interfaces to the kernel!
- Execution immediately jumps to syscall_entry function in the kernel after calling the syscall instruction
- Assures that it is being called from userspace
- We need to utilize the API's already given to us!
- This means we need to locate the addresses of functions and methods we need to execute.
Not the case for the Kernel!!!
- If we ran `pwn asm -c amd64 "mov rdi, 0; call prepare_kernel_creds` what will happen?
- Doesn't know what to do!
- How do we find the address of prepare_kernel_creds?
- if KASLR is disabled - get the address from /proc/kallsyms on an identical system
- if KASLR is enabled - You will need to leak the kernel address and calculate the offset (just like in userspace)
- Think of this like ret2libc
Figuring out Offsets in Kernel Functions
- You could in theory do this manually ...
- Way too difficult (especially with randomize_struct_offsets)
- Create a kernel module to figure this out!
- For homeworks, use vm build in practice mode to help you!
- Reverse Engineer it to see how actions work in assembly.
- Re-implement it in shellcode!
One important thing
- Make sure you have cleanup shellcode if it's needed
- In userspace, we can segfault and move on (unless we are trying to hide)
- In the kernel, we can't do that (we will crash the system).
- Ensure registers are in the proper place!
- If you are calling your shellcode like it's a function, ensure you return
- Maybe even have a prologue and epilogue
More Practice
Practice at pwn.college
- System Security Dojo - Kernel Security Module
- This lecture is based on this
- Best content for getting into the basics of Kernel Security
Next week we will focus on stack exploitation!
Homework
Create a Character Device
- You are going to write an encryption character device (basic XOR and shift encryption)
- Do development in either your local environment or pwn.college
- Ensure you pass the tests on Github Classroom!
- No flag for this one.
Privilege Escalation Shellcode
- You are going to write shellcode that bypasses seccomp and elevates you to root!
- Get flag and win
ENPM809V - Kernel Hacking Part 2
By Ragnar Security
ENPM809V - Kernel Hacking Part 2
- 151