s2-059的漏洞复现
前言
s2-059的漏洞复现
背景介绍
- 这篇文章归纳了s2 ongl漏洞的历史绕过方式 浅析OGNL的攻防史,s2059的沙盒绕过方式实际上是通过第一个请求重置OgnlUtil对象的excludedPackageNamePatterns,excludedClasses等属性来回到Struts 2.3.29前的情况,之后通过允许静态方法访问,来执行java.lang.Runtime.getRuntime().exec方法。
- s2059是源于对s标签中id属性的解析。
Ognl语言介绍
- 使用#来访问对象,不使用#会直接访问基本类型变量。#name ,取值为name对象。
- @来访问静态方法。@java.lang.math@max(10,2) 结果10
- new int[]{1,2,3}直接创建数组,或者{1,2,3}直接创建数组。new int[]{1,2,3}[0] 结果: 1
- xxx,xxx,
,
分割不同的表达式xxx。new int[]{1},1 结果:1 - #{‘user’:’1’,’user1’:2}来创建新的对象。
- = 可以直接赋值。#s1=1
- 调用方法的方式和正常情况下一样,使用.即可。
- 使用.{xxx}来选择元素
- #s1={‘12’,’23’,1},#s1.{
#
this},选择全部元素。 - #s1={‘12’,’23’,1},#s1.{^#this.length()==2},选择第一个元素’12’。
- #s1={‘12’,’23’,1},#s1.{?#this instanceof String} 选择全部满足条件的元素,’12’,’23’。
- #s1={‘12’,’23’,1},#s1.{
- 如果对象存在get或者set方法 ongl允许通过xxx.attr来访问或者xxx[‘attr’]=xx来设置元素的值。
- 1 in {1,2} 和python的用法一样。
复现环境
- 使用vulhub的s2-059环境,直接使用mvn自带的jerry启动调试模式,jdk8
调试过程
index.jsp,直接使用vulhub的poc打
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>S2-059 demo</title>
</head>
<body>
<s:a id="%{id}">your input id: ${id}
<br>has ben evaluated again in id attribute
</s:a>
</body>
</html>
1 | import requests |
启动过程中在setExcludedClasses方法下断点
在setExcludedPackageNames方法下断点
打过poc后在ognl.ASTChain的86行,一直f9直到返回的result到20几个的时候,这边的poc主要是获取attr对象中的struts.valueStack中的context,按照poc依次存储context,通过context获取com.opensymphony.xwork2.ActionContext.container,也就是当前上下文中container,最后通过getInstance方法获取ognlUtil对象。最终目的是重置ognlUtil对象中的ExcludedPackageNames和ExcludedClasses。
接着第二次请求,需要注意的是,整个流程没法依次完成,如果第一次就直接执行接下来的语句就会报stackoverflow的异常。
最终能够调用静态方法,直接java.lang.Runtime.getRuntime().exec()
现在回过头来看下为啥只有id被解析了。
最后一个断点下载Component类的150行的方法上,看下调用堆栈。
很明确解析表达式的条件是开启altSyntax,当前版本这个默认是关闭的,而且按照这里的containsExpression,表达式必须是%{xxx}才行。
1
2
3
4
5
6
7
8
9
10
11
12protected Object findValue(String expr, Class toType) {
if (this.altSyntax() && toType == String.class) {
return ComponentUtils.containsExpression(expr) ? TextParseUtil.translateVariables('%', expr, this.stack) : expr;
} else {
expr = this.stripExpressionIfAltSyntax(expr);
return this.getStack().findValue(expr, toType, this.throwExceptionOnELFailure);
}
}
public static boolean containsExpression(String expr) {
return expr != null && expr.contains("%{") && expr.contains("}");
}影响范围包括UIBean所有使用setId的tag,需要注意的是这边有递归解析限制。
总结
感觉这个洞需要结合白盒分析利用,看上去不是特别厉害。不过绕Ognl的思路真的很值得细细研究。