Description
Our security team wrote a vault to protect our password. Can you defeat it? The Java source code is provided.
Setup
Download VaultDoorTraining.java from the challenge page.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Read the checkPassword methodObservationI noticed the challenge provides Java source code directly, which meant no binary reversing or decompilation was needed; and the method name checkPassword() immediately signaled that it contains the comparison logic where the expected password would be stored as a plain string literal.Open VaultDoorTraining.java and locate the checkPassword() method. The password is hardcoded as a plain string literal - no encryption, no obfuscation. Reading that string directly gives you the flag contents.What didn't work first
Tried: Trying to compile and run the Java file to test passwords interactively.
The file likely has missing imports or a main() that expects a specific environment, so it may not compile cleanly without extra setup. More importantly, the flag is already visible as a plain string in the source - you never need to run the program. Just read the string literal inside checkPassword() directly.
Tried: Scanning main() and other methods for the password instead of reading checkPassword().
Beginners often start at main() and follow the control flow, which can lead through multiple layers of setup before reaching the actual validation. The method name checkPassword() directly tells you where the comparison happens - go there first and look for the string it compares the input against.
Learn more
Hardcoded credentials - passwords, API keys, tokens, or secrets embedded directly in source code - are one of the most pervasive and dangerous security vulnerabilities in software. When source code is shared, leaked, decompiled from a binary, or checked into version control, every hardcoded secret in it is immediately exposed to anyone who reads it.
This is so common that major secret scanning tools exist specifically to detect it:
- GitHub Secret Scanning - automatically scans public repos for API keys and tokens
- truffleHog - scans git history for high-entropy strings and known secret patterns
- gitleaks - fast secret scanner for git repos and CI pipelines
- detect-secrets - Yelp's tool for preventing secrets from entering codebases
The correct pattern is to store secrets in environment variables or a secrets manager (like AWS Secrets Manager, HashiCorp Vault, or Doppler) and read them at runtime. The source code then contains no secrets, so reading it reveals nothing. This is CWE-798 (Use of Hard-coded Credentials) in the Common Weakness Enumeration and is included in every major security standard including OWASP and NIST.
In the context of this challenge series, the Vault Door challenges progressively introduce more sophisticated obfuscation techniques - but all of them share the same fundamental flaw: the password validation logic is visible in source code. No amount of obfuscation in application logic can substitute for proper cryptographic authentication design.
Decompiling Java makes this vulnerability especially acute. Java programs compile to bytecode (
.classfiles) that can be decompiled back to near-original source code using tools like CFR, Procyon, or Fernflower (built into IntelliJ IDEA). Unlike C/C++ compilation which loses variable names and high-level structure, Java decompilation often produces code indistinguishable from the original. This means even distributing a compiled Java JAR provides essentially no protection for hardcoded secrets - any attacker can decompile it in seconds.Obfuscation tools like ProGuard and DexGuard are commonly used for Android APKs to rename classes, methods, and fields to meaningless single-letter names (e.g., class
VaultDoorbecomes classa). This makes decompiled code harder to read but does not change its functionality. String encryption obfuscators go further by replacing string literals with calls to a decryption function - but the decryption key must be present in the binary, and the string values will still appear at runtime. Debuggers and decompilers that perform dynamic analysis or emulation recover the plaintext strings anyway.The correct authentication pattern: instead of comparing the user's input against a stored plaintext password, a secure system stores a salted cryptographic hash of the password (using bcrypt, Argon2, or scrypt). The input is hashed with the same salt and the hash values are compared - the original password is never stored. Even with full access to source code and the stored hash, an attacker cannot directly reverse the hash to get the password. This is the fundamental design principle behind password storage in every serious authentication system.
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{w4rm1ng_Up_w1tH_jAv4_...}
Hardcoded plaintext string literal in VaultDoorTraining.java checkPassword()