DECEIVE,即带评估集成验证引擎的欺骗系统(DECeption with Evaluative Integrated Validation Engine),是一个高交互、低维护的蜜罐系统。与大多数高交互蜜罐不同,DECEIVE 不会向攻击者提供任何真实系统的访问权限。AI 实际承担了模拟逼真蜜罐系统的全部工作,其依据是一个可配置的系统提示词,描述您希望模拟的系统类型。与许多其他需要投入大量精力来填充真实用户、数据和应用程序的高交互蜜罐不同,DECEIVE 的 AI 后端会自动为您完成这一切。
此版本的 DECEIVE 通过 SSH 协议模拟 Linux 服务器。它会记录所有用户输入、LLM 后端返回的输出,以及每个会话结束后的会话摘要。它甚至会告诉您它认为某个用户的会话是良性、可疑,还是完全恶意。
⛔️⛔️ DECEIVE 是一个概念验证项目,并非生产级质量。您可以试用它并从中学习,但在生产环境中部署时请务必谨慎。 ⛔️⛔️
DECEIVE 主要在 MacOS 15 (Sequoia) 上开发,但应该可以在任何能够运行 Python3 的类 UNIX 系统上工作。这包括其他版本的 MacOS、Linux,甚至 Windows(通过适用于 Linux 的 Windows 子系统)。
您可以使用以下命令获取最新版本:
git clone https://github.com/splunk/DECEIVE
后续说明均假定您在克隆完成后已将当前目录切换到该仓库。
DECEIVE 使用 uv 进行 Python 依赖与虚拟环境管理。如果您尚未安装 uv,请使用 Astral 的独立安装程序进行安装:
curl -LsSf https://astral.sh/uv/install.sh | sh
接下来,从仓库根目录同步项目环境:
uv sync
pyproject.toml 和 uv.lock 文件是依赖项的权威来源。本项目有意不维护 requirements.txt 后备文件。
SSH 服务器需要 TLS 密钥对来保证安全通信。在仓库的顶层目录中,使用以下命令生成 SSH 密钥对:
ssh-keygen -t rsa -b 4096 -f SSH/ssh_host_key
将 SSH/config.ini.TEMPLATE 文件复制为 SSH/config.ini:
打开 SSH/config.ini 文件并查看各项设置。根据需要更新其中的值,请特别注意 [llm] 部分的值(您将在此处配置要使用的 LLM 后端),以及 [user_accounts] 部分的值(您可以在此配置希望蜜罐支持的用户名和密码)。
编辑 SSH/prompt.txt 文件,加入一段简短描述,说明您希望它伪装成什么类型的系统。您不必写得很详细,尽管提供的细节越多,模拟效果就越好。您可以写得概括一些,例如:
You are a video game developer's system. Include realistic video game source and asset files.
如果您愿意,也可以添加任何您认为有帮助的额外细节。例如:
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.
要启动 DECEIVE 蜜罐服务器,首先请确保已设置所选用 LLM 后端所需的任何环境变量。例如,如果您使用任何 OpenAI 模型,则需要按如下方式设置 OPENAI_API_KEY 变量:
export OPENAI_API_KEY="<your secret API key>"
接下来,从仓库根目录运行 SSH 蜜罐:
uv run python SSH/ssh_server.py
您也可以切换到 SSH 目录后运行:
uv run python ssh_server.py
服务器将启动,并在配置的端口上监听传入的 SSH 连接。它不会产生任何输出,但会保持在前台运行。
服务器运行后(这可能需要几秒钟),通过配置的端口访问它。如果您使用的是 Linux 或类 UNIX 系统,请尝试以下命令(根据您的配置替换 “localhost” 和 “8022”):
ssh guest@localhost -p 8022
运行 uv sync 后,从仓库根目录运行所有测试:
uv run pytest
要仅运行 SSH 集成测试:
uv run pytest tests/test_ssh_integration.py
集成测试会在本地随机端口上启动真实的 SSH 服务器,使用 SSH 客户端进行连接,并使用确定性的假 LLM 后端,这样断言就不依赖于实时模型输出。
日志将写入 log_file 配置选项中指定的文件。相对 log_file 路径会根据包含所加载配置文件的目录进行解析,因此默认模板值会写入 SSH/ssh_log.log。
DECEIVE 日志采用 JSON lines 格式,每行都是一个完整的 JSON 文档。
以下是简单 SSH 会话的完整示例,其中用户执行了两个简单命令(pwd 和 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}
需要注意的事项:
task_name 字段包含一个唯一值,该值在收到 SSH 连接时分配,并用于该会话的所有日志条目。SSH connection receivedAuthentication successUser inputLLM responseSession summarySSH connection closeddetails 字段,包含附加信息:
User input 消息在 details 字段中包含整个用户输入的 base64 编码副本,以及一个 interactive 字段(true/false),用于告诉您这是交互式还是非交互式命令(即,他们是使用终端会话登录,还是在 SSH 命令行上提供了命令)。LLM response 消息在 details 字段中包含整个模拟响应的 base64 编码副本。欢迎贡献!请提交拉取请求或开启 issue 来讨论任何更改或改进。
本项目采用 MIT 许可证。有关详细信息,请参阅 LICENSE 文件。
Session summary 消息不仅包含命令摘要,还包含对这些命令可能意图实现的目标的猜测。此外还会有一个 judgement 字段,其值为 “BENIGN”、“SUSPICIOUS” 或 “MALICIOUS” 之一。Authentication success 消息的 username 和 password 字段中。