Web cache poisoning là một lỗi khá là khó tấn công, một mối nguy hại thường được mọi người coi là "mang tính lí thuyết". Tuy vậy, đã có những tấn công được thực hiện thành công. Nếu muốn thử, ta nên tìm hiểu xem làm thế nào để "đầu độc" web cache.

Web Cache

Web cache là một vùng nhớ được đặt giữa client và server trong hệ thống. Công việc của nó là liên tục xem xét các request được gửi đến và tìm kiếm trong các response đã được lưu lại, đồng thời nó cũng sẽ lưu những response "mới". Như vậy cache có tác dụng rút ngắn thời gian phản hồi khi cùng một request hoặc nhiều request "tương đương nhau" được gửi đi nhiều lần.

Sơ đồ sau sẽ nói rõ hơn về cách cache hoạt động:

Screenshot-from-2018-09-16-23-29-41

Có thể thấy ở thời điểm ban đầu, user1 đã gửi đi 1 request và nó sẽ đi qua cache, cache sẽ xem xét request này, đối chiếu với dữ liệu của nó xem liệu có response đã được lưu lại cho request này chưa, và kết quả là chưa. Vì thế cache sẽ tiếp tục forward request đến cho server xử lí, server trả lại response, và cache cũng sẽ bắt được response này, lưu nó lại cho request trước đó. Và khi những người dùng tiếp theo gửi request tương tự, cache nhận request và tìm ra ngay được response cho request này và nó sẽ gửi lại response đó về cho phía client luôn.

Dựa vào vị trí mà cache được đặt, người ta chia web cache làm 3 loại chính :

  • Browser Cache

    Được đặt ở trên thiết bị của client, chính xác là 1 phần bộ nhớ của thiết bị. Chỉ phục vụ cho một người. Ví dụ phổ biến nhất là khi bấm nút back trên trình duyệt

  • Proxy Cache

    Làm việc giống Browser Cache, được đặt tại proxy server và cài đặt bởi nhà phân phối mạng. Proxy Cache có thể phục vụ 1 lượng người dùng lớn.

  • Reverse Proxy Cache

    Đặt gần với origin server nhất, được cài đặt bởi nhà quản trị, hoặc có thể mua cache từ bên thứ 3 (ví dụ như Content delivery networks (CDN))

    Screenshot-from-2018-09-17-00-24-25

Cache Key

Nói chung là cache sẽ nhận request và tìm trong dữ liệu của nó có response nào đáp ứng được request tương tự trên và trả về cho phía client. Vậy làm sao để cache biết rằng 2 request là tương tự, là giống nhau, và có thể đáp ứng bởi cùng 1 response ?

Lập trình viên có thể cài đặt cơ chế so sánh byte-to-byte cho cache. Tuy nhiên sử dụng cách này khá là kém hiệu quả. Thứ nhất, quá trình so sánh như vậy mất khá nhiều thời gian, tài nguyên. Thứ hai, trong một request có khá nhiều headers không quan trong và không ảnh hưởng nhiều tới response trả về như là User-Agent chẳng hạn.

Có một cách giải quyết khác cho vấn đề này đó chính là sử dụng cache key. Đó là một chuỗi các thành phần trong HTTP request mà cache sẽ chỉ dùng giá trị của chúng để so sánh giữa các request khác nhau để nhận biết được các request tương đương.

Ví dụ:

Screenshot-from-2018-09-17-10-06-44

Phần in đỏ bao gồm phương thức (GET), URI (/hello/hello.php), Host header (example.com), chính là những cache key, và những request nào có 3 thông tin trên giống nhau sẽ được hệ thống cache trả lại những response giống nhau.

Tuy nhiên việc sử dụng cache key không hoàn toàn là tốt. Nó tiềm ẩn nhiều nguy cơ dẫn đến việc response trả về cho client có nội dung không chính xác như trong trường hợp sau:

Screenshot-from-2018-09-17-10-05-53

Request đầu tiên được cache lại cùng response có nội dung tiếng Việt, request thứ 2 yêu cầu ngôn ngữ tiếng Anh nhưng sẽ lại được hệ thống cache trả về response có nội dung tiếng Việt.

