# OWASP Android Uncrackable Ở bài này ta sẽ đi crack mấy app android để lấy flag ở link sau bằng cách sử dụng Frida https://mas.owasp.org/crackmes/Android/ ## Android UnCrackable L1 ![](https://i.imgur.com/ppw9WQK.png) Khi install app, mở lên ta sẽ bị detect root: ![](https://i.imgur.com/Z2txs0Y.png) Dùng JADX-GUI để load source code, và search chữ root trong source code thì thấy được đoạn code detect root nằm ở đây: ![](https://i.imgur.com/H2bvvMO.png) Nếu 1 trong 3 method a, b, c trong class c return True thì sẽ in ra root detected. ![](https://i.imgur.com/h6Q153o.png) Không cần biết các method này làm gì, bây giờ ta chỉ cần hook để nó return false hết là được Python: ```python= import frida import time device = frida.get_usb_device() pid = device.spawn(["owasp.mstg.uncrackable1"]) device.resume(pid) time.sleep(1) session = device.attach(pid) script = session.create_script(open("un1.js").read()) script.load() #prevent the python script from terminating input() ``` Frida script: ```java= Java.perform(function () { var checkRoot = Java.use("sg.vantagepoint.a.c"); checkRoot.a.implementation = function() { return false; }; checkRoot.b.implementation = function() { return false; }; checkRoot.c.implementation = function() { return false; }; }); ``` Nhưng lại không thành công. Đó là do method này sẽ chỉ chạy 1 lần ngay khi start. ![](https://i.imgur.com/6MOFrpp.png) Do đó nếu muốn hook thành công ta phải hook đúng ngay lúc chương trình start. Bằng cách dùng command sau: ``` frida -U -f owasp.mstg.uncrackable1 -l un1.js ``` Command này sẽ chỉ target vào package `owasp.mstg.uncrackable1`, nếu ta muốn khởi chạy app cần phải nhập vào %resume để tiếp tục process. Và khi nhập %resume frida code của ta sẽ chạy cùng lúc đó, do đó nó sẽ hook thành công vào call ở onCreate ![](https://i.imgur.com/UZtrT0N.png) ![](https://i.imgur.com/slJUiBz.png) Ok bypass thành công, bây giờ ta sẽ tìm flag. Method check input: ![](https://i.imgur.com/yq7CWh0.png) method `sg.vantagepoint.uncrackable1.a#a()` sẽ nhận input của ta, nếu nó true thì sẽ thành công lấy flag Nếu hook vào method này cũng không lấy được flag Nó sẽ chỉ in ra dòng này chứ không in ra flag(Đoạn này nhìn code là ) ![](https://i.imgur.com/3bOh4DT.png) Method này sẽ check xem input của ta nhập vào có bằng với bArr không. ![](https://i.imgur.com/OGHuTmi.png) bArr được tạo ra bởi method sau: ![](https://i.imgur.com/QBpSeW3.png) Sau khi hỏi chat gpt thì thấy đây là một decrypt method. Do đó ta chỉ cần làm sao leak được giá trị return của method này là sẽ lấy được flag. Full frida code: ```java= Java.perform(function () { var checkRoot = Java.use("sg.vantagepoint.a.c"); checkRoot.a.implementation = function() { return false; }; checkRoot.b.implementation = function() { return false; }; checkRoot.c.implementation = function() { return false; }; function bufferToString(buf) { var buffer = Java.array('byte', buf); var result = ""; for(var i = 0; i < buffer.length; ++i){ result += (String.fromCharCode(buffer[i] & 0xff)); } return result; } Java.use("sg.vantagepoint.a.a").a.implementation = function(x, y) { const flag = this.a(x, y); console.log("flag: " + bufferToString(flag)); return flag; } }); ``` Khi click vào nút Verify, flag sẽ in ra ở console ## Android UnCrackable L2 ![](https://i.imgur.com/1Jt1SaO.png) Ở đây ta tiếp tục bypass root check. Load file apk vào jadx-gui. Đoạn code check root: ![](https://i.imgur.com/zXXPlDL.png) Nhìn có vẻ giống app trước, sửa frida script một tí là được. ![](https://i.imgur.com/2Vyd7e5.png) Bây giờ ta sẽ trace từ method verify để xem làm sao lấy flag. ![](https://i.imgur.com/OpKLfJY.png) Nó sẽ dùng method `g.vantagepoint.uncrackable2.CodeCheck#b` để check. Method này như sau: ![](https://i.imgur.com/RqefVfs.png) Sử dụng method bar để so sánh string, method này được định nghĩa trong native lib. Dùng Ghidra để reverse file libfoo.so: ![](https://i.imgur.com/VL2tx5r.png) Ta chỉ cần để ý đến usage của hàm so sánh chuỗi strncmp. Hàm này có tác dụng: ![](https://i.imgur.com/pwk0Mtk.png) Với challenge của ta, strncmp được dùng như sau: ``` strncmp(__s1,(char *)&local_38,0x17) ``` + __s1: input mà ta nhập vào + (char *)&local_38: flag + 0x17 = 23 Trong trường hợp là native code, ta sẽ sử dụng Interceptor để có thể hook vào code. https://erev0s.com/blog/how-hook-android-native-methods-frida-noob-friendly/ Format sẽ kiểu như sau: ``` Interceptor.attach(Module.getExportByName('libnative-lib.so', 'Jniint'), { onEnter: function(args) { } }); ``` Đối với bài này ta sẽ phải hook vào strcmp trong file libfoo.so, do đó code sẽ là như sau: ``` Java.perform(function () { var checkRoot = Java.use("sg.vantagepoint.a.b"); checkRoot.a.implementation = function() { return false; }; checkRoot.b.implementation = function() { return false; }; checkRoot.c.implementation = function() { return false; }; }); Interceptor.attach(Module.findExportByName("libfoo.so", "strncmp"), { onEnter: function(args) { var s2 = args[1]; var n = args[2].toInt32(); if (n == 23){ var str2 = new NativePointer(s2).readUtf8String(23); console.log("flag is: "+ str2); } } }); ``` Set điều kiện n==23 để nó có thể nhảy vào đúng chỗ mà ta cần intercept: ![](https://i.imgur.com/tU2uvEn.png) ![](https://i.imgur.com/m2P32XD.png)