Tags: reversing android
Rating: 5.0
# DCTF 2022 - UseForce
## Introduction
- We are given a file, `app-release.apk` and a hint: `'Are Dragons Bulletproof?'`.
- I have never worked with an APK file as, my RE skills have never expanded beyond the classic PE/EXE. Really stepped out of my comfort zone for this one. Which I am glad I did.
## Intiital research
- We can use [apktool](https://ibotpeaches.github.io/Apktool/) to unzip and have a look at source files.
- This really didn't offer much help, except looking at the [.smali](https://mobsecguys.medium.com/smali-assembler-for-dalvik-e37c8eed22f9) files.
- Smali is the assembly code for Android's VM.
- We can use [ByteCode-Viewer](https://github.com/Konloch/bytecode-viewer) to disassemble the package and see the code in java syntax which made reading the code much easier. Comparison:
##### Smali (app-release/com/dctf/useforce/MainActivity$2.smali)
``` smali
.class Lcom/dctf/useforce/MainActivity$2;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Landroid/view/View$OnClickListener;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/dctf/useforce/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/dctf/useforce/MainActivity;
.field final synthetic val$editText:Landroid/widget/EditText;
# direct methods
.method constructor <init>(Lcom/dctf/useforce/MainActivity;Landroid/widget/EditText;)V
.locals 0
.line 45
iput-object p1, p0, Lcom/dctf/useforce/MainActivity$2;->this$0:Lcom/dctf/useforce/MainActivity;
iput-object p2, p0, Lcom/dctf/useforce/MainActivity$2;->val$editText:Landroid/widget/EditText;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 2
.line 49
new-instance p1, Ljava/lang/StringBuilder;
invoke-direct {p1}, Ljava/lang/StringBuilder;-><init>()V
const-string v0, "check: "
invoke-virtual {p1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
iget-object v0, p0, Lcom/dctf/useforce/MainActivity$2;->this$0:Lcom/dctf/useforce/MainActivity;
iget-object v1, p0, Lcom/dctf/useforce/MainActivity$2;->val$editText:Landroid/widget/EditText;
invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v1
invoke-virtual {v0, v1}, Lcom/dctf/useforce/MainActivity;->a(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
invoke-virtual {p1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {p1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p1
const-string v0, "MainActivity"
invoke-static {v0, p1}, Landroid/util/Log;->w(Ljava/lang/String;Ljava/lang/String;)I
return-void
.end method
```
##### Java (app-release/com/dctf/useforce/MainActivity$2.class)
``` java
package com.dctf.useforce;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
class MainActivity$2 implements View.OnClickListener {
final MainActivity this$0;
final EditText val$editText;
MainActivity$2(MainActivity var1, EditText var2) {
this.this$0 = var1;
this.val$editText = var2;
}
public void onClick(View var1) {
StringBuilder var2 = new StringBuilder();
var2.append("check: ");
var2.append(this.this$0.a(this.val$editText.getText().toString()));
Log.w("MainActivity", var2.toString());
}
}
```
- We can emulate the Android package with [Anbox](https://anbox.io/).
- We can also interface with that emultaor using [adb](https://developer.android.com/studio/command-line/adb).
- This has us at a good spot. We can now look at source, disassemble byte-code, emulate the package, and interact with the emulator / application.
## Setup
- We install the tools via the steps supplied on the sites we visited.
- We can then install the app with the command: `sudo adb install app-release.apk`.
- Open `anbox` and launch the `useforce` application.
- We can see the emulator is up by running the command: `adb devices`.
``` bash
$ adb devices
List of devices attached
emulator-5558 device
```
- Launching the application we are greeted with a somewhat simple flag checker:
![first launch](images/application_launched.png)
## The Fun Part: Reversing the Applicaiton
- First thing to do is see how the application responded to input. We input text, click check, and nothing happens. Not a very exciting first experience.
- Using the disassembler, `Bytecode-Viewer`, not much stuck out inititally, except for one line:
``` java
import android.util.Log;
```
- I attempted to connect to the process for debugging with adb, but had no luck.
- Next thing to do is try and search for logs the application is writing to
- adb has a command which allows us to read system logs: `logcat`.
- We use the command and can see usefule data:
![logcat first](images/logcat_first.png)
- We can see the application is writing to these logs and of use we see: `UseForce: you're too short or to long!`
- We can carve out these specific log entries for the application with the command: `adb shell logcat | grep "UseForce"`
- Next step is to see if we can determine the length of the flag. This is can be done by iterively adding a character until something in the logs change:
![found length](images/found_length.png)
- We found the length of the flag is 23 characters.
- We also know the given format for the flag will start with `dctf{` and ends with `}`.
![partial_flag](images/some_flag_correct.png)
- We notice in the logs something changes. At indexes `0,1,2,3,4` and `22`, the value changes from `0` to `1`. We can assume this is the program logging we have the characters at those indexes correct. That's a good sign. The challenge gets significantly easier from here and isn't as much of a 'black box' anymore.
- We know from the flag format, the format inside the brackets will be any of the following characters: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`.
- Now we can iterate through the indexes of the flag and try each character until all indexes reflect `1` or we are given some sort of `success` message in the logs.
- Luckily [pwntools](https://docs.pwntools.com/en/stable/adb.html) has an adb framework baked in that we can use.
- Next we create a program to interact with the application to change the flag, check it, then repeat the process over and over until it is correct!
![solved](images/solved.png)
- I came up with three iterative solutions (`slow_solpy`, `fast_sol.py`, `fastest_sol.py`).