3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

米国・ドイツ・日本の3拠点でT-Potを動かし、拠点によって届く通信に違いがあるのかを見ていました。

最初からLLM関連のハニーポットを作るつもりだったわけではありません。T-Potのログを確認していると、11434番ポートへの通信が目に入りました。11434番はOllamaが標準で使用するポートです。そこへ来ている通信は、公開されたOllamaを探しているだけなのか、モデル一覧を取得しようとしているのか、それとも実際に推論を実行しようとしているのでしょうか。

この疑問から米国サーバーで試作を始め、対象がOllama以外にも広がったため、現在は PromptPot という名前で公開しています。以下は、配備版v0.1.0で実際に観測した記録です。

送信元IP、外部の配布先URL、資格情報らしき値、実行可能なペイロード全文は掲載しません。

T-Potの11434番ログが気になった

11434番だけを抽出した最初の調査結果は、2026年7月2日20時54分JSTに保存しています。この時点ではPromptPotはまだありません。

拠点 T-Pot上の11434関連イベント 復元できたHTTPイベント HTTP POST
米国 73,024 3,990 0
ドイツ 46,722 2,702 0
日本 19 0 0

このT-Potイベント数は複数のイベント種別を含むため、後述するPromptPotのHTTPリクエスト数とは直接比較できません。

復元できたHTTP通信はすべてGETでした。/api/tags/api/v1/version/など、Ollamaに関係するパスもありました。一方、推論APIに見えるパスへの通信もメソッドはGETで、POSTのbodyや実際のプロンプトは残っていませんでした。

この時点では、11434番が探索されていることまでは分かりましたが、公開されたLLMを実際に使おうとしているのかは分かりませんでした。

11434番では何をしようとしているのか

Ollamaの公式APIドキュメントでは、APIの標準URLはhttp://localhost:11434/apiです。モデル一覧はGET /api/tags、生成はPOST /api/generate、チャットはPOST /api/chatで扱われます。

そこで、次の違いを見たいと考えました。

  • ポートが開いているかだけを確認しているのか
  • /api/tags/api/versionからサービスやモデルを確認しているのか
  • /api/generate/api/chatへbody付きでPOSTしているのか
  • /api/pull/api/createなど、モデル管理まで試しているのか

既存のT-PotログではPOST bodyを確認できなかったため、11434番でOllamaに似たHTTP応答を返し、bodyを含むリクエストをJSONLへ保存する小さなサーバーを追加することにしました。

米国サーバーで小さく試した

最初は米国のT-PotだけにOllamaPotというコンテナを追加しました。既存のハニーポットは止めず、11434番の競合を確認してから、そのポートだけをコンテナへ割り当てました。

保存されている最初のOllamaPotログは2026年7月2日23時54分JSTです。これは設置日時ではなく、管理用テストを含む最初の記録時刻です。初期試作の正確なsource revisionは残っておらず、途中のログでは/api/psが404になっているものもありました。

この段階で確認したかったのは、OllamaらしいGETへ応答できることと、次のようなPOSTがbody付きで残ることでした。

GET  /api/tags
GET  /api/version
POST /api/generate

その後、1234、8000、7860、8188番でもAI周辺サービスに関係するパスが見えてきました。サービスごとにコンテナを増やすと管理しにくいため、1コンテナで5つのリスナーを持つ構成に変更し、名前もOllamaPotからPromptPotへ変えました。

PromptPotの構成

3拠点に配備したv0.1.0は、1つのPythonプロセスからポートごとにThreadingHTTPServerを起動します。実際のモデル、GPU、APIキーは使用していません。

ポート プロファイル 模倣対象
11434 ollama Ollama API
1234 lmstudio LM Studio / OpenAI互換API
8000 vllm vLLM / FastAPI系OpenAI互換API
7860 gradio Gradio系HTTP API
8188 comfyui ComfyUI HTTP API

MCPとLangflowは実装済みプロファイルではなく、関連パスを集計時に分類したものです。

v0.1.0は、モデル一覧、version、health、生成・チャットなどへ静的な応答を返します。GETはプロファイル別ですが、POSTの一部は5ポートで共通処理されています。生成テキストは空で、モデル推論、ダウンロード、受信コードの実行、外向き通信は行いません。

1 HTTPリクエストを1 JSONLイベントとして、接続元、method、URL、User-Agent、status、body、model、prompt、messagesなどを保存します。JSONLはbind mountしたT-Potホスト側のログディレクトリへ書き、LogstashからElasticsearchへ取り込みました。

