From 9c73ebae99952c7fff6f561643a301461d062a9c Mon Sep 17 00:00:00 2001 From: haskal Date: Tue, 14 Jul 2020 03:04:55 -0400 Subject: [PATCH] 2020: rgbctf: oop --- 2020/rgbctf/oop/README.md | 116 ++++++++++++++++++++++++++++++++++++++ 2020/rgbctf/oop/decode.py | 46 +++++++++++++++ 2020/rgbctf/oop/src.zip | Bin 0 -> 7011 bytes 3 files changed, 162 insertions(+) create mode 100644 2020/rgbctf/oop/README.md create mode 100644 2020/rgbctf/oop/decode.py create mode 100644 2020/rgbctf/oop/src.zip diff --git a/2020/rgbctf/oop/README.md b/2020/rgbctf/oop/README.md new file mode 100644 index 0000000..7d33bbe --- /dev/null +++ b/2020/rgbctf/oop/README.md @@ -0,0 +1,116 @@ +# Object Oriented Programming + +writeup by [haskal](https://awoo.systems) for [BLĂ…HAJ](https://blahaj.awoo.systems) + +**Pwn/Rev** +**413 points** +**88 solves** + +>There's this small up and coming language called java I want to tell you about + +provided file: + +## 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. + +```java + String userInput = getUserInputMethodFromScannerAndInvokeAndReturnOutput(scanner); + if (userInput.length() != SIXTEEN) + System.exit(0); + + 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). + +```java + 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 + +```python +mapping = {} + +for file in pathlib.Path("src").iterdir(): + if "Main" in file.name: + continue + 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("()", "") + else: + 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 :) + +```python +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 + +```python +data = bytearray(data.encode()) +for i in range(len(data)): + data[i] ^= 2 + +print(data) +``` diff --git a/2020/rgbctf/oop/decode.py b/2020/rgbctf/oop/decode.py new file mode 100644 index 0000000..596ae38 --- /dev/null +++ b/2020/rgbctf/oop/decode.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +import pathlib + +mapping = {} + +for file in pathlib.Path("src").iterdir(): + if "Main" in file.name: + continue + 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("()", "") + else: + val = line.strip().split(" ")[1].replace('"', "").replace(";", "") + thisfile[mname] = val + mname = None + mapping[name] = thisfile + +import pprint +pprint.pprint(mapping) + +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") + +data = bytearray(data.encode()) +for i in range(len(data)): + data[i] ^= 2 + +print(data) diff --git a/2020/rgbctf/oop/src.zip b/2020/rgbctf/oop/src.zip new file mode 100644 index 0000000000000000000000000000000000000000..38e54a2e07fe8cc93b58183d48620157627c4a4b GIT binary patch literal 7011 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 literal 0 HcmV?d00001