Description
The SafeOpener Java program stores an encoded password. Decode it, then wrap the plaintext inside picoCTF{...} to submit.
Open the Java source-openSafe() defines the Base64-encoded password (encodedkey).
Extract the string, decode it, and either run the program with that password or directly wrap it with picoCTF{...}.
grep encodedkey SafeOpener.javagrep encodedkey SafeOpener.java | sed -n '1p'grep encodedkey SafeOpener.java | sed -n '1p' | cut -d '"' -f2grep encodedkey SafeOpener.java | sed -n '1p' | cut -d '"' -f2 | base64 -djavac SafeOpener.java && java SafeOpener # optional sanity check (Java 11+ also accepts: java SafeOpener.java)Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Read the sourceObservationI noticed the challenge provides a Java source file (SafeOpener.java) rather than a compiled binary, which suggested that the encoded password is stored directly in the source code and can be found by reading it without any reverse engineering.The main method simply compares the user input (Base64-encoded) against the constant stored inencodedkey. No reversing needed; just decode.What didn't work first
Tried: Trying to compile and run the Java program and guess the password interactively.
Running the program and typing guesses one at a time is impractical - you do not know the password yet. The smarter move is to read the source first and find where the expected value is stored, which reveals the encoded password without any guessing.
Tried: Assuming the encoded string is encrypted and trying to brute-force or crack it.
Beginners sometimes mistake Base64 encoding for encryption and spend time looking for a key or trying cipher tools. Base64 is not encryption - it is a reversible encoding with no key. The equal-sign padding at the end of the string is a strong hint that it is Base64, and any Base64 decoder will recover the original text instantly.
Learn more
Source code auditing is the process of reading program source to find security vulnerabilities, hidden logic, or hardcoded secrets. When source is available (as in this challenge), it's far faster than reverse engineering a compiled binary - you can search for keywords like
password,key,secret, orencodedirectly.Java source files are particularly readable and widely used in enterprise applications. The
openSafe()method pattern - comparing user input against a stored encoded value - mirrors real authentication code that novice developers sometimes write, storing a known-good answer and checking against it rather than using a proper authentication framework.The critical insight is that Base64 encoding is not encryption. Storing
Base64.encode(password)in source code is functionally identical to storing the plaintext password - anyone who reads the code can reverse it in seconds. Passwords should be stored as salted hashes(bcrypt, Argon2) so that even database breaches don't expose them.Step 2
Format the flagObservationI noticed the decoded Base64 string is the raw password plaintext, and the challenge description explicitly states to wrap it inside picoCTF{...}, which suggested one final formatting step before submission.Take the decoded password and wrap it aspicoCTF{...}to produce the final submission.The four-stage pipeline narrows the file down step by step:
$ grep encodedkey SafeOpener.java String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz"; String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz"; if (password.equals(encodedkey)) { $ grep encodedkey SafeOpener.java | sed -n '1p' String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz"; $ ... | cut -d '"' -f2 cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz $ ... | base64 -d pl3as3_l3t_m3_1nt0_th3_saf3The final string goes inside
picoCTF{...}.What didn't work first
Tried: Submitting the raw Base64 string as the flag instead of the decoded plaintext.
After finding the
encodedkeyvariable, beginners sometimes copy the encoded value directly into the picoCTF{} wrapper. The flag requires the decoded text, not the Base64 representation. Runningbase64 -don the string or using CyberChef's From Base64 operation reveals the actual password to wrap.Tried: Submitting just the decoded string without the picoCTF{} wrapper.
The challenge description says to wrap the plaintext inside picoCTF{...}, but it is easy to overlook. Submitting the raw decoded password without the prefix and braces will be rejected - the full flag format is picoCTF{decoded_password}.
Learn more
In Java,
java.util.Base64(Java 8+) provides the standard Base64 encoder/decoder. Earlier code usedsun.misc.BASE64Decoder, which was internal and non-standard. On the command line,base64 -d(Linux/Mac) or CyberChef's "From Base64" operation decodes the string instantly.The pipeline approach used in the setup command (
cat | grep | sed | cut | base64 -d) demonstrates Unix philosophy: small tools chained together to accomplish a task. Each tool does one thing -grepfinds lines with the keyword,cutextracts the field between quotes,base64 -ddecodes the result.When auditing Java applications professionally, tools like jadx (decompiler), Checkmarx, and SonarQube automate source scanning for hardcoded secrets and insecure patterns across entire codebases.
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{pl3as3_l3t_m3_1nt0_th3_saf3}
Challenge reinforces that storing secrets in client-side code (even encoded) offers no real protection.