Skip to main content

vault-door-5 picoCTF 2019 Solution

Reverse engineer a Java program that hides a password behind multiple layers of encoding transformations.

Published: April 2, 2026Updated: August 25, 2026

Description

This vault uses Base64 and URL encoding for the password. Decode the layers to find the flag.

Download the Java source file and inspect it.

bash
wget <url>/VaultDoor5.java

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Read the Java source and identify the encoding chain
    Observation
    The description mentions both Base64 and URL encoding. So checkPassword applies those two layers in some specific order, and that order needs tracing before anything gets reversed.
    Open VaultDoor5.java. The checkPassword method applies URL encoding and Base64 encoding to the input, then compares it to a stored string. To reverse this: the stored string is Base64-decoded first, then URL-decoded, to recover the password.
    bash
    cat VaultDoor5.java
    What didn't work first

    Tried: Trying to crack the stored string as if it were a hash using a tool like hashcat or john.

    Hashcat and john expect a hash and need a dictionary or brute force. This stored string is not a hash; it is a layered encoding, deterministic and reversible with no key at all, so a cracker returns nothing and burns time. Recognize the Base64 padding (trailing '=' and a 64-character alphabet) and just decode.

    Tried: Looking only at the import statements for clues and missing the actual encoding order inside checkPassword.

    Imports tell you which libraries are available, but the checkPassword body decides the order URL encoding and Base64 are applied in. Reverse in the wrong order, URL-decode then Base64-decode, and the output is garbled. Trace the data flow through the method to fix the sequence first.

    Learn more

    Base64 encodes binary data as printable ASCII characters (A-Z, a-z, 0-9, +, /). It inflates the data by 33% and is reversible without a key.

    URL encoding (percent encoding) replaces special characters with a percent sign followed by their hex code (e.g., space becomes %20). This ensures text can be safely embedded in URLs.

    These are encodings, not encryption - they provide zero confidentiality. Anyone who recognizes the encoding chain can reverse it instantly.

  2. Step 2Reverse the encoding chain
    Observation
    The stored string in VaultDoor5.java carries Base64 padding, and checkPassword applies URL encoding before Base64. So reverse them in the opposite order: base64.b64decode first, then urllib.parse.unquote.
    Extract the stored encoded string from the Java source. First Base64-decode the stored string, then URL-decode the result to recover the password.
    bash
    # Base64-decode then URL-decode the stored string:
    python
    python3 -c "import urllib.parse, base64; s = '<paste stored string>'; print(urllib.parse.unquote(base64.b64decode(s).decode()))"
    What didn't work first

    Tried: Applying URL-decode first and Base64-decode second (reversing the reversal order).

    urllib.parse.unquote passes a raw Base64 string through mostly untouched, since Base64 characters are URL-safe, and then base64.b64decode fails or returns gibberish because the input was never URL-encoded Base64. The string was URL-encoded first and Base64-encoded second, so reverse it Base64 first and URL second.

    Tried: Using the command-line tool base64 -d on the stored string and piping to python -c urllib.parse.unquote separately, then wrapping the result in picoCTF{} by hand.

    base64 -d decodes the first layer fine, but the output may contain percent-encoded sequences that a plain print or echo will not interpret as escapes. Leave the percent signs unquoted and the password looks like raw percent-escaped text rather than clean ASCII, and the vault rejects it. Running urllib.parse.unquote in the same pipeline decodes both layers cleanly.

    Learn more

    Python's urllib.parse.unquote() performs URL decoding. base64.b64decode() performs Base64 decoding. Chain them in the reverse order of the encoding (Base64-decode first, then URL-decode) to recover the plaintext.

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.
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • Base64 & Base32 DecoderDecode Base64 and Base32 strings with auto-detection. Multi-layer mode unwraps nested encodings automatically.
Alternate Solution

Use the Base64 Decoder on this site to reverse the Base64 layer after manually URL-decoding the stored string.

Flag

Reveal flag

picoCTF{c0nv3rt1ng_fr0m_ba5e_64_...}

The password went through URL encoding then Base64 encoding before storage - reverse by Base64-decoding then URL-decoding.

Key takeaway

Base64 and URL encoding exist for data transport, not security: anyone who recognizes the format reverses them, with no key and no secret. Stack several layers and reversing the chain is still straightforward once the order is clear. Recognizing these encodings on sight, from their character sets, padding, and length, is core to CTFs and to real security reviews of APIs, cookies, and tokens.

Related reading

Useful tools for Reverse Engineering

Where to go next