Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
MemITM — Herramienta para realizar man-in-the-middle en memoria | Kitploit
Herramientas/GitHubGitHub/amossys/memitm
Análisis Dinámico (Sandboxing)Forensia de MemoriaExplotaciónIngeniería InversaDepuradoresFuzzingAnálisis de Binarios
GitHubamossys/memitm

MemITM

Herramienta para realizar man-in-the-middle en memoria

Ver Repositorio
12627hace 7 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

¿Qué es la herramienta MemITM?

La herramienta MemITM (Mem In The Middle) ha sido desarrollada para interceptar fácilmente "mensajes" en la memoria de procesos de Windows. Desarrollamos muchas herramientas personalizadas de intercepción de memoria para capturar mensajes de red antes del cifrado, o mensajes de IPC, y poder inspeccionarlos o alterarlos para hacer fuzzing. Cada herramienta era realmente personalizada, no genérica, implementada en C/ASM y no era fácil de usar/mantener/adaptar.

La herramienta MemITM ha sido desarrollada para abordar estos problemas, y consiste en:

  • un script de IDA Python, que genera un archivo de "config", indicando dónde y cómo deben colocarse los puntos de intercepción (dirección relativa, cómo encontrar el búfer y su tamaño, cómo colocar el hook, etc.) ;
  • el archivo DLL, que será inyectado en el proceso objetivo y cargará la configuración y colocará los hooks ;
  • un inyector de archivos DLL, que cargará la DLL en el proceso objetivo ;
  • un script de Python, que se comunica con la DLL/hooks inyectados, y obtiene en tiempo real los búferes interceptados (y puede alterarlos) en callbacks realmente simples que puedes modificar como desees.

Puedes descargarlo (fuentes + compilado) aquí: https://github.com/Amossys/MemITM

¿Qué tan simple es MemITM? (Ejemplo1: WriteFile)

Supongamos que deseas interceptar escrituras de archivos (hay formas más simples de hacerlo, pero es para el ejemplo) en un proceso específico de Windows. Las escrituras de archivos se realizan mediante la función WriteFile, que es exportada por kernelbase.dll, y sigue el esquema BOOL WriteFile( HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, ...). WriteFile es una función __fastcall : lpBuffer es apuntado por RDX y NumberOfBytesToWrite por R8. Interceptemos estos búferes.

  1. abre tu archivo "kernelbase.dll" en IDA Pro, carga el script generate.idapython.py, y simplemente ejecuta getHook(LocByName("WriteFile"), "rdx","r8") seguido de updateConfig("config.bin").

  2. ejecuta un bloc de notas y luego, python memitm.py notepad.exe config.bin.

¡Eso es todo! Se ha colocado un hook en la función WriteFile, y las funciones "logger" y "fuzzer" de memitm.py recibirán una copia del búfer.

¡Mi búfer no es apuntado por un registro! (Ejemplo2: NtCreateFile)

La función getHook permite especificar registros para el búfer y su tamaño, pero en algunos casos no es así. Supongamos que deseas interceptar llamadas al sistema NtCreateFile y obtener el nombre del archivo. NtCreateFile sigue el esquema NTSTATUS NtCreateFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, ...), y el nombre del archivo se puede obtener mediante ObjectAttributes->ObjectName->Buffer (el tamaño es ObjectAttributes->ObjectName->Length * sizeof(WCHAR)).

getHook también permite especificar un shellcode en su parámetro t1customOpcodes en lugar de registros. Este shellcode debe :

  • colocar el puntero al búfer en el registro RCX;
  • colocar el tamaño del búfer en el registro RDX;
  • no alterar la pila.

En el caso de NtCreateFile, podemos simplemente ejecutar este código ASM para hacer el trabajo:

root@kitploit:~
mov rax, [r8+0x10]    ; rax es ahora ObjectAttributes->ObjectName
mov rcx, [rax + 0x10] ; rcx es ahora ObjectAttributes->ObjectName->Buffer
mov rdx, [rax]        ; rdx es ahora ObjectAttributes->ObjectName->Length
and rdx, 0xFFFF       ; Length es un USHORT 
shl rdx, 1            ; y debe ser *2

Montemos esto (usando por ejemplo el sitio web de desensamblado en línea) : 498B4010488B4810488B104881E2FFFF000048D1E2. Nuestra llamada a getHook debería ser ahora getHook(LocByName("NtCreateFile", t1customOpcodes="498B…E2").

¿Puedo interceptar múltiples llamadas?

¡Sí! El archivo de configuración puede incluir múltiples definiciones de puntos de intercepción, y la función getHook añade al archivo. Puedes establecer puntos de intercepción en múltiples módulos. Por ejemplo, puedes interceptar mensajes ALPC e IOCTL al mismo tiempo.

Podrás diferenciarlos por su "ID de mensaje" en los callbacks de Python.

¡Ups, BSOD/congelación del sistema!

No te preocupes, también hay un servidor HTTP simple (logserver.py) y la función httpNetSend que te permiten enviar tus casos de prueba (y modificación) a un host remoto en tiempo real.

¿Cómo hago fuzzing?

Bueno, puedes empezar usando la función bufferBitFlip para... voltear varios bits. Registrar mensajes sin procesar te permitirá escribir tu propio disector y comenzar a implementar manualmente un mejor fuzzer :). Recuerda: ¡no puedes cambiar el tamaño del búfer!

