Struts2漏洞调试笔记[S2-001]
配置文件
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="struts2" extends="struts-default"> <action name="login" class="meizj.test"> <result name="success">success.jsp</result> <result name="error">index.jsp</result> </action> </package> </struts>
|
web.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Struts2-001 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>
|
index.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="s" uri="/struts-tags" %> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Struts2 001 Demo</title> </head> <body> <h1>Struts2 001 Demo</h1> <s:form action="login"> <s:textfield name="username" label="username"></s:textfield> <s:textfield name="password" label="password"></s:textfield> <s:submit></s:submit> </s:form> </body> </html>
|
success.jsp:
1 2 3 4 5 6 7 8 9 10 11 12
| <%@ 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>
|
漏洞调试
先简单了解下什么是拦截器:
拦截器可以在Action的业务逻辑执行前后进行拦截调用,从而实现特定功能。
而在Struts2 001这个洞中,触发点在于表单字段位置,因此先来看看拦截器的加载情况。
Struts2中规定了一些默认加载的拦截器,在Struts-default.xml中可以找到,我们直接看到对应的Param
:
调用的类为com.opensymphony.xwork2.interceptor.ParametersInterceptor
,跟进ParametersInterceptor
,可以看到:
在拦截器作用时,会进行值栈操作,我这里把getValueStack
、setParameters
以及return invocation.invoke()
都打了断点。
接下来可以step over
,接下来会走到return invocation.invoke()
,此时开始换用step into
,接着经过几次步入,会抵达
步入executeResult
:
不断步入,直到到达doFilter
方法后步入开始不显示源码,继续步入即可解决:
直到开始解析jsp文件,对于前面的标签可以直接step over
,着重关注password
字段的处理即可。
步入到org.apache.struts2.views.jsp.ComponentTagSupport
,执行doStartTag
:
解析结束标签doEndTag
:
步入到org.apache.struts2.components.UIBean
的end()
:
步入evaluteParams()
:
执行this.altSyntax()
后,由于默认是支持动态执行OGNL的因此会返回True,从而完成对expr
的赋值.
而对expr
中的值进行计算的过程则在这一步进行:
步入后会进入findValue()
:
继续步入,接着进入translateVariables()
,在translateVariables
中,有一步是十分关键的:
即,循环解析{
符号,我们可以通过插入%{1+1}
这样的poc使得执行OGNL表达式.
上面两张图便是循环两次分别的变量值,可以看到在第一次解析后,对password
中的OGNL表达式循环执行了,在findValue()
中完成了对OGNL的执行。
EXP构造
作为Struts2系列漏洞的"鼻祖",此时还是没有任何安全防范措施的,因此直接执行exec
: