Description
Python scripts are invoked kind of like programs in the terminal. Download and use the provided python script, password file, and encrypted flag.
Setup
Download ende.py, pw.txt, and flag.txt.en from the challenge page.
wget <url>/ende.pywget <url>/pw.txtwget <url>/flag.txt.enSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Read the password
ObservationThe challenge ships a separate pw.txt alongside the encrypted flag. The decryption password lives there, so read it before running the script.The decryption password is stored in pw.txt. Print it so you can supply it to the script.bashcat pw.txtWhat didn't work first
Tried: Open pw.txt in a text editor or use less/more instead of cat
The file opens fine, but copying from a pager or an editor quietly picks up a trailing newline or stray whitespace. Paste that into the password prompt and Fernet rejects the key with an InvalidToken error. cat prints the password cleanly on one line, which avoids the problem.
Tried: Skip reading pw.txt and guess the password is 'password' or an empty string
The script accepts any string at the prompt, but Fernet raises InvalidToken or InvalidSignature straight away, because the HMAC check fails on the wrong key. The password is a random-looking Base64 string in pw.txt and cannot be guessed, so read the file and supply the exact value.
Learn more
Storing a password in a separate file is a common pattern in software - rather than hard-coding credentials in the main script, they're kept in a dedicated file that can be protected with file system permissions or excluded from version control. In this challenge, the password file is provided to you intentionally as part of the puzzle.
In real applications you'd never want to store plaintext passwords in a file, but the pattern of reading configuration or secrets from a file is pervasive. Tools like
.envfiles,secrets.json, or environment variables serve the same purpose in production code. The key is that the secret is separate from the logic that uses it.Step 2Decrypt the flag
Observationende.py takes both -e and -d, and flag.txt.en carries an encrypted extension. So pass -d with the encrypted file and the password from pw.txt to get the plaintext back.Run ende.py with -d. The argument convention varies; try the script's interactive prompt first, then fall back to argv or stdin redirection if it expects the password directly.bash# Most common: prompt-driven, paste the password when askedpythonpython3 ende.py -d flag.txt.enbashbash# Argv-style: password as second positional argumentpythonpython3 ende.py -d flag.txt.en "$(cat pw.txt)"bashbash# Stdin-style: pipe the passwordpythonpython3 ende.py -d flag.txt.en < pw.txtExpected output
picoCTF{4p0110_1n_7h3_h0us3_...}What didn't work first
Tried: Run the script with -e instead of -d to try to decrypt
The -e flag runs the encrypt path, so the script treats flag.txt.en as plaintext and produces a doubly-encrypted blob rather than the flag. Use -d. If the output is a long Base64-looking string instead of picoCTF{...}, you reached for -e by mistake.
Tried: Run the script with python (Python 2) instead of python3
Where python points at Python 2, the cryptography import either fails outright or produces a bytes-versus-str mismatch inside the Fernet decode path. The script is written for Python 3 string semantics, so invoke python3 explicitly.
Learn more
Command-line flags (like
-d) are arguments passed to a program to modify its behavior. The convention of-dfor "decrypt" and-efor "encrypt" is common across many cryptographic tools. Python scripts parse these using thesys.argvlist or theargparsemodule, which provides structured argument parsing with help text and type checking.The
.enfile extension likely stands for "encrypted" - a naming convention to distinguish encrypted files from their plaintext originals. The underlying cipher is almost always Fernet (AES-128-CBC + HMAC-SHA256 from thecryptographypackage), which is the canonical symmetric encryption primitive in modern Python. Since the password is given, no cracking is needed; this challenge is purely about reading the script and supplying its argument convention.Running Python scripts:
python3 script.pyinvokes the Python 3 interpreter onscript.py. The distinction betweenpythonandpython3matters on systems where Python 2 is still the default (older Linux distros). In CTF environments, always checkpython3 --versionfirst. You can also make scripts directly executable withchmod +x ende.pyand then run./ende.py -d flag.txt.enif the script has a shebang line (#!/usr/bin/env python3).
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
- Regex TesterTest regular expressions against a string with live match highlighting, flag toggles, and common CTF pattern shortcuts.
- Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
Flag
Reveal flag
picoCTF{4p0110_1n_7h3_h0us3_...}
The -d flag means decrypt; the password from pw.txt is the decryption key. The 8-character hex suffix at the end is generated per instance and will differ from the value shown here.