An�lisis est�tico del c�digo ejecutable ELF – tutorial

El siguiente documento es la representaci�n pr�ctica de las acciones descritas en el art�culo La ingenier�a inversa del c�digo ejecutable ELF en el an�lisis de post intrusi�n (Hakin9 01/2005).
Objeto analizado: netc. Antes de empezar a analizar el archivo tenemos que copiarlo a la carpeta principal.

Preparativos

Est� claro que Hakin9 Live posee todas las herramientas necesarias para realizar el an�lisis. Sin embargo, cuando no las usamos, para realizar todo lo descrito es necesario el sistema Linux y las siguientes aplicaciones:

Aplicaciones del paquete binutils Scripts y aplicaciones del paquete fenris Las dem�s herramientas:

Diagn�stico previo del objeto analizado

[01] Por medio de la herramienta file conseguimos la informaci�n b�sica sobre el archivo analizado

# file netc
netc: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, statically linked, stripped

Como podemos observar el archivo analizado ha sido compilado est�ticamente y ha pasado el proceso de stripping.

[02] Buscamos en el archivo las cadenas de caracteres que nos interesen

# strings -a netc > strings.out

Al analizar el contenido recibido vamos a encontrar la siguiente informaci�n que nos ayudar� en las siguientes operaciones:

Otra forma de encontrar las cadenas de caracteres que nos interesen puede ser la b�squeda en el contenido de las secciones del archivo analizado. Por ejemplo, cuando queremos recibir informaci�n sobre el sistema y sobre la versi�n del compilador que se emple� para compilar el archivo, se guardan de forma est�ndar en la secci�n .comment.

Podemos leer el contenido de la secci�n indicada del archivo al aplicar el comando:

# objdump -j .comment -s nombre_de_la_aplicaci�n > comment.out

o

# objdump -h nombre_de_la_aplicaci�n > sections.out

y previsualizar con cualquier navegador el contenido del archivo con offset indicado.

Prueba de restaurar el array de s�mbolos

[03] Buscamos y descargamos de Internet la librer�a que se pueda emplear durante la compilaci�n

Del resultado de la acci�n del comando strings en el paso [02] veremos que el archivo ha sido compilado en el sistema Mandrake Linux 10.0 con el empleo del compilador GCC 3.3.2. En nuestro caso nos vamos a limitar a la prueba de restaurar los s�mbolos relacionados con la librer�a libc procedente del sistema Mandrake 10.0. Teniendo en cuenta el uso de la librer�a libc podemos suponer con mucha probabilidad que vamos a emplearla en el archivo analizado. Otra librer�a que tambi�n puede emplearse en el proceso de restaurar el array de s�mbolos es la librer�a libgcc.a. Sin embargo, nos vamos a limitar tan s�lo a la librer�a libc ya que los elementos de la librer�a libgcc.a los vamos a reconocer a continuaci�n, al comparar con una aplicaci�n compilada de forma correcta.

Guardamos la librer�a libc.a en la carpeta ~/analysis/libc_components/

�Qu� vamos a hacer si no poseemos la informaci�n que podr�a ayudarnos a la hora de fijar la versi�n de las librer�as empleadas durante la compilaci�n? En la misma situaci�n podemos descargar diferentes versiones de librer�as incluso para diferentes distribuciones del sistema y efectuar los siguientes pasos del proceso de la restauraci�n del array de s�mbolos y evaluar los resultados recibidos teniendo en cuenta la eficacia y el n�mero de alcances.

[04] Desempaquetamos los objetos de la librer�a

# ar x libc.a

[05] Comprobamos que en la aplicaci�n analizada est� incluido el c�digo de los respectivos objetos de la librer�a

# search_static netc ~/analysis/libc_components > obj_file

En este paso tenemos que tener en cuenta las colisiones que pueden aparecer durante la verificaci�n realizada. Las colisiones detectadas se encuentran en la parte final del archivo obj_file. �Qu� importancia pr�ctica y qu� influencia en el an�lisis tienen las colisiones? El problema es que sin el an�lisis detallado del c�digo de las funciones en las cuales aparecieron las colisiones no se puede determinar claramente cu�l de las funciones se emple� realmente en la aplicaci�n. Los ejemplos de la colisi�n detectada:

# Possible conflict below requiring manual resolution:
# ----------------------------------------------------
# /analysis/libc_components/getsrvbynm.o - match at 0x08057580 (0x000000ea bytes)
# /analysis/libc_components/getsrvbypt.o - match at 0x08057580 (0x000000ea bytes)

[06] Generamos el listado de las referencias simb�licas encontradas de los respectivos objetos de la librer�a

# gensymbols obj_file > symbols_db

El resultado de la acci�n del script es el listado de s�mbolos junto con las direcciones en las cuales podemos encontrar su c�digo.

[07] Realizamos el desensamblaje de la aplicaci�n analizada

# gendump netc > out1

[08] Eliminamos el c�digo de las funciones encontradas de la librer�a del archivo out1

# decomp_strip obj_file < out1 > out2

[09] Para facilitar el an�lisis a�adimos los nombres de las funciones encontradas en los lugares de sus llamadas

