Learned about this programming language called deadfish but it can’t do anything interesting. You can’t even call a function in deadfish! Therefore, I’m super confident my flag will remain safe & secure.
Tools
- pwntools
- ghidra
- python
Procedure
Lets begin! So we unzip the challenge and it comes with an ELF file named deadfish
. So, lets be the most
responsible hackers ever and run this un-sandboxed on my bare metal computer~!
|
|
Well, it looks like the file outputs a bit of text and takes some input. At the end it seems to print an address of some sort. Given what it says, perhaps that is the function address? A buffer overflow attack might be viable here. For that, we gotta open it in ghidra.
Analysing it, we can see that the main program calls a function read_program
which prints out the
text and reads in 0x108 bytes of data. It then passes that into a verify_program
function which
seems to check some random if else statements?, but wait. The program is called deadfish
, perhaps
it means something more?
Ahh, of course. They would put the deadfish esoteric language into a challenge wouldn’t they?
Anyways, it looks like that function verifies that the input is valid deadfish.
Lastly, it calls a function execute
which seems to do some logical operations before returning.
I also see a win
function that looks ripe for exploit, you known, with the __fd = open("./flag.txt",0);
and all.
Buffers
Allright, so we are taking input; how can we exploit this?
Ohh? You mean to say that deadfish
is reading in 0x108 bytes but only has storage for 256 bytes? Wait, I don’t know
hex… Python says that is 264 bytes! Looks like we have an overflow exploit.
Although, it seems like we have a slight issue, when checking the binary symbols, NX is enabled which means we cannot just execute arbitrary instructions at the end of the function… ohh darn~!
Luckily, there are other ways to achieve what we want.
First off, we should start setting up the pwn script:
|
|
Alright, lets unpack this. We start out setting up pwn tools to attach to our binary. Pretty standard stuff. Next, we need to take the output of the binary and store it. It has an address that we will need for our exploit. We can use some python to grab the hex output and store it as an integer.
After that, we also need to find the function address of the win
function. Since I am lazy, we can just open the
binary with the ELF
command and set win_addr
to the output of the symbol for win
. In small words, we are having
python find the address for us instead of wasting precious time and brainpower
Like they always say, why spend 30s on a task when you could spend 5 minutes automating it.
Awesome! Looks like we are getting closer, we have all the information we need to construct the payload, so lets!
First off, we know from earlier that we have 8 bytes of overflow to work with. Lovely! Tis just enough to overwrite the return address. So Lets do a little bit of trickery.
We know that at first we need a little bit of valid deadfish
because some genius thought that was a wonderful idea.
We can do about 8 bytes of that; however!, we need to null terminate it so that when it tries to read the string, it
stops before the payload. Lowercase i
is a valid deadfish
instruction, so…. 7 of them plus a null character gets
us our 8 bytes.
Next we need to put the win
address. Why you might ask? I don’t know either Tis because when computers were created
the stack grew downwards in memory, so when we later rewrite the return address with the stack address (the start of
this current function), we will need to have our next jump be here to go to the win
function.
Well, we can’t just write the win function yet, it needs to be overwriting the return address… so, time for a bit of BUFFER!
Since we need 16 bytes for the stack
address and the win
address, that means we need 240 bytes of buffer.
And, since we are now at the last 8 bytes, we can put the stack
address here, which completes the payload.
It looks like this:
|
|
Solve
That would be the completed payload. When it is all put into one script it looks like this:
|
|
If we replace the process with the remote connection, it prints out:
|
|
There we go, the flag is osu{wh0_says_d3adf1sh_ha5_n0_c0ntr0l_fl0w?}