diff --git a/oats1/README.md b/oats1/README.md new file mode 100644 index 0000000..85528d2 --- /dev/null +++ b/oats1/README.md @@ -0,0 +1,7 @@ +# oats1 +## Text +The first 'oats' challenge is the easiest one. Take a look at the APK. +## Files +[oats1.apk](oats1.apk) +## How to Deploy +n/a \ No newline at end of file diff --git a/oats1/SOLUTION.md b/oats1/SOLUTION.md new file mode 100644 index 0000000..23dc4c2 --- /dev/null +++ b/oats1/SOLUTION.md @@ -0,0 +1,14 @@ +## Difficulty +Easy +## Category +Reverse Engineering +## How To Solve +When you run the app on an android device/emulator, you immediately notice that you won't find the flag in the app itself. + +Instead, you need to use a tool like `apktool` to reverse engineer the APK file. Running `apktool d oats1.apk` will decode the file. Grep "IGCTF" in the obtained folder to discover the flag. +``` +> grep -r "IGCTF" . +./smali_classes3/com/example/oats/MainActivityKt.smali: const-string v14, "IGCTF{Unus3d_vari4bl3}" +``` +## Flag +`IGCTF{Unus3d_vari4bl3}` \ No newline at end of file diff --git a/oats1/oats1.apk b/oats1/oats1.apk new file mode 100644 index 0000000..17cfe0e Binary files /dev/null and b/oats1/oats1.apk differ diff --git a/oats2/README.md b/oats2/README.md new file mode 100644 index 0000000..ac6920a --- /dev/null +++ b/oats2/README.md @@ -0,0 +1,7 @@ +# oats2 +## Text +Second oats challenge. +## Files +[oats2.apk](oats2.apk) +## How to Deploy +n/a \ No newline at end of file diff --git a/oats2/SOLUTION.md b/oats2/SOLUTION.md new file mode 100644 index 0000000..9251955 --- /dev/null +++ b/oats2/SOLUTION.md @@ -0,0 +1,25 @@ +## Difficulty +Easy +## Category +Reverse Engineering +## How To Solve +When you run the app on an android device/emulator, you see that you are not a nice person. You will need to reverse engineer the APK to discover the flag. + +This time, you can use [JADX](https://github.com/skylot/jadx) to analyze the APK. After performing `jadx oats2.apk`, you will be able to navigate to a file named `MainActivityKt.java` located somewhere under `sources/`. The following function provides you with the flag when you are nice: +```java +public static final void Greeting$showFlag(MutableState mutableState, boolean isNice) { + if (isNice) { + int num2 = 42 + 58; + int num3 = (num2 * 42) + num2; + String[] array = {"zefiluhfz", "nelsqefvon", "maqzpeiuvfbqddela", "vcnbdqiyfub", "camw33pus", "woohvfdowinoo", "oiuyqecqer", "lusg9876hdfskj", "igc", "tf"}; + String fContent = array[8] + array[9] + '{' + array[num3 % array.length] + array[(num3 * num2) % array.length]; + String flag = fContent + '}'; + mutableState.setValue(flag); + return; + } + mutableState.setValue("NOPE"); +} +``` +In order to obtain the flag, you can either modify and recompile entire source code, or simply copy, compile and execute only the function itself. +## Flag +`igctf{zefiluhfzzefiluhfz}` \ No newline at end of file diff --git a/oats2/oats2.apk b/oats2/oats2.apk new file mode 100644 index 0000000..a3bdb30 Binary files /dev/null and b/oats2/oats2.apk differ diff --git a/oats3/README.md b/oats3/README.md new file mode 100644 index 0000000..4cc47df --- /dev/null +++ b/oats3/README.md @@ -0,0 +1,7 @@ +# oats3 +## Text +Third oats challenge. Find the missing topping! +## Files +[oats3.apk](oats3.apk) +## How to Deploy +n/a \ No newline at end of file diff --git a/oats3/SOLUTION.md b/oats3/SOLUTION.md new file mode 100644 index 0000000..f986b72 --- /dev/null +++ b/oats3/SOLUTION.md @@ -0,0 +1,80 @@ +## Difficulty +Difficult +## Category +Reverse Engineering +## How To Solve +You can again use any utility you like to analyze the APK; in this writeup we use [JADX](https://github.com/skylot/jadx). Decompile the APK using `jadx oats3.apk`. + +Open the the `MainActivity.java` file in the obtained folder, and take a look at the following lines. This is where the toppings are defined. +```java +public void onCreate(Bundle savedInstanceState) { + ... + String oats3 = getIntent().getStringExtra("oats3"); + final Ref.ObjectRef oatsToppings = new Ref.ObjectRef(); + oatsToppings.element = new String[]{"Peanut butter", "Strawberry", "Sugar", "Honey", "Peach", "Blueberry", "Pear"}; + if (Intrinsics.areEqual(oats3, "oats3")) { + oatsToppings.element = gmFunc.ensure((String[]) oatsToppings.element, gmFunc.function((String[]) oatsToppings.element, oats3, ((Object[]) oatsToppings.element).length, Random.INSTANCE.nextInt())); + } else { + oatsToppings.element = gmFunc.ensureNot((String[]) oatsToppings.element, gmFunc.nofunction((String[]) oatsToppings.element, "oats3", Random.INSTANCE.nextInt())); + } + ... +} +``` +You might want to try to find out what the `ensure`, `ensureNot`, `function` and `nofunction`, methods are doing. However, we intentionally obfuscated their functionality, so this might not be the easiest path towards the flag. + +You may notice that an extra string is retrieved from the [intent](https://developer.android.com/reference/android/content/Intent). That string is then compared to the string `oats3", determining the rest of the program. By default, intents have no 'extra' values. Hence, we need to make sure that the MainActivity is started with an extra value. In this case, both the key and the value need to be "oats3". + +When you take a look at the `AndroidManifest.xml`file, you can see the following lines containing intent filters that guide deep links into `MainActivity` using the scheme `app_scheme://flags.all`. +```xml + + ... + + + + + + + +``` + +You can also see from this file that the app's package name is `com.example.oats`. + +This information suffices to write our own small app that launches the Oats app and starts the `MainActivity` with an extra string payload. Here is an example of a function you might need in this app: +```java +private fun launchOtherAppActivity() { + val packageName = "com.example.oats" // Replace with the target app's package name + val scheme = "app_scheme" + val host = "flags.all" + + val intent = Intent(Intent.ACTION_VIEW) + val uri = Uri.parse("$scheme://$host") + intent.data = uri + + // Set the oats3 payload + intent.putExtra("oats3", "oats3") + + // Set the flag to launch the activity in a new task + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + + // Check if the app is installed before launching + val packageManager = packageManager + val isAppInstalled = packageManager.getLaunchIntentForPackage(packageName) != null + + if (isAppInstalled) { + startActivity(intent) + } +} +``` +Also don't forget to add the following lines to your `AndroidManifest.xml`. You won't be able to launch the other application without this: +```xml + + + +``` +This write-up also contains a full [write-up apk](oats3_writeup.apk) that can be used to perform flag extraction. + +When you run the exploit app, you are immediately redirected to the Oats app. However, you can now see another topping added at the bottom of the list: `SUdDVEZ7TzR0c193MXRoX00xbGt9`. Enter this value into [CyberChef](https://gchq.github.io/CyberChef/#input=U1VkRFZFWjdUelIwYzE5M01YUm9YMDB4Ykd0OQ) and you can obtain the flag. +![](screenshot1.png) + +## Flag +`IGCTF{O4ts_w1th_M1lk}` \ No newline at end of file diff --git a/oats3/TODO.md b/oats3/TODO.md new file mode 100644 index 0000000..2c1db90 --- /dev/null +++ b/oats3/TODO.md @@ -0,0 +1,2 @@ +# TODO +- [ ] Check whether code needs more advanced obfuscation in order to force participants to write their own 'exploit app' \ No newline at end of file diff --git a/oats3/oats3.apk b/oats3/oats3.apk new file mode 100644 index 0000000..f6a8aa1 Binary files /dev/null and b/oats3/oats3.apk differ diff --git a/oats3/oats3_writeup.apk b/oats3/oats3_writeup.apk new file mode 100644 index 0000000..0cf17e7 Binary files /dev/null and b/oats3/oats3_writeup.apk differ diff --git a/oats3/screenshot1.png b/oats3/screenshot1.png new file mode 100644 index 0000000..86fd8da Binary files /dev/null and b/oats3/screenshot1.png differ