# HTB | Angler

Machine -[https://app.hackthebox.com/challenges/Angler](https://app.hackthebox.com/challenges/Angler)/

File - Angler.apk

**Skill Learned**

* Learn how to trigger BATTERY\_LOW events.
* Become more experienced in hooking function arguments with Frida.

## Enumeration

### Running the application

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FBLfCZ8xnHv9Ehgior8ZY%2Fimage.png?alt=media&#x26;token=2d33202e-0895-46f7-8763-32f32a3f84a0" alt=""><figcaption><p>application</p></figcaption></figure>

From the application, it looks like it is a one-page app, and 100% maybe indicating battery (?)

### Triggering LOW\_Battery Intent

on analysing the code via jadax we can see registered event "android.intent.action.BATTERY\_LOW"

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FxZfJN8wYwMOWKYEKsGVg%2Fimage.png?alt=media&#x26;token=33368d98-624a-4080-8f1f-165c03f52913" alt=""><figcaption><p>Batter low intent</p></figcaption></figure>

But to invoke this intent, we have broadcast the data along with it.

> Android has [intent action](http://developer.android.com/guide/topics/security/permissions.html) for broadcast receiver. [BroadCast receiver](http://developer.android.com/reference/android/content/BroadcastReceiver.html) will be trigger when it listen any action which registered within it.

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fy9o7PfLwjBKNtIYm3Scw%2Fimage.png?alt=media&#x26;token=5c836a48-b805-4056-8e6a-5aed8601fb73" alt=""><figcaption></figcaption></figure>

For calling this Intent, we will use `adb`

```
PS D:\htb\Angler> adb shell am broadcast -a "android.intent.action.BATTERY_LOW" --es "Is_on" "yes"
```

where,

* **am**: for activity manager
* **broadcast**: for sending a broadcast message
* **a**: for intent action
* **es**: for an extra of type string.

This will trigger the intent and display the screen below

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FLcvDd3nm5HgaRrD5aHZ8%2Fimage.png?alt=media&#x26;token=45a0a150-a5b0-4f79-b116-b7291638f69a" alt=""><figcaption></figcaption></figure>

We can see a toast `Look me inside` (logs ?)

Let’s go to logcat and see the logs for `com.example.angler` and we can see `I am not here, I am there` (there means code ?)

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FOj5QU0RWNErULHYbHgQW%2Fimage.png?alt=media&#x26;token=37dc15fe-a559-477e-9e27-d98288693675" alt=""><figcaption></figcaption></figure>

### Decompiling the library

On checking the code, we found the native library being loaded

```
    static {
        System.loadLibrary("angler");
    }
```

* This is a **static block**, executed when the class is loaded.
* `System.loadLibrary("angler")` loads a **native shared library** (e.g., `libangler.so` on Linux, `angler.dll` on Windows, or `libangler.dylib` on macOS).
* The name passed does **not include** the `lib` prefix or file extension; the JVM handles that based on the OS.

We found the `libangler.so` in Resources/lib/x86\_64/

We can disassemble this library file using a tool called Ghidra. We have to mind that about the architecture of the device, the app is installed when we disassemble it. Then we discover where that method is implemented.

We can see that `getInfo()` is calling two functions `illusion` and `ne`

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FxHewpd66F3E8yJ5w1hjn%2Fimage.png?alt=media&#x26;token=90514559-78df-499e-a7ba-54b7f24b3e4c" alt=""><figcaption></figcaption></figure>

**illusion**

In this, we can see the initial value of the flag (which is obvious since it is called first)

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FFSeWySO5GE5AxJRsGuZl%2Fimage.png?alt=media&#x26;token=502826c9-629a-4954-b8bf-65c0a600a675" alt=""><figcaption></figcaption></figure>

**ne**

In the below code, there is a string that was discovered before in the logcat, and there is another string which says `You found the flag`. These two strings are returned after strcmp. We can try to hook this up with Frida and see the copied string

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2FNkOS0Y8JFZhui5DGYeJe%2Fimage.png?alt=media&#x26;token=095a7ec9-57f2-423c-b288-312695c91e1c" alt=""><figcaption></figcaption></figure>

## Exploitation using Frida

Our next step is to figure out what the strings are being compared in the above code.

In order to achieve this, we need to hook on strcmp function, but there are two challenges here:

* One, we need to make sure the strcmp is the actual name of the function being imported.
* Two which is the main problem here is how we can hook into a native method that is not being declared in the Java Code.

To solve the first challenge, we can simply list the exports and the imports of the shared object.

```
[Android Emulator 5554::Angler ]-> Module.enumerateExports("libangler.so")

[Android Emulator 5554::Angler ]-> Module.enumerateImports("libangler.so")
```

but the above output is so big that I was unable to get the full content. We can use below JS for copying the content into a text file

```
//for Export

// Enumerate the exports of libangler.so module and print the JSON
Module.enumerateExports("libangler.so", {
  onMatch: function (exp) {
    // Directly print the export details in JSON format
    console.log(
      JSON.stringify({
        name: exp.name,
        address: exp.address.toString(),
        type: exp.type,
      })
    );
  },
  onComplete: function () {
    console.log("Enumeration Complete");
  },
});


//for Imports

// Enumerate the Import of libangler.so module and print the JSON
Module.enumerateImports("libangler.so", {
  onMatch: function (exp) {
    // Directly print the export details in JSON format
    console.log(
      JSON.stringify({
        name: exp.name,
        address: exp.address.toString(),
        type: exp.type,
      })
    );
  },
  onComplete: function () {
    console.log("Enumeration Complete");
  },
});

```

```
PS D:\htb\Angler> frida -U Angler -l .\Module_exports.js | tee output_export.json
PS D:\htb\Angler> frida -U Angler -l .\Module_imports.js | tee output_import.json

```

We found `strcmp` in Imports

```
{"name":"strcmp","address":"0x793e9a463820","type":"function"}
```

Now all that is left is to figure out a way to hook and monitor the native library methods.

Since we found the **imported `strcmp`** address in `libangler.so`, and the flag is being passed as the **second argument (`args[1]`)** to `strcmp`

Let’s write a **Frida script** that hooks **that specific import**, logs only when `strcmp` is called from `libangler.so`, and prints the second argument, which should be the flag.

```
// Replace this with the exact import address of strcmp in your lib
var strcmpAddr = ptr("0x793e9a463820");

Interceptor.attach(strcmpAddr, {
    onEnter: function (args) {
        try {
            var str1 = Memory.readUtf8String(args[0]);
            var str2 = Memory.readUtf8String(args[1]);

            console.log("[*] strcmp called");
            console.log("    Arg1: " + str1);
            console.log("    Arg2: " + str2);  // ← Likely the flag
        } catch (err) {
            console.log("Error reading strcmp args:", err);
        }
    }
});
```

Now we need to run the Frida, and then we need to trigger the broadcast receiver that will trigger getInfo(), that will trigger ne(), that will trigger strcmp.

```
//run Frida
PS D:\htb\Angler> frida -U Angler -l .\flag_script.js

//trigger the broadcast
PS D:\Andriod_Studio\testapp> adb shell am broadcast -a "android.intent.action.BATTERY_LOW" --es "Is_on" "yes"
Broadcasting: Intent { act=android.intent.action.BATTERY_LOW flg=0x400000 (has extras) }
Broadcast completed: result=0
PS D:\Andriod_Studio\testapp> 

```

And we got the flag (need to [convert](https://www.rapidtables.com/convert/number/hex-to-ascii.html) the hexadecimal to text)

<figure><img src="https://2050535832-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FC1JOqzbmZkOvdQTzItEo%2Fuploads%2Fxa5PRjZ14vFjQA3Ehq8A%2Fimage.png?alt=media&#x26;token=4fa63f16-e8bc-4a74-adf2-142b9ce4a76f" alt=""><figcaption></figcaption></figure>
