mitmproxy のintercept機能の使い方をhackerschool.jp Take #17のwriteupで解説

#はじめに
mitmproxy というのはコンソール型の通信監視ツールで、プロキシ機能を通じて通信サーバと端末の間に入り、その通信内容を表示するものです。

このmitmproxyの使い方をCTFの問題を解きつつ解説します。
(使い方と言っても intercept 機能に絞ってます)

#環境
MacBook Air (11-inch, Early 2015)
macOS High Sierra バージョン 10.13.6
Google Chrome バージョン: 68.0.3440.106（Official Build） （64 ビット）

(本記事では以下をインストールします)
mitmproxy: stable 4.0.4
Google Chrome 拡張機能 Proxy SwitchySharp 1.10.6

#問題
http://www.hackerschool.jp/hack/take17.php
この問題を解きつつ、mitmproxyの使い方を解説していきます。

パスワードを入力して「突破する」ボタンを押下するだけですが、なんのパスワードを入力するか探すことが問題ですね。

#writeup
##準備
###インストール
mitmproxyをインストールします。
`$ brew install mitmproxy`

Chrome上で手軽にプロキシを設定できるように拡張機能「Proxy SwitchySharp」もインストールしてください。そしてHTTP Proxyの設定を、127.0.0.1:8080 にセットし、名前を「mitmproxy」等つけてください。「Direct Connection」をクリックすれば通常通りProxy無しに、「mitmproxy」をクリックすればセットしたアドレスとポートがProxyになります。

「Direct Connection」
`Chrome --------------------------------> internet`
「mitmproxy」
`Chrome --> mitmproxy(127.0.0.1:8080) --> internet`

ですね。

###mitmproxyの起動
ターミナルで
`$ mitmproxy`

Proxy SwitchySharp で「mitmproxy」にセットします。

これでchromeで好きなサイトを見ると、ターミナルにキャプチャされたHTTP requestが表示されています。これで準備完了です。

##HPへアクセス
http://www.hackerschool.jp/hack/take17.php

まずはソースを読みます。
chromeで 表示 > 開発/管理 > ソースを表示

```html:
<form action="./take17.php" method="post" name="form1" id="form1" onsubmit="return false;" class="form-horizontal">
　　<fieldset>
　　　　<div class="control-group">
　　　　　　<label class="control-label">パスワード：</label>
　　　　　　<div class="controls">
　　　　　　　　<input type="text" name="input_id" value="" style="">
　　　　　　　　　　<br><span class="red"></span>
　　　　　　</div>
　　　　</div>
　　　　<div class="form-actions">
　　　　　　<button class="btn btn-primary" type="button"  onclick="fnFormSubmit()">突破する！</button>
　　　　</div>
　　</fieldset>
```
突破するボタンをクリックすると、fnFormSubmit()が呼ばれます。
fnFormSubmit()を探すと、2箇所あります.

```javascript:1110行目
<script type="text/javascript">
  function binary(input) {
    return input.toString(2);
  }

  //パスワードチェック
  function fnFormSubmit(){
    if (binary(parseInt(document.form1.input_id.value))==100110100100) {
      self.location=document.form1.input_id.value + '.html';
    } else {
      alert('残念！');
      document.form1.submit();
    }
  }
</script>
```

```javascript:1220行目
<!--見つかった・・-->
<script type="text/javascript">
  //パスワードチェック
  function fnFormSubmit(){
    if(document.referrer
        =="http://www.hackerschool.jp/hack/take17_dummy_referrer/"){
      if (binary(parseInt(document.form1.input_id.value))==11010100001011) {
        self.location=document.form1.input_id.value + '.html';
      } else {
        alert('残念！');
        document.form1.submit();
      }
    }else{
      alert('残念！');
      document.form1.input_id.value = "";//パスワード初期化
      document.form1.submit();
    }
  }
</script>
```

javascriptは後から出てきたほうが勝つので後者のfnFormSubmit()が勝ちます。

