SSTエンジニアブログ

SSTのエンジニアによるWebセキュリティの技術を中心としたエンジニアブログです。

Raspberry Pi 4 を使ったスマホ向け透過型Proxy環境の構築

こんにちは、SSTでWeb脆弱性診断用のツール(スキャンツール)開発をしている坂本(Twitter, GitHub)です。

前回の記事では Raspberry Pi 4 Model B Starter Kit (以下「ラズパイ」) をセットアップしました。 本記事では WiFi AP 化した上で、HTTP(S) アクセスを PC 上の Burp の Invisible (透過型) Proxy に転送し、スマホからのHTTP(S)通信をキャプチャできる環境を構築します。

f:id:msakamoto-sf:20210730142734p:plain
本記事で目指す WiFi AP + 透過型 Proxy 構成図

検証環境:

  • Burp Suite Community Edition v2021.5.1
  • Raspberry Pi 4 Model B, OS: Raspbian (32bit)
  • iPad (iOS 12.5.4)*1

なぜ WiFi AP を経由して Invisible(透過型) Proxy を通すのか?

そもそも iOS *2 /Android では WiFi 接続設定から HTTP Proxy を設定可能です。 なぜわざわざ WiFi AP を立ち上げ、AP中のiptables で tcp:80/443 を Burp の Invisible (透過型) Proxy に転送するのでしょうか?

一言で答えると、スマホアプリによってはHTTP Proxy に対応していないケースがあるためです。

スマホアプリが WiFi 接続設定の Proxy に対応するには「1. iOS/Android の WiFi 接続設定から Proxy 設定を取得し」、「2. Proxy 設定に応じて HTTP(S) のHTTPリクエストをProxy用にカスタマイズする」 *3必要があります。 iOS/Android が提供する標準のHTTP通信機能や、それをベースに拡張したライブラリなどでは自動でこれらの要件を満たします *4 ので、それらを使ったスマホアプリであれば今回のような構築は不要です。

ところがまれに、フレームワークなどでHTTP通信機能が独自実装されているせいか、スマホのWiFi 接続で Proxy を設定してもそれを無視するアプリがあります。 先日の記事 iOSのHTTP通信ライブラリとWiFiのHTTP Proxyサポート状況の調査メモ - SSTエンジニアブログ を例にすると、 iOSが提供する NSURLSession/URLSession を使うアプリであれば自動でProxy設定に対応しますが、Flutter 製のアプリではデフォルトでは WiFi の Proxy 設定を無視するようになっています。

つまり「Proxy 未対応のHTTPクライアント」のHTTP(S)通信を Burp 等のHTTP Proxy に通したいわけですが、そのようなケースにまさにピッタリなのが先日紹介した Invisible(透過型) Proxy になります。 Burp側では Invisible(透過型) Proxy を起動しておき、WiFi AP 側でHTTP(S)通信を Burp に転送します。 これによりスマホアプリのHTTP Proxy 対応状況に関わらず、 Burp の Invisible(透過型) Proxy でHTTP(S)通信をキャプチャすることが可能となります。

SSTのWeb脆弱性診断サービスではスマホアプリによるHTTP(S)通信も対応しています。 近年は iOS/Android アプリの診断依頼も増加しており、WiFi の Proxy 設定をしても Burp で通信をキャプチャできないケースが何件か発生しています。 そのようなケースでも本記事で紹介する環境を構築することで HTTP(S) 通信をキャプチャし、脆弱性診断が可能となります。

ラズパイで WiFi AP を構築

ラズパイを WiFi AP にする方法は、公式ドキュメントで詳細に解説されています。

解説されている構成は今回の目的にそのまま当てはまります。 そのため、基本的にドキュメントどおりに進めました。

差分としては以下になります:

  1. IPアドレスについては自宅のネットワークをベースに調整しました。
  2. /etc/hostapd/hostapd.conf の編集で、公式ドキュメントの例から以下の点をカスタムしました。
    • country_code=JP に修正しました。
    • hw_mode も 5GHz 帯にしようと思ったが、チャネル選択し直しでトラブルになるのを避けるため、公式ドキュメント通りの hw_mode=g (2.4GHz), channel=7 のままにしました。
  3. 前回のセットアップでステルスSSIDへの接続設定を /etc/wpa_supplicant/wpa_supplicant.conf に追記しましたが、これをコメントアウトしました。

設定完了して reboot 後、手持ちのスマホ端末 (iPad) からSSIDを確認成功、無事接続することができました。 IPアドレスも dhcp で設定したレンジ内が割り振られ、インターネットに接続できました。 また iPad から Burp を動かすPCのIPアドレスに ping も飛ばせましたので、iPad - ラズパイ - PC の疎通確認もできました。

続いて iptables によるHTTP(S) 通信の転送設定を実施します。

その他参考記事:

iptables によるHTTP(S) 通信の転送設定

ここのセクションについては同僚である ymaehira が書いてくれた社内文書をベースにしています。 どういうことかというと、実は数年前にも同様にラズパイ(当時は Raspberry Pi 3) を使って WiFi AP 化して透過型Proxyを設定した事例があり、その時に苦戦しつつもなんとか環境構築し、手順書を社内に残してくれていたのです。 今回は Raspberry Pi 4 となり、ラズパイ部分の設定手順は変わったものの、iptables の部分はほぼそのまま使わせてもらいました。 改めてお礼申し上げます。

iptablesの設定としては、WiFi (wlan0) で受けた tcp:80/443 を DNAT で Burp が動いているPCに PREROUTING します。 Burp の Invisible(透過型) Proxy の仕組みと使い方 - SSTエンジニアブログで解説したとおり、Burp 側でも tcp:80, tcp:443 それぞれで Invisible Proxy Listener を起動します。 そのため tcp:80 はそのまま tcp:80 へ、tcp:443 もそのまま tcp:443 に転送するのがポイントになります。

