NỘI DUNG
Sau màn giới thiệu dạo đầu trong nội dung Penetration Testing Step 3 – File upload vulnerabilities là gì?, kỳ này tôi sẽ bắt đầu đi vào phần demo cụ thể để làm rõ các phương án tấn công để khai thác lỗ hổng file upload vulnerabilities. Cụ thể, trước mắt, tôi sẽ minh họa 2 tình huống:
- Hệ thống không có giải pháp bảo vệ nào để đối phó file upload vulnerabilities;
- Hệ thống không có giải pháp bảo vệ để đối phó file upload vulnerabilities nhưng tồn tại vấn đề trong quá trình triển khai (kiểm soát file upload với Content-Type bypass và kiểm soát quyền thực thi file với directory traversal);
Lưu ý:
- 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 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. Khai thác file upload vulnerability với hệ thống không có giải pháp bảo vệ
Kịch bản đầu tiên tôi muốn đề cập là đỉnh cao của sự bẩn bựa khi mục tiêu không kiểm soát gì sất, tôi thích upload server-side scripts (PHP, Python, Java,…) gì lên nó cũng chiều. Và kinh hoàng hơn nữa, mục tiêu còn được thiết lập cho phép thực thi các đám script này như code nên việc tạo web shell để triển remote code execution (thực thi code từ xa) không thể dễ dàng hơn.
Nhắc lại: Web shell có thể hiểu là script độc hại cho phép attacker thực thi (từ xa) các command tùy ý trên web server thông quay việc gửi HTTP request đến endpoint phù hợp. Và với web shell, tôi đã có toàn quyền kiểm soát server. Do vậy, ngoài việc khai thác hết nguồn dữ liệu ở server này, tôi còn có thể sử dụng nó làm bàn đạp tấn công vào các vị trí lân cận khác.
Rồi, tôi vô phần demo để làm rõ. Việc đầu tiên tôi làm là đăng nhập vào hệ thống (với Burp Suite Interception đã bật). Ở đây có xuất hiện một nội dung mới lạ là chức năng upload avatar image để sống ảo.
Bốc đại một image vớ vẩn, tôi upload hàng lên thử.
Nhảy qua Burp Suite Proxy History, tôi bật filter theo Images kiểu như sau.
Và sau khi Apply, tôi nhanh chóng xác định cái GET request liên quan đến công tác upload image để gửi qua Burp Suite Repeater.
Tiếp đến, tôi bắt đầu thử nghiệm mưu đồ đen tối của mình bằng cách chuẩn bị một file độc hại (ví dụ exploit.php) nhằm khai thác các bí mật của nạn nhân carlos với nội dung kiểu như sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Vì mục tiêu không có phương án bảo vệ gì sất nên tôi dễ dàng đẩy hàng exploit.php lên server thông qua chức năng upload.
Với hàng đã được đẩy lên server, công việc tiếp theo của tôi là lấy cái mẫu request đã đẩy qua Burp Suite Repeater để chỉnh sửa lại endpoint cho phù hợp (để truy cập đến exploit.php). Và với request này, server sẽ thực thi cái exploit.php và trả về cho tôi bí mật mà nạn nhân carlos đang muốn che dấu.
Trong một diễn biến khác, giả sử nếu muốn “ăn” nhiều hơn, tôi có thể cập nhật exploit.php thành kiểu:
<?php echo system($_GET['command']); ?>
Với script này, tôi sẽ có thể quất command tùy ý thông qua query parameter kiểu như sau:
GET /example/exploit.php?command=id HTTP/1.1
#2. Khai thác file upload vulnerability với hệ thống có giải pháp bảo vệ
Sau khi trải nghiệm cái kịch bản hư cấu level max ở Mục 1 (thực tế tìm được một mục tiêu không kiểm soát file upload lẫn quyền thực thi chắc cũng khó không thua gì trúng vietlott), giờ tôi chuyển sang các kịch bản thực tế hơn tí. Cụ thể trong các kịch bản tiếp theo, hệ thống đã bắt đầu có phương án phòng bị với các mức độ hiệu quả khác nhau. Và đâu đó trong quá trình triển khai các phương án vẫn có thể tồn tại các lỗ hổng cho phép tôi chấm mút.
#2.1 Xuyên thủng lớp bảo vệ xác minh file type với Content-Type restriction bypass
Trước khi đề cập tình huống xử lý lỗi khi xác minh file type. Tôi xin tóm lược nhanh về vấn đề khai báo và xử lý content type trước. Cụ thể, khi submit (gửi) HTML form, browser sẽ có thể sử dụng content type kiểu:
- Application/x-www-form-url-encoded: Dùng gửi simple text kiểu ngắn gọn, đơn giản như tên tuổi, địa chỉ,…;
- Multipart/form-data: Dùng gửi lượng lớn binary data như file ảnh, pdf.
Với trường hợp thứ 2, message body sẽ được tách ra thành nhiều phần. Và mỗi phần sẽ chứa một Content-Disposition header cung cấp các thông tin cơ bản về input field liên quan. Đồng thời, các phần này cũng có thể có Content-Type header riêng để báo cho server đối chiếu MIME type tương ứng của data được gửi theo input này.
Lưu ý: MIME type tôi có đề cập trong kỳ trước, bạn có thể xem lại nếu chưa rõ.
Quay trở lại vấn đề chính, lúc này mục tiêu có thể chọn phương án xác minh file upload dựa vào việc đối chiếu Content-Type header và MIME type tương ứng (ví dụ đang nhận image thì nó sẽ cho phép các thể loại như image/jpeg hay image/png).
Và ở đây sẽ phát sinh vấn đề khi mục tiêu dại khờ tin tưởng hoàn toàn vào nội dung khai báo trong header (vốn dĩ có thể bị user thao túng) mà không có hành động kiểm tra xác nhận nội dung của file.
Rồi, tôi vào phần demo ngay đây. Cũng tương tự như tình huống đầu tiên, với Burp Suite Interception đã bật, tôi đăng nhập vào hệ thống và ghi nhận chức năng upload file để thay đổi avatar cho ảo lòi.
Sau đó, tôi cũng kiểm tra phần Burp Suite Proxy History để hốt cái GET request truy cập đến file image vừa mới upload và đẩy qua Burp Suite Repeater.
Kế đến tôi cũng soạn sẵn một file độc hại (exploit.php) có nội dung như sau nhằm soi mói secret của nạn nhân carlos.
<?php echo file_get_contents('/home/carlos/secret'); ?>
Lúc này, chơi kiểu ngựa quen đường cũ, upload con hàng exploit.php lên hệ thống tôi sẽ bị ăn chửi (vì hệ thống đang mong chờ image chứ script riếc gì tầm này???):
Hơi ê chề, tôi cắp đít quay về chỗ Burp Suite Proxy Histoy thực hiện filter và xác định lại cái request tương ứng.
Sau đó, tôi đẩy các POST request này sang Repeater. Tại đây, tôi thử giở trò đồi bại thay đổi Content-Type chỗ nội dung file exploit.php sang image/jpeg rồi send lại. Và ngạc nhiên chưa, âm mưu của tôi thành công trót lọt với response 200 trả về nhẹ nhàng tình cảm.
Hàng đã được đẩy lên mục tiêu, tôi giở trò cũ quay lại cái GET request truy cập avatar image ban đầu (đã gửi sang Burp Suite Repeater) và chỉnh lại cái endpoint tương ứng đến con hàng exploit.php.
Và rồi chuyện phải đến cũng đã đến. Secret mà carlos đang che giấu cũng đã hiện ra trước mắt tôi.
#2.2 Xuyên thủng lớp bảo vệ ngăn ngừa thực thi file với directory traversal
Như đã đề cập ở trên, giải pháp kiểm soát file upload vulnerability ngoài việc kiểm duyệt nội dung upload còn bao gồm lớp kiểm soát khả năng thực thi (đặc biệt quan trọng với đám file có võ công cao dễ dàng xé rào chui được vào hệ thống). Cụ thể, với lớp bảo vệ thứ 2, server nên được cấu hình chỉ cho phép một số MIME type cụ thể được thực thi. Và khi đám bẩn bựa khác đòi thực thi sẽ bị ăn lỗi hoặc nhận hàng về kiểu plain text mà thôi.
Vấn đề ở đây là server có thể có các cấu hình thiết lập khác nhau trên các thư mục khác nhau. Ví dụ thư mục chứa avatar image cho phép user upload sẽ chịu kiểm soát gắt gao trong khi các thư mục khác (ví dụ thằng thư mục cha của avatar image directory) lại bị thả trôi thả nổi. Và lúc này, nếu attacker tìm được cách thay đổi vị trí đẩy hàng lên thì giải pháp kiểm soát thực thi sẽ bị mất hiệu lực.
Lưu ý: Web servers thường sẽ dùng filename field trong multipart/form-data requests để xác định tên và vị trí lưu file.
Giờ tôi đi vào phần demo cho rõ. Với tình huống này tôi cũng sẽ đăng nhập hệ thống thử upload file rồi nhảy qua Burp Suite Proxy History để hốt cái GET request truy cập avatar image quẳng qua Repeater như trước đó.
Kế đến, tôi cũng tạo một con hàng độc hại exploit.php để nhăm nhe hốt cái secret của nạn nhân carlos như sau:
<?php echo file_get_contents('/home/carlos/secret'); ?>
Và trong kịch bản này, phi vụ tuồn hàng cấm exploit.php lên server của tôi khá thuận lợi.
Nhưng lưới trời lồng lộng, khi điều chỉnh cái endpoint trong request để hướng đến exploit.php tôi nhận ngay cái kết đắng khi response trả về là nội dung của script dạng plain text.
Không bỏ cuộc, tôi quay lại Burp Suite Proxy History tìm cái request POST /my-account/avatar để upload image rồi đẩy qua Repeater.
Sau đó, tôi thử mông má lại nội dung chỗ Content-Disposition tương ứng của exploit.php. Cụ thể, tôi thử giở trò directory traversal (tạm hiểu là di chuyển qua lại giữa các thư mục) thông qua việc điều chỉnh filename với “../” (hàm ý là đẩy exploit.php ra thư mục cha của avatar image directory).
Content-Disposition: form-data; name="avatar"; filename="../exploit.php"
Và một lần nữa tôi lại ăn đòn. Lúc này dòng thông báo “The file avatars/exploit.php has been upload.” trong response cho tôi biết hệ thống đã xử đẹp cái directory traversal sequence “/” từ đó bóp chết mưu đồ thay đổi vị trí upload của tôi từ trong trứng nước.
Nhưng như mọi khi, với phương châm “còn thở còn gỡ”, tôi đâu dễ dàng gì từ bỏ. Lúc này tôi thử triển tiếp chiêu thức obfuscate (tạm hiểu là che giấu) cái directory traversal sequence với URL encoding kiểu như sau:
filename="..%2fexploit.php"
Và ô hô, lần này tôi đã đạt được mục đích khi con hàng exploit.php đã chễm chệ đáp xuống vị trí tôi mong muốn.
Phần tiếp theo của câu chuyện chỉ còn mang tính thủ tục khi tôi có thể dễ dàng điều chỉnh lại endpoint để hốt cái secrect của nạn nhân carlos.
Ở chỗ này, nếu bạn thấy cái endpoint /files/avatars/..%2fexploit.php
ngứa mắt quá thì có thể hiệu chỉnh lại cho gọn đẹp thành /files/exploit.php
.
Đến đây, tôi cũng xin kết thúc hiệp một của nội dung demo khai thác file upload vulnerabilities. Hẹn gặp lại bạn trong các kỳ tiếp theo.
1 thought on “Penetration Testing Step 3 – Khai thác file upload vulnerabilities (Hiệp 1)”