
DECeption con Motor de Validación Integrada Evaluativa (DECEIVE): ¡Deja que un LLM haga todo el trabajo difícil del honeypot!
DECEIVE, el DECeption with Evaluative Integrated Validation Engine, es un sistema honeypot de alta interacción y bajo esfuerzo. A diferencia de la mayoría de los honeypots de alta interacción, DECEIVE no proporciona a los atacantes acceso a ningún sistema real. La IA hace todo el trabajo de simular un sistema honeypot realista basándose en un prompt de sistema configurable que describe qué tipo de sistema quieres simular. A diferencia de muchos otros honeypots de alta interacción que requieren un esfuerzo considerable para poblarlos con usuarios, datos y aplicaciones realistas, el backend de IA de DECEIVE hará todo esto por ti, automáticamente.
Esta versión de DECEIVE simula un servidor Linux mediante el protocolo SSH. Registrará todas las entradas de los usuarios, las salidas devueltas por el backend de LLM, así como un resumen de cada sesión cuando finalicen. Incluso te dirá si cree que la sesión de un usuario fue benigna, sospechosa o directamente maliciosa.
⛔️⛔️ DECEIVE es un proyecto de prueba de concepto. No tiene calidad de producción. Pruébalo, aprende de él, pero ten cuidado al desplegarlo en un entorno de producción. ⛔️⛔️
DECEIVE se desarrolla principalmente en MacOS 15 (Sequoia), pero debería funcionar en cualquier sistema tipo UNIX que pueda ejecutar Python3. Esto incluye otras versiones de MacOS, Linux e incluso Windows (a través del Subsistema de Windows para Linux).
Puedes obtener la última versión usando el siguiente comando:
git clone https://github.com/splunk/DECEIVE
El resto de estas instrucciones asumen que has cambiado tu directorio actual al repositorio después de completar la clonación.
DECEIVE utiliza uv para la gestión de dependencias de Python y del entorno virtual. Si aún no tienes uv instalado, instálalo con el instalador independiente de Astral:
curl -LsSf https://astral.sh/uv/install.sh | sh
A continuación, sincroniza el entorno del proyecto desde la raíz del repositorio:
uv sync
Los archivos pyproject.toml y uv.lock son la fuente de verdad para las dependencias. Este proyecto, intencionadamente, no mantiene un respaldo requirements.txt.
El servidor SSH requiere un par de claves TLS para las comunicaciones seguras. Desde el directorio principal del repositorio, genera un par de claves SSH con el siguiente comando:
ssh-keygen -t rsa -b 4096 -f SSH/ssh_host_key
Copia el archivo SSH/config.ini.TEMPLATE a SSH/config.ini:
Abre el archivo SSH/config.ini y revisa los ajustes. Actualiza los valores según sea necesario, prestando especial atención a los valores de la sección [llm], donde configurarás el backend de LLM que deseas utilizar, y a la sección [user_accounts], donde puedes configurar los nombres de usuario y contraseñas que quieres que el honeypot admita.
Edita el archivo SSH/prompt.txt para incluir una breve descripción del tipo de sistema que quieres que finja ser. No es necesario que seas muy detallado, aunque cuantos más detalles puedas proporcionar, mejor será la simulación. Puedes mantenerlo a alto nivel, como:
You are a video game developer's system. Include realistic video game source and asset files.
Si lo deseas, puedes añadir cualquier detalle adicional que creas útil. Por ejemplo:
You are the Internet-facing mail server for bigschool.edu, a state-sponsored university in Virginia. Valid user accounts are "a20093887", "a20093887-admin", and "mxadmin". Home directories are in "/home/$USERNAME". Everyone's default shell is /bin/zsh, except mxadmin's, which is bash. Mail spools for all campus users (be sure to include email accounts that are not valid for logon to this server) are in /var/spool/mail. Be sure to simulate some juicy emails there, but make them realistic. Some should be personal, but some should be just about the business of administering the school, dealing with students, applying for financial aid, etc. Make the spool permissions relaxed, simulating a misconfiguration that would allow anyone on the system to read the files.
Para iniciar el servidor honeypot de DECEIVE, primero asegúrate de haber establecido las variables de entorno requeridas por el backend de LLM que hayas elegido. Por ejemplo, si usas cualquiera de los modelos de OpenAI, necesitarás establecer la variable OPENAI_API_KEY de la siguiente manera:
export OPENAI_API_KEY="<tu clave API secreta>"
A continuación, ejecuta el honeypot SSH desde la raíz del repositorio:
uv run python SSH/ssh_server.py
También puedes cambiar al directorio SSH y ejecutar:
uv run python ssh_server.py
El servidor se iniciará y quedará a la escucha de conexiones SSH entrantes en el puerto configurado. No producirá ninguna salida, pero permanecerá ejecutándose en primer plano.
Una vez que el servidor esté en ejecución (esto puede tardar unos segundos), accede a él en el puerto configurado. Si estás en un sistema Linux o tipo UNIX, prueba el siguiente comando (sustituye "localhost" y "8022" según corresponda a tu configuración):
ssh guest@localhost -p 8022
Después de ejecutar uv sync, ejecuta todas las pruebas desde la raíz del repositorio:
uv run pytest
Para ejecutar solo las pruebas de integración SSH:
uv run pytest tests/test_ssh_integration.py
Las pruebas de integración inician el servidor SSH real en un puerto local aleatorio, se conectan con un cliente SSH y utilizan un backend de LLM falso y determinista para que las aserciones no dependan de la salida de un modelo en vivo.
Los registros se escribirán en el archivo especificado en la opción de configuración log_file. Las rutas relativas de log_file se resuelven desde el directorio que contiene el archivo de configuración cargado, por lo que el valor de la plantilla predeterminada escribe en SSH/ssh_log.log.
Los registros de DECEIVE están en formato JSON lines, donde cada línea es un documento JSON completo.
El siguiente es un ejemplo completo de una sesión SSH simple, en la que el usuario ejecutó dos comandos sencillos (pwd y exit):
{"timestamp": "2025-01-10T20:37:55.018+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "SSH connection received", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 59, "funcName": "connection_made", "created": 1736541475.0183098, "msecs": 18.0, "relativeCreated": 13872.790813446045, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": null}
{"timestamp": "2025-01-10T20:37:55.177+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "Authentication success", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 75, "funcName": "begin_auth", "created": 1736541475.1775439, "msecs": 177.0, "relativeCreated": 14032.02486038208, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "username": "guest", "password": ""}
{"timestamp": "2025-01-10T20:37:57.456+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "LLM response", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 174, "funcName": "handle_client", "created": 1736541477.4568708, "msecs": 456.0, "relativeCreated": 16311.351776123047, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "details": "V2VsY29tZSB0byBHYW1lRGV2IENvcnAncyBEZXZlbG9wbWVudCBFbnZpcm9ubWVudAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICBXZWxjb21lLCBndWVzdCEgCiAgIExhc3QgbG9naW46IFR1ZSBPY3QgMjQgMTQ6MzI6MTUgMjAyMyBmcm9tIDE5Mi4xNjguMS4xMAogICBQcm9qZWN0czoKICAgICAtIEZhbnRhc3lRdWVzdAogICAgIC0gU3BhY2VFeHBsb3JlcnMKICAgICAtIFJhY2luZ01hbmlhCiAgIFN5c3RlbSBTdGF0dXM6IEFsbCBzeXN0ZW1zIG9wZXJhdGlvbmFsCiAgIFJlbWVtYmVyIHRvIGNvbW1pdCB5b3VyIGNoYW5nZXMhCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmd1ZXN0QGRldi13b3Jrc3RhdGlvbjp+JCA="}
{"timestamp": "2025-01-10T20:37:59.333+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "User input", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 184, "funcName": "handle_client", "created": 1736541479.3334038, "msecs": 333.0, "relativeCreated": 18187.88480758667, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "details": "cHdk"}
{"timestamp": "2025-01-10T20:38:00.189+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "LLM response", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 200, "funcName": "handle_client", "created": 1736541480.189375, "msecs": 189.0, "relativeCreated": 19043.855905532837, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "details": "L2hvbWUvZ3Vlc3QKCmd1ZXN0QGRldi13b3Jrc3RhdGlvbjp+JCA="}
{"timestamp": "2025-01-10T20:38:01.944+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "User input", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 184, "funcName": "handle_client", "created": 1736541481.944072, "msecs": 944.0, "relativeCreated": 20798.552989959717, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "details": "ZXhpdA=="}
{"timestamp": "2025-01-10T20:38:04.132+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "Session summary", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 151, "funcName": "session_summary", "created": 1736541484.1324642, "msecs": 132.0, "relativeCreated": 22986.945152282715, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": "session-6355218b-59e5-4549-add3-49e6d1efc133", "details": "The user issued basic commands like `pwd` to check the current working directory and `exit` to terminate the session. This activity is typical of a benign user checking their environment upon logging in and then closing the session. There is no indication of reconnaissance, exploitation, or any post-foothold activity such as privilege escalation or data exfiltration. The actions appear to be standard and routine.\n\nJudgement: BENIGN", "judgement": "BENIGN"}
{"timestamp": "2025-01-10T20:38:04.139+00:00", "level": "INFO", "task_name": "session-6355218b-59e5-4549-add3-49e6d1efc133", "src_ip": "::1", "src_port": 58164, "dst_ip": "::1", "dst_port": 8022, "message": "SSH connection closed", "name": "__main__", "levelname": "INFO", "levelno": 20, "pathname": "/home/deceive/DECEIVE/SSH/./ssh_server.py", "filename": "ssh_server.py", "module": "ssh_server", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 65, "funcName": "connection_lost", "created": 1736541484.139776, "msecs": 139.0, "relativeCreated": 22994.2569732666, "thread": 8145041472, "threadName": "MainThread", "processName": "MainProcess", "process": 10823, "taskName": null}
Cosas a tener en cuenta:
task_name contiene un valor único que se asigna cuando se recibe la conexión SSH y se usa en todas las entradas de registro de esa sesión.SSH connection receivedAuthentication successUser inputLLM responseSession summarySSH connection closeddetails con información adicional.
User input contienen una copia codificada en base64 de toda la entrada del usuario en el campo details, así como un campo interactive (true/false) que te indica si se trató de un comando interactivo o no interactivo (es decir, si iniciaron sesión con una sesión de terminal o proporcionaron un comando en la línea de comandos SSH).LLM response contienen una copia codificada en base64 de toda la respuesta simulada en el campo details.Session summary contienen no solo un resumen de los comandos, sino también una conjetura sobre cuál podría haber sido su intención. También habrá un campo judgement que contiene uno de estos valores: "BENIGN", "SUSPICIOUS" o "MALICIOUS".Authentication success, en los campos username y password.¡Las contribuciones son bienvenidas! Por favor, envía pull requests o abre issues para discutir cualquier cambio o mejora.
Este proyecto está licenciado bajo la Licencia MIT. Consulta el archivo LICENSE para más detalles.