Tags: reversing 

Rating: 5.0

# Object Oriented Programming

writeup by [haskal](https://awoo.systems) for [BLÅHAJ](https://blahaj.awoo.systems)

**413 points**
**88 solves**

>There's this small up and coming language called java I want to tell you about

provided file: <src.zip>

## writeup

we are given a zip file with java source. there's a Main.java and a bunch of 2-character source
files, with classes that contain a bunch of 2-character methods that return 2-character strings.
examining Main, we see it uses reflection to call into these classes and methods to map the input
string to the output.

String userInput = getUserInputMethodFromScannerAndInvokeAndReturnOutput(scanner);
if (userInput.length() != SIXTEEN)

if (executeCodeThatDoesSomethingThatYouProbablyNeedToFigureOut(userInput).equals(scanner.getClass().getPackageName().replace(".", ""))) {
invokePrintLineMethodForOutputPrintStream(outputPrintStream, printLineMethod, "Nice. Flag: rgbCTF{" + userInput + "}");
} else {
invokePrintLineMethodForOutputPrintStream(outputPrintStream, printLineMethod, "Try again.");

this code shows us the user input must be 16 chars exactly, and then a transformation function is
called (with the parameter `javautil`, the package of Scanner without periods).

public static String executeCodeThatDoesSomethingThatYouProbablyNeedToFigureOut(String stringToExecuteAforementionedCodeOn) throws Exception {
String encryptedString = reallyBasicQuoteUnquoteEncryptionFunctionThatWillOnlyTakeTimeToFigureOutIfYouKeepReadingTheseRidiculouslyLongMethodNames(stringToExecuteAforementionedCodeOn);
String returnValueOfThisFunction = new String();
String[] chunksOfEncryptedStringOfLengthFour = splitStringIntoChunksOfLength(encryptedString, FOUR);
for (String chunkOfEncryptedStringOfLengthFour : chunksOfEncryptedStringOfLengthFour) {
String[] chunksOfChunkOfEncryptedStringOfLengthFourOfLengthTwo = splitStringIntoChunksOfLength(chunkOfEncryptedStringOfLengthFour, TWO);
String firstChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo = chunksOfChunkOfEncryptedStringOfLengthFourOfLengthTwo[0];
String secondChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo = chunksOfChunkOfEncryptedStringOfLengthFourOfLengthTwo[1];
Class classAndExtraCharactersSoItsNotAKeyword = Class.forName(firstChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo);
Object object = classAndExtraCharactersSoItsNotAKeyword.getConstructors()[ZERO].newInstance();
for (int loopArbitraryCounterIterator = 0; loopArbitraryCounterIterator < THREE; loopArbitraryCounterIterator++) {
Method method = classAndExtraCharactersSoItsNotAKeyword.getMethod(secondChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo);
secondChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo = (String)method.invoke(object);
returnValueOfThisFunction = new String(returnValueOfThisFunction + secondChunkOfChunkOfEncryptedStringOfLengthFourOfLengthTwo);
return returnValueOfThisFunction;

looking at the transformation function, we find it calls a method that XORs all the characters in
the input with a key, which turns out to be `2` (found by modifying the code to print it out). then,
it splits the input into chunks of 4, uses the first 2 chars as a class name, and iterates 3 times
to transform the second 2 chars by calling the method in the class. the result is concatenated
together. this can be solved with a simple script to parse the java files to map the
transformations, then reversing the transformation by doing the opposite of this operation.

first, parse the java. it's very regular so this isn't too hard

mapping = {}

for file in pathlib.Path("src").iterdir():
if "Main" in file.name:
name = file.name.replace(".java", "")
with file.open("r") as f:
data = f.read()
thisfile = {}
mname = None
for line in data.split("\n"):
if mname is None:
if "public String" in line:
mname = line.strip().split(" ")[2].replace("()", "")
val = line.strip().split(" ")[1].replace('"', "").replace(";", "")
thisfile[mname] = val
mname = None
mapping[name] = thisfile


next, go through backwards to find which class has 3 methods that can be chained to produce the
required output. (implemented this with horrible CTF spaghetti code, please don't tell my fundies
professor :)

start = "javautil"

def rfind(what):
for file,data in mapping.items():
for k,v in data.items():
if v == what and k in data.values():
for k2, v2 in data.items():
if v2 == k and k2 in data.values():
for k3, v3 in data.items():
if v3 == k2:
return file + k3

data = rfind("ja") + rfind("va") + rfind("ut") + rfind("il")

finally compute XOR for the flag

data = bytearray(data.encode())
for i in range(len(data)):
data[i] ^= 2


see original writeup for full source

Original writeup (https://git.lain.faith/BLAHAJ/writeups/src/branch/writeups/2020/rgbctf/oop/README.md).