$ sudo iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80  -j DNAT --to-destination (Burpを動かすPCのIPv4):80
$ sudo iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 443 -j DNAT --to-destination (Burpを動かすPCのIPv4):443

次回起動時にも反映させたい場合は sudo netfilter-persistent save して設定を保存しておきます。

その他 iptables コマンド紹介

iptables設定確認:

$ sudo iptables -nvL
$ sudo iptables -t nat -nvL
$ sudo cat /etc/iptables/rules.v4

BurpのIPが変わった場合などに、iptablesの設定を変更:

# 1. 番号確認
$ sudo iptables -t nat -nvL --line-numbers

# 2. 削除
$ sudo iptables -t nat -D PREROUTING 1
$ sudo iptables -t nat -D PREROUTING 1

※1番を2回削除してるのは、tcp:80 用と tcp:443 用の2つのフォワード設定をしてたので、1つ削除するともう片方が1番に繰り上がる。 → 1番を2回削除すれば tcp:80, tcp:443 の2つのフォワード設定を削除完了となる、ということ。 1つ削除するごとに sudo iptables -t nat -nvL --line-numbers すればその様子が分かる。

Burp の Invisible(透過型) Proxy 設定

Burp 側の Proxy 設定を行います。

  1. tcp:80/443 それぞれで "Support invisible proxying" にチェックを入れた listener を作成し、"Bind to address" を "All interfaces" にします。
  2. tcp:443 の listener では TLSv1.3 を無効化します。 *5
  3. AppStore や Google Play, 決済系, 一部SNSアプリ向けに Proxy タブ → Options タブ →TLS Pass Through → "Automatically add entries on client TLS negotiation failure" にチェックを入れます。

→ Proxy 設定は以下のようになりました。

f:id:msakamoto-sf:20210730161026p:plain

なお、場合によっては Project options タブ → HTTP タブ → "HTTP/2" で "Enable HTTP/2" のチェックを外した方が良いかもしれません。 今回 iOS の Safari で確認したところ、ここのチェックがONの状態だと、なぜか HTTP/2 のレスポンスがヘッダーも含めてまるごとブラウザ画面に表示される現象が発生しました。 チェックを外すと通常の表示に戻りましたので、以降はチェックを外したままにしています。 詳細は不明で、iOS/Safari/Burp のバージョンによっては発生しない可能性もあります。 参考までの共有でした。

実際にスマホ端末(iOS)から HTTP(S) 通信をキャプチャ

準備が整いましたので、いよいよ実際にスマホ端末(今回はiOS)からHTTP(S) 通信をキャプチャしてみます。

  1. iOSをラズパイのWiFi AP に接続 ( Proxy は未設定のままにしておく)
  2. (まだプロファイルをインストール & 信頼していなければ) Safari で http://(burp のIPアドレス):8080 にアクセスして "CA Certificate" (プロファイル) をダウンロードしてインストール → 「設定」→「一般」→「情報」→「証明書信頼設定」から「ルート証明書を全面的に信頼する」で「PortSwigger CA」を有効化
  3. Safari を起動し、以下のURLにアクセスしてみる。
  4. Burp の Proxy タブ → HTTP history タブでそれぞれのHTTP(S)通信をキャプチャできているか確認する。

筆者の環境では無事キャプチャに成功し、HTTPS通信についてもHTTPリクエスト/レスポンスの内容(= 平文)を見ることができました。 Twitter 等の一部通信は TLS Pass Through に自動追加されたためキャプチャできていないものの、アプリとしては正常に動作しました。

正常に通信できない場合は、以下の点をチェックしてみてください。

  1. Burp を動かしているホストで、firewall 設定で tcp:80/443 をオープンしていること。
  2. Burp の Proxy の listener 設定で、"Bind to address" が "All interfaces" になっていること。
  3. Burp の Proxy の listener 設定で、 tcp:443 の invisible proxy listener で TLSv1.3 が無効化されていること。
  4. Burp の Proxy の TLS Pass Through 設定で、クライアントのnegotiation failure で自動追加する設定が ON になっていること。
  5. Burp の Project options の HTTP 設定で、HTTP/2 を無効化してみる。
  6. ラズパイでの iptables 設定は想定通りであること。
  7. 各所で設定したIPアドレスは想定通りであること。
  8. ラズパイを sudo reboot で再起動後に、もう一度 iptables を設定してみる。

まとめ

本記事ではラズパイを WiFi AP 化し、スマホのHTTP(S)通信を iptables で Burp の Invisible (透過型) Proxy に転送し、HTTP通信内容のキャプチャに成功しました。

  1. ラズパイの公式ドキュメントに従って WiFi AP を構築しました。
  2. iptables で tcp:80/443 を Burp が動いているPC に forward しました。
  3. Burp では tcp:80/443 それぞれで Invisible Proxy Listener を動かしました。
  4. 実際に iOS の Safari を使って、WiFi 接続で Proxy を未設定の状態でも HTTP(S) 通信を Burp でキャプチャできることを確認しました。

今回の環境を使えば、HTTP Proxy に対応しているか不明なデバイスからの HTTP(S) 通信を Burp でキャプチャできるようになります。 脆弱性診断のみならず、開発現場でも役に立つと思います。 今回はラズパイを使いましたが、Linux が動いたり iptables 相当のルーティングが設定できる WiFi ルータであれば同様な設定が可能と思われます。 皆様のお役に立てば幸いです。