xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



Exploit Development

IDA Free



Al desarrollar exploits generalmente no tenemos el codigo fuente disponible, las aplicaciones escritas en lenguajes de alto nivel como Java o C# suelen decompilarse facilmente y obtener un codigo muy parecido al original, sin embargo cuando es escrito con un lenguaje mas de bajo nivel como C o C++ este proceso es mas complicado y generalmente en su lugar usamos un desensamblador

Un desensamblador analiza el binario y lo convierte a instrucciones en ensamblador, algunos de ellos tienen la capacidad ordenar el codigo de forma en que sea mas intuitivo entender el flujo del programa, uno de los desensambladores mas conocidos es IDA, sin embargo hay otras alternativas como Ghidra, Radare2 o BinaryNinja


Open


Despues de instalar y abrir IDA se nos muestra una ventana donde podemos abrir un nuevo archivo para analizarlo o cargar un proyecto antes analizado y no iniciar de 0

Para aprender a usarlo cargaremos el binario notepad.exe de nuestro Windows 10, para ejecutables de windows de 32 bits (.exe) y librerias (.dll) usaremos la opción Portable executable for 80386 con las opciones por defecto que tiene IDA

Al cargar el binario notepad.exe este empezará a analizarlo, este proceso suele tardar incluso hasta un par de minutos dependiendo del peso del archivo, cuando IDA termine de analizarlo nos mostrará una ventana como la siguiente

Cuando terminamos de trabajar y cerramos el archivo tenemos la opción de guardar el proyecto para renaudarlo mas tarde o simplemente cerrarlo sin guardar nada


View


La ventana que mas usaremos será la del desensamblado, en esta podemos organizar el codigo de 3 diferentes formas de acuerdo lo que necesitemos:

• Graph View: La vista grafica separa el codigo en funciones ordenando el codigo de la funcion en bloques, esta vista es bastante intuitiva ya que se puede seguir el flujo del programa con cada bloque que esta conectado por saltos o condicionales

La flecha verde indica si la condición se cumplió a través de saltos condicionales como jz y la flecha roja si esta no lo hizo, la flecha azul simplemente indica que solo hay un camino generalmente un jmp sin ningun tipo de condición

• Text View: La vista de texto muestra todo el codigo de forma lineal, de esta forma tambien podemos analizar el código pero es menos intuitivo seguir el flujo, algo curioso es que podemos alternar ente estra vista y la anterior usando la tecla Space

• Proximity View: La vista de proximidad es un poco mas avanzada y lo que hace es que nos permite ver las relaciones entre funciones, variables globales y constantes, esta podemos encontrarla en View > Open subviews > Proximity browser


Basic Parts


Aunque lo que más usaremos sera el desensamblador a la izquierda podemos encontrar 2 ventanas, la primera de ellas nos muestra todas las funciones existentes, cuando los simbolos no son cargados las funciones tendran como nombre sub_addr, al hacer doble clic sobre alguno de ellos se nos mostrará su código desensamblado

Usando Ctrl + F se nos abre un cuadro de busqueda donde podemos ingresar el nombre de una función o su dirección para encontrarla rápidamente, ademas nos muestra datos como su sección, su dirección y la longitud que ocupa la función

Otra ventana a la izquierda es una previsualización del gráfico, esto nos sirve para desplazarnos rápidamente en el flujo de una función grande, el bloque donde estamos trabajando se muestra con un cuadro con un contorno de puntos

Podemos ir a bloques anteriormente analizados usando las flechas en la barra


Basic Usage


Algo bastante util para el analisis es la opción Line prefixes que nos mostrará detrás de cada función su dirección, esta la encontrarmos Options > General

Otra cosa bastante util es la pequeña pestaña con colores presente en cada bloque

Aqui podemos elegir un color para colorear todo el bloque, esto es util indentificar el flujo mas facilmente a la hora de analizarlo siguiendo un color especifico

Se puede usar cualquier colores pero para el analisis nos puede ayudar usar solo 2, en este caso verde para caminos deseados y rojo para caminos no deseados

Al presionar : sobre una instrucción nos permite ingresar un comentario en esta

Presionando la tecla n sobre una variable podemos cambiarle el nombre para hacerlo las identificable, en este caso pasamos de dword_addr a my_variable

Esto funciona no solo para cambiar el nombre de variables sino también de funciones

La pestaña Imports nos muestra todas las funciones importadas al binario desde una libreria externa (.dll), y al lado de ella información sobre ella como su dirección

Al presionar x sobre el nombre de una función o una variable se abrirá una pestaña con todas las referencias a este como llamadas en este caso a la función malloc()


Dynamic Usage


La forma de aprovechar IDA es un analisis estatico para guiarnos en uno dinamico, sin embargo para saltar entre el debugger y el desensamblador necesitamos que la dirección base coincida con la del proceso, gracias a protecciones como ASLR la dirección cambia constantemente, podemos saber la dirección actual desde WinDbg

