破解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 CAApp都会立即断开连接并可能抛出诸如“证书验证失败”、“网络连接错误”等提示或者干脆静默失败、无响应。注意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 环境准备与基础配置测试设备准备一台已Root的安卓手机或模拟器如Genymotion自带Root。iOS则需要越狱设备。本文以安卓为例。安装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 配置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.); });使用脚本将上述代码保存为ssl_pinning_bypass.js。确保frida-server在设备上运行。在电脑上执行命令附加到目标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查看反编译代码搜索关键词如X509TrustManager、checkServerTrusted、CertificatePinner、pin等找到具体的校验类和方法然后针对性地编写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。反编译APKapktool d target.apk -o target_output这会在target_output目录下生成反编译后的所有文件其中smali目录存放代码res目录存放资源。定位Pin存储位置使用Jadx-GUI打开target.apk在全局搜索栏搜索关键词pin、Pinning、sha256、public key、CertificatePinner、checkServerTrusted。仔细查看搜索结果找到类似CertificatePinner.Builder().add(api.example.com, sha256/AAAAAAAA...)的代码。记下这个类的完整路径和关键方法。修改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。回编译与签名# 回编译 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安装测试将target_modified.apk安装到测试设备上配置Burp代理尝试抓包。5.3 常见问题与避坑指南回编译失败最常见的原因是apktool版本与APK的编译环境不兼容或者APK本身有特殊的保护。尝试更新到最新版apktool。如果资源文件导致错误可以尝试用apktool d -r不反编译资源和-s不反编译代码来排除。App闪退Smali代码修改错误导致。可能是寄存器使用错误、方法签名不对、或NOP了不该NOP的指令。务必仔细核对。修改前备份原Smali文件。签名后无法安装可能签名方式不对。确保使用apksigner进行V1V2V3签名。安装时提示“与已安装应用冲突”需要先卸载原版App。加固App如果APK被腾讯乐固、梆梆、爱加密等加固第一步反编译出来的可能就是壳的代码。你需要先进行脱壳获取原始的DEX文件这涉及到更深层的逆向技术不在本文基础讨论范围内。6. 方案三实操安卓系统证书安装辅助方案这个方法不能直接破解SSL Pinning但它能解决很多“抓不到包”是因为系统不信任用户证书的问题。它将Burp的CA证书提升到系统级信任。前提设备必须已Root。从Burp导出证书在BurpSuite中Proxy-Options-Import / export CA certificate选择Certificate in DER format导出为cacert.der。转换证书格式并计算哈希# 将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推送证书到系统目录# 将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重启设备重启后Burp的证书就会出现在系统的“受信任的凭据” - “系统”列表中。此时所有默认信任系统证书的App即未启用SSL Pinning的App都会信任Burp的代理。重要提示在Android 7.0 (API 24) 及以上版本App默认不再信任用户安装的证书但依然信任系统证书。这就是为什么很多App在安卓高版本上即使安装了用户证书也抓不到包的原因。此方法正是为了解决这个问题。但对于启用了SSL Pinning的App此方法无效仍需配合方案一或二。7. 实战问题排查与高阶技巧即使掌握了方法实战中还是会遇到各种“妖魔鬼怪”。这里分享几个我踩过坑后总结的排查思路和技巧。7.1 抓包失败通用排查清单当Burp抓不到包时按顺序检查以下列表可以解决90%的问题代理设置手机Wi-Fi代理的IP和端口是否正确电脑防火墙是否允许了Burp的入站连接尝试在手机浏览器访问http://burp是否能下载证书。证书安装Burp的CA证书是否已正确安装到手机的用户凭据目录在安卓设置中搜索“证书”确认是否存在。对于安卓7考虑使用方案三安装为系统证书。目标App限制App是否使用了SSL Pinning本文核心是否使用了其他防代理技术如检测系统代理设置并拒绝连接可以尝试使用透明代理工具如redsocksiptables将流量强制转发到Burp。非HTTP/S流量App是否使用了纯Socket、WebSocket、gRPC或自定义协议的通信这些流量Burp默认无法解析。你需要使用更底层的抓包工具如tcpdump或Wireshark。证书绑定时机有些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-server或frida相关进程。可以重命名frida-server二进制文件并使用ps、proc等命令的Hook来隐藏进程。使用隐藏工具考虑使用如objection基于Frida的android anti-root-detection bypass命令或使用修改版的、具备更强隐藏能力的frida-server。7.3 针对特定框架的Hook技巧Flutter/DartFlutter应用的网络请求可能由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和静态分析反编译这两大武器并具备根据实际情况进行调试和适配的能力。多动手多分析遇到问题善用搜索引擎和社区你的“抓包”技能树就会越来越扎实。在实际测试中记得始终在合法授权的范围内进行尊重软件的安全边界。