OWASP MSTG Crackme 2 writeup (Android)
The application
├── owasp
│ └── mstg
│ └── uncrackable2
│ └── R.java
└── sg
└── vantagepoint
├── a
│ ├── a.java
│ └── b.java
└── uncrackable2
├── CodeCheck.java
└── MainActivity.java
As we can see, the structure is very similar to the previous challenge, but there is a new file CodeCheck.java
. When we inspect the content of MainActivity.java
we can see how the root detection is handled (same as in the previous challenge), and how the secret is checked. The function verify
handles the secret checks
//MainActivity.java
public void verify(View view) {
String str;
String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
AlertDialog create = new AlertDialog.Builder(this).create();
if (this.m.a(obj)) {
create.setTitle("Success!");
str = "This is the correct secret.";
} else {
create.setTitle("Nope...");
str = "That's not it. Try again.";
}
create.setMessage(str);
create.setButton(-3, "OK", new DialogInterface.OnClickListener() {
/* class sg.vantagepoint.uncrackable2.MainActivity.AnonymousClass3 */
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
});
create.show();
}
where this.m.a(obj)
is the function that will check whether the secret is the right one.
Who is this.m?
MainActivity
class definition, we see
private CodeCheck m;
static {
System.loadLibrary("foo");
}
where the CodeCheck
class declares a function that is implemented from the native library foo
.
private native boolean bar(byte[] bArr);
CodeCheck native function
bar
function we will:- rename the .apk in .zip
- extract the native module
lib/libfoo.so
reverse it using Ghidra
Ghidra
libfoo.so
Java_sg_vantagepoint_uncrackable2_CodeCheck_bar
that will check whether – the input string has 23 chars (0x17
) – the string in input matches the secret using the strncmp
function.strncmp
function used in libfoo.so
.Frida
strcmp
function, we need first to get rid of the root detection block.Root detection control bypass
onClick
event of the OK button, to avoid that the application will call System.exit(0)
.
/*
Dirty way of bypassing the root detection, avoiding the app to close.
*/
Java.perform(function() {
console.log("[*] Hijacking the onClick button")
var clazz_main = Java.use('sg.vantagepoint.uncrackable2.MainActivity$1')
clazz_main.onClick.implementation = function () {
console.log('onCLick() is replaced ');
};
});
Clicking OK will close the dialog, while the app will still run.
Exploit
The strncmp function has the following signature:
int strncmp(char *__s1,char *__s2,size_t __n)
and is used in our Java_sg_vantagepoint_uncrackable2_CodeCheck_bar
function in this way
iVar1 = strncmp(__s1,(char *)&local_30,0x17);
*__s1
is the text passed in input from the user(char *)&local_30
is the secret we are looking for0x17
is the length (23 bytes)
*__s1
matches our string I want your secret asap
function extractSecret(){
/*
To use this function, we need to pass in input an argument with 23 chars. We chose: I want your secret asap
*/
console.log()
console.log('[*] ACTION NEEDED: Insert the string "I want your secret asap" as input')
console.log()
setTimeout(function(){
Interceptor.attach(Module.findExportByName('libfoo.so', 'strncmp'),{
onEnter: function(args){
if( Memory.readUtf8String(args[1]).length == 23 && Memory.readUtf8String(args[0]).includes("I want your secret asap")){
console.log()
console.log()
console.log("*******SECRET********")
console.log(Memory.readUtf8String(args[1]))
console.log("*******SECRET********")
console.log()
console.log()
}
},
onLeave: function(retval){
}
});
},2000);
}
Once we call the function via Frida, and insert our magic string, the secret will be printed in the console
and when we insert the new secret in the input field we see
The full script can be downloaded from our repo https://github.com/dcodx/owasp-mstg-crackme