Logo
De4flag

De4flag

Mr. Wan Mr. Wan
May 15, 2025
2 min read

de4flag-img-1

โจทย์นี้จะให้เราหา Flag ที่ซ่อนอยู่ใน App ออกมา แต่โจทย์นี้คือต้องแกะ Native library ออกมา

พอหลังดาวโหลดไฟล์ de4flag.apk และติดตั้งเข้า Androi Emulator จะเห็นหน้าเข้าสู่ระบบ

de4flag-img-2

แต่พอลองกรอกเข้าไปแล้วเจอขึ้ว่า ❌ Wrong credential

de4flag-img-3

ทีนี่เราก็ไม่รู้ Username & Password ว่าคืออะไร ดังนั้นจะใช้โปรแกรม JadX ในการ Decompile APK ออกมาเพื่อดู Source code ด้านในของ App

ทีนี้เราลองไปเช็คที่ AndroidManifest.xml เพื่อทราบชื่อ Package ว่าชื่ออะไร

de4flag-img-4

พอทราบว่าชื่อ Package คือ com.main.de4flagnative ก็จะไป Folder ที่ Source code > com > main > de4flagnative

de4flag-img-5

พอลองเช็คจะเห็นว่าตัว function SendToServer วิ่งไปยัง Host localhost:8000 ผมก็เลยลองจำลองเป็น HTTP Server ธรรมดาขึ้นมา และ reverse adb เข้าไปยัง Android Emulator

python3 -m http.server 8000
adb reverse tcp:8000 tcp:8000

แต่ลองทดสอบปรากฏว่า ก็ยังเหมือนเดิม ผมก็ “เอ๊ะ OwO! ได้ไงกันนะ” ผมก็ลองเปิด log โดยใช้ adb logcat ดูปรากฏว่า

3331 3331 I System.out: [Request] Sending login request to http://localhost:8000/login
3331 3331 I System.out: [Request] Failed to connect: Cleartext HTTP traffic to localhost not permitted

ก็เลยถึงบางอ้อ เลยเพราะเนื่องด้วยใน Android 9 (Pie) เป็นต้นมา มีการ บังคับใช้งาน Network Security Configuration เพื่อเพิ่มความปลอดภัย ปิดการอนุญาต HTTP แบบไม่เข้ารหัส (cleartext) ตามค่า default แล้วบังคับใช้เฉพาะ HTTPS (TLS/SSL) แทน

แต่ปัญหาคือ Code นี้ถูก Obfuscator มา + กลัวว่าหากไปแก้ Code อะไรจะทำให้ตัว Verify signature ไม่ผ่านทำให้แอพเด้งออก ก็เลยจะใช้ Frida ในการ Injection ใน function ที่ Android ถูกเรียกใช้งาน

โดยการเขียนผมจะเป็นดังนี้

Java.perform(() => {
const clsName = 'com.main.de4flagnative.DevCheck';
try {
const DevCheck = Java.use(clsName);
DevCheck.SecretVerify.overload('java.lang.String').implementation = function (value) {
console.log('[*] SecretVerify(String) ENTER');
console.log("[*] User: ", value);
return true;
};
console.log('[*] Hooked:', clsName + '.decodePromo(Context)');
} catch (e) {
console.log('[-] Hook setup error:', e);
}
});

โดย Script นี้จะทำการ Bypass การยิง API ไปยังเซิฟเวอร์ โดยให้กาาคืนค่าให้เป็น true แทน

และก็รันด้วย Script frida

frida -U -f com.main.de4flagnative -l ./de4flag.js

แต่พอลองแล้วรอบนี้ไม่เกิดอะไรขึ้น งั้นแสดว่า HTTP นี้คือหลอกติดกับดักสินะ OwO! แล้วต้องทำยังไงละทีนี้

ก็เลยลองไปอ่านดี ๆ

private boolean SecretVerify(String str) throws IOException {
if (!this.isDevDebug || this.authFailCount != 0) {
SendToServer(str);
this.authFailCount++;
return false;
}
if (str.equals("pass9876::myuser5555")) {
System.out.println("Secret value printed via Console Log");
new SecretFlag().print(str, this);
}
return true;
}

ผมก็เอ๊ะ Function มันก็ไม่ได้มีอะไร Action กับการเรียก Function ด้านล่าง แต่จะเห็นเงื่อนไขว่า !this.isDevDebug || this.authFailCount != 0 ก็เลยสันนิฐานว่าอันนี้คือหากไม่ใช้ Debug dev mode จะให้ยิงไปหา API แทน

ก็เลยลองปรับให้ไปยิงเข้า SecretFlag ตรง ๆ เลยว่าจะได้อะไรกลับมา

Final frida code

Java.perform(() => {
const clsName = 'com.main.de4flagnative.DevCheck';
try {
const DevCheck = Java.use(clsName);
let SecretFlag = Java.use("com.main.de4flagnative.SecretFlag");
DevCheck.SecretVerify.overload('java.lang.String').implementation = function (value) {
console.log('[*] SecretVerify(String) ENTER');
console.log("[*] User: ", value);
const pass = "pass9876::myuser5555";
let flag;
// Correct overload with two params
const p = SecretFlag.print.overload('java.lang.String', 'com.main.de4flagnative.DevCheck');
try {
// If print is static: receiver is the class wrapper; second arg is the *instance* (this)
flag = p.call(SecretFlag, pass, this);
} catch (e1) {
// If print is an instance method: create an instance and use that as receiver
try {
const sf = SecretFlag.$new();
flag = p.call(sf, pass, this);
} catch (e2) {
console.log('[-] Failed to invoke SecretFlag.print:', e1, e2);
return this.SecretVerify(value); // fallback to original if you want
}
}
console.log('[*] Flag =>', flag);
return true;
};
console.log('[*] Hooked:', clsName + '.decodePromo(Context)');
} catch (e) {
console.log('[-] Hook setup error:', e);
}
});

ทีนี้ลองใหม่

de4flag-img-6

STH{6ea68d9d69ead13e0a08c6b08a53a38f}

เย้! ได้ Flag ออกมาแย้ว >w< ”