起因
struts官方照例更新补丁,这次更新了061,从官方通告上来看与059相似,059的通告类似029与036,既然这样,那大胆猜测一下,059如果修复了,061大概率会是补丁绕过,这里贴一个官方通告地址,方便大家自行查阅:
https://cwiki.apache.org/confluence/display/WW/Security+Bulletins
跟踪
进一步跟踪struts版本改动,得到以下可能存在的漏洞点以及类似黑名单:
根据官方描述,上述为黑名单机制,匹配其中的包名,当然还有类名,由于太长了,这里就不贴了。OK,既然看到类似的漏洞点了,不分析一下怎么可以呢,到此打开idea,maven导入struts2.5.26版本,分析过029的对此类应该不陌生,属于二次ognl表达式执行,看一下官方对此方法的修复情况如何
public static boolean containsExpression(String expr) {
return expr != null && expr.contains("%{") && expr.contains("}");
}
对应上图可以看到如果expr中存在%{
和}
时会返回true,就不会对expr进行嵌套。更一步确定了,这次修复肯定还与二次ognl表达式有关。由此可知,这次061为059的补丁绕过。接下来开始惊心动魄的构造poc阶段
构造
首先搭建环境,这里为了给广大白帽子一个福利,啥下载官方all包了,啥maven导版本然后再创建xml了,通通不用,直接使用idea官方maven create from archetype,如下图所示,直接一键操作搭建
创建完成后,需要对index.jsp进行一点点改造,写入特定标签
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@taglib prefix="s" uri="/struts-tags" %>
<%
String payload = request.getParameter("payload");
request.setAttribute("payload",payload);
%>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Index</title>
<s:head />
</head>
<body>
<s:a id="%{#request.payload}">testurl</s:a>
<s:form action="helloWorld">
<s:textfield label="What is your name?" name="name" />
<s:textfield label="What is the date?" name="dateNow" />
<s:submit />
</s:form>
</body>
</html>
这时如果不了解struts框架的人就会踩到第一个坑了,包括我(菜鸡哭泣),此时传入payload字符会显示无法处理,这是因为此处关联了index.action,需要在index.action中增加一些方法,这里直接贴出
import com.opensymphony.xwork2.ActionSupport;
import java.util.Date;
import com.opensymphony.xwork2.conversion.annotations.Conversion;
import com.opensymphony.xwork2.conversion.annotations.TypeConversion;
@Conversion()
public class IndexAction extends ActionSupport {
private String payload;
private Date now = new Date(System.currentTimeMillis());
@TypeConversion(converter = "Struts2.DateConverter")
public Date getDateNow() { return now; }
public String getPayload(String payload){
return payload;
}
public void setPayload(String payload){
this.payload=payload;
}
public String execute() throws Exception {
now = new Date(System.currentTimeMillis());
return SUCCESS;
}
}
由此环境搭建完毕,可以开始愉快的调试之旅啦。这里需要对之前的漏洞有一定了解,推荐天融信的文章,分析的很好,链接放到最后。第一步,获取struts.valueStack,通过request全局变量。这一步,没有问题,第二步,开始正儿八经绕过获取context对象的限制,采用application根变量,获取org.apache.tomcat.InstanceManager到DefaultInstanceManager类,虽然推荐文章分析的很好了,但是这边啰嗦一下,贴出对应需要调用的方法
public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException {
Class<?> clazz = this.loadClassMaybePrivileged(className, this.classLoader);
return this.newInstance(clazz.newInstance(), clazz);
}
当然光写,不贴图,也感受不到调试的乐趣,于是这里贴图,如何获取需要的类和调用它的方法
看到上述回显,高高兴兴开始下一阶段,进一步通过org.apache.commons.collections.BeanMap的setBean和get方法获取context,这时第二个坑遇到了,这个坑会让你甚至以为之前做的全都有错,同样用贴图,表述问题
既然内存溢出了,这简直是懵逼,没办法源代码调试吧,通过跟踪setBean方法,确认数据正确压入Map中,问题出在get方法中,观察调用链,太长具体就不贴了,可以观察到在获取context时首先会是root对象,root对象同时又是根对象,这样就会导致,root对象获取root对象,产生死循环,导致内存溢出。所以我们需要将目前获取到的context再次压入Map中,获取其他属性。所以,接着构造,这时已经拿到了context对象,ok,接下来就是操作context对象去覆盖strust的黑名单。首先获取到黑名单类
看到响应体,离成功已经很接近啦,接下来只需将安全沙箱置空,直接调用一波struts黑名单中的类,完成代码执行,接下来的就不操作了,太多公众号有写了。
参考文章:
Struts2 S2-061漏洞分析(CVE-2020-17530): https://mp.weixin.qq.com/s/RD2HTMn-jFxDIs4-X95u6g
BY:先知论坛
相关推荐: 如何利用http tunnel使用burpsuite拦截某个app的tcp数据包(非http)做安全分析 - freud****
需求 之前的burpsuite只能拦截http相关的应用,对于tcp方面的流量就不能做到很好的拦截,现在勉强在NoPE的基础上造了一个轮子。NoPE这个插件主要是通过dns,如果是针对某个特定应用,或者说是硬编码的ip的tcp流量拦截,就显得不是很方便,现在提…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论