```javascript:抜粋
if(document.referrer=="http://www.hackerschool.jp/hack/take17_dummy_referrer/"){
  if (binary(parseInt(document.form1.input_id.value))==11010100001011) {
    self.location=document.form1.input_id.value + '.html';
  } else {
    alert('残念！');
    document.form1.submit();
  }
}
```
リファラーの条件が邪魔です。こんなURLから飛んできたわけではないので。
input boxに入れた整数値を2進数にすると 11010100001011 と等しくなるのがパスワードですね。10進に変換します。

```terminal:
$ echo "obase=10;ibase=2;11010100001011"|bc
13579
```
さて、13579をinput boxに入れてボタンを押しても、リファラーが異なるので適正にパスワード評価がなされません。

ということで、mitmproxyを使ってjavascriptを無理やり書き換えてやります。

##mitmproxyの使い方
mitmproxyの基本的な使い方はこちら等を見てください。
https://qiita.com/hkurokawa/items/9034274cc1b9e1405c68

? を押すとヘルプが出ます。key bindとfilterのコマンドが左右キーで切り替えられます。
元の画面に戻るには q を押下します。基本的な操作は vi と似ています。

ここでやりたいことは
1. http://www.hackerschool.jp/hack/take17.php にアクセス
2. レスポンスをinterceptして一時止める。
3. レスポンスボディに含まれる上記JavaScriptを一部書き換え、resumeする。
4. パスワードを入力し、ボタン押下
です。

インターセプトするには i 押下し、以下のように設定します。
~bs というのはResponse bodyの中に「take17_dummy_referrer」が含まれれば一時止める。と読みます。
![スクリーンショット 2018-08-13 19.26.13.png](https://qiita-image-store.s3.amazonaws.com/0/272771/8b461315-cebe-c961-1657-b7f21f93eba7.png)

リターン押下で
![スクリーンショット 2018-08-13 19.26.38.png](https://qiita-image-store.s3.amazonaws.com/0/272771/fb6d44d6-da28-99a4-8efb-5d34f533dc02.png)
とセットされます。

これでインターセプトの準備ができました。
http://www.hackerschool.jp/hack/take17.php にアクセスすると、
![スクリーンショット 2018-08-13 19.27.46.png](https://qiita-image-store.s3.amazonaws.com/0/272771/749afcbc-83d9-9cf0-e96d-ede9b1eaab4a.png)

条件に適合したHTTP通信が赤色で表示されます。
当該行でエンター押下

![スクリーンショット 2018-08-13 20.03.51.png](https://qiita-image-store.s3.amazonaws.com/0/272771/6fdfa6eb-9ec5-eec1-0229-0dcd77c4673d.png)

Response intercepted というタブになってますね。
ここからResponse Bodyを書き換えてやります。

eを押下すると小窓が開きます
![スクリーンショット 2018-08-13 20.04.37.png](https://qiita-image-store.s3.amazonaws.com/0/272771/649b94db-f18b-4e24-dd65-1ae2e414ff6c.png)

a) response-body を選択肢、エンター押下。
するとviが立ち上がり、response bodyの内容が表示されます。

```javascript:1220行目
<!--見つかった・・-->
<script type="text/javascript">
  //パスワードチェック
  function fnFormSubmit(){
    if(document.referrer
        !="http://www.hackerschool.jp/hack/take17_dummy_referrer/"){
```
リファラーチェックを == から != に書き換えてやります。これで適正にパスワードが評価されるようになります。

viなので
:wq
で保存すると、書き換えたレスポンスが返ります。

一時停止した通信を再開(resume)するには a か A を押下します。
a だと当該通信のみ。A だとすべてのinterceptされた通信がresumeします。


問題はこの後も続くのですが、mitmproxyの解説が終わったのでここまでとします。
Happy Hacking!

#感想
mitmproxy。便利です。wiresharkだとBodyの日本語が化けるので、その点でも良いです。

ちなみに、Man In The Middle Proxy で、mitmproxyです。

#参考
[モバイルアプリ開発者のための mitmproxy 入門](https://qiita.com/hkurokawa/items/9034274cc1b9e1405c68)

[mitmproxyでandroidの通信を改竄](http://yamori-jp.blogspot.com/2017/10/mitmproxyandroid.html)

[mitmproxy cheat sheet](https://gist.github.com/2bard/e114c57e3cebec7d5eb5)

#履歴
2018/08/13 初版