Skip to main content

vault-door-1 picoCTF 2019 Solution

Reverse engineer a Java program that validates a password one character at a time to reconstruct the correct input.

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

Description

This vault uses some complicated arrays to store the password. Can you decrypt it? The Java source code is provided.

Download VaultDoor1.java from the challenge page.

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Trace the character index checks
    Observation
    checkPassword() in VaultDoor1.java is a long chain of charAt(i) == 'x' comparisons. Every required character and its exact position is spelled out in the source, so the password can be extracted without running anything.
    Open VaultDoor1.java and inspect checkPassword(). The method checks individual characters at specific indices using charAt() - for example, password.charAt(0) == 'd', password.charAt(29) == '3', etc. Collect each required character, placing it at the index specified, to reconstruct the full password string.
    What didn't work first

    Tried: Trying to compile and run VaultDoor1.java, then guessing passwords interactively.

    Running the program only prompts for a password and tells you right or wrong; it never reveals what the password is. Static analysis means reading the source directly instead of poking at the program as a black box.

    Tried: Reading the charAt() comparisons in the order they appear in the file and writing down characters in that order.

    The comparisons are intentionally listed in a scrambled index order, not in sequential order from index 0 upward. Reading them top to bottom produces a garbled string. You must note the index alongside each character and sort by index before assembling.

    Learn more

    This challenge demonstrates static analysis - reading source code or compiled bytecode to understand a program's behavior without executing it. The checkPassword() method validates each character of the password individually using Java's String.charAt(index) method, which returns the character at a given zero-based position.

    Because the checks are written out in source code, every required character and its required position are fully visible to the reader. The "security" relies entirely on the hope that an attacker won't read the source - a strategy known as security through obscurity, which is universally considered ineffective. Once source code is available (or a binary is decompiled), this protection provides zero resistance.

    This pattern is a classic example of what the OWASP Top 10 calls Insecure Design - the fundamental approach to authentication is flawed regardless of implementation details. The correct approach is to store a cryptographic hash of the password and compare hashes, never the plaintext characters directly.

  2. Step 2Reassemble the password in order
    Observation
    The charAt() comparisons are listed in scrambled index order rather than sequentially. Joining the characters in file order gives garbage, so sort the pairs by index first.
    Sort all the charAt index-value pairs by index and concatenate the characters. The resulting string is the flag content to put inside picoCTF{...}.
    What didn't work first

    Tried: Submitting the raw reassembled string as the flag without wrapping it in picoCTF{}.

    The checkPassword() method strips the picoCTF{ prefix and } suffix before validating, so the characters you extract are just the inner content. The full flag must be wrapped in picoCTF{...} to be accepted by the scoring system.

    Learn more

    Reconstructing a scrambled string from index-value pairs is a straightforward permutation reversal. If you have a list of (index, character) pairs, sorting by index and joining the characters gives the original string. In Python this looks like: ''.join(c for _, c in sorted(pairs)).

    In real-world security research, this type of reconstruction is common when analyzing obfuscated code. Malware authors frequently split strings across multiple assignments, reverse them, or interleave characters to defeat simple strings analysis. But once the obfuscation logic is understood, reconstruction is mechanical. Tools like de4dot (for .NET) and jadx (for Android APKs) automate much of this deobfuscation.

    The key lesson: any password check implemented in application logic can be reversed by reading that logic, no matter how cleverly the characters are scattered. True authentication security requires cryptographic primitives (hashing, signing) that are mathematically hard to reverse - not code complexity.

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.

Flag

Reveal flag

picoCTF{d35cr4mbl3_tH3_cH4r4cT3r5_...}

Character-by-index scrambling provides no security - reading the source and reassembling characters in index order immediately reveals the password.

Key takeaway

Any password check written as ordinary application logic can be reversed by reading that logic, however the characters are scattered across index comparisons. Splitting a secret over dozens of charAt(i) == 'x' tests hides nothing once you have the source, which is the same reason deobfuscating malware that interleaves or reverses strings is routine work. Real authentication has to rest on cryptography that is hard to invert, never on the attacker not reading the code.

Related reading

Useful tools for Reverse Engineering

Where to go next