Tags: pwn radare2 

Rating:

For this challenge we are given an executable which asks for some input on startup. Let's decompile it with [`r2ghidra-dec`](https://github.com/radareorg/r2ghidra-dec) -- a [Ghidra](https://ghidra-sre.org/) decompiler integration into [radare](https://www.radare.org/r/).

```c
undefined8 main(void)
{
char *s;
uint32_t var_4h;

var_4h = 0;
sym.imp.setbuf(_reloc.stdout, 0);
sym.imp.setbuf(_reloc.stdin, 0);
sym.imp.setbuf(_reloc.stderr, 0);
sym.imp.puts("Please pour me some coffee:");
sym.imp.gets(&s);
sym.imp.puts("\nThanks!\n");
if (var_4h != 0) {
sym.imp.puts("Oh no, you spilled some coffee on the floor! Use the flag to clean it.");
sym.imp.system("cat flag.txt");
}
return 0;
}
```
Something to note is that if we were to use [Ghidra](https://ghidra-sre.org/), it would show something like `char s [44];`, but let's find this out using [radare](https://www.radare.org/r/) and see how these two variables are placed one after the other on the stack.
```r2
┌ 158: int main (int argc, char **argv, char **envp);
│ ; var char *s @ rbp-0x30
│ ; var uint32_t var_4h @ rbp-0x4
│ 0x00401156 55 push rbp
│ 0x00401157 4889e5 mov rbp, rsp
│ 0x0040115a 4883ec30 sub rsp, 0x30
│ 0x0040115e c745fc000000. mov dword [var_4h], 0
│ ; <redacted>, Sets up stdio buffers and prompts for input
│ 0x004011ad 488d45d0 lea rax, [s]
│ 0x004011b1 4889c7 mov rdi, rax ; char *s
│ 0x004011b4 b800000000 mov eax, 0
│ 0x004011b9 e8a2feffff call sym.imp.gets ;[3] ; char *gets(char *s)
│ 0x004011be 488d3d5f0e00. lea rdi, str.Thanks ; 0x402024 ; "\nThanks!\n" ; const char *s
│ 0x004011c5 e866feffff call sym.imp.puts ;[2] ; int puts(const char *s)
│ 0x004011ca 837dfc00 cmp dword [var_4h], 0
│ ┌─< 0x004011ce 741d je 0x4011ed
│ │ ; <redacted>, Flag is printed here
│ └─> 0x004011ed b800000000 mov eax, 0
│ 0x004011f2 c9 leave
└ 0x004011f3 c3 ret
```

At the very start we see the two variables, `s` and `var_4h` defined by [radare](https://www.radare.org/r/) with offsets off `rbp` and then assigned to in assembly below:
```r2
; var char *s @ rbp-0x30
; var uint32_t var_4h @ rbp-0x4
0x0040115e c745fc000000. mov dword [var_4h], 0
0x004011ad 488d45d0 lea rax, [s]
```

It's clear that the size of them together is `0x30`:
```r2
0x0040115a 4883ec30 sub rsp, 0x30
```

`s` is placed at the start with offset `rbp - 0x30` and then `var_4h` is placed at `rbp - 0x4`. This means that the `s` buffer which we control is of size `0x30 - 0x4 = 0x2c` or `44` in decimal. Thus, we can overflow this buffer with the vulnerable `gets()` call and overwrite `var_4h` by sending 44 bytes followed by our new value for `var_4h`.

The flag is printed if `var_4h` is no longer 0, so overwriting it with anything but null bytes should do the trick. The comparison can be seen here:
```r2
0x004011ca 837dfc00 cmp dword [var_4h], 0
```

The flag we get is: `csictf{y0u_ov3rfl0w3d_th@t_c0ff33l1ke@_buff3r}`

Original writeup (https://fluix.dev/blog/csictf-2020-pwn-intended/).