# decomp_insert_symbols symbols_db < out2 > out3

[10] Para aumentar la legibilidad del c�digo en los lugares de referencia a las cadenas de caracteres introducimos su contenido

# decomp_xref_data netc < out3 > out4

Para recuperar el contenido del array de s�mbolos tambi�n podemos aplicar las herramientas del paquete fenris.

Los siguientes pasos:
[a] Abrimos para editar el script getfprints
[b] En el par�metro TRYLIBS introducimos las rutas y los nombres de librer�as de las cuales queremos crear las bases de signaturas

# getfprints

[c] Sustituimos el nombre del archivo de destino con el nombre predeterminado del archivo de signaturas

# mv NEW-fnprints.dat fnprints.dat

[d] Aprovechamos la aplicaci�n dress y restauramos los s�mbolos eliminados

# dress -F ./fnprints.dat nombre_de_la_aplicaci�n > listado_de_s�mbolos_recuperados

o

# dress -F ./fnprints.dat nombre_de_la_aplicaci�n_con_el_listado_de_s�mbolos_a�adido

Fijamos las funciones a�adidas por el compilador

Cuando conocemos la versi�n del compilador empleado en la compilaci�n de la aplicaci�n analizada (y nosotros s� la conocemos) o bien podemos sobreentender esta informaci�n, podemos empezar a tratar de encontrar la localizaci�n de las funciones a�adidas por el compilador ( deber�amos obtener un resultado parecido empleando la librer�a libgcc.a en el proceso de restauraci�n del array de s�mbolos). Para realizar esta acci�n vamos a comparar una aplicaci�n modelo compilada con el mismo compilador que el archivo analizado.

[11] Creamos nuestra propia aplicaci�n modelo sample.c

int main (int argc, char **argv[])
{
return 0;
}

[12] Compilamos una aplicaci�n modelo

# gcc -static -o sample sample.c

[13] Comparamos los elementos de la aplicaci�n compilada con el c�digo del archivo analizado - out4

Como consecuencia somos capaces de fijar las siguientes funciones:

La funci�n _start() - Direcci�n = 08048100


La funci�n call_gmon_start() - Direcci�n = 08048124


La funci�n __do_global_dtors_aux() - Direcci�n = 08048150


La funci�n frame_dummy() - Direcci�n = 080481b0


Conseguimos tambi�n la localizaci�n de la funci�n _start() al leer el valor entrypoint de la cabecera ELF

Fijamos la localizaci�n de la funci�n main()

[14] Cuando comparamos la estructura de la funci�n _start() de la aplicaci�n modelo sample con el c�digo de esta funci�n encontrada en el archivo encontrado fijamos la localizaci�n de la funci�n main().

08048100: xor %ebp,%ebp
08048102: pop %esi
08048103: mov %esp,%ecx
08048105: and $0xfffffff0,%esp
08048108: push %eax
08048109: push %esp
0804810a: push %edx
0804810b: push $0x804aa90
08048110: push $0x804aa30
08048115: push %ecx
08048116: push %esi
08048117: push $0x804994f
0804811c: call 0x0804a3b0 &lt;__libc_start_main&gt;
08048121: hlt

Fijamos la funci�n del usuario

[15] Fijamos las funciones del usuario (m�s concretamente - las funciones que no han sido reconocidas como objetos de la librer�a)

# grep 'call 0x' out4 | grep -v '<' > user_f.out

[16] Como en el c�digo analizado muchas funciones llamadas se repiten, vamos a tratar de conseguir tan s�lo las direcciones �nicas de funciones

# grep 'call 0x' out4 | grep -v '<' | awk '{print $3}' | sort -u

0x0804812d
0x080481bd
0x08048204
0x080482a5
0x08048303
0x0804834b
0x080483b5
0x080483fd
0x080486b8
0x080488ab
0x08048951
0x080489b3
0x08048a3b
0x08048d9d
0x08049235
0x08049311
0x0804950b
0x0804aed0
0x0804bf70
0x0804bf90
0x08057370
0x08057580


Como vemos en el resultado, una parte de las direcciones conseguidas no existen en nuestro c�digo out4. Su falta resulta de la existencia de las signaturas de funciones que fueron eliminadas en el paso [8].

An�lisis real de las acciones realizadas por la aplicaci�n

[17] En los siguientes pasos cuando empezamos por la funci�n main(), deber�amos realizar el an�lisis del flujo del control entre las funciones del usuario y las acciones realizadas por �ste. Cuando efectuemos este paso, deber�amos conseguir la respuesta a las preguntas de tipo: �qu� papel desempe�o en el sistema el objeto analizado y qu� mecanismos emple�? Para la interpretaci�n real de las acciones realizadas por las respectivas funciones es necesario el conocimiento del lenguaje Assembler al nivel por lo menos b�sico.

Funci�n main()
0x0804812d
0x080481bd
0x08048204
0x080482a5
0x08048303
0x0804834b
0x080483b5
0x080483fd
0x080486b8
0x080488ab
0x08048951
0x080489b3
0x08048a3b
0x08048d9d
0x08049235
0x08049311
0x0804950b