---
# System prepended metadata

title: LAB PortSwigger Web cache poisoning

---

## LAB Web cache poisoning

### 1. Web cache poisoning with an unkeyed header
>Lab có lỗ hổng WCP vì không xử lí an toàn input từ unkeyed header.
Poison cache khiến response thực thi `alert(document.cookie)`.

Xem qua trong HTTP history thấy xuất hiện một số trang được cache.
![image](https://hackmd.io/_uploads/r1YeX5PTkg.png)

Tiến hành dò header ẩn với các request có response được cache:
![image](https://hackmd.io/_uploads/Sy9z7cPpJl.png)

Phát hiện ra lỗ hổng "Cache posoning" với `X-Forwarded-Host` header:
![image](https://hackmd.io/_uploads/ByLm7qvTkx.png)
![image](https://hackmd.io/_uploads/SkTVmcv6kg.png)
- Khi request chứa `X-Forwarded-Host` header, nó sẽ được reflect trong thuộc tính `src` của thẻ `<script>`.

Truyền payload để thực hiện `alert()`. Sau đó gửi request để response được cache.
![image](https://hackmd.io/_uploads/BygvQ5P6ye.png)
Thành công kích hoạt trên victim's browser.
![image](https://hackmd.io/_uploads/r1Wdm5PpJx.png)
___
### 2. Web cache poisoning with an unkeyed cookie
>Lab có lỗ hổng WCP vì cookies không được coi là cache key.
Poison cache khiến response thực thi `alert(document.cookie)`.

Khi mở `/`, xuất hiện một số dữ kiện:
![image](https://hackmd.io/_uploads/HJi9EpvTkx.png)
- Trang này được cache, được thể hiện thông qua một số response header.
- Response chứa giá trị của cookie, sau vài lần kiểm tra thì xác nhận nó reflect giá trị của cookie.

Truyền vào payload để kích hoạt XSS:
![image](https://hackmd.io/_uploads/SkkhN6Pa1x.png)

Thành công kích hoạt XSS, khi victim mở `/` thì cache sẽ gọi ra trang này:
![image](https://hackmd.io/_uploads/BJvrVaPakl.png)
___
### 3. Web cache poisoning with multiple headers
>Lab có lỗ hổng WCP nhưng chỉ khai thác được bằng cách kết hợp nhiều header.
Poison cache khiến response thực thi `alert(document.cookie)`.

Thử load `/` thì thấy dấu hiệu trang được cache:
![image](https://hackmd.io/_uploads/S1luoRwa1x.png)
- Ngoài ra `/resource/js/tracking.js` cũng được cache, và nó được nhúng vào `/`.

Sử dụng "Param miner" để tìm các header có khả năng khai thác:
![image](https://hackmd.io/_uploads/ry-J3RDpye.png)
- Phát hiện được 2 header nguy hiểm là `X-Forwarded-Scheme` và `X-Forwarded-Host`.
- ![image](https://hackmd.io/_uploads/Hy8UCRvpkl.png)

Kiểm tra đơn giản với 2 header trên:
![image](https://hackmd.io/_uploads/HJfe2RDayx.png)
- Ứng dụng xử lí `HTTPS` vì vậy khi gửi scheme `HTTP` thì nó sẽ redirect tới `HTTPS`.
- Ứng dụng nhận giá trị của `X-Forwarded-Host` header làm host của redirect.
- Có thể lợi dụng điều này để redirect victim tới domain của attacker.

Dựng payload cho exploit server:
![image](https://hackmd.io/_uploads/SyQznRDTJl.png)
- Nếu đặt path là `/exploit` thì tại target website, đây không phải path khớp với cache rule.
- Nếu đặt path là `/` thì hợp cache rule tại target website, nhưng lại redirect tới trang dựng payload chứ không phải gọi payload.
- Khi đặt path như bên, trang `tracking.js` sẽ cache payload độc hại. Sau đó trang này được nhúng vào `/`.

Thay đổi giá trị cho header độc hại, thành công thực thi script:
![image](https://hackmd.io/_uploads/HJje3APa1e.png)
![image](https://hackmd.io/_uploads/HkfX2CD6Jg.png)
___
### 4. Targeted web cache poisoning using an unknown header
>Lab có lỗ hổng WCP.
Poison cache khiến response thực thi `alert(document.cookie)`.
Ngoài ra đảm bảo rằng đưa response độc hại tới victim phù hợp.

Tải trang `/` và thấy có dấu hiệu trang được cache:
![image](https://hackmd.io/_uploads/rk6yUedTJl.png)
- Tuy nhiên, cache server sử dụng cache key là `User-Agent`.
- Do vậy, với mỗi `User-Agent` khác nhau thì cache sẽ khác nhau.
- ![image](https://hackmd.io/_uploads/BJUOUe_ayl.png)

Khi này, cần phải xác định được `User-Agent` của victim thì mới có thể tấn công WCP.

Tại `/post?postId=1` cho chức năng đăng nhập, và cho phép HTML:
![image](https://hackmd.io/_uploads/B1UpLxdTyx.png)
- Nó đã whitelist các thẻ và thuộc tính được phép.
- Tuy nhiên vẫn dùng được `<img>` và `src`.

Gửi comment chứa payload:
![image](https://hackmd.io/_uploads/rkrzDlOp1l.png)
- Khi này, thẻ `<img>` được tạo, và với thuộc tính `src`, nó gửi request tới domain của attacker.

Request do victim vô tình gửi, được đi kèm `User-Agent`:
![image](https://hackmd.io/_uploads/SkuIwe_6Jg.png)
- Thành công lấy được `User-Agent` header của victim.

Sử dụng "Param miner" quét trang `/` để tìm kiếm lỗ hổng:
![image](https://hackmd.io/_uploads/r1ZOvxuaJg.png)
- Phát hiện một số header có khả năng khai thác `x-host`, `origin`, `via`.

Xác định lỗ hổng nằm ở `X-Host` header:
![image](https://hackmd.io/_uploads/By03De_T1e.png)
- Giá trị của header này được reflect trong response. Và được thẻ `<script>` sử dụng để request.

Xác định đường header độc hại và `User-Agent` của nạn nhân, ta gửi payload:
![image](https://hackmd.io/_uploads/rkIz_l_p1l.png)
- Khi này, js script được ta chèn vào sẽ được cache vào trang `/`.
- Do phù hợp `User-Agent` nên nạn nhân sẽ nhận được cache nay.

Thành công thực thi script:
![image](https://hackmd.io/_uploads/SJJ8Og_Tyg.png)
___
### 5. Web cache poisoning to exploit a DOM vulnerability via a cache with strict cacheability criteria
>Lab có lỗ hổng DOM-based có thể khai thác thông qua WCP.
Cần phải xem xét kĩ tiêu chuẩn response được cache.
Poison cache khiến response thực thi `alert(document.cookie)`.

Truy cập `/` thì nhận thấy:
![image](https://hackmd.io/_uploads/B15W58YTke.png)
![image](https://hackmd.io/_uploads/rkYE9LYTye.png)
- Nếu không có `Cookie` header thì trang không được cache.
- Miễn là có `Cookie` header thì cache sẽ được phục vụ mà không phân biệt sự khác nhau.
- Có thể thấy ứng dụng sử dụng `Cookie` header làm key để xác định có cache hay không, nhưng lại không sử dụng nó như một cache key thông thường.

Xác định lỗ hổng WCP cùng với sink và source của lỗ hổng DOM-based:
![image](https://hackmd.io/_uploads/rk-Xq8Fpkl.png)
- Sử dụng "Param miner", xác định được `X-Forwarded-Host` header có lỗ hổng, khi giá trị của nó được reflect vào response và được sử dụng để gán giá trị cho biến bằng JS.
- Ứng dụng sử dụng 2 file JS để xử lí và lấy dữ liệu.
- File `geolocate.js` chứa sink là giá trị file JSON nhập vào vào cụ thể là trường "country" và source là hàm `innerHTML` cho phép nhúng phần tử vào DOM.
- File `geolocate.json` chứa dữ liệu mà được chỉ định để lấy ra.

Sau khi xác nhận được các lỗ hổng, tả dựng payload cho exploit server:
![image](https://hackmd.io/_uploads/rJwtiLFake.png)
- Cần phải đổi path thành `/resources/js/geolocate.json` vì ứng dụng chỉ trỏ thẳng đến path như vậy.

Thao túng `X-Forwarded-Host` header: 
![image](https://hackmd.io/_uploads/S1KU5LFTJe.png)

Khi này, `/` sẽ dùng giá trị của `X-Forwarded-Host` header để đặt làm domain của biến `data`. Sau đó, biến này được truyền vào `initGeoLocate()` để fetch, vô tình lại fetch exploit server của ta. Lúc này, giá trị độc hại trong trường "Country" được lấy ra.

Tuy nhiên lúc này, nội dung file lại bị chặn do CORS policy:
![image](https://hackmd.io/_uploads/ryIvcIFT1x.png)
- CORS policy là chính sách giới hạn việc gửi nhận dữ liệu cross-site.

Bổ sung "Access-Control-Allow-Origin" header trong response độc hại:
![image](https://hackmd.io/_uploads/Bkx_5LYpye.png)
- Do cách ứng dụng cấu hình và triển khai policy này lỏng lẻo, nên ta chỉ cần thêm header trên vào là ứng dụng chấp nhận dữ liệu từ cross-site.

Thực hiện tương tự, thành công thực thi mã:
![image](https://hackmd.io/_uploads/BJsOq8Fake.png)
___
### 6. Combining web cache poisoning vulnerabilities
>Lab có lỗ hổng WCP. Nhưng phải khai thác kết hợp phức tạp.
Cần phải xem xét kĩ tiêu chuẩn response được cache.
Poison cache khiến response thực thi `alert(document.cookie)`.

Bắt request, thấy rõ '/' được cache:
![image](https://hackmd.io/_uploads/H1xpmzGAJg.png)

Tại `/`, ứng dụng cung cấp chức năng đổi ngôn ngữ:
![image](https://hackmd.io/_uploads/Hk6Z1MG0kx.png)
![image](https://hackmd.io/_uploads/S1ad1MM0ke.png)
+ Sau khi chọn ngôn ngữ, nó sẽ gửi request tới `/setlang` và sau đó được redirect và đặt một `lang` cookie.

Ngoài ra, `/` còn nhúng trên file JS để xử lí dịch ngôn ngữ:
![image](https://hackmd.io/_uploads/rJU2xGzCJl.png)
- Nó gồm 3 phần để nhận dữ liệu về ngôn ngữ được chọn, thực hiện thay thế và lấy dữ liệu về từ điển dịch.
- Tại phần đầu, cụ thể là hàm `lang`, nó tách cookie hiện tại ra và lấy giá trị của `lang` cookie, ở đây là loại ngôn ngữ ("en", "es", ...).
- Phần tiếp,cụ thể là hàm `translate` nó duyệt qua toàn bộ DOM và thay thế trường nội dung tồn tại trong bản dịch tương ứng.
- Tại phần thứ cuối, nó thực hiện `fetch` tới URL của file JSON để lấy dữ liệu từ điển dịch. sau đó, nó gọi tới hàm `translate` để thực hiện dịch dựa trên JSON lấy được.

Tại `/`, hàm `initTranslations` được gọi và truyền vào URL:
![image](https://hackmd.io/_uploads/HJHsbzzCkx.png)
- URL được truyền vào lấy host trong `data` và path `/resource/jsotranslations.json`.
- Trong file JSON tương ứng cung cấp từ điển dịch thuật tương ứng với các trường.

Phần `data` được nhúng vào `/` qua JS:
![image](https://hackmd.io/_uploads/B1A8MGM0Jg.png)

Sử dụng "Param miner" để đoán header có thể ảnh hưởng tới `data`:
![image](https://hackmd.io/_uploads/BJ4tzGMC1g.png)
- Xác định `X-Forwarded-Host` được reflect vào `data.host`.

Sau khi xác định được các yếu tố cần thiết cho cuộc khai thác, xây dựng kịch bản khai thác và exploit server:
- Victim sẽ mở `/`. `/` được cache mà không quan tâm cache key. `data.host` được reflect từ `X-Forwarded-Host` header và nó được truyền vào sink là một hàm JS và trực tiếp gọi tới URL tương ứng.
- Từ đó ta sẽ truyền `X-Forwarded-Host` header là domain độc hại, lợi dụng `/` được cache để lưu lại `data.host` bị reflect.
- Sau đó, tại exploit server, tạo JSON file, chứ chuỗi độc hại, khiến khi ứng dụng gọi ra thì thực thi script.

Dựng payload độc hại trên exploit server:
![image](https://hackmd.io/_uploads/BJzNOrz0Jl.png)

Tuy nhiên, payload bị chặn bởi CORS policy:
![image](https://hackmd.io/_uploads/B14kdMG0kl.png)

Bổ sung header để bypass CORS policy:
![image](https://hackmd.io/_uploads/Hk4durfA1l.png)

Tuy nhiên, do victim không chủ động mở ngôn ngữ khác ngoài "en", nên ta buộc phải tìm cách ép victim's browser trỏ đến "es".

Quan sát lại HTTP history, nhận thấy, rõ luồng request:
![image](https://hackmd.io/_uploads/ryOYuHMR1g.png)
- Có thể lợi dụng request tới `/setlang/` để đặt ngôn ngữ được dịch.
- Tuy nhiên, với response của request này lại không được cache.

Quan sát trong source code, phát hiện điều kì quặc:
![image](https://hackmd.io/_uploads/SyJZYBzCJg.png)
- Có thể thấy, dù đều là `src` của thẻ `script` nhưng thường ta dùng forward slashes (`/`), nhưng lại có backslashes (`\`) được sử dụng.
- Có thể đây là một cách ứng dụng xử lí hoặc có thể nó đã bình thường hoá khiến 2 kí tự này tương đương nhau.

Thử với request tới `/setlang` nhưng thay thế `/` bằng `\`:
![image](https://hackmd.io/_uploads/HJd2KrzA1g.png)
- Có thể thấy rõ, ứng dụng đã có một bước bình thường hoá `\` thành `/` thông qua redirect.
- Và chính quá trình này lại được cache.

Tuy nhiên, ta cần phải thực hiện ép buộc victim's browser thực hiện request này vì bản thân victim sẽ không thực hiện request này.
Do đó, quay lại `/` cùng với phát hiện được `X-Original-URL` header bằng "Param Miner". Thực hiện chèn thử header này vào `/`:
![image](https://hackmd.io/_uploads/BJ0UoSGC1g.png)
- Sau khi thử thì nhận thấy, với `\setlang\en` thì ứng dụng redirect, có thể là do sai cú pháp khi mà không có path `/setlang`. Điều này xảy ra có thể là do ứng dụng kiểm tra path trước khi đưa vào bình thường hoá. Khi này nó kiểm tra `\setlang\en` thấy không tồn tại `\setlang`.
- Đối với `/setlang\en` thì nó kiểm tra thấy path `/setlang` tồn tại hợp lệ nên sau đó nó bình thường hoá `setlang\en` thành `setlang/en` thông qua redirect.

Cuối cùng, gửi 2 request sau đi để khiến web cache lại:
![image](https://hackmd.io/_uploads/rJe46SGAkl.png)
- Với request đầu sẽ khiến `/` được cache thực hiện mục đích ép victim's browser redirect tới đúng ngôn ngữ ta cài payload.
- Với request kế tiếp sẽ khiến `/?localized=1` được cache lại và truy cập URL chứa payload độc hại.

Thành công kích hoạt script.
![image](https://hackmd.io/_uploads/S1ScpBzA1l.png)

---
### 7. Web cache poisoning via an unkeyed query string
>Lab có lỗ hổng WCP vì query string là unkeyed.
Poison cache khiến response thực thi `alert(1)`.

Kiểm tra request và response tại `/` thấy được:
![image](https://hackmd.io/_uploads/rJNUSjjRke.png)
- Tại đây thực hiện cache response.
    - Tuy nhiên, mặc dù tồn tại query param `abc=` response vẫn không được cache một cách khác biệt.
    - Có thể thấy, tại đây ứng dụng cache mà không sử dụng query string như cache key, có thể do nó đã bị loại bỏ khi xử lí cache.
- Bên cạnh đó, giá trị của URL path được reflect vào thẻ HTML trong response 

Khi này, với query string được reflect thẳng vào response, nếu ứng dụng không xử lí cẩn thận có thể bị tấn công. Đồng thời query string không được sử dụng như cache key nên có thể dễ dàng đưa các cuộc tấn công tới victim.

Gửi payload độc hại thông qua query param và thực hiện WCP:
![image](https://hackmd.io/_uploads/rkeYrji0ye.png)
___
### 8. Web cache poisoning via an unkeyed query parameter
>Lab có lỗ hổng WCP vì nó loại bỏ param nhất định khỏi cache key.
Poison cache khiến response thực thi `alert(1)`.

Xác định `/` được cache. Đồng thời response chứa URL path được reflect:
![image](https://hackmd.io/_uploads/ryRqlhs01e.png)

Thử kiểm tra cách ứng dụng cache với query string:
![image](https://hackmd.io/_uploads/S1C0x3sRJe.png)
- Có thể thấy rõ, ứng dụng đã lấy query param là cache key, khiến cho cache response khác biệt với mỗi query param.
- Tuy nhiên, với param `utm_content` thì lại không trở thành cache key.

Gửi payload độc hại thông qua param `utm_content` và thực hiện WCP:
![image](https://hackmd.io/_uploads/HkLNb3j0Je.png)
___
### 9. Parameter cloaking
>Lab có lỗ hổng WCP vì nó loại bỏ param nhất định khỏi cache key. Đồng thời, Cache và BE parse param một cách không nhất quán.
Poison cache khiến response thực thi `alert(1)`.

Website được nhúng vào file JS như sau:
![image](https://hackmd.io/_uploads/SyxjeWp_Jll.png)

Kiểm tra resquest và response, nhận thấy được:
![image](https://hackmd.io/_uploads/ByMHZ6_1gg.png)
- Ứng dụng có cache lại trang này. Đồng thời nó sử dụng `callback` param làm cache key. Sau đó, khi thử nghiệm với một số trường hợp khác thì bất kì param nào cũng được sử dụng làm cache key, trừ `utm_content`.
- Giá trị của 'callback' param được reflect vào tên hàm.

Nhận thấy bất thường trong khi thử các payload:
![image](https://hackmd.io/_uploads/ryaTZT_yeg.png)
- Khi sử dụng `;` thì toàn bộ kí tự đằng sau nó đều không được reflect, nhưng dùng dạng URL-encode thì vẫn nhận được.
- Phỏng đoán, Server sử dụng Ruby on Rail, nên khi này nó xử lí `;` như `&`, và nó parse trước khi URL-decode.

Tiếp theo, thử nghiệm để xác định Server có sử dụng Ruby on Rail không:
![image](https://hackmd.io/_uploads/rJQmXaukll.png)
- Dễ dàng nhận thấy, giá trị `foo` được reflect thay vì `alert`.
- Từ đó có thể xác định, Server sử dụng Ruby, thông qua việc nó nhận `;` là kí tự phân cách và sử dụng param cuối cùng (nếu có sự trùng lặp param).

Xây dựng được kịch bản khai thác. Thông qua việc ứng dụng luôn nhúng file JS với tham số `callback=setCountryCookie` và cache lại. Khi này, lợi dụng `utm_content` param không phải là cache key ta sẽ đưa payload độc hại vào giá trị của `utm_content` param. Và Server sử dụng Ruby on Rail, ta sẽ đưa `callback` param vào payload rồi phân cách nó bằng `;`. Khi này, Cache sẽ nhận toàn bộ payload là giá trị của `utm_param` trong khi Server sẽ xử lí chi tiết nó.

Dựng payload và gửi đi để khiến website cache lại nó theo cache key `callback=setCountryCookie`:
![image](https://hackmd.io/_uploads/SJJ2QpOJee.png)

Thành công WCP và thực hiện script:
![image](https://hackmd.io/_uploads/ryIiST_1ee.png)
___
### 10. Web cache poisoning via a fat GET request
>Lab có lỗ hổng WCP. Nó nhận `GET` request có cả body, nhưng body không phải là cache key.
Poison cache khiến response thực thi `alert(1)`.

Website được nhúng vào file JS như sau. Kiểm tra request và response liên quan:
![image](https://hackmd.io/_uploads/rkLEkRuJgx.png)
- Ứng dụng có cache lại trang này. Đồng thời nó sử dụng `callback` param làm cache key. Sau đó, khi thử nghiệm với một số trường hợp khác thì bất kì param nào cũng được sử dụng làm cache key, kết cả `utm_content`.
- Giá trị của 'callback' param khả năng cao là được reflect vào tên hàm.

Thử thêm body cho GET request này, có tên param tương tự:
![image](https://hackmd.io/_uploads/HkNHk0_yeg.png)
- Nhận thấy, ứng dụng nhận phần body của GET request và ưu tiên reflect giá trị của `callback` param trong body vào tên hàm.
- Đồng thời, sau nhiều lần thử thì ứng dụng chỉ sử dụng cache key là GET param, còn phần body param thì không.

Dựng payload khai thác:
![image](https://hackmd.io/_uploads/Syl8y0_Jxl.png)

Thành công WCP và kích hoạt script:
![image](https://hackmd.io/_uploads/rk3LJ0Oyxx.png)
___
### 11. URL normalization
>Lab có lỗ hổng XSS nhưng không thể khai thác trực tiếp vì browser URL-encoding. Lợi dụng quá trình bình thường hoá của cache để khai thác.
Poison cache khiến response thực thi `alert(1)`.

Khi truy cập đến path không tồn tại, website trả về lỗi:
![image](https://hackmd.io/_uploads/BkjMr1Kyxg.png)
- Tuy nhiên, phát hiện được là path được truy cập sẽ resflect vào response.
- Có tiềm năng khai thác XSS.
- Đồng thời, nó cũng cache lại response, với cache key là URL.

Tuy nhiên, khi truy cập trực tiếp thông qua URL, thì không khai thác được:
![image](https://hackmd.io/_uploads/Hy-mBkY1ge.png)
- Do khi nhận request, ứng dụng sẽ URL-encode, nhưng khi reflect thì nó lại không thực hiện URL-decode.

Khi này, một số Cache server sẽ thực hiện bình thường hoá trước khi tạo cache key, nên URL path bị URL-encode cũng có giá trị tương tự như không bị encode. Điều này dẫn tới, dù khác nhau khi duyệt, nhưng khi được xử lí cache thì payload hoàn toàn có thể được cache.

Lợi dụng cách cache xử lí để poison cache với paylaod XSS:
![image](https://hackmd.io/_uploads/ry3mH1tJgg.png)

Thành công WCP để cache payload XSS:
![image](https://hackmd.io/_uploads/S1ENHyY1ex.png)
___
### 12. Cache key injection
> Lab chứa nhiều lỗ hổng độc lập, gồm cache key injection.
Sử dụng `Pragma:x-get-cache-key` header cùng WCP để thực thi `alert(1)`.
"wiener:peter"

