Description
This vault uses some complicated arrays to store the password. Can you decrypt it? The Java source code is provided.
Setup
Download VaultDoor1.java from the challenge page.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Trace the character index checksObservationI noticed that VaultDoor1.java's checkPassword() method contains a long series of charAt(i) == 'x' comparisons, which meant every required character and its exact position were written out in plain source code and could be extracted directly without running the program.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 just prompts for a password and tells you if you're right or wrong - it gives you no information about what the correct password is. The point of static analysis is to read the source code directly rather than treating 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'sString.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.
Step 2
Reassemble the password in orderObservationI noticed the charAt() comparisons in checkPassword() were listed in a scrambled index order rather than sequentially, which meant concatenating characters in file order would produce garbage and the pairs had to be sorted by index before joining.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
stringsanalysis. 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.