0:000> lm m notepad
Browse full module list
start    end        module name
00f60000 00f9f000   notepad    (pdb symbols)  

Desde Edit > Segments > Rebase program podemos modificar la dirección base por la que nos muestra el debugger que esta siendo utilizada en tiempo de ejecucuón

Al hacer esto sincronizamos el analisis estatico y dinamico por lo que comparten direcciones, una forma de verlo es encontrando la una función dentro de notepad como StringLengthWorkerW, con u podemos ver su codigo desensamblado

0:000> x notepad!StringLengthWorkerW
00f78fc4          notepad!StringLengthWorkerW (void)

0:000> u notepad!StringLengthWorkerW
notepad!StringLengthWorkerW:
00f78fc4 8bff            mov     edi,edi
00f78fc6 55              push    ebp
00f78fc7 8bec            mov     ebp,esp
00f78fc9 51              push    ecx
00f78fca 56              push    esi
00f78fcb baffffff7f      mov     edx,7FFFFFFFh
00f78fd0 b8a01df600      mov     eax,offset notepad!`string' (00f61da0)  
00f78fd5 57              push    edi

Con la tecla g podemos ir a esa dirección donde podemos ver que coincide y podemos seguir el flujo mas fácilmente desde IDA en lugar de WinDbg

Como ejemplo vamos a establecer un breakpoint en la función CreateFileW para correr el bloc de notas y detenernos cuando se crea un nuevo archivo

0:000> bp kernel32!CreateFileW  
0:000> g

Si intentamos averiguar donde se llamó a la función en IDA tendriamos que buscar las referencias a esta función, lamentablemente tenemos 20 posibilidades diferentes

Para ello crearmos un archivo y el programa se detiene en el breakpoint, podemos ir hasta el siguiente ret y salir de la función para tener una idea de la dirección

0:000> g
Breakpoint 0 hit
eax=00000000 ebx=00000001 ecx=0085ef4c edx=77931670 esi=0675bd48 edi=00000003
eip=774ac260 esp=0085ef70 ebp=0085f810 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
KERNEL32!CreateFileW:
774ac260 ff25a0435077    jmp     dword ptr ds:0023:775043a0={KERNELBASE!CreateFileW (74c761a0)}

0:000> pt
eax=000003e0 ebx=00000001 ecx=a07b680f edx=00000000 esi=0675bd48 edi=00000003
eip=74c76201 esp=0085ef70 ebp=0085f810 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
KERNELBASE!CreateFileW+0x61:
74c76201 c21c00          ret     1Ch

0:000> p
eax=000003e0 ebx=00000001 ecx=a07b680f edx=00000000 esi=0675bd48 edi=00000003
eip=00f6865e esp=0085ef90 ebp=0085f810 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
notepad!SaveFile+0x8f:
00f6865e a39cf6f700      mov     dword ptr [notepad!fp (00f7f69c)],eax ds:0023:00f7f69c=00000000  

La dirección después de salir de la función es 0x00f6865e, si ingresamos esto a IDA nos lleva al bloque especifico donde se llamó a la función CreateFileW, algo interesante es que IDA nos muestra como comentarios los argumentos que se le pasan al llamar a una función basandose en WinApis para hacerlo mas legible

Seguimos el flujo de IDA y localizamos una llamada a ReadFile dentro de la misma función que hizo una llamada a CreateFileW, en el bloque podemos ver que el contenido de eax en la direccion 0x00f650a4 es comentado como lpBuffer que de acuerdo a la documentacion es el puntero al buffer que recibe los datos leidos

Establecemos un breakpoint en la llamada a ReadFile y corremos el programa, al abrir un archivo se detiene en el breakpoint y el segundo valor en el stack o el valor actual de eax que es 0x0073ea08 deberia ser el puntero de lpBuffer

0:000> bp 0x00f650a6

0:000> g
Breakpoint 0 hit
eax=0073ea08 ebx=00000880 ecx=09d33001 edx=00000000 esi=00c0b8fc edi=06832368
eip=00f650a6 esp=0073e9d8 ebp=0073ee0c iopl=0         nv up ei pl nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200217
notepad!UpdateEncoding+0x7e:
00f650a6 ff15c401f800    call    dword ptr ds:0023:00f801c4={KERNEL32!ReadFile (774ac5e0)}  

0:000> dds esp L5
0073e9d8  00000880
0073e9dc  0073ea08
0073e9e0  00000400
0073e9e4  0073ea00
0073e9e8  00000000

Después de ejecutar la función en la dirección 0x0073ea08 se deberia haber guardado el contenido del archivo, esto podemos comprobandolo usando da

0:000> p
eax=00000001 ebx=00000880 ecx=09a0d9d1 edx=77931670 esi=00c0b8fc edi=06832368  
eip=00f650ac esp=0073e9ec ebp=0073ee0c iopl=0         nv up ei pl nz na pe nc  
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206  
notepad!UpdateEncoding+0x84:
00f650ac 85c0            test    eax,eax

0:000> da 0073ea08
0073ea08  "test"