Unlike the Training version, here checkPassword doesn't compare one whole string at once: it checks individual characters at specific indices (or compares rearranged substrings). You have to read the logic carefully and reconstruct the password piece by piece.
- Platform: picoGym
- Category: Rev Eng
- Points: 200 pts
- Difficulty: Intermediate
- Tools: javacjavagrep
Challenge description
Second door in the series: a new file, VaultDoor1.java, is provided, noticeably longer than the previous challenge's. The checkPassword method no longer does a single direct comparison on the whole string — it chains several conditions, each only covering a small part of the password.
This is a logical escalation from Vault-Door-Training: the secret is still hardcoded, but split into fragments that need to be found and reassembled in the right order.
Step 1 — Read the structure
We go through checkPassword and spot a series of if conditions that must ALL be true for the function to return true — each covering a different slice of the input string, via substring() or charAt():
public boolean checkPassword(String password) {
return password.length() == 32
&& password.substring(0, 5).equals("vault")
&& password.substring(5, 6).equals("_")
&& password.substring(6, 11).equals("d00r_")
&& password.charAt(11) == 't'
&& password.charAt(12) == 'r'
&& password.substring(13, 19).equals("a1n1ng")
&& password.substring(19, 20).equals("_")
&& password.substring(20, 26).equals("clear")
&& password.substring(26).equals("_check");
}
Each condition is independent of the others — no way to simply read a single string literal like in the Training challenge. We have to collect each fragment one by one.
Step 2 — Reconstruct
We note down every constraint found in the code, in the order of the indices it covers, so nothing gets left out:
- Index 0–5:
"vault" - Index 5–6:
"_" - Index 6–11:
"d00r_" - Index 11:
't' - Index 12:
'r' - Index 13–19:
"a1n1ng" - Index 19–20:
"_" - Index 20–26:
"clear" - Index 26+:
"_check"
A good habit here: build this table as you read, rather than keeping it all in your head, especially as the number of conditions grows in later levels of the series.
Step 3 — Assemble
We concatenate every fragment found, strictly in the order of their starting indices:
// vault + _ + d00r_ + t + r + a1n1ng + _ + clear + _check
vault_d00r_tra1n1ng_clear_check
The assembled result forms a consistent 32-character string — which incidentally confirms the password.length() == 32 constraint seen at the top of the function. A good way to check no fragment was missed.
Step 4 — Verify
We compile and run the program with the reconstructed password:
$ javac VaultDoor1.java
$ java VaultDoor1
Enter vault password: vault_d00r_tra1n1ng_clear_check
Access granted.
picoCTF{...}
🚩 picoCTF{ flag intentionally hidden }
The flag is deliberately hidden — follow the method, you've earned it. 💪
Key takeaways
- Splitting a check into fragments doesn't make it more secure — it just makes it slower for a human to read
- A script that automatically parses the constraints (or a simple
grep -n "equals\|charAt"on the source file) massively speeds up this kind of static analysis - Building a table of indices as you read prevents assembly errors, especially as the number of conditions grows
Originally published on CTFdojo — join the CTFdojo Discord to discuss writeups and get notified about new ones.
Top comments (0)