rcmdnk's blog

20210302_mitmit_200_200

アプリなどが何ら化クラウドサーバーと交信して色々やってる部分を 確認して別のところで操作出来るようにしてみるという話。

mitmproxy

mitmproxyはプロキシサーバーをたてて、通信をそこを通すことで通信の内容を 監視したり、パラメータを変更して通信を送ったりすることを実現してくれるツール。

インストールは上記ページからインストーラーなりバイナリをダウンロードして使うか、 Homebrewを使っているならMacでもWindows WSLでも

$ brew install mitmproxy

で入れられます。

これで

$ mitmproxy

とすることでプロキシサーバーを立ち上げられます。デフォルトでは8080番ポートを使いますが、 変更したい場合は

$ mitmproxy -p 10080

の様な感じでポートを指定します。

Windows WSLでの利用

WindowsのWSLから実行する場合は、WSLのポートとWindowsの外向けIPアドレスとを結びつける必要があります。

詳しくは以下で。

この方法の中で外部向けファイアウォールの設定も行うので外部からWindowsのIPアドレス:8080(ポートを変更している場合は8080を変更したもの)でアクセス出来るようになります。

ファイアウォールに関する確認をしたい場合はWindows Defenderファイアウォールから。

設定したらアクセスするためにIPアドレスを調べます。

設定ネットワークとインターネット状態プロパティ

で使っているネットワークのプロパティにいって、下の方にあるIPv4アドレスの値を取得します。

もしくはWSLの中からなら

$ ipconfig.exe

出でてくるネットワークのうち、 イーサネットかWireless LANで使っているもののIPv4アドレスを取得。

Macでの利用

システム環境設定セキュリティーとプライバシーファイアウォールから必要なポートを開放したりしてください。

IPアドレスは システム環境設定ネットワーク で使っているネットワークの詳細を表示させて、 TCP/IPのタブにいってIPv4アドレスを取得。

もしくはターミナルで

$ ifconfig
...
en0 flags=...
   ...
   inet 192.168.11.3 netmask ...

とかで使っているネットワークのinetの値を取得。

iPhoneからの接続

まずは

まず、MacなりWindows WSLなりで体制を整えて、mitmproxyを実行して待つ状態にしておきます。

1
2
3
4
5
$ mitmproxy
Flows


[0/0]

みたいな感じの表示になってるはずです。

この状態でiPhoneから接続してみます。

使っているWi-Fiの設定を開き、 下の方に行くとプロキシを構成という項目があってオフになっていると思います。

20210302_wifi.jpg

このここを開いて、手動を選択するとサーバポートの入力が出来るようになるので、 サーバに上で取得したIPアドレスと、ポートに8080(別途指定してたらそれ) を入力して保存します。 (認証の欄はオフのママ。)

20210302_proxy.jpg

これで保存。

この設定で一時的にiPhoneからネットワークに接続できない状態になっているので注意してください。

ネットワークを有効にするために、プロキシサーバーに対する証明書をインストールする必要があります。

上の設定後、Safariを開いて、http://mitm.itを開きます。

もしプロキシ設定がきちんとできてないと

20210302_notpassing.jpg

If you can see this, traffic is not passing through mitmproxy.
Visit the Documentation

みたいなページが出てきます。(この状態だと普通にネットワーク接続は出来るがmitmproxyは通してない状態。)

正しく設定されていると以下の様なページが出てきます。

20210302_mitmit.jpg

もし、どちらのページも出てこず接続が出来ないような状況であれば mitmproxyを立ち上げているサーバーに接続できていない状態なので、 サーバー側のファイアウォールやポートの設定などを再度調べてみてください。

ここで、iOSのGet mitmproxy-ca-cert.pemをクリックすると、 以下の様にこのWebサイトは構成プロファイルをダウンロードしようとしています。 許可しますか? という問いが出てくるので許可します。

20210302_download.jpg

このとき、ブラウザがSafari以外のChromeとかだとこのダイアログが出ないので、 必ずSafariで開く必要があります。

ここでダウンロードが完了したら、設定を開きます。 そうすると、Apple IDの情報の下に以下のような ファイルがダウンロードされましたという項目が追加されています。

20210302_settings.jpg

そこをクリックするとダウンロードしたプロファイルのインストールページに行くのでインストールします。

20210302_install.jpg

正しくインストールされたかどうかは設定一般プロファイル に行ってmitmproxyがあれば確認できます。

20210302_profile.jpg

これで証明書はインストールされましたがまだ有効にはなってない状態です。

有効にするために、設定情報証明書信頼設定(一番下) に行って、mitmproxyの欄があるはずなので、そのチェックを有効に変更します。

20210302_enable.jpg

このルート証明書を全面的に信頼する、の欄でチェックを有効に。

これでmitmproxyを通した通信が出来るようになりました。

mitmproxyを使って通信内容を見てみる

