
DECeption with Evaluative Integrated Validation Engine (DECEIVE): Let an LLM do all the hard honeypot work!
DECEIVE(DECeption with Evaluative Integrated Validation Engine)は、高対話型・低労力のハニーポットシステムです。ほとんどの高対話型ハニーポットとは異なり、DECEIVEは攻撃者に実際のシステムへのアクセスを一切提供しません。AIが、シミュレートしたいシステムの種類を記述する設定可能なシステムプロンプトに基づいて、現実的なハニーポットシステムのシミュレーションをすべて自動で行います。現実的なユーザー、データ、アプリケーションを用意するために多大な労力を必要とする他の多くの高対話型ハニーポットとは異なり、DECEIVEのAIバックエンドがこれらすべてを自動的に行ってくれます。
このバージョンのDECEIVEは、SSHプロトコルを介してLinuxサーバーをシミュレートします。すべてのユーザー入力、LLMバックエンドが返した出力、および各セッション終了後のサマリーをログに記録します。さらに、ユーザーのセッションが良性なのか、疑わしいのか、それとも完全に悪意のあるものなのかを、DECEIVEが判断して教えてくれます。
⛔️⛔️ DECEIVEは概念実証(proof-of-concept)プロジェクトです。本番品質ではありません。試して学ぶことはできますが、本番環境への導入には注意してください。 ⛔️⛔️
DECEIVEは主にMacOS 15(Sequoia)で開発されていますが、Python3を実行できるあらゆるUNIX系システムで動作するはずです。これには、他のバージョンのMacOS、Linux、さらにはWindows(Windows Subsystem for Linux経由)も含まれます。
次のコマンドで最新バージョンを取得できます:
git clone https://github.com/splunk/DECEIVE
以降の手順では、クローン完了後にカレントディレクトリをリポジトリへ変更していることを前提としています。
DECEIVEは、Pythonの依存関係および仮想環境の管理にuvを使用しています。uvがまだインストールされていない場合は、Astralのスタンドアロンインストーラーでインストールしてください:
curl -LsSf https://astral.sh/uv/install.sh | sh
次に、リポジトリのルートからプロジェクト環境を同期します:
uv sync
pyproject.toml と uv.lock ファイルは、依存関係の正本(source of truth)です。このプロジェクトは意図的に 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ドキュメントとなっています。
以下は、ユーザーが2つの単純なコマンド(pwd と exit)を実行しただけのシンプルなSSHセッションの完全な例です:
{"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 メッセージには、ユーザー入力全体のbase64エンコードされたコピーが details フィールドに含まれ、さらに、これが対話型コマンドか非対話型コマンドかを示す interactive フィールド(true/false)もあります(つまり、ターミナルセッションでログインしたのか、SSHコマンドラインでコマンドを指定したのか)。LLM response メッセージには、シミュレートされた応答全体のbase64エンコードされたコピーが フィールドに含まれます。コントリビューションを歓迎します!変更や改善について話し合うために、プルリクエストを送信するか、イシューを開いてください。
このプロジェクトはMITライセンスの下でライセンスされています。詳細はLICENSEファイルを参照してください。
detailsSession summary メッセージには、コマンドのサマリーだけでなく、それらが何を目的として実行された可能性があるかについての推測も含まれます。また、judgement フィールドには "BENIGN"、"SUSPICIOUS"、"MALICIOUS" のいずれかが含まれますAuthentication success メッセージの username フィールドと password フィールドに含まれます。