Chuck it in ghidra or your favourite decompiler/analyser - we see it prints the system address to us, then uses gets to read an input. This is a classic buffer overflow which we'll attack with ret2libc.
As it prints the libc address of system, we can simply use that to calculate the libc base. The binary is 32-bit, and it reads input into ebp-0x1c, giving 32 bytes of padding until return address overwrite. Then, we just send system + junk + /bin/sh address
Note that we don't know the remote libc - I used libc-database find to get the remote libc binary, which is libc6_2.30-0ubuntu2_i386
So: 1. Receive libc address 2. Calculate libc base 3. Build ret2libc system("/bin/sh") chain 4. Pop shell, cat flag.txt
The binary has no protections except Partial RELRO.
The menu has 3 options besides exiting, one of which is secret.
We can read into a shellcode pointer, but only 5 bytes get read. We can execute said shellcode. This is all pretty much useless since 5 bytes of shellcode is not enough to do literally anything useful.
There's a secret option - gomugomunomi. It reads 100 bytes of input(no BOF) and then printfs it, allowing us to execute the classic format string exploit.
I tried to do the simple %p leak, but found no useful addresses on the stack. Instead, I used %s to read my buffer(offset 7, found through pwntools automation) as an address of a string in order to read got entries.
By doing gotaddress + %7$s we can leak got addresses to get a libc leak. We'll use libc-database find yet again to get the remote libc, libc6_2.30-0ubuntu2.2_i386
Then, we'll execute a got overwrite attack by overwriting printf@got with system. Next gomugomunomi, the input will be system'd, so we enter /bin/sh to get dropped into a shell.
But it's not over! On the remote, there is no cat. The solution to read flag.txt is simple - while read line; do echo $line; done < flag.txt
This reveals the flag.
gotaddress+ %7$s to leak libc
Format string overwrite to map printf to system
In gomugomunomi, send /bin/sh
Use while read line; do echo $line; done to read the flag file as cat is nonexistent
Numbers
The program is a constant prompt that... 1. Reads a number from us 2. Checks if the number is greater than 60, if so it tells us we're naughty and exits 3. Reads that amount of data into a 64 length buffer 4. Prints the data 5. Asks if we want to try again, just dont type n
There's also some prompts inbetween but those aren't important. At first glance, this seems perfectly secure. But actually, note this code snippet.
It actually uses atoi to convert our input to a number, and atoi allows signed integers.
This means we can enter a negative number, like -1, and atoi will return 0xffffffff
the read function takes a size_t parameter - it wont think we're trying to read -1 bytes of data, but 4294967295
bytes of data. Now that's a lot of overflow.
PIE is on, so we cant just overwrite the return address of the integer reading function, ret2plt and call it a day. Because it prints our input back at us, we can exploit it similarly to skywriting from redpwn.
As a recap, strings are terminated by null bytes. When a function, like printf in this case, attempts to print a string, it will continue reading data until it reaches a null byte, at which it will stop.
If we make our input long enough, overwriting null bytes and nudging itself next to some data, said data can be leaked. Imagine it like this:
(our input is at the beginning, and we wish to leak the 0xdeadbeef data) currently this reads as an empty string let's fill the input with AAAA
Now, the null bytes have been overwritten, so the 0xdeadbeef is part of the string! This reads to be AAAA\xde\ad\be\ef.
8 bytes from the beginning of our buffer is atoi+16, we can leak this using this method and calculate the libc base. Our input is 72 bytes from the return address, so after leaking we will send 72 bytes of padding + poprdi + /bin/sh + retgadget(stack alignment) + system to overwrite the return address of the buffer reading function and pop a shell.
Then, cat flag.txt
to get the flag.
Send size of -1 to gain large buffer overflow
Send 8 bytes to leak libc address(atoi+16)
Use libc-database find to get the remote libc(libc6_2.28-0ubuntu1_amd64)
Use size -1 trick again to overwrite return address and send system("/bin/sh") rop chain to pop a shell