Practical combat | Remember to bypass multiple restrictions on an APP

A certain app has hardening, frida detection and root detection, and during testing it was found that it uses certificate binding, two-way certificate authentication, and data encryption.

frida detection bypass

At first, I found that the obfuscated frida would still be detected. First, use frida hook dlopen to view the loaded so. dlopen is mainly used to load some system libraries. You can see that the libc.so library is opened, based on libc.so Detection is generally divided into two types: one is the file reading and writing class, such as maps and status, and the other is the thread class. Through dlopen_ext, we can also know that libexec and libexecmain are most likely the so that detects frida.

picture

From the above, we know that libexec or libexecmain called pthread_create and created the relevant detection thread, so use Thread.backtrace([context, backtracer]): to grab the call stack of the current thread and obtain the so file name by printing out the stack.

picture

At this point, it can be confirmed that libexec called pthread_create to create the relevant detection method, and the method we are looking for is the method pthread_create created before the program crashed. Then the offset of the relevant method can be located by subtracting the libexec base address from the obtained relevant dynamic address, and finally the corresponding method can be replaced when pthread_create creates the detection thread.

function getunfrida() {
   
       var pthaddr = Module.findExportByName("libc.so","pthread_create");    var timeaddr=Module.findExportByName("libc.so","time");    Interceptor.attach(pthaddr,{
   
           onEnter: function(args){
   
               var baseaddr=Module.findBaseAddress("libexec.so");            if(args[2]-baseaddress==270080 ||args[2]-baseaddress==193128 ||args[2]-baseaddress==193072){
   
                   args[2]=timeaddr;            }        },onLeave: function(retval){
   
       }});}

root detection bypass

When the rooted phone is opened, it will prompt that the device is rooted, and it will automatically exit the program, unpack the code, find the relevant code in jadx, and use the checkroot method to detect whether it is rooted.

picture

After hooking this method, the program pops up with an environment risk and exits. It turns out that there is also a checkmagisk method.

picture

Write a hook script to intercept these two methods.

Java.perform(function(){
   
       let LoginActivity = Java.use("com.xxxx.LoginActivity");    LoginActivity["checkroot"].overload('java.lang.Object').implementation = function () {
   
         console.log('checkroot is pass');    };    LoginActivity["checkmagisk"].implementation = function () {
   
           console.log('checkmagisk is pass');    };    });

picture

Two-way certificate authentication bypass

Both methods were hooked, and then it was found that the data packet could not be captured. Check the network_security_config.xml resource file of the apk. The app trusts the user certificate.

picture

Due to time constraints, I did not look at the related methods of root detection at the beginning. I directly used the privilege escalation vulnerability to obtain the frida script run by root. Even if the app only trusts the system certificate, the test machine that obtains the root shell command line through the vulnerability can also temporarily mount a memory. file system and import the system certificate into it.

picture

charles monitors 16666.

picture

The mobile phone forwards 16666 socks5 to charles through posterior, and configures External Proxy to burp.

picture

Check the data on burp and find that the data packet returns 400. It is judged that it may use two-way certificate authentication. You can directly try to spit out the password.

function hook_KeyStore_load() {
   
       Java.perform(function () {
   
           var StringClass = Java.use("java.lang.String");        var KeyStore = Java.use("java.security.KeyStore");        KeyStore.load.overload('java.security.KeyStore$LoadStoreParameter').implementation = function (arg0) {
   
               console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));            console.log("KeyStore.load1:", arg0);            this.load(arg0);        };        KeyStore.load.overload('java.io.InputStream', '[C').implementation = function (arg0, arg1) {
   
               console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));            console.log("KeyStore.load2:", arg0, arg1 ? StringClass.$new(arg1) : null);            this.load(arg0, arg1);        };
        var AssetManager = Java.use("android.content.res.AssetManager");        AssetManager["open"].overload('java.lang.String', 'int').implementation = function (fileName, accessMode) {
   
               console.log('open is called' + ', ' + 'fileName: ' + fileName );            let ret = this.open(fileName, accessMode);            return ret;            };
    });}

Successfully obtained the certificate password.

picture

Of course, you can also locate the relevant code through the code (simplified). Through the code, you can know that the password comes from the getValue method.

picture

After writing a script hook, you can obtain the password of the certificate.

picture

After obtaining the certificate password, find the two corresponding certificate files in the resource file and import them into burp.

picture

Also import charles here.

picture

Successfully captured the data packet of domain name 1.

picture

However, clicking login cannot capture the data packet of domain name 2. At this time, the data packet finds that there is a data packet showing the socket protocol of port 8099.

picture

Add the non-standard https port in Charles' proxy setting.

picture

Click Login again to successfully capture the login data packet.

picture

Encryption algorithm bypass

Automatically forward to burp through Charles to facilitate testing, and you can see that the data is encrypted.

picture

Locate the encryption algorithm location.

picture

Write a hook script and add the sm4 encryption hook code to the frida bypass script.

Java.perform(function(){
   
       let hooksm4 = Java.use("com.xx.xxxx");    hooksm4["sm4De"].implementation = function (cipherStr, sm4Key) {
   
           console.log('sm4De is called' + ', ' + 'cipherStr: ' + cipherStr + ', ' + 'sm4Key: ' + sm4Key);        let ret = this.sm4Decrypt(cipherStr, sm4Key);        console.log('sm4De ret value is ' + ret);        return ret;};    });

Through hook, you can obtain the pre-encrypted content and the key of the national secret sm4 algorithm.

picture

Of course, the key found through the hook is a dynamic key. After writing the fixed key, the test can be started. Subsequent tests found that both domain name 3 and domain name 4 have certificate bindings.

picture

Therefore, the certificate binding bypass code must be added to the frida bypass script.

function checkTrustedRecursive() {
   
       Java.perform(function () {
   
           var array_list = Java.use("java.util.ArrayList");        var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');        TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
   
               console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host);            return array_list.$new();        };});}

picture

At this point all data packets can be captured.

picture

Replenish

During the intermediate test, the frida spawn mode was started and the script was bypassed. Although the password of the certificate could be hooked, the program was stuck on the startup page and could not enter the app normally. When the spawn mode was not used, Failed to attach: unable to access process with pid 7854 due appeared again. to system restrictions; try `sudo sysctl kernel.yama.ptrace_scope=0`, or run Frida as root error.

picture

It seems that there is still dual-process protection. After testing several times, I finally started it by executing spawn mode first. The program got stuck. It asked whether to continue waiting or exit. Click to exit.

picture

After the program crashes and exits, do not reopen the app and execute frida Attach mode (you can load it at this time without being prompted that the program cannot be found).

picture

When you open the app, you successfully enter the app and the script is executed successfully (very mysterious).

picture

Guess you like

Origin blog.csdn.net/ab6326795/article/details/131822492
Recommended