当frida来“敲”门



这是 酒仙桥六号部队 的第 6 篇文章。

全文共计3156个字,预计阅读时长9分钟


1

渗透测试瓶颈


目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。

而现在挖漏洞除了拿到shell以外,客户又要求可以尽可能的挖到核心业务系统的漏洞,并将漏洞范围订在主域名,核心业务系统现在又基本集中在移动端,移动端现在都会进行APP加壳,流量加密。这就导致无法进行平常渗透测试过程,像老生常谈的中间人攻击,进行拦截,篡改数据包就很难进行。

接下来就尝试解决中间人攻击的问题,目标是

1.看到明文的request和response的数据包;

2.做到可以拦截,篡改数据包。


2
frida

frida是平台原生app的Greasemonkey,说的专业一点,就是一种动态插桩工具,可以插入一些代码到原生app的内存空间去,(动态地监视和修改其行为),这些原生平台可以是Win、Mac、Linux、Android或者iOS。而且frida还是开源的。

环境需要越狱的IOS或者ROOT的Android。安装的版本需要一致。

MAC:

越狱Iphone:

通过USB链接越狱手机,可以执行frida-ps -aU 就代表环境安装成功。


3
越狱检测绕过

启动目标APP时,APP自身会进行环境检测,如果处于越狱环境会提示如下:

点击“我知道了”就直接退出APP。

所以先尝试先绕过第一步越狱环境检测。可以先尝试搜索包含“jail,jeil,jb,break"关键字的函数。

关于函数追踪可以使用frida-trace,如:


# Trace recv* and send* APIs in Safari$ frida-trace -i "recv*" -i "send*" Safari
# Trace ObjC method calls in Safari$ frida-trace -m "-[NSView drawRect:]" Safari
# Launch SnapChat on your iPhone and trace crypto API calls$ frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"

burp的插件brida也支持对函数名进行检索hook,和"Jail"相关的越狱检测函数如下:

**** Result of the search of Jail
OBJC: +[BLYDevice isJailBreak]
OBJC: +[IFlySystemInfo isJailbroken]
OBJC: +[UIScreen _shouldDisableJail]
OBJC: +[UIStatusBarWindow isIncludedInClassicJail]
OBJC: -[_UIHostedWindow _isConstrainedByScreenJail]
OBJC: -[_UIRootWindow _isConstrainedByScreenJail]
OBJC: -[_UISnapshotWindow _isConstrainedByScreenJail]
OBJC: -[BLYDevice isJailbroken]
OBJC: -[BLYDevice setJailbrokenStatus:]
OBJC: -[RCCountly isJailbroken]
OBJC: -[UIClassicWindow _isConstrainedByScreenJail]
OBJC: -[UIDevice isJailbroken]
OBJC: -[UIStatusBarWindow _isConstrainedByScreenJail]
OBJC: -[UITextEffectsWindowHosted _isConstrainedByScreenJail]
OBJC: -[UIWindow _clampPointToScreenJail:]
OBJC: -[UIWindow _isConstrainedByScreenJail]

想将目标定在“OBJC: +[BLYDevice isJailBreak]”。

frida启动APP,并加载脚本的命令如下:
frida -U -f com.x.x -l js-scripts
js脚本编写可以看官方文档:
https://frida.re/docs/javascript-api/



//hook传入值,ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments Interceptor.attach(myFunction.implementation, {   onEnter: function(args) {    var myString = new ObjC.Object(args[2]);    console.log("String argument: " + myString.toString());  }});
//hook返回值,Interceptor.attach(Module.getExportByName('libc.so', 'read'), {  onEnter: function (args) {    this.fileDescriptor = args[0].toInt32();  },  onLeave: function (retval) {    if (retval.toInt32() > 0) {      /* do something with this.fileDescriptor */    }}});

定义js脚本后,尝试hook出“OBJC:

+[BLYDevice isJailBreak]”的传入值和返回值。

image.png

image.png

篡改后,发现未能绕过,可能不是这个函数做最终的逻辑判断,想到竟然都弹窗提示了,和UI有关系。

那么可能是“OBJC: -[UIDevice isJailbroken]这个类,最终构造绕过越狱检测代码如下:

if (ObjC.available)
{
    try    
    {  
          var className = "UIDevice";        
          var funcName = "- isJailbroken";        
          var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');//目标类+方法        
          Interceptor.attach(hook.implementation,         
        {        
            onLeave: function(retval) {        
              console.log("[*] Class Name: " + className);            
              console.log("[*] Method Name: " + funcName);            
              console.log("\t[-] Return Value: " + retval);//输出原本的返回值            
              var newretval = ptr("0x0")             
              retval.replace(newretval)//替换新的返回值            
             console.log("\t[-] New Return Value: " + newretval)         
          }}        
       );    
     }    
     catch(err)    
    {   
         console.log("[!] Exception2: " + err.message);    
     }    
  }
  else
 {
     console.log("Objective-C Runtime is not available!");
 }

执行结果如下

image.png

成功绕过

image.png

4
HOOK加解密函数

越狱检测绕过后,进一步开始尝试定位加解密的函数。

关于定位加解密函数这块在Android可以尝试使用traceview去分析追踪函数。