上の状態でブラウザでなにか見たり、なにか通信するアプリを使うと、 mitmproxyを起動したターミナルに色々と通信内容が出てくると思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Flows
>> GET https://lh3.googleusercontent.com/-DD1vxNl412w/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclA1zzNkcym…
       ← 200 image/png 3.7k 167ms
   GET https://lh4.googleusercontent.com/-LctrK_qMfHM/AAAAAAAAAAI/AAAAAAAAAAA/AMZuucnl1ioWQwg-…
       ← 200 image/png 2.46k 372ms
   GET https://lh5.googleusercontent.com/-cFfiOvjaCq8/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclMRErLwKii…
       ← 200 image/png 2.84k 172ms
   POST https://update.googleapis.com/service/update2 HTTP/2.0
        ← 200 text/xml 234b 145ms
   POST https://oauthaccountmanager.googleapis.com/v1/issuetoken HTTP/2.0
        ← 200 application/json 361b 139ms
   POST https://oauthaccountmanager.googleapis.com/v1/issuetoken HTTP/2.0
        ← 200 application/json 422b 147ms
   POST https://oauthaccountmanager.googleapis.com/v1/issuetoken HTTP/2.0
        ← 200 application/json 422b 137ms
   POST https://oauthaccountmanager.googleapis.com/v1/issuetoken HTTP/2.0
        ← 200 application/json 391b 162ms
   GET https://clientservices.googleapis.com/chrome-variations/seed?osname=ios&channel=stable&…
       ← 304 [no content] 243ms
   POST https://oauthaccountmanager.googleapis.com/v1/issuetoken HTTP/2.0
        ← 200 application/json 424b 105ms
   POST https://accounts.google.com/ListAccounts?gpsia=1&source=ChromiumBrowser&json=standard …
        ← 200 application/json 332b 95ms
⇩  [1/166]                                                                                [*:8080]

この画面での操作はVimライクなもので、

  • j: 上を選択
  • k: 下を選択

また、選んだ状態でEnterを押すと各通信の詳細を見ることが出来て、 RequestResponseDetailsのタブを持ったページに飛びます。

1
2
3
4
5
6
7
2021-XX-XX XX:XX:XX POST https://clients4.google.com/chrome-sync/command/?client=Google+Chrome&
                         client_id=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX HTTP/2.0
                         ← 200 application/vnd.google.octet-stream-compressible 475b 102ms
             Request                         Response                          Detail
content-length:    2396
pragma:            no-cache
...

このページでもVimライクに

  • h: 左を選択
  • l: 右を選択

このページからはqを押すと元の一覧ページに戻ります。

それぞれのページで?を押すと ショートカットキーの一覧のヘルプを見ることも出来ます。

よく使う便利な使い方としては、 一覧ページで 他に便利な使い方として、

  • 一覧ページでShift-F: 新しい通信があったとき一覧を常時更新する
    • デフォルトでは画面いっぱい表示されるとそこで停止する。jとかで下に行くと新しいものが見れる。
  • 一覧ページでf: 文字入力モードに入って、入力してEnterを押すと入力した文字列でフィルターした通信のみを表示する。
  • 一覧ページ、もしくは特定の通信を選んだページで:でコマンドモードに入り、: export.clip curl @focusを実行。
    • 選択中の通信をcurlコマンドで再現するものをクリップボードに入れる。

あたり。

通信を見始めるといろいろな通信が出てきて溢れてしまいますが、 必要な通信は通信先のドメイン名などに特定のものがあるはずなので、それでフィルター。

興味がありそうな通信をそれぞれ見つつ、 使いたい通信が合った場合、: export.clip curl @focusでコマンドを取得。

コマンドラインにペーストして実際に通信が成功するか見てみる、といった具合。

さらに下のページを使うと適当な言語で通信を再現することが出来るようになります。

Convert cURL command syntax to Python requests, Ansible URI, browser fetch, MATLAB, Node.js, R, PHP, Strest, Go, Dart, JSON, Elixir, and Rust code

上のページのcurl command部分に取得したcURLコマンドを入力して、 欲しい言語をLanguageで選ぶとその言語で使える形で 通信を再現してくれます。

例えば、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2021-XX-XX XX:XX:XX GET http://mitm.it/
                        ← 200 OK text/html 16.72k 25ms
             Request                         Response                          Detail
Host:                       mitm.it
Connection:                 keep-alive
Proxy-Connection:           keep-alive
Upgrade-Insecure-Requests:  1
Accept:                     text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent:                 Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X)
                            AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77
                            Mobile/15E148 Safari/604.1
Referer:                    http://mitm.it/
Accept-Language:            ja-jp
Accept-Encoding:            gzip, deflate
No request content                                                                        [m:auto]

みたいな通信があった場合 cURLコマンドを取得すると

curl -H 'Connection: keep-alive' -H 'Proxy-Connection: keep-alive' -H 'Upgrade-Insecure-Requests: 1' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1' -H 'Referer: http://mitm.it/' -H 'Accept-Language: ja-jp' --compressed http://mitm.it/

みたいなものになります。

これを上のページで整形すると、例えばPythonなら

mitm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
import requests

headers = {
    'Connection': 'keep-alive',
    'Proxy-Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1',
    'Referer': 'http://mitm.it/',
    'Accept-Language': 'ja-jp',
}

response = requests.get('http://mitm.it/', headers=headers)

Node.js (fetch)なら

mitm.js
1
2
3
4
5
6
7
8
9
10
11
12
13
var fetch = require('node-fetch');

fetch('http://mitm.it/', {
    headers: {
        'Connection': 'keep-alive',
        'Proxy-Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1',
        'Referer': 'http://mitm.it/',
        'Accept-Language': 'ja-jp'
    }
});

Goなら

mitm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest("GET", "http://mitm.it/", nil)
  if err != nil {
    log.Fatal(err)
  }
  req.Header.Set("Connection", "keep-alive")
  req.Header.Set("Proxy-Connection", "keep-alive")
  req.Header.Set("Upgrade-Insecure-Requests", "1")
  req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
  req.Header.Set("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1")
  req.Header.Set("Referer", "http://mitm.it/")
  req.Header.Set("Accept-Language", "ja-jp")
  resp, err := client.Do(req)
  if err != nil {
    log.Fatal(err)
  }
  bodyText, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("%s\n", bodyText)
}

といった感じ。

これで簡単に好きな言語で通信を再現できるようになります。

Sponsored Links
Sponsored Links

« Windows WSL2に外部から直接アクセスするための設定 シャープの加湿空気清浄機をアプリ外から操作する »

}