In this reverse engineering challenge, the barista at the local coffee shop left us a flag, but it’s encoded…
Solution
The main function of this script is displayed below:
public static void main(String[] args) {
String encodedFlag = "ZrgnPGS{pncchppvab_jvgu_n_ebgngvba_bs_pernz_cyrnfr}";
if (args.length == 0) {
System.out.println("Usage: java cafffineconundrum.java <your_guess>");
System.out.println("Hint: The barista left a flag, but it seems to be encoded...");
return;
}
String userGuess = args[0];
String encodedGuess = encodeFlag(userGuess);
if (encodedGuess.equals(encodedFlag)) {
System.out.println("Correct! Time for a coffee break!");
} else {
System.out.println("Not quite it! Keep trying...");
}
}
The main function prompts us for our input, encodes it using the encodeFlag()
function, compares the function output against the string stored in the variable encodedFlag
, and states whether the strings are a match.
Presumably, we need to figure out what input will generate a match, but that requires knowing what the flag is, which creates a “catch-22” situation. Perhaps there are other ways to figure out what the flag is…
Function Analysis
The source code for the encodeFlag()
function is displayed below. The way it works is as follows:
- The
result
variable is initialized with aStringBuilder
object. This creates a string that can be modified - The input string is converted to a character array and iterated through
- If the current character, c, is a letter, the variable
base
is set to either ‘A’ or ‘a’ depending on the case of the current character - The ASCII value of
base
is subtracted from the ASCII value ofc
and the value 13 is added to the result - The value obtained in the previous step is reduced by modulo 26, then the ASCII value of
base
is added to it (modulo is first due to order of operations) - The resulting character from the previous step (or from step 3 if the initial character isn’t a letter) is appended to the
StringBuilder
object stored inresult
private static String encodeFlag(String input) {
StringBuilder result = new StringBuilder();
for (char c : input.toCharArray()) {
if (Character.isLetter(c)) {
char base = Character.isUpperCase(c) ? 'A' : 'a';
result.append((char) (base + (c - base + 13) % 26));
} else {
result.append(c);
}
}
return result.toString();
}
As an example, let’s use the character ‘Z’, or ASCII value 90. Because ‘Z’ is uppercase, the value of base
will be ‘A’, or ASCII value 65. Subtracting 65 from 90 gives us 25, and adding 13 gives us 38. Reducing by modulo 26 gives us a value of 12 and reduces the number to be within the range of the English alphabet which consists of 26 letters. Assuming A = 0
, the letter that corresponds to the number 12 would be ‘M’. Adding the base value of 65 shifts the number 12 to its corresponding ASCII value of 77, otherwise known as the ASCII character ‘M’.
The key part of this function is the transformation on the characters in the input string. The use of base
is a way to convert to and from ASCII values, but the shifting of characters by 13 places and reduction by modulo 26 is also known as a ROT13 cipher. The properties of ROT13 allows for decoding to occur by applying the cipher twice, which we can do to the encoded flag to reveal its initial value. We can perform this decoding process through use of an external tool or by supplying the encoded flag as input to the script and printing out the result.
Once we perform the decoding process, we get the flag:
MetaCTF{cappuccino_with_a_rotation_of_cream_please}
Outsourcing the Solution
Another way to decode the flag is to let something else do the work for us. If we take the encoded string and plug it into something like dCode’s Cipher Identifier, we see that the top suggestion is the ROT13 cipher. Opening a ROT13 tool and decoding the encoded string reveals the flag.