破解SSL Pinning:三种实战方案助你绕过BurpSuite抓包限制

📅 2026/7/28 4:25:47 👁️ 阅读次数 📝 编程学习
破解SSL Pinning:三种实战方案助你绕过BurpSuite抓包限制

1. 项目概述:当BurpSuite遇上SSL Pinning

如果你正在做移动端或者桌面端应用的渗透测试或安全评估,BurpSuite绝对是你的主力武器。但不知道你有没有遇到过这种情况:一切配置看起来都完美无缺,代理设置正确,证书也安装了,可Burp就是抓不到目标App的包,或者干脆App直接闪退、提示网络错误。这时候,你大概率是遇到了一个叫“SSL Pinning”的安全机制。这玩意儿就像给App和服务器的通信上了一把物理锁,即使你作为中间人拿着Burp签发的“万能钥匙”(证书),它也只认自己内置的那把“原配钥匙”,直接把你这个“中间人”给拒之门外了。

简单来说,SSL Pinning(证书绑定)是一种增强型的安全策略,它要求客户端(App)在建立TLS/SSL连接时,不仅验证服务器证书链的合法性,还要进一步校验服务器证书的“指纹”(比如公钥哈希、证书哈希)是否与预先硬编码在App内部的某个或某几个可信指纹匹配。如果不匹配,即使证书是受信任的CA(如你的Burp CA)签发的,连接也会被强制终止。这直接导致了我们最常用的中间人代理抓包工具——BurpSuite、Fiddler、Charles——全部失效。

今天,我就结合自己这些年跟各种App“斗智斗勇”的经验,把手头最常用、成功率最高的三种破解SSL Pinning的思路和方法,掰开揉碎了讲给你听。无论你是安全研究员、渗透测试工程师,还是对移动安全感兴趣的开发者,这篇内容都能给你一套清晰的“破局”路线图。我们会从原理出发,讲到具体操作,最后再分享一些实战中积累的独家避坑技巧。

2. SSL Pinning核心原理与影响范围解析

在动手破解之前,我们必须先搞清楚对手是怎么工作的。知其然,更要知其所以然,这样在面对不同App时,你才能灵活应变,而不是死记硬背几个命令。

2.1 SSL/TLS握手与中间人攻击(MitM)基础

正常情况下,当你的浏览器或App访问一个HTTPS网站时,会进行TLS握手。服务器会出示它的证书,客户端会验证这个证书是否由受信任的根证书颁发机构(CA)签发,以及域名是否匹配等。BurpSuite作为中间人,工作原理就是让自己成为这个受信任的CA。你需要在设备上安装Burp生成的CA证书,这样当Burp拦截流量时,它会动态地为目标域名生成一个由这个CA签发的“假”证书,递给客户端。由于客户端信任你的Burp CA,所以它会接受这个“假”证书,从而让Burp能够解密并查看所有明文流量。

2.2 SSL Pinning如何阻断中间人攻击

SSL Pinning就是App开发者针对上述中间人攻击场景布下的一道防线。它在开发阶段,就将目标服务器证书的某些特征信息(即“Pin”),直接写死在App的代码或配置文件中。常见的Pin包括:

  • 证书公钥哈希:最常见的一种,计算服务器证书公钥的SHA-256哈希值。
  • 证书哈希:计算整个证书的哈希值。
  • 证书主题公钥信息(SPKI)哈希:一种更精确的绑定方式。

当App启动TLS握手时,除了完成标准的证书链验证,它还会额外计算当前连接中服务器证书的对应特征值,并与内置的Pin进行比对。如果比对失败,无论这个证书是否来自受信任的CA(比如你的Burp CA),App都会立即断开连接,并可能抛出诸如“证书验证失败”、“网络连接错误”等提示,或者干脆静默失败、无响应。

注意:SSL Pinning通常用于保护App与自家关键API服务器之间的通信,而不是用于访问所有外部网站。所以你可能发现同一个App,访问A接口能抓到包,访问B接口就抓不到,这很正常。

2.3 影响范围:哪些场景下你会遇到它?

