[SharifCTF] REV300 Catch Me If You Can
This challenge was pretty intresting since I didn’t foud the flag in the first 30 seconds like the 3 previous one.
Okay, first things ou can download the sample here : Login.apk.tar.xz
Right, an APK ! an Android Package !
Thirst thing I did i to disassemble it, with dex2jar and jd-gui.
So get a look at the first class ( you can see the ):
package sharif.cert.ctf;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.TextView;
class a
implements View.OnClickListener {
a(MainActivity paramMainActivity) {}
public void onClick(View paramView) {
new String(" ");
paramView = this.a.b.getText().toString(); // Retrieve user input
paramView = this.a.a(paramView);
int i = this.a.processObject(paramView); // Call a strange method (processObject())
if ((i == 1) && (this.a.e != "unknown")) {
this.a.c.setText("Congratulations!");
}
if ((i == 1) && (this.a.e == "unknown")) {
this.a.c.setText("Just keep Trying :-)");
}
if (i == 0) {
this.a.c.setText("Just keep Trying :-)");
}
}
}
We can see that the processObject()
method is not declared inside all the class we found .. But look at this class :
package sharif.cert.ctf;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity
extends Activity {
Button a;
EditText b;
TextView c;
int d = 123;
String e = "Code";
static {
System.loadLibrary("validation"); // What is this ?
}
public String a(String paramString) {
return new HidingUtil().hide(paramString); // get a look at HidingUtils()
}
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2130968600);
this.a = ((Button) findViewById(2131492942));
this.b = ((EditText) findViewById(2131492941));
this.c = ((TextView) findViewById(2131492943));
this.e = Build.SERIAL;
this.a.setOnClickListener(new a(this));
}
public native int processObject(String paramString);
}
Okay what is loadLibrary ? by looking at the fabulous Internet, I found some documentation about Loading native code to an Android Mobile Application.
So look at the HidingUtils code :
#include <string.h>
#include <jni.h>
#include "Base64Util.h"
#include <android/log.h>
static unsigned char passwordKey[] = "My_S3cr3t_P@\$\$W0rD";
void xor_value_with_key(const char* value, char* xorOutput){
int i = 0;
while(value[i] != '\0'){
int offset = i % sizeof(passwordKey);
xorOutput[i] = value[i] ^ passwordKey[offset];
i++;
}
}
/**
* com.apothesource.hidingpasswords.HidingUtil.hide
*
* This function uses a hard-coded password to XOR hide (encrypt) a provided message.
*
*/
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
char xorOutput[BUFFFERLEN + 1] = "";
xor_value_with_key(nativeString, xorOutput);
char encodedoutput[BUFFFERLEN + 1] = "";
Base64Encode(xorOutput, encodedoutput, BUFFFERLEN);
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
return (*env)->NewStringUTF(env, encodedoutput);
}
/*
* com.apothesource.hidingpasswords.HidingUtil.unhide
*
* This function uses a hard-coded password to XOR unhide (decrypt) a provided message.
*
* jstring Java_com_apothesource_hidingpasswords_HidingUtil_unhide(JNIEnv_ env, jobject thiz,
* jstring javaString) {
*/
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
char decodedoutput[BUFFFERLEN + 1] = "";
Base64Decode(nativeString, decodedoutput, BUFFFERLEN);
char xorOutput[BUFFFERLEN + 1] = "";
xor_value_with_key(decodedoutput, xorOutput);
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
return (*env)->NewStringUTF(env, xorOutput);
}
A Simple xor function sets tho ! So now we know that the java application contains some .so for HidingUtils.
I did a simple binwalk extracting and I found something intresting (by extracting Login.apk with binwalk):
[sakiir@SakiiR-PC test]$ file _Login.apk.extracted/lib/x86_64/libhidingutil.so
_Login.apk.extracted/lib/x86_64/libhidingutil.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=95bfd010a331f19445de63db36939c216aa32263, stripped
When I looked to the binary strings I found something relative to the encryption routine :
$ strings _Login.apk.extracted/lib/x86_64/libhidingutil.so
[...]
AUATI
[]A\A]A^A_
My_S3cr3t_P@$$W0rD
fx1uagMGQQMWOWhyFBxnBUdzN35NPWYHUBQHRmozeEY=
;*3$"
GCC: (GNU) 4.9.x 20150123 (prerelease)
gold 1.11
.shstrtab
.note.gnu.build-id
.dynsym
.dynstr
[...]
You can see that right after the Xor Encryption Key ( My_S3cr3t_P@$$W0rD ), a base64 string is present ! we have to find out why !
$ echo "fx1uagMGQQMWOWhyFBxnBUdzN35NPWYHUBQHRmozeEY=" | base64 -d | xxd
00000000: 7f1d 6e6a 0306 4103 1639 6872 141c 6705 ..nj..A..9hr..g.
00000010: 4773 377e 4d3d 6607 5014 0746 6a33 7846 Gs7~M=f.P..Fj3xF
mmmh nothing readable, let’s decrypt it with the super secret key ( My_S3cr3t_P@$$W0rD ) :
#!/usr/bin/python2
key = "My_S3cr3t_P@\$\$W0rD\x00"
flag = "fx1uagMGQQMWOWhyFBxnBUdzN35NPWYHUBQHRmozeEY=".decode("base64")
out = ""
i = 0
for c in flag:
out += chr(ord(c) ^ ord(key[i % len(key)]))
i += 1
print "SharifCTF{" + out + "}"
This code give us the flag ;)