Por ejemplo, en nuestro ejemplo de WriteFile, la siguiente función fuzzer reemplazará "hello" por "world":

root@kitploit:~
def fuzzer(data, msgID=None, pid = 0):
   return data.replace("hello","world")

Ejemplo3: diseccionando mensajes ALPC

Por ejemplo, para mensajes ALPC, podrías tener la siguiente configuración de memitm.py:

root@kitploit:~
def logger(data, msgID=None, pid=0):
    totalLen = 0
    dataLen = 0
    typ = 0
    dataInfoOffset = 0
    cid = 0
    tid = 0
    messageID = 0
    clientViewSize = 0
    # skip the PORT_MESSAGE header (0x18 bytes)
    if len(data) > 0x18:
        totalLen = struct.unpack("<H",data[:2])[0]
        dataLen = struct.unpack("<H",data[2:4])[0]
        typ = struct.unpack("<H",data[4:6])[0]
        dataInfoOffset = struct.unpack("<H",data[6:8])[0]
        zeroInit = struct.unpack("<L",data[4:8])[0]
        cid = struct.unpack("<L",data[8:0xC])[0]
        tid = struct.unpack("<L",data[0xC:0x10])[0]
        messageID = struct.unpack("<L",data[0x10:0x14])[0]
        clientViewSize = struct.unpack("<L",data[0x14:0x18])[0]
    logMessage = "ALPC message : %x:%x - %x:%x - %d:%d - %x - %x" % (totalLen, dataLen, typ, dataInfoOffset, cid, tid, messageID, clientViewSize)
    print logMessage
    return

¿Cómo funciona internamente?

El script de IDA Pro incorpora un simple motor de "hooking", que permite mover varias instrucciones a un área específica (derivado de nuestra herramienta DIMCT). Debe manejar muchos casos límite, como instrucciones relativas a la memoria, referencias cruzadas, etc. y probablemente mostrará muchos "no se puede instalar hook aquí" si intentas interceptar bloques básicos realmente pequeños (<5 bytes para binarios x86, <12 bytes para x64) que contienen múltiples referencias cruzadas. Para más información, solo lee el código fuente :).

Genera la siguiente información en el archivo de configuración:

  • el nombre del módulo;
  • la dirección relativa del punto de intercepción;
  • el área del hook de intercepción (también conocido como "T1 trampoline"), que coloca el búfer/longitud en RCX/RDX y llama a la rutina de registro DLL;
  • el área del hook de restauración (también conocido como "T2 trampoline"), que restaura el contexto y ejecuta las instrucciones reemplazadas antes de regresar al punto de intercepción;
  • las reubicaciones del área del hook de restauración, para instrucciones relativas que han sido convertidas a absolutas y deben ser parcheadas.

El inyector DLL es un simple inyector DLL (cosas de CreateRemoteThread/LoadLibraryA).

La DLL misma inicia un área de memoria compartida y espera los datos de configuración (el área de memoria compartida tiene 3 campos genéricos: el ID de mensaje de memoria compartida, el tamaño del mensaje y el búfer del mensaje). Una vez recibidos, analiza e instala los hooks en memoria, y no se permitirá ninguna actualización de configuración después de esto (debes matar el proceso si deseas establecer nuevos hooks). Cualquier hook colocado terminará en la función DLL genericHookFunction. Esta función simplemente llena el área de memoria (protegida con secciones críticas) con los datos del búfer, su tamaño y el ID de mensaje (establecido en los bits superiores del campo ID de mensaje de memoria compartida). Para notificar al proceso de Python, se utilizan 2 eventos para señalar nuevos mensajes y esperar a que el proceso los parchee (el tiempo de espera es de 2 segundos). Si el búfer ha sido actualizado, el búfer original también se modifica.

El script memitm.py ejecuta el proceso inyector y espera a que se cree la memoria compartida. Luego envía la configuración y espera el evento de mensaje. Cuando se recibe, se lee la memoria compartida y se llaman a las funciones logger y fuzzer con el búfer, el ID del proceso y el ID del mensaje. Si la función logger devuelve un búfer diferente al original y su tamaño es igual, se escribe en el área de memoria compartida. Luego se señala el evento "ACK", y el script espera un nuevo mensaje.

¡Eso es todo!

Esperamos que esta herramienta sea útil, ¡cualquier contribución/revisión será apreciada! Además, si eres francés y te gusta Rennes, estamos contratando :)

Descargar herramienta