Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2024-27198 | Kitploit
도구/GitHubGitHub/hpt-intern-task-submission/cve-2024-27198
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingAuthenticationLearning & Education
GitHubhpt-intern-task-submission/cve-2024-27198

CVE-2024-27198

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
2년 전아직 검토되지 않음

CVE-2024-27198: Jetbrain Teamcity의 인증 우회로 인한 원격 코드 실행

======================

개요

TeamCity는 지속적 통합 및 배포 서버로, 즉시 사용 가능한 지속적 단위 테스트, 코드 품질 분석, 빌드 문제 조기 보고 기능을 제공합니다.

이 취약점은 공격자가 인증되지 않은 임의의 엔드포인트에 접근할 수 있게 하는 라이브러리에서 발생합니다.

코드 분석

취약한 코드는 lib 디렉토리의 web-openapi.jar 라이브러리에 있습니다.

jetbrains.buildServer.controllers.BaseController 클래스는 요청과 응답을 처리하는 역할을 담당하지만, 부적절하게 구현되어 있습니다. 코드가 어떻게 생겼는지 살펴보겠습니다:

root@kitploit:~
public abstract class BaseController extends AbstractController {
//////
public final ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    try {  
        ModelAndView modelAndView = this.doHandle(request, response);  
        if (modelAndView != null) {  
            if (modelAndView.getView() instanceof RedirectView) {  
                modelAndView.getModel().clear();  
            } else {  
                this.updateViewIfRequestHasJspParameter(request, modelAndView);  
            }  
        }

ModelAndView 메서드의 주요 목적은 요청된 페이지를 UI에 렌더링하는 것입니다. 여기서 버그가 시작됩니다. 요청이 리다이렉트되지 않는 경우 updateViewIfRequestHasJspParameter가 호출된다는 점에 주목하세요. 취약점의 근본 원인을 찾으려면 더 깊이 조사해야 합니다.

root@kitploit:~
private void updateViewIfRequestHasJspParameter(@NotNull HttpServletRequest request, @NotNull ModelAndView modelAndView) {  
    boolean isControllerRequestWithViewName = modelAndView.getViewName() != null && !request.getServletPath().endsWith(".jsp");  
    String jspFromRequest = this.getJspFromRequest(request);  
    if (isControllerRequestWithViewName && StringUtil.isNotEmpty(jspFromRequest) && !modelAndView.getViewName().equals(jspFromRequest)) {  
        modelAndView.setViewName(jspFromRequest);  
    }  
  
}

이 메서드는 특정 조건을 충족할 때 ModelAndView 객체의 뷰 이름을 업데이트하는 데 사용됩니다. isControllerRequestWithViewName은 modelAndView 객체에 이름이 있고 URL의 path가 .jsp로 끝나지 않을 때 True가 됩니다. 예를 들어, 해당 조건을 충족하는 URL은 http://localhost:8111/random_string이며, 유효하지 않은 URL은 http://localhost:8111/admin/admin.html 또는 http://localhost:8111/admin.jsp입니다. 위에서 논의한 대로, 리다이렉션을 유발하는 페이지(일반적으로 인증이 필요한 페이지)에 접근해서는 안 됩니다. 그런 다음 프로그램은 getJspFromRequest() 메서드를 호출하는 jspFromRequest라는 변수를 할당합니다. 이제 해당 메서드로 넘어가겠습니다. 나머지 코드는 이후에 설명하겠습니다. if 문은 isControllerRequestWithViewName 이 true인지, 메서드 호출 결과가 비어 있지 않은지, 그리고 객체의 이름이 우리가 요청하려는 페이지와 같지 않은지 확인합니다.

root@kitploit:~
protected String getJspFromRequest(@NotNull HttpServletRequest request) { String  jspFromRequest  = request.getParameter("jsp"); return  jspFromRequest  == null || jspFromRequest.endsWith(".jsp") && !jspFromRequest.contains("admin/") ? jspFromRequest : null; }

이 함수는 먼저 jsp라는 요청 매개변수의 값을 가져옵니다. 이 검사는 jsp가 .jsp로 끝나야 하고 /admin을 포함하지 않아야 함을 보장합니다. 위의 if 문과 결합하면:

root@kitploit:~
if (isControllerRequestWithViewName && StringUtil.isNotEmpty(jspFromRequest) && !modelAndView.getViewName().equals(jspFromRequest)) {  
        modelAndView.setViewName(jspFromRequest);  
    }  

URL이 어떻게 생겼는지 전체적인 그림을 파악할 수 있습니다:

  1. 경로는 리다이렉션을 유발하지 않아야 하며 .jsp를 포함하지 않아야 합니다.
  2. jsp 요청 매개변수는 path와 같지 않아야 합니다. 예를 들어, /random?jsp=/random은 유효하지 않습니다.
  3. 가장 중요한 것은 jsp가 .jsp로 끝나야 한다는 것입니다.

TeamCity는 외부 애플리케이션을 통합하고 TeamCity 서버와 스크립트 상호 작용을 생성하기 위한 REST API를 제공합니다. URL 경로를 통해 리소스에 접근할 수 있습니다. 브라우저에서 http://<TeamCity Server host>:<port>/app/rest/server URL을 열어 REST API 작업을 시작할 수 있습니다. 이 페이지는 API를 탐색하기 위한 몇 가지 포인터를 제공합니다.

TeamCity는 인증을 우회할 수 있다면 민감한 리소스에 접근할 수 있게 해주는 REST API를 제공합니다. 예를 들어, 이 경우 /app/rest/server에 접근을 시도해 보겠습니다.

unauthenticated_request

예상대로, /app/rest/server에 요청하면 서버는 /login.html로 리다이렉트합니다. 이 제한을 우회할 완벽한 URL을 구성해 봅시다. 먼저 경로는 404 상태 코드 또는 200을 반환하는 한 무엇이든 될 수 있습니다(예: login.html). 다음으로 jsp를 사용하여 /app/rest/server에 요청하되, .jsp로 끝나야 합니다. 이 상황에서 이 검사를 우회하는 데 사용할 수 있는 두 가지 트릭이 있습니다. 세미콜론 ;을 매개변수 구분자로 사용할 수 있습니다: /app/rest/server;.jsp, 이 경우 .jsp는 두 번째 매개변수로 처리됩니다. 두 번째 우회 방법은 URI 프래그먼트 #을 사용하는 것입니다: /app/rest/server%23.jsp. URI 프래그먼트 뒤의 내용은 라우팅에 사용되지 않으며, 페이지 내 탐색에만 사용됩니다. 해당 문자는 URL 인코딩이 필요합니다. 그렇지 않으면 브라우저가 먼저 이를 무시합니다.

unauthenticated_request_bypass.png

이 기법을 사용하면 관리자 권한을 가진 새 사용자를 만들 수도 있습니다. TeamCity 문서에 따르면 /app/rest/users 엔드포인트를 통해 새 사용자를 만들 수 있습니다.

create_new_user

관리자 패널로 이동하여 새 사용자가 생성되었는지 확인해 봅시다.

confirmed

예상대로 관리자 권한을 가진 새 사용자가 생성되었습니다. 관리자 권한으로 서버를 완전히 제어할 수 있습니다. 하지만 원격 코드 실행을 획득하면 더 나아갈 수 있습니다. 이 CVE는 2023.11.4 이전의 모든 버전에 영향을 미치지만, 이 RCE는 2023.11 이전 버전에서만 가능합니다. 관리자 권한이 있는 사용자가 임의의 명령을 실행할 수 있게 해주는 문서화되지 않은 엔드포인트 /app/rest/debug/processes가 있습니다. 요청 URL에 2개의 요청 매개변수를 포함한 POST 요청을 보냅니다. Windows의 경우 ?exePath=cmd.exe&params=/c%20[our command here]이고, Linux의 경우 ?exePath=/bin/sh&params=-c%20[our command here]입니다. 저는 Windows에서 TeamCity를 실행 중이므로 전체 경로는 /app/rest/debug/processes?exePath=cmd.exe&params=/c%20whoami가 됩니다.

failed_attempt

서버는 요청에 csrf token이 없다는 403 오류를 반환합니다. TeamCity 문서는 토큰을 검색하기 위한 엔드포인트인 /authenticationTest.html?csrf도 제공합니다.

토큰을 검색한 후 요청 헤더 X-TC-CSRF-Token 또는 tc-csrf-token HTTP 매개변수에 추가합니다. 여기서는 X-TC-CSRF-Token을 선택했습니다.

done

csrf token을 제공한 후 원격으로 명령 실행에 성공하여 서버에 대한 완전한 제어 권한을 얻습니다.

이 CVE에서 보안 결함은 입력 검증이 아니라 코드의 로직에 있었습니다. 이 애플리케이션은 매우 복잡해서 개발자들이 어떻게든 실수를 하게 됩니다. 또한 인증을 우회하는 새로운 기법을 배웠습니다. 이 분석을 통해 유용한 것을 배우셨기를 바랍니다. 즐거운 해킹 되세요!!!

도구 다운로드
getJspFromRequest()
modelAndView