(https://developer.android.google.cn/studio/profile/traceview)

image.png

IOS可以尝试使用runtime去追踪函数,uidump从界面按钮入手,Nslog日志等位置入手,或者直接找相关关键字的函数去入手。

例如crypt(decryot,encrypt),HTTP,Network,目标厂商的名字简写找不到,可以尝试搜索NSString系统库等。

这边推荐一个大佬的github项目。使用可以参考这个githu项目,非常好用,先用之前写好的绕过越狱检测的脚本启动APP,这边通过查找函数名找到对方关键的加解密函数“*encryptor”。

github项目:https://github.com/lyxhh/lxhToolHTTPDecrypt

image.png

hook此函数的所有方法,在点击登录按钮后,观察到有请求的数据包被当做参数传入到-[XXEncryptor RSAEncrypt:]方法内,并返回了加密后的字符串。-[XXEncryptor setRSAPublicKey:]根据定义的方法名判断应该是RSA公钥信息。

image.png

其他方法则去处理了返回包。如-[XXEncrytor AESDecrypt:]方法,将服务端返回的加密字段,使用AES对称解密解密为明文。

image.png

之前我们在Hook请求包函数的时候发现明文的数据包里面带有aeskey,说明此处的逻辑应该是:

本地生成aeskey代入到request包->使用定义的RSA公钥加密request->发送到服务端并解密request后->处理请求包内容,并使用AESkey加密Response返回到客户端->客户端在使用Aeskey解密服务端的Response包。

image.png

大概是这么一个流程,事实也证明返回包确实可以使用hook到的aeskey进行解密。

image.png

后面的思路是hook[XXEncrytor AESDecrypt:]解密方法去解密请求包和返回包,返回包是可以解,但是突然想到请求包是RSA非对称的,需要私钥。想尝试在客户端找到RSA的私钥或者RSA解密方法,结果也确实有RSADecrypt方法。

image.png

但是事实是,从头到尾这个方法都没有被使用过,没有参数被传入,也没有返回值。所以想,可能本地不做请求包的解密。那么调用他的函数解密返回包可行,但解密请求包不行。但是咱们之前是有Hook到明文的request,可以再request被传入到-[XXEncryptor RSAEncrypt]方法前,先去修改arg。

image.png

具体操作方法可以参考lyxhh,将加密前的请求包转入Burp后就可以实现篡改数据了。

lyxhh:https://github.com/lyxhh/lxhToolHTTPDecrypt

微信图片_20200720155559.png

新手的话可以先用la0s的JS,先看看对方是不是使用了IOS统一封装的Crypto库,js脚本如下:

JS:https://la0s.github.io/2018/12/07/iOS_Crypto/


/ Intercept the CCCrypt call.Interceptor.attach(Module.findExportByName('libcommonCrypto.dylib', 'CCCrypt'), {    onEnter: function (args) {        // Save the arguments        this.operation   = args[0]        this.CCAlgorithm = args[1]        this.CCOptions   = args[2]        this.keyBytes    = args[3]        this.keyLength   = args[4]        this.ivBuffer    = args[5]        this.inBuffer    = args[6]        this.inLength    = args[7]        this.outBuffer   = args[8]        this.outLength   = args[9]        this.outCountPtr = args[10]
       console.log('CCCrypt(' +            'operation: '   + this.operation    +', ' +            'CCAlgorithm: ' + this.CCAlgorithm  +', ' +            'CCOptions: '   + this.CCOptions    +', ' +            'keyBytes: '    + this.keyBytes     +', ' +            'keyLength: '   + this.keyLength    +', ' +            'ivBuffer: '    + this.ivBuffer     +', ' +            'inBuffer: '    + this.inBuffer     +', ' +            'inLength: '    + this.inLength     +', ' +            'outBuffer: '   + this.outBuffer    +', ' +            'outLength: '   + this.outLength    +', ' +            'outCountPtr: ' + this.outCountPtr  +')')
       if (this.operation == 0) {            // Show the buffers here if this an encryption operation            console.log("In buffer:")            console.log(hexdump(ptr(this.inBuffer), {                length: this.inLength.toInt32(),                header: true,                ansi: true            }))            console.log("Key: ")            console.log(hexdump(ptr(this.keyBytes), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))            console.log("IV: ")            console.log(hexdump(ptr(this.ivBuffer), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))        }    },    onLeave: function (retVal) {        if (this.operation == 1) {            // Show the buffers here if this a decryption operation            console.log("Out buffer:")            console.log(hexdump(ptr(this.outBuffer), {                length: Memory.readUInt(this.outCountPtr),                header: true,                ansi: true            }))            console.log("Key: ")            console.log(hexdump(ptr(this.keyBytes), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))            console.log("IV: ")            console.log(hexdump(ptr(this.ivBuffer), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))        }    }})

如果只能hook到部分明文流量,再考虑去对方定义的函数里去找关键的加密函数,如这个APP的关键的XXEncryptor类。


本文作者:酒仙桥六号部队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/135848.html

Tags:
评论  (0)
快来写下你的想法吧!

酒仙桥六号部队

文章数:45 积分: 720

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号