V. Case study và ví dụ
1. Case study: Redirect DoS
Case study đầu tiên tôi muốn giới thiệu tới các bạn là sự kết hợp lỗ hổng web cache poisoning nhằm tấn công DoS (denial of service) tới người dùng khác thông qua quy trình chuyển hướng request của Cloudflare.
Một đường dẫn đăng nhập của Cloudflare tại dash.cloudflare.com/login
, sau khi người dùng đăng nhập, họ được chuyển hướng tới /login/
, chú ý rằng đường dẫn đích có thêm một ký tự /
. Tác giả James Kettle sau khi quan sát cơ chế caching của ứng dụng, đã phát hiện các tham số gửi kèm trong request được loại bỏ khỏi cache key:
GET /login?x=abc HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/ HTTP/1.1 301 Moved Permanently
Location: /login/?x=abc
GET /login HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/ HTTP/1.1 301 Moved Permanently
Location: /login/?x=abc
Tuy nhiên, ở giá trị header Location
vẫn giữ nguyên các tham số này. Bởi vậy, tác giả đã nảy ra ý tưởng sử dụng một tham số có giá trị với kích thước lớn, đạt tới giới hạn cho phép của URL.
GET /login?x=very-long-string... HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/
Như vậy, khi ứng dụng xử lý chuyển hướng, nếu mọi thứ bình thường, header Location
được thêm một ký tự /
như sau:
HTTP/1.1 301 Moved Permanently
Location: /login/?x=very-long-string...
Bởi URL ban đầu đã đạt đến giới hạn ký tự, nên khi chuyển hướng tới /login/?x=very-long-string...
có thêm ký tự /
đã vượt qua giới hạn, dẫn đến hệ thống không chấp nhận, trả về response lỗi:
GET /login/?x=very-long-string... HTTP/1.1
Host: www.cloudflare.com
Origin: https://dontpoisoneveryone/ HTTP/1.1 414 Request-URI Too Large
CF-Cache-Status: MISS
Lúc này, khi response được lưu trữ trong hệ thống cache, dẫn đến một cuộc tấn công từ chối dịch vụ tới người dùng sau.
2. Lab Cache key injection
2.1. Thu thập thông tin
Sử dụng extension Param Miner, chúng ta có thể nhận thấy request khi truy cập trang đăng nhập của bài lab cho phép sử dụng param utm_content
.
Quan sát mã nguồn tại /login
, phát hiện tệp tin /js/localize.js
:
2.2. Phân tích
Chú ý rằng tham số lang=en
được đính kèm tại đường dẫn /login/
Chúng ta có thể thay đổi tùy ý giá trị tham số này, kết quả được hiển thị trong response, sử dụng bởi /js/localize.js
:
Hơn nữa, giống với case study đã phân tích phía trên, khi chúng ta gửi request ở trang đăng nhập với tham số tại /login
dạng /login?lang=
, ứng dụng thực hiện chuyển hướng trình duyệt tới /login/
:
Ở đây cũng bao gồm cơ chế caching, thử một vài hướng khai thác đã nêu ở các bài viết trước, các bạn sẽ nhận thấy rằng cơ chế caching ở đây có thể tấn công bởi phương pháp Cache parameter cloaking, kết hợp tham số utm_content
, chúng ta có thể lưu trữ tài nguyên cache với payload: /login?lang=en?utm_content=viblo
, thật vậy:
Lúc này, tất cả người dùng truy cập đường dẫn /login?lang=en
sẽ được chuyển hướng và response trả về chứa dữ liệu caching bị kẻ tấn công control.
Chuyển hướng tới:
Tại /js/localize.js
, chú ý tham số cors=0
và header Vary
trong response cho biết response có thể thay đổi khi request chứa header Origin
cho biết nguồn gốc của request, ở đây chúng ta cần thay đổi tham số cors=1
để cho phép điều đó:
Đồng thời, tại header Origin
chúng ta có thể thực hiện tấn công CRLF:
Do đó chúng ta có thể sử dụng lỗ hổng CRLF tại đây nhằm thay đổi nội dung response với payload header Origin: x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)
(lưu ý giá trị tham số cors=1
)
Lúc này, nếu chúng ta có thể khiến trang web sử dụng nội dung file localize.js
chứa payload này sẽ có thể thực thi XSS.
Trong bài lab này, chúng ta có thể sử dụng header Pragma: x-get-cache-key
để yêu cầu ứng dụng trả về bộ cache key cho tài nguyên đang truy cập nếu nó đang có sẵn trong bộ nhớ cache.
Với payload XSS đã caching ở phía trên, tìm kiếm bộ cache key của nó:
Quan sát phản hồi nhận thấy ứng dụng trả về bộ cache key /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)
Tại đây chúng ta cũng có thể control giá trị bộ cache key này. Ý tưởng rõ ràng hơn: nếu ứng dụng trả về response tương ứng với bộ cache key này, payload XSS sẽ được thực thi.
Cấu tạo của bộ cache key sẽ thêm ký tự $$
vào sau chuỗi URL truy vấn. Thật vậy, kiểm tra bộ cache key khi truy cập /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)
:
Thực hiện lưu trữ cache response có bộ cache key là /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)$$
bằng cách sử dụng header Origin
Lúc này khi truy cập /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)
sẽ trả về response tương ứng với bộ cache key /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)$$
, đồng thời chứa payload XSS:
Mục tiêu cuối cùng của chúng ta là khiến ứng dụng trả về response lấy nội dung tại /js/localize.js?lang=en?cors=1&x=1$$origin=x%0d%0aContent-Length:%208%0d%0a%0d%0aalert(1)
chứa payload XSS.
2.3. Tấn công
Bước : Kết hợp CRLF, Cache parameter cloaking để lưu trữ payload thực thi XSS:
Bước : Sử dụng Cache parameter cloaking tại /login
nhằm cache payload:
Người dùng truy cập /login?lang=en
lúc này:
Tiếp theo được chuyển hướng đến response chứa dữ liệu caching: