one punch
Problem
Solution
Basic file checks
We're given a binary with a ld linker and a libc, first thing we'll do is run pwninit with the provided linker so it can segfaultlessly load the provided libc
pwninit --bin ./one_punch --libc ./libc.so.6 --ld ./ld-linux-x86-64.so.2Next lets do some basic file check
FULL RELRO: so overwriting GOT is not an option
No Stack Canary: easier for us to do BOFs
NX enable: Shellcode is also not an option
PIE Enabled: means we have to do some leaking to correctly craft the ROP chains
Next, lets statically analyse the binary using ghidra
Binary Analysis

First the function will check if mapped_region in the .data section is empty, if not it will execute init, we'll take a look at that later. Next we're greeted with an address leak, lets check what that is using gdb-pwndbg

pop rdi; ret; gadgetIt seems the address is pointing to an address that can be useful as our pop rdi; ret; gadget which will enable our ROP chains.

The init function fills the mapped_region with the value of key which holds the value POWER, GET THE POWER. . Next lets check vuln

Crafting ROP chains
Immediately we see that it's using the gets which will enable our overflow, from here we already get an overview of how we'll exceute the ROP chains. First we'll leak one of the function within the GOT and print it out. We can then subtract that with its corresponding offset to find the Libc base address. we can call system with /bin/sh that's exist within the Libc as follows:
1st Payload:
pop rdi -> GOT puts -> PLT puts -> Main (Eventually will call vuln)
2nd Payload:
pop rdi -> binsh -> system
but there's a twist, vuln will do a a comparison between key and mapped_region . If the two values is not the same, it will exit the program. Below it, the instruction will overwrite the first 21 bytes of mapped_region with 0s. This basically is a check to make sure that vuln can only be called once. To bypass this, we simply have to call init to restore the value. In order to do that we cant return to main after our first BOFs since there's check on mapped_region if the memory is empty. So instead, we need to return to init passing the if statement and eventually will return to vuln through main.
1st Payload:
pop rdi -> GOT puts -> PLT puts -> init
2nd Payload:
pop rdi -> binsh -> system
Flag
dead{I_w4nn4_b3_4_s41ky0u_H3R00000000}
Last updated