Web cache poisoning - Lỗ hổng đầu độc bộ nhớ cache (phần 3)
IV. Phân tích và khai thác các lỗ hổng Web cache poisoning (tiếp)
4. Cache parameter cloaking
Ở các phần trước, chúng ta đã cấu hình Varnish Cache ngăn chặn tấn công web cache poisoning bằng cách loại bỏ các tham số vô nghĩa khỏi quá trình xử lý caching, đồng thời chú ý đến các tham số UTM. Điều này hầu như đã ngăn chặn tốt việc tấn công web cache poisoning bằng cách tấn công Unkeyed query string và Unkeyed query string. Tuy nhiên, trong một số trường hợp kẻ tấn công có thể lợi dụng tính bất đồng trong việc xử lý cú pháp URL giữa cơ chế xử lý caching và ứng dụng, từ đó tạo ra một số yêu cầu tới URL đặc biệt nhằm bypass cơ chế ngăn chặn của ứng dụng.
Xét cấu hình Varnish Cache như sau:
sub vcl_recv {
# Remove all parameters after the first "?"
set req.url = regsub(req.url, "\?.*$", "");
// ...
}
Với yêu cầu /?example=123?excluded_param=bad-stuff-here
, cấu hình trên sử dụng regsuball()
sẽ tìm thấy hai chuỗi được phân tách bằng dấu ?
, lấy giá trị của tham số example
và loại bỏ tham số excluded_param
. Đối với server sẽ không chấp một một URL với hai dấu ?
, nên chỉ chấp nhận tham số đầu tiên là example
cùng với giá trị chứa cả payload của chúng ta.
Bạn đọc có thể luyện tập kỹ thuật tấn công này trong bài lab Parameter cloaking.
Để ngăn chặn tấn công Cache parameter cloaking, ta cần bổ sung một số bước kiểm tra và xử lý trong cấu hình Varnish Cache. Ví dụ cấu hình dưới đây:
sub vcl_recv {
# Block requests with more than one question mark
if (req.url ~ "\?.*\?") {
return(synth(400, "Bad Request"));
}
# Strip out any parameters starting with "utm_" or containing "gclid"
if (req.url ~ "\?(.*&)?(utm_|.*gclid.*)") {
set req.url = regsuball(req.url, "([\?&])(utm_[^&=\s]*|.*gclid[^&=\s]*)(=[^&\s]*)?(&|$)", "\1");
}
# Set cache key to include only the relevant parameters
if (req.url ~ "\?") {
set req.url = regsub(req.url, "\?.*$", "");
}
return(hash);
}
Ở đây, ta đã thêm hai bước kiểm tra để ngăn chặn tấn công Cache parameter cloaking. Bước đầu tiên là kiểm tra số lượng dấu hỏi ?
trong URL, nếu nó lớn hơn , chúng ta sẽ coi đây là một yêu cầu không hợp lệ và trả về mã lỗi . Bước thứ hai là loại bỏ các tham số bắt đầu bằng "utm_" hoặc chứa từ khóa gclid
trong URL. Cuối cùng, sử dụng regex để cắt bỏ tất cả các tham số không cần thiết khỏi cache key.
Tùy thuộc vào yêu cầu của ứng dụng cụ thể, ta có thể cần bổ sung thêm các bước kiểm tra và xử lý khác để đảm bảo an toàn cho cache khỏi các cuộc tấn công.
5. Exploiting fat GET support
HTTP GET request thường được sử dụng để truy xuất dữ liệu từ máy chủ, và không bao gồm phần thân (body).
Tuy nhiên, một số ứng dụng hoặc framework có thể hỗ trợ GET request bao gồm phần body yêu cầu, được gọi là "fat GET request".
Như vậy, kẻ tấn công có thể tạo ra một yêu cầu fat GET có dạng như sau:
GET / HTTP/1.1
Host vulnerable-website.com
...
...payload malicious data...
Varnish Cache xử lý yêu cầu này và đưa các dữ liệu độc hại lưu trữ trong cache, kẻ tấn công có thể lợi dụng để tìm kiếm hướng khai thác cho một số lỗ hổng khác và tấn công người dùng trang web.
Bạn đọc có thể luyện tập phương thức tấn công này trong bài lab Web cache poisoning via a fat GET request.
Để ngăn chặn loại tấn công này, có thể áp dụng một số cấu hình trên máy chủ web hoặc trên Varnish Cache, ví dụ như:
5.1. Chuẩn HTTP
Sử dụng chuẩn HTTP và hạn chế sử dụng phần body cho GET request.
5.2. Công cụ
Sử dụng một số công cụ chặn thư rác (spam) như CAPTCHA hoặc Google reCAPTCHA để giảm thiểu các request tấn công từ bot.
5.3. Cấu hình Varnish Cache
Cấu hình Varnish Cache để xử lý các request GET chứa phần body. Để làm điều này, có thể sửa file cấu hình VCL (Varnish Configuration Language) bằng cách thêm đoạn mã sau đây vào phần vcl_recv
:
if (req.method == "GET" && req.body) {
return (pipe);
}
Đoạn mã này sẽ kiểm tra xem request method là GET và có phần body không. Nếu có phần body, Varnish sẽ xử lý request bằng phương thức pipe
, đồng nghĩa với việc Varnish sẽ đẩy request đến backend server mà không lưu vào cache.
5.4. Firewall
Ngoài ra, có thể sử dụng các giải pháp bảo mật như Web Application Firewall (WAF) để chặn các request độc hại. Với WAF, có thể tùy chỉnh các quy tắc để chặn các request không hợp lệ hoặc có chứa các chuỗi độc hại.
6. Từ lỗ hổng web cache poisoning thực hiện tấn công XSS
Kẻ tấn công có thể lựa chọn thời điểm ngay sau khi thời gian caching kết thúc, lợi dụng giá trị unkeyed là header X-Forwarded-Host
thực hiện poisoning tài nguyên cache của ứng dụng.
Dựa vào cấu tạo trong response, có thể xây dựng payload tấn công XSS như sau:
X-Forwarded-Host: "></script><script>alert(origin)</script>//
Tài nguyên cache sau khi bị poisoning:
Tất cả người dùng sau khi truy cập tới ứng dụng được trả về tài nguyên cache sẽ trở thành nạn nhân của cuộc tấn công:
Để các bạn có thể nắm vững các bước khai thác lỗ hổng web cache poisoning dẫn tới tấn công XSS, chúng ta sẽ cùng phân tích bài lab Web cache poisoning to exploit a DOM vulnerability via a cache with strict cacheability criteria.
Sử dụng extension Param Miner chúng ta tìm được unkeyed value là header X-Forwarded-Host.
Chúng ta có thể sử dụng unkeyed value này để ghi đè giá trị data.host
trong response. Chú ý rằng ứng dụng có thực thi hàm initGeoLocate()
với data.host
được sử dụng trong tham số input.
Hàm initGeoLocate()
tại /resources/js/geolocate.js
:
function initGeoLocate(jsonUrl)
{
fetch(jsonUrl)
.then(r => r.json())
.then(j => {
let geoLocateContent = document.getElementById('shipping-info');
let img = document.createElement("img");
img.setAttribute("src", "/resources/images/localShipping.svg");
geoLocateContent.appendChild(img)
let div = document.createElement("div");
div.innerHTML = 'Free shipping to ' + j.country;
geoLocateContent.appendChild(div)
});
}
Hàm trên lấy dữ liệu từ jsonUrl
, trong trường hợp trang web hoạt động bình thường là tại:
Sau đó sử dụng innerHTML
tạo ra chuỗi Free shipping to United Kingdom trên giao diện trang chủ. Do không chứa cơ chế ngăn chặn các ký tự đặc biệt nên nếu có thể thay đổi giá trị j.country
thì trang web ẩn chứa nguy cơ bị tấn công XSS:
Với unkeyed value X-Forwarded-Host
, chúng ta có thể poison giá trị data.host
, dẫn đến trong thời gian caching, ứng dụng thực hiện fetch dữ liệu từ nguồn do chúng ta control, chẳng hạn, với X-Forwarded-Host: anysite.com
, ứng dụng sẽ lấy dữ liệu từ //anysite.com/resources/json/geolocate.json
Lúc này, do không tìm thấy //anysite.com/resources/json/geolocate.json
nên không còn chuỗi trên giao diện:
Bởi vì bắt buộc cần truy cập đến path /resources/json/geolocate.json
, nên có thể tạo ra path này tại chính exploit server được lab cung cấp. Cài đặt như sau:
Thêm giá trị X-Forwarded-Host
là domain exploit server để poison cache:
Lúc này, ứng dụng lấy dữ liệu biến country
từ exploit server của chúng ta để sinh chuỗi trên giao diện trang chủ:
{
"country": "<img src=1 onerror=alert(origin) />"
}
Dẫn tới người dùng truy cập trang web với response trả về từ tài nguyên cache sẽ thực thi payload kích hoạt XSS:
Các tài liệu tham khảo
- https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws
- https://portswigger.net/research/practical-web-cache-poisoning
- https://portswigger.net/research/web-cache-entanglement
- https://varnish-cache.org/docs/3.0/reference/index.html
©️ Tác giả: Lê Ngọc Hoa từ Viblo
All rights reserved