
Autonomous honeypot SSH autónomo para capturar interacciones de atacantes y convertirlas en inteligencia de seguridad estructurada.
SSHintel es un honeypot SSH ligero construido con Python y Paramiko. Simula una shell Linux falsa para registrar intentos de acceso no autorizados, capturar credenciales y analizar el comportamiento de los atacantes en un entorno controlado.
ls, cd, pwd, , , , , , , , , , , , , , , , etc.)catechogrepfindtreeheadtailwcstatpsdffreeenvidwhoami--tarpit opcional para ralentizar a los atacantes con salida retardadaSSHintel no es una shell Bash/Linux completa. Simula un subconjunto creíble de comandos comunes para recopilar telemetría de atacantes. Los comandos se despachan mediante un registro ligero; agregar un comando significa agregar una pequeña función de manejo.
pip install -r requirements.txt
Nota: La clave de host SSH se genera automáticamente en la primera ejecución. No se necesita generación manual de claves.
Ejecute el honeypot con un puerto, nombre de usuario y contraseña específicos:
python3 run.py serve --port 2222 --username user1 --password pass123
El puerto predeterminado es
2222y el host es0.0.0.0.
El honeypot genera automáticamente una clave de host SSH en static/server.key en la primera ejecución si no existe. No se necesita generación manual de claves.
Para habilitar el modo tarpit:
python3 run.py serve --port 2222 --username user1 --password pass123 --tarpit
Para deshabilitar la telemetría SQLite (solo JSONL):
python3 run.py serve --port 2222 --username user1 --password pass123 --no-db
SSHintel protege contra el agotamiento de recursos por muchas conexiones concurrentes o conexiones mantenidas activas indefinidamente. Estos son configurables mediante la CLI:
| Indicador | Predeterminado | Propósito |
|---|---|---|
--max-connections | 50 | Máximo de conexiones activas simultáneas; las conexiones adicionales se rechazan y se registran como un evento connection_rejected |
--auth-timeout | 60 (s) | Tiempo permitido para completar el handshake/autenticación SSH; los clientes estancados se desconectan |
--session-idle-timeout | 300 (s) | Tiempo de espera de inactividad para una shell autenticada; una sesión inactiva finaliza, pero un atacante que escribe activamente nunca se elimina |
Ejemplo:
python3 run.py serve --port 2222 --username user1 --password pass123 \
--max-connections 25 --auth-timeout 30 --session-idle-timeout 300
Cuando hay demasiadas conexiones abiertas, la conexión adicional se cierra inmediatamente y se escribe un evento de seguridad connection_rejected (con reason: connection_limit) en el registro JSONL. Una autenticación estancada se registra como una desconexión con reason: auth_timeout; una shell inactiva finaliza con reason: idle_timeout.
El modo tarpit envía intencionalmente la salida lentamente para mantener al atacante comprometido, por lo que el bucle del banner tarpit no está sujeto al tiempo de espera de inactividad — pero las sesiones tarpit sí cuentan contra el límite de conexiones.
SSHintel incluye un panel web local que visualiza la telemetría de seguridad almacenada en SQLite.
python3 run.py dashboard
Luego abra http://localhost:5000 en su navegador.
El panel lee de la base de datos SQLite en
data/sshintel.dbpor defecto. Inicie primero el honeypot para que se capture la telemetría, luego lance el panel para ver cómo se completa.
Haga clic en un ID de sesión (o navegue a /session/<session_id>) para abrir la vista de investigación de sesión, que reconstruye un solo ataque cronológicamente:
$ comando de todo lo que escribió el atacante, con directorios de trabajo# Terminal 1: iniciar el honeypot
python3 run.py serve --port 2222 --username user1 --password pass123
# Terminal 2: iniciar el panel
python3 run.py dashboard
# Terminal 3: simular un atacante
ssh user1@localhost -p 2222
# (ejecutar algunos comandos, luego salir)
Luego abra http://localhost:5000 para inspeccionar la actividad capturada.
El panel admite telemetría en vivo — consulta el honeypot cada 2 segundos y se actualiza automáticamente. Las nuevas sesiones, comandos y eventos aparecen en tiempo real sin actualizar la página. Un indicador en vivo (● Live) muestra el estado de la conexión.
Abra una segunda terminal e intente conectarse:
ssh user1@localhost -p 2222
Si las credenciales coinciden, se le llevará a la shell emulada.
Para eliminar huellas SSH obsoletas:
notepad "%USERPROFILE%\.ssh\known_hosts"
Elimine la línea relevante que contenga
localhosto la IP del honeypot.
creds_loggerfunnel_loggerlog_files/events.jsonl como JSON Lines (JSONL) — un objeto JSON válido por líneaCada evento JSONL incluye una timestamp UTC ISO-8601, un event_type, un session_id único y la source_ip. La conexión, los intentos/resultados de autenticación, la ejecución de comandos, la activación de tarpit y las desconexiones se registran todos como eventos estructurados.
Cada conexión SSH entrante se rastrea como una sesión independiente con su propio session_id. Una sesión registra la IP de origen, las horas de conexión/desconexión, el resultado de la autenticación y la duración de la conexión, y cada evento generado dentro de esa conexión lleva el mismo session_id (para que los intentos de autenticación, comandos y desconexiones puedan vincularse a una sola conexión). Las sesiones están aisladas por conexión — no se comparte estado entre clientes concurrentes.
Cada sesión también recibe su propio sistema de archivos falso aislado en memoria — el sistema de archivos simulado se crea nuevo para cada conexión y se limpia cuando la conexión finaliza. Los archivos, directorios y el directorio de trabajo creados o modificados por un atacante nunca son visibles para otro atacante conectado al mismo tiempo. Todo el sistema de archivos se simula en la memoria de Python y nunca toca el sistema de archivos real del host.
Valores actuales de event_type: connect, auth_attempt, auth_success, auth_failure, command, disconnect, connection_rejected, tarpit.
SSHintel/
├── honeypot/ # Lógica central del honeypot
│ ├── __init__.py
│ ├── main.py # Bucle de aceptación + límite de conexiones
│ ├── handlers.py # Configuración del transporte SSH + shell emulada
│ ├── server.py # Interfaz del servidor Paramiko (autenticación)
│ ├── session.py # Seguimiento de sesión por conexión
│ ├── fs.py # Sistema de archivos falso en memoria (aislado por sesión)
│ ├── shell.py # Shell falsa: registro de comandos + despachador
│ ├── limits.py # Límite de conexiones concurrentes seguro para hilos
│ ├── logger.py # Registro de eventos JSONL + puente SQLite
│ └── telemetry_store.py # Almacén de telemetría SQLite + capa de consultas
│
├── dashboard/ # Panel web local
│ ├── app.py # Aplicación Flask + rutas API
│ ├── templates/
│ │ ├── index.html # Plantilla principal del panel
│ │ └── session.html # Plantilla de investigación de sesión
│ └── static/
│ ├── style.css # Estilos del panel
│ ├── dashboard.js # JS principal del panel (actualizaciones en vivo)
│ └── session.js # JS de investigación de sesión
│
├── log_files/ # Registros de ejecución (ignorados por git)
│ ├── creds_audits.log # Intentos de credenciales
│ ├── cmd_audits.log # Rastro de auditoría de comandos
│ └── events.jsonl # Eventos de seguridad JSONL estructurados
│
├── data/ # Base de datos SQLite (ignorada por git)
│ └── sshintel.db
│
├── static/ # Clave de host SSH (generada automáticamente)
│ └── server.key
│
├── .github/workflows/ # Configuración de CI
│ └── tests.yml
│
├── Dockerfile
├── README.md
├── requirements.txt # Dependencias de ejecución (paramiko, flask)
├── requirements-dev.txt # Dependencias de prueba (pytest, pytest-cov)
└── run.py # Punto de entrada CLI
Si prefiere ejecutar el honeypot en un entorno contenedorizado, puede usar el Dockerfile incluido.
docker build -t sshintel .
Esto crea una imagen Docker llamada
sshintel.
docker run -p 2222:2222 sshintel
Esto:
static/server.key (si no existe)2222 con credenciales predeterminadas:username: user1, password: pass123Abra una segunda terminal y conéctese mediante SSH:
ssh user1@localhost -p 2222
Se le llevará a la shell simulada si las credenciales coinciden.
Para detener el contenedor:
docker ps # Encontrar el ID del contenedor
docker stop <container_id>
Para eliminar la imagen:
docker rmi sshintel
También puede exportar la imagen usando
docker save -o sshintel.tar sshintely cargarla más tarde condocker load -i sshintel.tar.
Este proyecto está licenciado bajo la Licencia MIT.
Sonit Bahl
🔗 LinkedIn
🔗 Portafolio