バージョンに関係のないBurpSuiteでAndroidのHTTPS通信を診断する手法を発見
スマートフォン診断を実施している皆様こんにちは、バージョンが上がる度BurpSuiteでAndroidのHTTPS通信を取るのに苦労しているかと存じます。ついにそんな悩みから解放される日が来たかも知れません。最後の壁は人間になりますが、そこに関しても幾つか対策を記載しています。
結論から言うと
アプリファイルをデコンパイルしてres/xml/network_security_config.xmlがあれば開き、なければ作成しファイルの<certificates src=”system” />に「追加」して<certificates src=”user” />を書き込んで再度ビルドして署名してインストールするとBurpSuiteでAndroidのHTTPS通信が取れます
でピンとくる方は、以下は釈迦に説法になりそうですので、直接🔗手順に飛んで頂ければと存じます。
iOSのATS(App Transport Security)の後追いでAndroid 9(Pie)がデフォルトでHTTPS通信となった際に、開発中のアプリでHTTP通信の際に弄った記憶があるのではないでしょうか。この場合弄るのは「app/src/debug/res/xml/network_security_config.xml」なので少し異なりますが発想のきっかけにはなります。
この手順は、これからバージョンアップが進んでも使い続けることが可能な手法です。この方法を思い付いた瞬間は先駆者的な達成感に浸ってましたが、答えがわかって検索してみると先に答えに辿り着いている海外の先駆者がたくさんいました。日本語圏内ではまだ記事が出てなさそうでしたので先人に敬意を表しつつ記事にすることとしました。
なぜ、毎度苦労してまでプロキシツール(BurpSuite)で通信を取ろうとしているのか
苦労して通信を取得しようとしていると冷ややかな反論受ける可能性がありますので備えておくに越したことはありません。
よくある反論として、「これなら中間者攻撃あり得ないんだからやる意味なくない?」などと自身の前提と相手の前提が同じだとたかを括ってくる方がいらっしゃいます。通信をプロキシする理由は中間者攻撃に限った話ではなく、対サーバの診断やコンテンツ汚染された通信先をエミュレートしたりなどありますが、一番大事なのは何を実施したのか通信ログを残して説明責任を果たすことです。「企業で提供するサービスとして通信ログを取り説明責任を果たすことにつながることに実施の意味があります」と必要があれば、前後なるべく短く枕をつけて返答しましょう。
「デコンパイルでコード見れば通信エミュレートできる」という意見に対しては上の話だと少し足りないので、「画面上のUXと対応づけて通信を説明しないと、受け取り手が理解し辛いため」と説明するといいでしょう。レイヤー8(人間)と疎通し作業が許可されたら早速、BurpSuiteでAndroidのHTTPS通信を取得していく手段を紹介したいと思います。レイヤー8(人間)の疎通に失敗した場合、デバック・再ビルドを受け入れてもらえないケースも想定して🔗旧来の方法も後述紹介しておりますのでご参考くださいませ。
Android10以上が要件に入っている場合や、レイヤー8(人間)の疎通に成功している場合はこのまま次の章にお進み頂ければと存じます。
バージョンに関係のないBurpSuiteでAndroidのHTTPS通信を診断する手法
この手順ではAPKファイルをデコードして、ビルドする関係でAPK TOOLがインストールされている必要があります。
公式にもインストール方法が出ていますが、MACOSの場合は以下のようにbrewで導入するのが楽かと存じます。
brew install apktool
以下のコマンドでデコンパイルできます(ファイルをターミナルにドロップするとパスが入ります)。このデコンパイルはAndroidManifest.xmlを可読な状態で読む際にも使用しますね。
$apktool d MyApp.apk
展開したファイルは以下のようになっているかと存じます。
- AndroidManifest.xml(サービス許可宣言や設定類)
- res(画像等のリソース類)
- classes.dex(プログラム本体)
- resources.arsc(言語等のリソース)
- META-INF(署名ファイル)
ここにresディレクトリが存在するはずなのでres/xml/network_security_config.xmlがあれば開き
ファイルの中に<certificates src=”system” />に「追加」して<certificates src=”user” />を書き込み保存しましょう。
もしなかったらres/xml にnetwork_security_config .xmlを作成し以下のように記載します。
<?xml version=”1.0″ encoding=”utf-8″?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src=”user”/>
<certificates src=”system”/>
</trust-anchors>
</base-config>
</network-security-config>
さらにAndroidManifest.xml にも以下の変更を加えます。
<application android:allowBackup=”false”
android:networkSecurityConfig=”@xml/network_security_config”
この状態でAPKファイルをビルドします
$apktool b MyApp
ただこのままだと署名されていないためインストールできないので、署名を行うためにkeystoreを以下のように適当に作りましょう(パスフレーズ忘却すると終わるので控えておく)
$keytool -genkey -v -keystore myapp.keystore -alias myappstore -keyalg RSA -keysize 2048 -validity 10000
以下で署名します。パスフレーズはここで使います。
$jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore myapp.keystore MyApp.apk myappstore
adb install としてこのアプリを端末にインストールします。(ファイルをターミナルにドロップするとパスが入ります)。必要に応じて-rオプションをつけてください。
adb install MyApp.apk
これで強引ですが、このアプリについては信頼された証明書に関係なくHTTPSトラフィックが取れるようになります。
※Androidエミュレータ側で①〜③が設定されていることが前提となります(盛大にボケをかましてしまう前に確認しましょう)
次に、Android10が出るまで「/system/etc/security/cacerts」に証明書を入れようという手法に関してもAndroidの仕組みや経緯の学びにつながるので少し振り返ってみましょう。
Android10以前の「/system/etc/security/cacerts」に証明書を入れてBurpSuiteでAndroidのHTTPS通信を診断する手法
Android 7 以降、アプリファイル内で明示的に証明の仕様が指定されない限り、システム CA 証明書のみを信用する仕様に変更になりました。
このためBurpSuiteの証明書をシステム CA 証明書として、「/system/etc/security/cacerts」に証明書を入れ込む必要がありました。
BurpSuiteの証明書自体は、BurpSuiteを以下のようにバッティングしなそうなポートで立ち上げて(嘗ては8080ポートでSkypeなどとバッティングして事故ってました)
上の場合、「127.0.0.1:9090」にアクセスして右上の青枠部分を押下するとDER形式の証明書が落ちてきます。素材が手に入ったところで手順に入っていきます。
証明書をシステム CA 証明書に入れるために加工する手順
まず、下拵えとして証明書の形式を DER から PEM に変更します。
$openssl x509 -inform DER -in cacert.der -out cacert.pem
Android の CA 証明書は、拡張子として「0」を付けたハッシュ名となるため、hashを取得
$openssl x509 -inform PEM -subject_hash_old -in cacert.pem |head -1
この出力結果を使用して「ハッシュ値.0」にリネームします。これで証明書の準備は完了です。
エミュレータの立ち上げから証明書の書き込みと確認
書き込み可能で立ち上げる(Start an AVD (without Play Store) with writable “/system”:)因みに再起動すると書き込めなくなります(素直にやり直すしかない)-show-kernelをつけおくとカーネルのログが取れて判断材料が増えます。
emulator -avd AVD_Name -writable-system
launchctl setenv studio.emu.params -writable-system
launchctl getenv studio.emu.params
セキュアブートが原因で失敗する場合は以下も試します。
adb shell avbctl disable-verification
起動したらroot権限になれるか確認します。
adb root
adb remount
ダメだった場合、以下も試してみましょう。
adb shell mount -o rw,remount,rw /system
adb shell mount -o ro,remount,rw /system
/sdcardに「adb push 」してからadb shellで入るとルートになっているので「/system/etc/security/cacerts」に証明書を入れる
chmod 644 /system/etc/security/cacerts/ハッシュ値.0
Settings -> Security -> Trusted Credentials > Systemに「Portswigger CA」がいればOKです。お疲れ様でした。
手順的にミスするとやり直しが発生することや、失敗部分の追跡がやや高度で対応可能なエンジニアの確保に苦労することから今回冒頭でお伝えしたデコンパイル&再ビルドの手法は、対応可能な組織が広がるのではないでしょうか。
以上です。日本のサービスがセキュアになり、皆様のサービスの末永い健康経営に繋がれば幸いです。