SSL Pinning在金融、支付、社交、企业内部应用等高安全要求的App中非常普遍。随着安全意识的提升,越来越多的主流App都采用了这一技术。它不仅影响安全测试,也影响开发调试(如果你想用代理查看自己App的API流量)。因此,掌握破解方法,对于安全评估和深度测试来说,是一项必备技能。

3. 破解思路总览与方案选型

面对SSL Pinning,我们的核心攻击思路就是“欺骗”或“绕过”客户端的证书指纹校验逻辑。根据对App的控制程度和技术难度,主要有以下三种主流方案,我将它们总结为一张决策表:

方案名称核心原理所需条件/环境优点缺点/局限适用场景
方案一:Hook大法(运行时注入)在App运行时,通过Frida、Xposed等框架,注入代码,动态修改或绕过证书校验的关键函数。1. 已Root/越狱的安卓/iOS设备或模拟器。
2. 能安装Frida/Xposed环境。
3. 对App有基本的逆向分析能力。
通用性强,可应对大多数自定义和第三方库的校验逻辑。
无需修改App包,动态生效,方便快捷。
依赖特定环境(Root/越狱),在加固或反调试较强的App面前可能失效。最推荐的首选方案,适用于大多数测试场景,尤其是快速验证。
方案二:证书替换法(静态修改)反编译App,找到存储Pin的代码或配置文件,将其替换为Burp证书的指纹,然后重打包签名。1. 能获取App安装包(APK/IPA)。
2. 掌握反编译、代码修改、重打包签名工具链。
一劳永逸,修改后安装的App永久有效。
不依赖运行时环境。
技术门槛较高,流程繁琐。遇到代码混淆、加固或Pin校验逻辑复杂时,定位和修改困难。适用于无法Root/越狱的环境,或需要将修改后的App分发给他人使用的情况。
方案三:系统级证书信任(安卓特供)将Burp的CA证书直接安装到安卓系统的系统证书目录,使其获得与厂商预装证书同等的信任级别。1. 已Root的安卓设备。
2. 能访问系统分区。
全局生效,所有App(除非用了Pinning)都会信任Burp证书。
无需对每个App单独操作。
仅适用于安卓,且需要Root权限。对于使用了SSL Pinning的App,此方法依然无效,需结合方案一。作为辅助手段,解决那些没开Pinning但依然抓不到包的App(它们可能只信任系统证书)。

在实际操作中,方案一(Frida Hook)因其灵活性和高成功率,是我最常用、也最推荐大家优先尝试的方法。方案二可以作为备选,方案三则是解决非Pinning问题的好帮手。下面,我们就进入实操环节。

4. 方案一实操:Frida动态Hook破解详解

Frida是一个强大的动态代码插桩工具,我们可以编写一小段JavaScript脚本,在目标App运行时,拦截并修改其证书验证相关的函数,使其总是返回“验证成功”。

4.1 环境准备与基础配置

  1. 测试设备:准备一台已Root的安卓手机或模拟器(如Genymotion,自带Root)。iOS则需要越狱设备。本文以安卓为例。
  2. 安装Frida
    • 在电脑(攻击机)上pip install frida-tools
    • 在安卓设备上:下载对应架构的frida-server文件,推送到设备并运行。
    # 查看设备架构 adb shell getprop ro.product.cpu.abi # 推送并运行frida-server (以arm64为例) adb push frida-server-16.1.14-android-arm64 /data/local/tmp/frida-server adb shell su cd /data/local/tmp chmod 755 frida-server ./frida-server &
  3. 配置BurpSuite:确保Burp代理监听正确,手机Wi-Fi代理已设置为Burp,且Burp的CA证书已安装到手机的用户证书目录。

4.2 编写与使用通用Hook脚本

SSL Pinning的校验逻辑通常集中在几个关键类和方法上。以下是一个针对安卓的、非常通用的Frida脚本,它尝试Hook多个常见网络库(如OkHttp3, Apache HttpClient, TrustManager)的证书验证点:

