jueves, 26 de diciembre de 2013

Writeup prueba 6 - h4ckc0nt3st - GSICKMINDS 2013




El fichero omgdos es un ejecutable ELF 32bit Linux

$ file omgdos
omgdos: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x9b85ac423ba72581a5c483f8a1ed077004bde96e, stripped

El traceado revela llamadas de sistema a vm86, se usa el modo 8086 virtual :


# strace ./omgdos
...
execve("./omgdos", ["./omgdos"], [/* 21 vars */]) = 0
[ Process PID=7405 runs in 32 bit mode. ]
mmap2(NULL, 1048576, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0
...
vm86(0x1, 0x804a780, 0x8048db2, 0, 0xfffc) = -1 ENOSYS (Function not implemented)

Para la ejecución en el modo virtual 8086 el programa host tiene que mmap-ear todo el código y los datos usados a la memoria y configurar handlers para los callbacks. La memoria esta en :


if ( alloc_mem(1048576u) == -1 )
 {
   v2 = __errno_location();
   v3 = strerror(*v2);
   fprintf(stderr, "%s: cannot mmap: %s\n", *(_DWORD *)a2, v3);
   exit(1);
 }
 sub_8048E3C(0, 31744u);
 sub_8048EDB(105u);
 v4 = sub_8048940(0, 0x7C00u);
 emulate((int)code, 671, v4, "C:\\WINDOWS\\RUNDLL32.EXE");

Para la interacción con el programa host se usa la interrupción 105 (0x69), el handler se implementa en


.text:08049016 handler         proc near               ; CODE XREF: sub_8048BFF+114#p
.text:08049016

Funciones:

0 – exit
1 – imprimir a stdout
2 – leer de stdin


El modo real se puede obtener interrumpiendo en la llamada de sistema VM86_INIT y volcando la reserva de memoria con la función alloc_mem():


# gdb -q ./omgdos
Reading symbols from /home/user/coruna/omg/omgdos...(no debugging symbols found)...done.
gdb-peda$ catch syscall vm86
Catchpoint 1 (syscall 'vm86' [166])
gdb-peda$ r
Catchpoint 1 (call to syscall vm86), 0xf7fdf430 in __kernel_vsyscall ()
gdb-peda$ generate-core-file core
Saved corefile core

Después se puede extraer el core:

$ cat extract_core
#!/usr/bin/python

f = open('core').read()
open('dmp', 'w').write(f[1600:1600+1000000])

Code is loaded on address 0x7C00 (like MBR):

seg000:7C00                 mov     sp, offset stack
seg000:7C03                 mov     ax, offset aDimeQuICenIElP ; "Dime, -+qu+¬ cen+¬ el pen+¦ltimo d+¡a e"...
seg000:7C06                 call    print
seg000:7C09                 mov     ax, 2
seg000:7C0C                 mov     bx, offset input
seg000:7C0F                 mov     cx, 100
seg000:7C12                 int     69h
seg000:7C14                 mov     ax, offset input
seg000:7C17                 call    near ptr decrypt_compare+1
seg000:7C1A                 test    ax, ax
seg000:7C1C                 jnz     short loc_7C23
seg000:7C1E                 mov     ax, offset winner ; "\x1B[1m-íS+¡!\x1B[0m -+C+¦mo lo has sab"...
seg000:7C21                 jmp     short loc_7C26
seg000:7C23 loc_7C23:                               ; CODE XREF: seg000:7C1C#j
seg000:7C23                 mov     ax, offset nope ; "Pffff pero qu+¬ me est+ís contando.\n"
seg000:7C26
seg000:7C26 loc_7C26:                               ; CODE XREF: seg000:7C21#j
seg000:7C26                 call    print
seg000:7C29                 mov     ax, 0
seg000:7C2C                 int     69h

Imprime la cadena
Dime, ¿qué cené el penúltimo día en el festival de Ortigueira?
comprueba la entrada de usuario, y si acierta imprime
¿Cómo lo has sabido? Venga, pon la solución en la web y luego búscame para explicarme cómo demonios lo has hecho.
y en error
Pffff pero qué me estás contando.

Rutina de descifrado:


seg000:7C2E aLgimijhflyUMns db 'Lgimijhfly+u-mnsp}' ; DATA XREF: seg000:7C47#o
seg000:7C40                 db  7Fh ;  
seg000:7C41 ; ---------------------------------------------------------------------------
seg000:7C41                 jnz     short near ptr aDimeQuICenIElP+24h
seg000:7C43
seg000:7C43 decrypt_compare:                        ; CODE XREF: seg000:7C17#p
seg000:7C43                 cmp     [bp+57h], dl
seg000:7C46                 push    cx
seg000:7C47                 mov     si, offset aLgimijhflyUMns ; "Lgimijhfly+u-mnsp}"
seg000:7C4A                 mov     di, ax
seg000:7C4C                 xor     cx, cx
seg000:7C4E
seg000:7C4E loc_7C4E:                               ; CODE XREF: seg000:7C60#j
seg000:7C4E                 inc     cx
seg000:7C4F                 cmp     cx, 16h
seg000:7C52                 jz      short loc_7C67
seg000:7C54                 mov     al, [di]
seg000:7C56                 xor     al, cl
seg000:7C58                 mov     ah, [si]
seg000:7C5A                 cmp     al, ah
seg000:7C5C                 jnz     short loc_7C62
seg000:7C5E                 inc     si
seg000:7C5F                 inc     di
seg000:7C60                 jmp     short loc_7C4E

Hace un XOR con la posición de cada caracter y lo compara con un string prefijado. La entrada se puede calcular:


t='4C67696D696A68666C792B752D6D6E73707D7F756138'.decode('hex')
s=''
for i in xrange(len(t)):
s += chr(ord(t[i])^(i+1))
print s

Así que la respuesta correcta es “Mejillones y cacaolat.”


No hay comentarios:

Publicar un comentario