Cache Poisoning

Bây giờ hãy tìm hiểu kĩ hơn về kĩ thuật tấn công Cache Poisoning.

Mục tiêu của tấn công này là hacker phải gửi một request tới server mà response của nó trở nên độc hại, đồng thời phải làm cho response này lưu được trên cache để nó đưuọc gửi đến nhiều người khác. Có một vài cách để làm cho response sau khi gửi request trở nên độc hại như là : ghi chèn vào HTTP headers, phương pháp HTTP Response Splitting, HTTP Request Smuggling.

Các bước tấn công:

Trước hết hacker cần xác định giá trị có thể ghi chèn trong request mà ảnh hưởng tới response trả về (gọi là unkeyed input), và đánh giá về tiềm năng của nó. Tiếp theo là gửi đi request đã được sủa đổi để response trả về đầu độc cache hay nói cách khác là cache sẽ lưu lại response độc hại. Tuy nhiên bước này không phải là dễ dàng, để response độc hại lưu lại trên cache, hacker cần phải nắm được nguyên tắc lưu đệm của hệ thống, cũng như xác định được phần web page có thể được lưu đệm. Sơ đồ sau cho ta cái nhìn tổng quan hơn:

Screenshot-from-2018-09-17-09-49-07

Ở bước 1 có thể dùng tay, hoặc dùng tool. James Kettle có giới thiệu một công cụ trên Burp Suite đó là Param Miner ( 1 extension miễn phí). Công cụ này sẽ đưa ra một số header có thể là unkeyed input, và ta sẽ nhanh chóng tìm được unkeyed input "tiềm năng".

Tấn công

  1. Ghi chèn thêm giá trị vào HTTP request

    Cùng xem qua một số tấn cong trong thực tế của James Kettle:

    James đã thử tấn công vào trang redhat.com và sử dụng Param Miner tìm ra được unkeyed input X-Forwarded-Host

    Screenshot-from-2018-09-17-11-58-48

    Và tấn công, nếu ressponse được lưu trên cache thành công, thì ai truy cập vào www.redhat.com/en?cb=1 cũng sẽ bị alert(1).

    Screenshot-from-2018-09-17-11-59-00

    Vấn đề khác khó hơn, làm sao để cái response độc hại được cache lại? Hacker có thể spam gửi request liên tục, hoặc là bằng cách nào đó dịch ngược được hệ thống cache của mục tiêu. Nhìn chung thì spam thì lại quá tải băng thông, dịch ngược thì cũng khoai. Nhưng mà đôi khi server lại giúp hacker lưu được response độc hại lên cache 1 cách dễ dàng hơn. James đã tìm được trên website unity3d.com

    Screenshot-from-2018-09-17-12-00-11

    Để ý trên response, trong header Cache-Controlmax-age=1800 , như vậy ta biết được thời gian mà response được lưu trên cache cho tới khi hết hạn (1800 giây). Ngoài ra có header Age :174 cho biết nội dung này đã được lưu trên cache 174 giây. Từ đó mà hacker biết thời điểm nào để gửi resquest sao cho response được cache lại.

  2. HTTP Response Splitting

    Trước hết hay xem qua về cơ chế hoạt động của cách thức tấn công này

    Giả sử mình gửi 1 request đến URL sau:

    http://www.example.com/welcome.php?lang=vi

    Khi đó response trả về sẽ là:

    HTTP/1.0 302 Redirect
    Location: http://www.example.com/welcome.php?lang=vi
    Connection: Keep-Alive
    Content-Length: 0
    
    

    Bây giờ mình sẽ thay đổi request đi một chút:

    http://www.example.com/welcome.php?lang=Foo%0d%0aConnection:%20Keep-Alive%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.0%20200%20OK%0d%0aContent-Type:%20text/html%0a%0aContent-Length:%2020%0d%0a%0d%0a<html>Sorry:)</html>

    Lúc này response trả về sẽ là:

    HTTP/1.0 302 Redirect
    Location: http://www.example.com/welcome.php?lang=Foo
    Connection: Keep-Alive
    Content-Length: 0
    
    HTTP/1.0 200 OK
    Content-Type: text/html
    Content-Length: 20
    
    <html>Sorry:)</html>Connection: Keep-Alive
    Content-Length: 0
    
    

    Đúng như cái tên của nó, response đã bị chia ra làm đôi, tức là server sẽ trả lại 2 response trong khi chỉ có 1 request gửi tới.

    Và trên lí thuyết, ta có thể tận dụng điều này để thực thi Cache Poisoning. Bây giờ ta sẽ biến trang http://www.example.com/welcom.php thành trang Sory:) nhé.