// ssl_pinning_bypass.js Java.perform(function() { console.log("[*] Starting SSL Pinning Bypass..."); // 1. 绕过证书验证(最暴力通用) var TrustManager = Java.use('javax.net.ssl.TrustManager'); var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); var TrustManagerFactory = Java.use('javax.net.ssl.TrustManagerFactory'); var SSLContext = Java.use('javax.net.ssl.SSLContext'); // Hook SSLContext.init 方法,传入我们自定义的、什么都不校验的TrustManager SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom').implementation = function(keyManagers, trustManagers, secureRandom) { console.log("[+] SSLContext.init() hooked"); // 创建一个空的TrustManager数组,或者传入自定义的绕过TrustManager var emptyTrustManagers = Java.array('Ljavax.net.ssl.TrustManager;', []); return this.init(keyManagers, emptyTrustManagers, secureRandom); }; // 2. 针对OkHttp3的CertificatePinner (非常常见) try { var CertificatePinner = Java.use('okhttp3.CertificatePinner'); CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(pin, certs) { console.log("[+] OkHttp3 CertificatePinner.check() bypassed for: " + pin); // 直接不执行任何检查,相当于绕过 return; }; console.log("[*] OkHttp3 CertificatePinner class found and hooked."); } catch (err) { console.log("[!] OkHttp3 CertificatePinner not found: " + err); } // 3. 针对Apache HttpClient的SSLContextBuilder try { var SSLContextBuilder = Java.use('org.apache.http.conn.ssl.SSLContextBuilder'); SSLContextBuilder.loadTrustMaterial.overload('java.security.KeyStore', 'org.apache.http.conn.ssl.TrustStrategy').implementation = function(keystore, strategy) { console.log("[+] Apache HttpClient SSLContextBuilder.loadTrustMaterial() hooked"); // 返回一个信任所有证书的TrustStrategy var TrustAllStrategy = Java.registerClass({ name: 'com.example.TrustAllStrategy', implements: [Java.use('org.apache.http.conn.ssl.TrustStrategy')], methods: { isTrusted: function(chain, authType) { console.log("[+] TrustAllStrategy: Trusting all certificates."); return true; // 信任所有! } } }); return this.loadTrustMaterial(keystore, TrustAllStrategy.$new()); }; } catch (err) { console.log("[!] Apache HttpClient classes not found."); } console.log("[*] SSL Pinning Bypass script loaded successfully."); });

使用脚本:

  1. 将上述代码保存为ssl_pinning_bypass.js
  2. 确保frida-server在设备上运行。
  3. 在电脑上执行命令,附加到目标App进程并注入脚本:
    # 先列出运行中的进程,找到目标App的包名 frida-ps -U # 附加并执行脚本 (以包名 com.example.targetapp 为例) frida -U -f com.example.targetapp -l ssl_pinning_bypass.js --no-pause
    -f参数表示启动App,--no-pause表示立即启动主线程。

4.3 实操心得与注意事项

  • 脚本不是万能的:上述脚本覆盖了常见情况,但有些App会使用自定义的证书校验逻辑,或者对网络库进行了深度封装。如果通用脚本无效,你需要对App进行简单的逆向(使用Jadx-GUI查看反编译代码),搜索关键词如X509TrustManagercheckServerTrustedCertificatePinnerpin等,找到具体的校验类和方法,然后针对性地编写Hook脚本。
  • 反调试与加固:一些强安全意识的App会检测Frida等调试环境。你可能需要对抗反调试,比如使用frida的隐藏技术,或者使用修改版的frida-server。对于加固的App,可能需要先脱壳才能看到真实代码。
  • 多进程Hook:有些App的网络请求可能发生在非主进程(如WebView独立进程)。你需要用frida-N参数指定进程名,或者使用Spawn模式来确保Hook到所有相关进程。
  • 先验证环境:在Hook之前,先用frida-ps -U确认设备连接和frida-server运行正常。注入脚本后,观察命令行是否有[+]开头的成功Hook日志。

5. 方案二实操:反编译与静态修改证书Pin

当动态Hook行不通,或者你需要一个“干净”的、修改后的App时,静态修改是另一种选择。其核心流程是:解包 -> 反编译 -> 定位Pin代码/资源 -> 修改 -> 回编译 -> 签名。

