Description
Find the flag in droids2.apk. The app asks for a password. Decompile it, reverse the Java logic to derive the password, enter it in an emulator, and the app hands you the flag.
Setup
Download the APK file.
wget <url>/droids2.apkSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Decompile the APK with jadxObservationI noticed the challenge provided an APK file with a password prompt and no source code, which suggested the password-checking logic was compiled into DEX bytecode that jadx could reconstruct into readable Java for analysis.Run jadx on the APK to produce Java source. Look inside the decompiled output for a class named FlagstaffHill. Its getFlag method is where the password check lives.bashjadx droids2.apk -d droids2_java/bashgrep -r 'FlagstaffHill' droids2_java/Expected output
droids2_java/sources/com/hellocmu/picoctf/FlagstaffHill.java
What didn't work first
Tried: Using apktool instead of jadx to get readable Java source
apktool disassembles the APK to smali bytecode (a human-readable Dalvik assembly), not Java. Reading smali is much harder than Java - register names like v0, v1 replace named variables, and control flow is expressed as goto labels. jadx is the right tool when you want reconstructed Java source to trace the password logic.
Tried: Running grep for 'password' or 'flag' directly on the APK binary before decompiling
The APK is a ZIP archive containing compiled .dex bytecode; grep on the raw binary finds some string literals but misses computed or concatenated values entirely. The password in this challenge is assembled at runtime from array elements and index arithmetic, so it never appears as a single literal string in the binary. Decompiling with jadx first is required to see the construction logic.
Learn more
jadx re-creates Java source from the compiled .dex bytecode inside the APK. The output is not always identical to the original source, but the logic is preserved accurately enough to reverse engineer passwords and algorithms.
Step 2
Read the password-construction logic in FlagstaffHillObservationI noticed jadx placed the validation code in a class named FlagstaffHill, and the grep output confirmed its location, which pointed me to inspect the getFlag method directly to trace how the expected password was assembled from the witches array.Open the decompiled FlagstaffHill.java. The getFlag method declares a String array called witches containing six witch names: weatherwax, ogg, garlick, nitt, aching, and dismass. It then computes integer indices through arithmetic (e.g. second = 3 - 3, third = (3 / 3) + second) and concatenates the selected names with dots to form the expected password. Evaluate each arithmetic expression to find the actual index values, then read off the names in order.Learn more
The witches array:
{"weatherwax", "ogg", "garlick", "nitt", "aching", "dismass"}(indices 0-5).Evaluating the arithmetic gives: second = 0, third = 1, fourth = 2, fifth = 5. The concatenation order selects indices 5, 1, 0, 4, 3, 2, producing the password:
dismass.ogg.weatherwax.aching.nitt.garlick.The method then calls
sesame(input)if your input matches, which returns the flag. The key insight is that all of this logic is plain Java - no native library is involved.Step 3
Enter the password in an Android emulator to get the flagObservationI noticed the sesame() method only executes and returns the flag when the correct password is supplied at runtime, which meant the password derived from the index arithmetic had to be entered through the running app rather than extracted statically.Start an Android emulator (e.g. via Android Studio AVD Manager or the standalone emulator). Install droids2.apk, launch it, enter dismass.ogg.weatherwax.aching.nitt.garlick as the password, and submit. The app calls sesame() internally and displays the flag on screen.bashemulator -avd <your_avd_name> &bashadb install droids2.apkbashadb shell am start -n com.hellocmu.picoctf/.MainActivityWhat didn't work first
Tried: Trying to extract the flag with adb shell without entering the password in the UI
The flag is returned by the sesame() method only when the correct password is passed in at runtime - it is not stored as a constant in a file or SharedPreferences on disk. Commands like adb shell cat or adb pull will not find a flag file; the app must execute the verification branch to produce it. You need to interact with the UI (or automate input via adb shell input text) to trigger sesame().
Tried: Installing the APK on a physical Android device instead of an emulator
A physical device works in principle, but most CTF players do not have a rooted device handy and the challenge expects emulator access. More importantly, if you misread the password even slightly (e.g. garlick vs garlic, dots vs underscores) the app silently shows nothing - the emulator lets you paste text precisely via adb shell input text, avoiding typing errors that look like a logic mistake in your decompilation.
Learn more
Alternatively, you can patch the smali bytecode with apktool (change the call from nope to yep, or copy yep's body into nope), recompile, sign, and install the patched APK to bypass the password check entirely. But simply entering the derived password is simpler when the logic is fully readable from the Java decompilation.
Flag
Reveal flag
picoCTF{what.is.your.favourite.colour}
The password dismass.ogg.weatherwax.aching.nitt.garlick is derived by evaluating the index arithmetic in FlagstaffHill.getFlag(). Entering it in the app triggers sesame() which returns the flag.