前段时间发现某目标一系列S2-016的站,于是:
1、漏洞信息
官方说明:
就是通过控制参数前缀redirect:
、action:
、redirectAction:
最后远程代码执行。官方的poc
2、搭建环境
ide用的是idea2019.3,用的jar包是vulhub里s2-016的jar包。
在idea选择创建struts2项目,之后再放入vulhub里s2-016的jar包,再配置一下xml,之后写个action(就是一个struts2的HelloWorld项目)。
POC 验证,redirect:${3*4}
url编码redirect%3a%24%7b3*4%7d
,执行了OGNL表达式:
3、调试追踪
从 https://cwiki.apache.org/confluence/display/WW/S2-016 看,是 DefaultActionMapper 处理重定向前缀参数出的问题。在DefaultActionMapper构造方法里面,有new了一个PrefixTrie对象。
这里选择重定向前缀redirect:
也是REDIRECT_PREFIX的那个put方法下个断点。
216行再下个断点,可以看到payload设置到了mapping的result里的location里面。
往下走,到了handleSpecialParameters方法,功能大概是处理一下参数(参数唯一什么的):
继续往下走,来到getMapping函数,先处理了一下action后缀名,发现之后调用了handleSpecialParameters,之后设置mapping的name和method然后return了。
之后来到findActionMapping函数,最后返回了个ActionMapping对象。
下来到了StrutsPrepareAndExecuteFilter过滤器,发现执行了execute.executeAction()函数。
继续F8下去,来到ServletRedirectResult的doExecute函数,发现已经执行了payload(ognl表达式:${3*4},finalLocation值为执行结果,payload换为执行whoami命令行,finalLocation存储执行结果)。
返回execute.executeAction()调试,f7跟进,发现执行了serviceAction方法。
再f7跟进,一直f8下来,执行了result.execute()
执行了父类StrutsResultSupport的 execute 方法,进入,可以看到payload在location。
进入conditionalParse,发现执行了TextParseUtil.translateVariables之后return,继续往下,发现payload已经执行,parsedValue存储执行结果。
继续看TextParseUtil.translateVariables函数
public static Object translateVariables(char[] openChars, String expression, final ValueStack stack, final Class asType, final TextParseUtil.ParsedValueEvaluator evaluator, int maxLoopCount) {
TextParseUtil.ParsedValueEvaluator ognlEval = new TextParseUtil.ParsedValueEvaluator() {
public Object evaluate(String parsedValue) {
Object o = stack.findValue(parsedValue, asType);
if (evaluator != null && o != null) {
o = evaluator.evaluate(o.toString());
}
return o;
}
};
TextParser parser = (TextParser)((Container)stack.getContext().get("com.opensymphony.xwork2.ActionContext.container")).getInstance(TextParser.class);
XWorkConverter conv = (XWorkConverter)((Container)stack.getContext().get("com.opensymphony.xwork2.ActionContext.container")).getInstance(XWorkConverter.class);
Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
return conv.convertValue(stack.getContext(), result, asType);
}
再跟入parser.evaluate函数,发现执行evaluator.evaluate(var),此时var为`3*4
一直往下,OgnlValueStack类的getValue函数获得值,最后由ognlUtil.getValue执行ognl表达式返回结果。
三、参考文章
https://www.jianshu.com/p/de165430e8a8
原文地址:https://www.cnblogs.com/nobgr/p/12291701.html