zoukankan      html  css  js  c++  java
  • S2-002漏洞分析

    漏洞概述

    Struts2-002是一个 XSS 漏洞,该漏洞发生在 <s:url><s:a>标签中,未对标签内字符进行转义,当标签的属性 includeParams=all 时,即可触发该漏洞。

    漏洞影响版本: Struts 2.0.0 - Struts 2.1.8.1 。更多详情可参考官方通告:https://cwiki.apache.org/confluence/display/WW/S2-002

    环境搭建

    直接在上一次S2-001的环境上做一些修改
    index.jsp中,将上次的form表单删掉,添加一个<s:url>标签

    <%--
      Created by IntelliJ IDEA.
      User: twosmi1e
      Date: 2020/11/19
      Time: 7:32 下午
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page language="java" contentType="text/html"
             pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>S2-001</title>
    </head>
    <body>
    <h2>S2-001 Demo</h2>
    <p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https://cwiki.apache.org/confluence/display/WW/S2-001</a></p>
    
    <s:url action="login" includeParams="all"></s:url>
    
    
    </body>
    </html>
    

    LoginAction.java中添加url变量,将对用户名密码的处理删掉

    package com.demo.action;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    public class LoginAction extends ActionSupport {
        private String username = null;
        private String password = null;
        private String url = null;
    
        public String getUsername() {
            return this.username;
        }
    
        public String getPassword() {
            return this.password;
        }
    
        public String getUrl(){
            return this.url;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public void setUrl(String url){
            this.url = url;
        }
    
    
    
        public String execute() throws Exception {
    
            return "error";
        }
    }
    

    运行复现漏洞

    成功触发XSS

    漏洞分析

    当在 JSP 文件中遇到 Struts2 标签 <s: 时,程序会先调用 doStartTag ,并将标签中的属性设置到对应标签对象相应属性中。最后,在遇到 /> 结束标签的时候调用 doEndTag 方法。

    跟进component.start函数

    可以看到函数会根据标签includeParams属性不同做不同处理
    all 和 get 的不同只有一个 mergeRequestParameters 方法,在 includeParams 为 all 的情况下会调用 mergeRequestParameters 将 tomcat 处取来的参数:

    这里取到了我们输入的payload,并且保存在parameters

    在 mergeRequestParameters 方法之后,依次是 includeGetParameters、includeExtraParameters 方法。 includeGetParameters 方法主要是将 HttpRequest.getQueryString() 的数据存入 this.parameters 属性,而 includeExtraParameters 方法则用来存入其它数据。

    而在 get 时会调用的两个函数中,includeGetParameters 方法则是先获取请求参数字符串,再进行处理分割:

    而调用 this.req.getQueryString 从 tomcat 处获取的请求参数字符串是经过 URL 编码的,所以无法造成 XSS 漏洞。

    includeExtraParameters 则一般为 null。

    执行完doStartTag后进入doEndTag,调用buildUrl

    然后返回result触发XSS

    漏洞修复

    2.0.11.1 版本修复

    对 s:a 标签的修复如下:

    if (this.href != null) {
        this.addParameter("href", this.ensureAttributeSafelyNotEscaped(this.findString(this.href)));
    }
    

    加上了一个 ensureAttributeSafelyNotEscaped 方法来过滤双引号:

    protected String ensureAttributeSafelyNotEscaped(String val) {
        return val != null ? val.replaceAll(""", "&#34;") : "";
    }
    

    对 s:url 标签的修复如下:

    for(result = link.toString(); result.indexOf("<script>") > 0; result = result.replaceAll("<script>", "script")) {
        ;
    }
    

    在拼接完之后对 script 进行了处理,但是只是简单的将 script 标签的两个尖括号去掉了,所以可以轻松绕过:

    http://localhost:8080/login.action?<script 1>alert(1)</script>=hello

    2.2.1 版本修复

    private static String buildParameterSubstring(String name, String value) {
        StringBuilder builder = new StringBuilder();
        builder.append(translateAndEncode(name));
        builder.append('=');
        builder.append(translateAndEncode(value));
        return builder.toString();
    }
    public static String translateAndEncode(String input) {
        String translatedInput = translateVariable(input);
        String encoding = getEncodingFromConfiguration();
        try {
            return URLEncoder.encode(translatedInput, encoding);
        } catch (UnsupportedEncodingException e) {
            LOG.warn("Could not encode URL parameter '" + input + "', returning value un-encoded");
            return translatedInput;
        }
    }
    

    使用url编码修复了漏洞

    参考

    https://aluvion.gitee.io/2020/07/15/struts2系列漏洞-S2-002/
    https://mochazz.github.io/2020/06/17/Java代码审计之Struts2-002/

  • 相关阅读:
    POJ3468 A Simple Problem with Integers(线段树成段增减,区间求和)
    HDU1698 Just a Hook(线段树成段替换、区间求和,延迟标记的应用)
    HDU2795 Billboard(线段树基础题单节点更新区间查询)
    HDU1754 I Hate It(线段树基础题单节点更新区间查询)
    HDU5410 CRB and His Birthday(完全背包)
    HDU1166 敌兵布阵(线段树基础题单节点更新区间查询)
    cf C. Bombs
    cf B. Resort
    cf B. Color the Fence
    cf B. Little Dima and Equation
  • 原文地址:https://www.cnblogs.com/twosmi1e/p/14134511.html
Copyright © 2011-2022 走看看