3拠点のログを集計し直した

対象期間と除外条件

2026年7月12日02時45分JSTに、3拠点からraw JSONLとElasticsearch文書を回収しました。今回の主集計は、Elasticsearchへ索引されていた外部イベント7,426件です。

  • Elasticsearch上の最初の外部イベント: 2026年7月3日05時14分53秒JST
  • Elasticsearch上の最後の外部イベント: 2026年7月12日02時38分02秒JST
  • 対象: 3拠点のPromptPotと、米国で先に動かしたOllamaPot
  • 除外: 管理元、センサー自身、loopback、Docker bridgeからの通信
  • 除外前のElasticsearch文書: 7,478件
  • 除外後の外部イベント: 7,426件

米国のOllamaPotについて、外部イベントとして残ったのは1件でした。集計ではOllamaプロファイルへ含めています。

各拠点の公開開始時刻は揃っていないため、国別件数をそのまま拠点差として比較することはしていません。

プロファイル別の件数

プロファイル ポート 全イベント POST/PUT 推論イベント
Ollama 11434 5,143 2,639 2,476
vLLM 8000 1,689 247 71
LM Studio 1234 422 59 0
Gradio 7860 108 33 0
ComfyUI 8188 64 0 0
合計 7,426 2,978 2,547

Ollamaプロファイルは全イベントの69.3%、推論イベントの97.2%でした。

全体では1,713セッションあり、そのうち推論イベントを含むものは236セッションでした。

推論より前に何が記録されていたか

推論セッション236件について、最初の推論イベントより前に、定義済みの探索GETまたはHEADがあるかを調べました。

  • 先行する探索GET/HEADがあった: 207セッション(87.7%)
  • 先行探索が記録されなかった: 29セッション(12.3%)
  • 207セッションすべてで、推論と同じポート・プロファイルへの先行リクエストがあった
  • 207セッション中205件では、先行探索の少なくとも1件がHTTP 200だった
  • 残る2件では、先行探索として分類したリクエストへの応答は200ではなかった

矢印はセッション内の観測時刻順を表します。

先行していたパスの主なものは、/v1/modelsが150回、/api/tagsが68回、/api/versionが47回、/api/psが7回でした。これはパスの出現回数で、互いに排他的なセッション数ではありません。

実際に記録されたセッションの一つでは、先頭部分が次の順序でした。送信元は匿名化しています。User-Agentはaxios/1.18.1でした。

GET  /v1/models
POST /v1/chat/completions
POST /v1/chat/completions
GET  /v1/models
POST /v1/chat/completions

同じ並びは時間を空けて繰り返されていました。先にモデル一覧を確認してから推論しているようにも見えますが、最初から決められた順序を実行している可能性もあります。

実際に送られたプロンプト

2,547推論イベントのうち、promptmessages、必要に応じてbodyから作った分析用テキストが空でなかったものは2,529件でした。特に多かった完全一致の例は次の通りです。

回数 実際の内容
588 system: Today is April 27, 2026. | user: In one short English sentence: who built you, what is 17 times 23?
437 Return exactly this text and nothing else: LAYERCLOUD_AI_TEST_OK
206 hi
145 Answer only with the number: 7 What is 3 + 4?
145 Reply with exactly one word: blue
145 What is your model name? If unknown, answer exactly: unknown

588回のプロンプトはドイツ拠点で記録され、匿名化した2つの送信元IPから、deepseek-r1:8bqwen2.5:7bへ294回ずつ送られていました。

固定文字列、簡単な計算、モデル名の回答を求める内容が多く、可用性確認やフィンガープリントに使われていそうです。

Ollama以外の関連パスも届いた

MCPと思われる通信

MCP関連として分類したイベントは120件でした。

項目 件数
GET 24
POST 96
30分セッション 41
/mcp 41
/jsonrpc 31
/ 31
/sse 11
/mcp-sse 6

96件のPOSTは、すべてJSON-RPCのinitializeでした。93件のbodyではclientInfo.nameCensysInspect/1.1を含み、protocolVersion2025-03-26でした。残り3件は2025-06-18を宣言していました。これらのversionはMCP 2025-03-26 LifecycleMCP 2025-06-18 Lifecycleに存在します。

body内ではCensysInspect/1.1を名乗っていました。

