某开门软件签名算法、蓝牙开门、密码开门分析

查看 73|回复 10
作者:方块君   
0x00 前言
  • 工具:burp、frida、ida
  • 难点:Flutter
    小区在很早之前就换了某科技的门禁系统

    支持手机开门、门卡开门、人脸开门
    所有信息均已脱敏和打马赛克
    手机开门软件及其逆天,广告满天飞,一气之下就逆了(


    image-11.png (182.43 KB, 下载次数: 0)
    下载附件
    2025-1-19 20:26 上传

    0x01 准备
    获取安装包
    下载最新版发现加壳了,是 蛮犀加固企业壳
    很久之前给这软件写过去广告模块,所以已知旧版本是无壳的
    所以只用往回找没壳的版本,就能使用 Frida Hook 了
    SSL 验证
    使用代{过}{滤}理抓包发现无法抓到,并且有 SSL 验证
    使用 IDA 打开 libflutter.so


    image-0.png (100.87 KB, 下载次数: 0)
    下载附件
    2025-1-19 20:25 上传

    搜索 ssl_client


    image-1.png (293.16 KB, 下载次数: 0)
    下载附件
    2025-1-19 20:25 上传

    获取到 SSL 验证 函数为 0x3E0F74
    libapp.so 逆向
    使用 Blutter 一把梭哈
    把脚本导入 IDA


    image-2.png (202.5 KB, 下载次数: 0)
    下载附件
    2025-1-19 20:25 上传

    可以看到函数名也全部都还原了
    0x02 抓包分析
    初始化抓包
    导出 Burp 的 SSL 证书,并存到 /data/local/tmp/cert-der.crt
    使用 Blutter 提供的 frida 脚本
    /*
       Android SSL Re-pinning frida script v0.2 030417-pier
    $ adb push burpca-cert-der.crt /data/local/tmp/cert-der.crt
       $ frida -U -f it.app.mobile -l frida-android-repinning.js --no-pause
    https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
       UPDATE 20191605: Fixed undeclared var. Thanks to @oleavr and @ehsanpc9999 !
    */
    setTimeout(function () {
      Java.perform(function () {
        console.log("");
        console.log("[.] Cert Pinning Bypass/Re-Pinning");
        var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
        var FileInputStream = Java.use("java.io.FileInputStream");
        var BufferedInputStream = Java.use("java.io.BufferedInputStream");
        var X509Certificate = Java.use("java.security.cert.X509Certificate");
        var KeyStore = Java.use("java.security.KeyStore");
        var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
        var SSLContext = Java.use("javax.net.ssl.SSLContext");
        // Load CAs from an InputStream
        console.log("[+] Loading our CA...");
        var cf = CertificateFactory.getInstance("X.509");
        try {
          var fileInputStream = FileInputStream.$new(
            "/data/local/tmp/cert-der.crt"
          );
        } catch (err) {
          console.log("[o] " + err);
        }
        var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
        var ca = cf.generateCertificate(bufferedInputStream);
        bufferedInputStream.close();
        var certInfo = Java.cast(ca, X509Certificate);
        console.log("[o] Our CA Info: " + certInfo.getSubjectDN());
        // Create a KeyStore containing our trusted CAs
        console.log("[+] Creating a KeyStore for our CA...");
        var keyStoreType = KeyStore.getDefaultType();
        var keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        // Create a TrustManager that trusts the CAs in our KeyStore
        console.log(
          "[+] Creating a TrustManager that trusts the CA in our KeyStore..."
        );
        var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        console.log("[+] Our TrustManager is ready...");
        console.log("[+] Hijacking SSLContext methods now...");
        console.log("[-] Waiting for the app to invoke SSLContext.init()...");
        SSLContext.init.overload(
          "[Ljavax.net.ssl.KeyManager;",
          "[Ljavax.net.ssl.TrustManager;",
          "java.security.SecureRandom"
        ).implementation = function (a, b, c) {
          console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
          SSLContext.init
            .overload(
              "[Ljavax.net.ssl.KeyManager;",
              "[Ljavax.net.ssl.TrustManager;",
              "java.security.SecureRandom"
            )
            .call(this, a, tmf.getTrustManagers(), c);
          console.log("[+] SSLContext initialized with our custom TrustManager!");
        };
    }, 0);
    var libflutter = null;
    function onLibFlutterLoaded() {
      const ssl_pinning_addr = 0x3e0f74;
      Interceptor.attach(libflutter.add(ssl_pinning_addr), {
        onEnter: function (args) {
          console.log("Disabling SSL validation");
        },
        onLeave: function (retval) {
          console.log("Retval: " + retval);
          retval.replace(0x1);
        },
      });
    }
    function tryLoadLibFlutter() {
      libflutter = Module.findBaseAddress("libflutter.so");
      if (libflutter === null) setTimeout(tryLoadLibFlutter, 500);
      else onLibFlutterLoaded();
    }
    tryLoadLibFlutter();
    加上 Bypass SSL 验证
    开始抓包
    禁止检查更新


    image-4.png (87.92 KB, 下载次数: 0)
    下载附件
    2025-1-19 20:25 上传

    将 /v1/appVersion 地址替换为空即可绕过更新检查
    发送验证码
    Host: aHR0cHM6Ly9nYXRld2F5Mi5xaW5saW5rZWppLmNvbQ==
    URL: /member/sms/sendSecurityCode
    Header
    [table]
    [tr]
    [td]Key[/td]
    [td]Comment[/td]
    [/tr]
    [tr]
    [td]Openid

    下载次数, 下载附件

  • mobanche   

    大佬优秀!
    方块君
    OP
      


    TWYX 发表于 2025-1-23 16:05
    笑死了,回家进门前还得先看广告?这不把物业搞走换一家吗?

    因为设备免费提供,只有软件开门会弹广告,软件开门本来就是小众需求,所以和物业说也没啥用(
    amn2007   

    虽然看不懂
    大雅   

    看不懂啊,有现成的没?
    xixicoco   

    可以用小天才开门
    方块君
    OP
      


    xixicoco 发表于 2025-1-19 21:42
    可以用小天才开门

    小天才要开会员(
    它有个手表开门会员
    521wuyanfei   

    学习学习谢谢
    a2523188267   

    以为是翼回家app呢,好像翼回家也是此类功能,逻辑大致相同吧
    beataxp   

    完全看不懂,但佩服
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部