Concurrent CLI archiver for CTF platforms. It mirrors a whole event into a tidy output/<ctf-name>/ tree: every challenge (metadata, README, rendered view, files) plus the site's notifications, behind a live progress dashboard. Re-run it during the CTF to pull new and changed challenges.
Supports CTFd today, with more platforms (rCTF and others) coming soon.
Needs Go 1.25+.
git clone https://github.com/UmmItKin/CTF-dlers
cd CTF-dlersInstall to /usr/local/bin:
./install.sh # or: ./install.sh ~/.local/bin to pick the target dirOr just build the binary in place:
just build # -> ./CTF-dlers (plain: go build -o CTF-dlers ./cmd)# Download every challenge (API token) into output/scriptctf-2026/
./CTF-dlers -url https://ctf.example.com -token ctfd_abc123 -ctf-name scriptctf-2026
# No token? Point -from-browser at the CTF and it grabs your logged-in session cookie
./CTF-dlers -from-browser https://ctf.example.com -ctf-name scriptctf-2026
# ...or paste the cookie yourself
./CTF-dlers -url https://ctf.example.com -cookie "<session-cookie>" -ctf-name scriptctf-2026
# Check auth, or preview without downloading
./CTF-dlers -url https://ctf.example.com -token ctfd_abc123 -test
./CTF-dlers -url https://ctf.example.com -token ctfd_abc123 -ctf-name scriptctf-2026 -dry-run-ctf-name is the competition name; challenges land under output/<ctf-name>/. It's required
to download (but not for -test).
You authenticate one of two ways:
- Token: get one from CTFd → Settings → Access Tokens. Also read from
CTFD_TOKEN. - Session cookie: for instances without tokens. Easiest is
-from-browser https://ctf..., which takes the CTF URL and reads itssessioncookie straight from your logged-in Firefox/Floorp/LibreWolf profile (no-url/-cookieneeded; Chrome isn't supported, its cookies are OS-encrypted). Or pass it yourself with-cookie(orCTFD_COOKIE), bare value orsession=...pair.
-url can also come from CTFD_URL or a config file. After a run you're prompted to
bundle everything into a .tar.gz to share with teammates.
Re-running the same -ctf-name checks for updates first: it lists New challenges and
Changed ones (an attachment is newer on the server, shown with its date) and asks before
downloading. Only the tool's own files get refreshed; your solve scripts and notes in those
folders are never touched. (CTFd's API exposes no timestamp for challenge text, so text-only
edits can't be detected; file changes are detected via each attachment's Last-Modified.)
Attachments come from CTFd's file list and from links in each challenge's description (some CTFs host files on external storage like S3 or DigitalOcean Spaces, which are plain public downloads). Any host works; only share-preview pages that can't be fetched directly (Google Drive, Proton Drive, Dropbox, MEGA, etc.) are skipped. Description links over 250 MB are skipped too, so a stray VM image or installer link can't run away.
| Flag | Description | Default |
|---|---|---|
-url |
CTFd base URL (or use -from-browser) |
n/a |
-token, -cookie |
Access token or session cookie (one auth method required) | n/a |
-from-browser |
CTF URL to target with your browser's session cookie (sets URL + auth in one) | n/a |
-ctf-name |
Competition name; output goes under output/<ctf-name>/ (required to download) |
n/a |
-output |
Base output directory | output |
-config |
YAML config file (see below) | n/a |
-workers |
Concurrent challenge workers | 5 |
-rate-limit |
Requests per second | 10 |
-retry, -retry-delay |
Retry attempts / delay between them | 3, 1s |
-hints, -solves |
Include hints / solves in metadata | false |
-skip-existing |
Skip challenges already downloaded | true |
-verbose, -dry-run, -test, -version |
Logging / preview / auth check / version | false |
base_url: "https://ctf.example.com"
token: "ctfd_abc123" # or use cookie instead
# cookie: "<session>"
ctf_name: "scriptctf-2026"
output_dir: "output"
max_workers: 5
rate_limit: 10
retry_count: 3
retry_delay: "1s"
include_hints: false
include_solves: falseCLI flags override the config file, which overrides defaults. Run with -config config.yml.
output/<ctf-name>/
├── notifications.md # the site's announcements
└── <category>/
└── <challenge>/
├── challenge.yml # metadata (id, value, tags, files with sha1, hints, solves)
├── README.md # human-readable description
├── view.html # CTFd's rendered challenge modal (instance launcher, etc.)
└── <files> # challenge attachments
MIT. See LICENSE.