tools/listresources/listtools/callは観測されていません。v0.1.0はMCPを実装していないため、initializeには404を返していました。

LangflowのAPIと似た通信

Langflow関連として分類したイベントは27件で、POST 25件、GET 2件でした。4つの匿名化した送信元IP、5セッションに分かれていました。

パス 件数
/api/v1/auto_login 12
/api/v1/validate/code 7
/api/v1/flows/ または /api/v1/flows 7
/api/v1/runs 1

同一の匿名化した送信元とUser-Agentによる8リクエストの並びが、ドイツ、米国、日本の3拠点で記録されていました。bodyには次の種類が含まれていました。

  • shellを用いた外部ファイルの取得・実行
  • Windows Installer形式のファイル取得・実行
  • Pythonを用いた外部ファイルの取得・実行
  • 認証状態やflow作成に関係する入力

外部URL、コマンド、資格情報らしき値は省略しています。

/api/v1/validate/codeは、CVE-2025-3248 / GHSA-rvqx-wpfh-mfx7で問題となったLangflow APIと一致します。パスとペイロードの形も、既知のLangflow向け試行とよく似ていました。

同じ送信元は404の後も同じリクエスト列を繰り返していました。

そのほかの候補API

Ollamaのモデル管理に関係するイベントは80件あり、そのうち41件は実装済みのPOST /api/showでした。ほかにAnthropic Messages互換が13件、Open WebUI固有パスが1件ありました。

現在の応答では見えなかった部分

v0.1.0では、MCP、Langflow、Anthropic Messagesと一部のモデル管理APIへ404を返します。受信コードは実行せず、外向き通信も行いません。

そのため、MCPのinitializeに成功応答を返した後や、Langflowらしいtokenやflow情報を返した後に、どのような通信が続くのかはまだ観測できていません。

また、未対応POSTのログstatusが200になる不具合があるため、今回の分析ではソースコードとローカルでの再現結果も使って応答を確認しました。現在のmainではこの不具合を修正しています。

これからどこまで実装するか迷っている

PromptPotはMIT Licenseで公開しています。

T-Potのような汎用基盤や、MCP専用のwaspholeを置き換えるものではありません。PromptPotは、実モデルを動かさず、1コンテナで複数のAIサービス用ポートを観測する範囲に絞っています。

今回のログからは、次の実装候補が残りました。

  • status記録修正のリリース
  • Ollamaモデル管理APIへの応答
  • MCPのinitializeへの最小応答
  • Langflow向けの偽tokenやflow状態
  • Anthropic Messages互換API

ただ、対応するAPIを増やすほどよいとも限りません。MCPだけを深く実装するなら専用ハニーポットとの差が小さくなり、広く浅く対応しすぎると、PromptPotが何を観測するためのものなのか分かりにくくなります。

自分の3拠点だけでは観測環境も偏ります。別のネットワークで試してくれる人や、レスポンスfixture、テスト、MCP・Langflow周り、T-PotやKibanaとの連携を一緒に見てくれる人がいれば助かります。

手順はCONTRIBUTING.md、候補はROADMAP.mdIssuesに置いています。

付録: v0.1.0をローカルで確認する

観測時と同じ公開イメージはghcr.io/ta-061/promptpot:0.1.0です。最初は外部公開せず、localhostだけへbindします。

mkdir -p log

docker run --rm --name promptpot \
  -p 127.0.0.1:11434:11434 \
  -p 127.0.0.1:1234:1234 \
  -p 127.0.0.1:8000:8000 \
  -p 127.0.0.1:7860:7860 \
  -p 127.0.0.1:8188:8188 \
  -v "$PWD/log:/data/honeypots/log" \
  ghcr.io/ta-061/promptpot:0.1.0

別のターミナルから、Ollama形式のGETとPOSTを確認します。

curl -s http://127.0.0.1:11434/api/tags | jq

curl -s http://127.0.0.1:11434/api/generate \
  -H 'Content-Type: application/json' \
  -d '{"model":"qwen2.5:7b","prompt":"hello","stream":false}' | jq

生成レスポンスのresponseは空文字列です。ログは次の場所へ1行1JSONで保存されます。

tail -n 1 log/promptpot.log | jq

インターネットへ公開する場合は、管理ポートを公開せず、機密情報のない隔離環境を使用します。また、T-Pot上で既に使われているポートと、ログ保存先の永続化を先に確認します。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?