5.1 工具链准备

  • 反编译/回编译apktool。用于将APK解包成Smali代码和资源文件。
  • 代码查看Jadx-GUI。图形化工具,将APK反编译成可读性更好的Java代码,用于分析。
  • 签名keytool(生成密钥库) 和apksigner(对APK进行V1/V2/V3签名)。Android Studio的Build Tools里自带。

5.2 详细操作步骤

我们假设目标APK文件为target.apk

  1. 反编译APK

    apktool d target.apk -o target_output

    这会在target_output目录下生成反编译后的所有文件,其中smali目录存放代码,res目录存放资源。

  2. 定位Pin存储位置

    • 使用Jadx-GUI打开target.apk,在全局搜索栏搜索关键词:pinPinningsha256public keyCertificatePinnercheckServerTrusted
    • 仔细查看搜索结果,找到类似CertificatePinner.Builder().add("api.example.com", "sha256/AAAAAAAA...")的代码。记下这个类的完整路径和关键方法。
  3. 修改Smali代码

    • 根据Jadx找到的类路径,在target_output/smali/目录下找到对应的.smali文件。例如,对应com/example/app/NetworkUtils.smali
    • Smali是Android的汇编语言,直接修改需要一些技巧。我们的目标是让校验函数直接返回成功,或者将Pin值替换成我们Burp证书的指纹
    • 方法A(推荐):NOP掉校验调用。找到调用校验方法(如invoke-virtual调用check)的指令,将其替换为nop(空操作)指令。这需要一定的Smali基础。
    • 方法B:修改Pin值。在Smali文件中找到存储Pin字符串常量的地方(通常在.local变量定义或const-string指令后),将其值替换为你计算出的Burp证书对应域名的公钥SHA256哈希(以sha256/开头)。如何获取?用Burp访问一次目标域名,在Proxy历史里找到该请求,查看证书详情,导出证书,用命令计算:openssl x509 -in certificate.cer -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
  4. 回编译与签名

    # 回编译 apktool b target_output -o target_modified.apk # 生成签名密钥(如果已有,跳过) keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000 # 签名 apksigner sign --ks my-release-key.keystore --ks-key-alias alias_name target_modified.apk
  5. 安装测试:将target_modified.apk安装到测试设备上,配置Burp代理,尝试抓包。

5.3 常见问题与避坑指南

  • 回编译失败:最常见的原因是apktool版本与APK的编译环境不兼容,或者APK本身有特殊的保护。尝试更新到最新版apktool。如果资源文件导致错误,可以尝试用apktool d -r(不反编译资源)和-s(不反编译代码)来排除。
  • App闪退:Smali代码修改错误导致。可能是寄存器使用错误、方法签名不对、或NOP了不该NOP的指令。务必仔细核对。修改前备份原Smali文件。
  • 签名后无法安装:可能签名方式不对。确保使用apksigner进行V1+V2+V3签名。安装时提示“与已安装应用冲突”,需要先卸载原版App。
  • 加固App:如果APK被腾讯乐固、梆梆、爱加密等加固,第一步反编译出来的可能就是壳的代码。你需要先进行脱壳,获取原始的DEX文件,这涉及到更深层的逆向技术,不在本文基础讨论范围内。

6. 方案三实操:安卓系统证书安装(辅助方案)

这个方法不能直接破解SSL Pinning,但它能解决很多“抓不到包”是因为系统不信任用户证书的问题。它将Burp的CA证书提升到系统级信任。

前提:设备必须已Root。

  1. 从Burp导出证书:在BurpSuite中,Proxy->Options->Import / export CA certificate,选择Certificate in DER format,导出为cacert.der
  2. 转换证书格式并计算哈希
    # 将DER格式转换为PEM格式 openssl x509 -inform DER -in cacert.der -out cacert.pem # 计算PEM证书的哈希值(用于命名) openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -1 # 假设输出是 `a0b1c2d3`
  3. 推送证书到系统目录
    # 将PEM证书重命名为 哈希值.0 cp cacert.pem a0b1c2d3.0 # 推送证书到设备系统证书目录 adb root # 需要root权限 adb remount # 重新挂载系统分区为可写(部分设备可能需要) adb push a0b1c2d3.0 /system/etc/security/cacerts/ # 修改证书权限 adb shell su chmod 644 /system/etc/security/cacerts/a0b1c2d3.0
  4. 重启设备:重启后,Burp的证书就会出现在系统的“受信任的凭据” -> “系统”列表中。此时,所有默认信任系统证书的App(即未启用SSL Pinning的App)都会信任Burp的代理。