Untitdasd

Về cơ bản là hacker sẽ gửi 2 request bao gồm : 1 HTTP response splitting request và 1 request bình thường tới trang http://www.example.com/welcom.php. Và cache được đặt trên proxy server sẽ gán response đầu tiên cho request đầu tiên, và request thứ 2 (tới /welcome.php) sẽ được gán với response thứ 2 (Sorry:)), và xong, cache bị đầu độc.

Tuy nhiên để thực hiện thành công thì hacker cần phải căn time chuẩn sao cho cái request thứ 2 tới được proxy trước cái response Sorry:). Nghĩa là hacker phải gửi request thứ 2 đi thật nhanh, chưa kể còn nhiều yếu tố ảnh hưởng như đường truyền mạng.

  1. HTTP Request Smuggling

    Request "lậu" là một kĩ thuật tấn công nhằm vào các server. Trong đường truyền mà request từ phía client được phân tích bởi nhiều hệ thống thì sẽ có nguy cơ bị dính tấn công này.

    Ví dụ luôn cho dễ hiểu, ví dụ dưới đây cũng sẽ chỉ ra cách mà HTTP Request Smuggling đầu độc cache như thế nào

    Trước hết hãy có nhìn qua 1 HTTP request như sau:

    Screenshot-from-2018-09-17-00-15-50

    Ta thấy đây là một POST request có 2 header Content-Length. Một vài server sẽ loại bỏ những cái request kiểu này (như Apache). Tuy nhiên có những hệ thống chỉ loại bỏ 1 trong 2 cái header bị lặp kia. Có server thì loại bỏ cái thứ 2 dùng cái thứ nhất (SunONE web server 6.1), có server lại dùng cái thứ 2 loại cái thứ nhất (SunONE proxy server). Và đây chính là điểm mấu chốt để hacker có thể khai thác và tấn công.

    Okey, giả sử www.example.com là trang web trên SunONE web server đước đặt sau SunONE proxy. Khi ta gửi request này, trước tiên, proxy sẽ phân tích POST request (màu xanh dương) và nhận thấy có 2 header Content-Length, và như đã nói, nó sẽ bỏ cái Content-Length : 0, nó sẽ cho rằng phần body của request này là 44 bytes, nên nó sẽ đọc tiếp 44 bytes sau dấu xuống dòng (màu xanh lá). Vậy proxy sẽ coi 2 vùng màu xanh là request đầu tiên, và màu đỏ là request thứ 2.

    Giờ thì xem request trên khi gửi tới web server nó sẽ xử lí ra sao. Không như proxy, web server sẽ lấy cái Content-Length :0 và nó sẽ coi phần màu xanh dương là request đầu tiên, và phần còn lại (màu xanh lá và đỏ) là request thứ 2

    Bây giờ, thử xem response nào sẽ được gửi lại cho client. Những request mà web server thấy là POST /welcome.htmlGET /poison.html, do đó nó sẽ gửi lại 2 response với nội dung của welcome.htmlpoison.html. Còn proxy, 2 request của nó POST /welcom.htmlGET /index.html. Và nếu poison.html có thể được cache lại, thì nội dung của trang poison.html sẽ được cache cho request GET /index.html và thế là xong, cache đã bị nhiễm độc.

Tham khảo thêm tại: https://portswigger.net/blog/practical-web-cache-poisoning