重要提示:在Android 7.0 (API 24) 及以上版本,App默认不再信任用户安装的证书,但依然信任系统证书。这就是为什么很多App在安卓高版本上,即使安装了用户证书也抓不到包的原因。此方法正是为了解决这个问题。但对于启用了SSL Pinning的App,此方法无效,仍需配合方案一或二。

7. 实战问题排查与高阶技巧

即使掌握了方法,实战中还是会遇到各种“妖魔鬼怪”。这里分享几个我踩过坑后总结的排查思路和技巧。

7.1 抓包失败通用排查清单

当Burp抓不到包时,按顺序检查以下列表,可以解决90%的问题:

  1. 代理设置:手机Wi-Fi代理的IP和端口是否正确?电脑防火墙是否允许了Burp的入站连接?尝试在手机浏览器访问http://burp是否能下载证书。
  2. 证书安装:Burp的CA证书是否已正确安装到手机的用户凭据目录?在安卓设置中搜索“证书”,确认是否存在。对于安卓7+,考虑使用方案三安装为系统证书。
  3. 目标App限制:App是否使用了SSL Pinning?(本文核心)是否使用了其他防代理技术,如检测系统代理设置并拒绝连接?可以尝试使用透明代理工具(如redsocks+iptables)将流量强制转发到Burp。
  4. 非HTTP/S流量:App是否使用了纯Socket、WebSocket、gRPC或自定义协议的通信?这些流量Burp默认无法解析。你需要使用更底层的抓包工具,如tcpdumpWireshark
  5. 证书绑定时机:有些App在启动时或首次联网时才绑定证书。尝试在启动App就挂上Frida脚本,或者清除App数据后重试。

7.2 对抗反调试与Frida检测

一些安全等级高的App会检测Frida:

  • 检测常见端口:Frida默认监听27042端口。可以启动frida-server时指定其他端口:./frida-server -l 0.0.0.0:8080
  • 检测进程名/文件:检测/data/local/tmp/frida-serverfrida相关进程。可以重命名frida-server二进制文件,并使用psproc等命令的Hook来隐藏进程。
  • 使用隐藏工具:考虑使用如objection(基于Frida)的android anti-root-detection bypass命令,或使用修改版的、具备更强隐藏能力的frida-server。

7.3 针对特定框架的Hook技巧

  • Flutter/Dart:Flutter应用的网络请求可能由Dart代码发起,最终调用底层的Android网络库。你需要Hook的是Android层,但校验逻辑可能在Dart侧。一种方法是Hook Flutter引擎加载的so库中的SSL相关函数(如SSL_CTX_set_cert_verify_callback),这需要一定的Native层逆向知识。
  • React Native / Xamarin:这些框架最终也会调用系统网络库。通用脚本(方案一)通常有效。如果无效,尝试找到框架自己封装的网络模块进行Hook。
  • 证书双向验证(mTLS):这是比SSL Pinning更狠的招,客户端也需要出示证书。破解思路是:从App中提取客户端证书和私钥(通常存储在keystore或资源文件中),然后在BurpSuite中配置使用这个客户端证书。这涉及到更深度的逆向和密码学知识。

最后,我想说的是,破解SSL Pinning是一场“道高一尺,魔高一丈”的持续对抗。今天有效的方法,明天可能因为App更新或加固升级而失效。核心能力不在于记住某条命令或某个脚本,而在于理解其原理,掌握动态分析(Frida)和静态分析(反编译)这两大武器,并具备根据实际情况进行调试和适配的能力。多动手,多分析,遇到问题善用搜索引擎和社区,你的“抓包”技能树就会越来越扎实。在实际测试中,记得始终在合法授权的范围内进行,尊重软件的安全边界。