File uploads
Last updated
Lỗ hổng file upload là khi web server cho phép người dùng tải tệp lên hệ thống tệp của mình mà không xác thực đầy đủ các thông tin như tên, loại, nội dung hoặc kích thước.
Một số hành động tải tệp lên tự nó đã đủ gây ra thiệt hại. Số khác liên quan đến các HTTP request theo sau, thường là để kích hoạt việc thực thi tệp đó bởi máy chủ
Tác động của lỗ hổng file upload phụ thuộc vào hai yếu tố chính:
Trang web không xác thực đúng yếu tố nào của tệp: có thể là kích thước, loại tệp, nội dung, v.v.
Những hạn chế được áp dụng cho tệp sau khi tải lên thành công.
Trong trường hợp xấu nhất, nếu loại tệp không được xác thực đúng và cấu hình máy chủ cho phép thực thi các loại tệp nhất định (như .php
hoặc .jsp
) như code, kẻ tấn công có thể tải lên một tệp mã phía máy chủ hoạt động như một web shell, cho phép họ kiểm soát hoàn toàn máy chủ.
Nếu tên tệp không được xác thực đúng cách, điều này có thể cho phép kẻ tấn công ghi đè lên các tệp quan trọng chỉ bằng cách tải lên một tệp cùng tên. Nếu máy chủ cũng dễ bị tấn công thông qua kỹ thuật directory traversal (đi ngang qua thư mục), kẻ tấn công thậm chí có thể tải lên tệp vào những vị trí không ngờ tới.
Việc không đảm bảo kích thước tệp nằm trong giới hạn mong đợi cũng có thể dẫn đến một cuộc tấn công từ chối dịch vụ (DoS), trong đó kẻ tấn công làm đầy dung lượng đĩa có khả dụng.
Các trang web thường không để người dùng tải lên file mà không có bất kỳ hạn chế nào do nguy cơ rõ ràng của việc này. Tuy nhiên, các nhà phát triển thường áp dụng các biện pháp xác thực mà họ cho rằng an toàn nhưng lại có những điểm yếu vốn có hoặc có thể bị bypass dễ dàng.
Ví dụ, họ có thể blacklist các loại file nguy hiểm, nhưng không tính đến sự khác biệt trong việc phân tích các đuôi file. Ngoài ra còn có thể dễ dàng bỏ sót các loại file ít phổ biến nhưng vẫn có thể gây nguy hiểm.
Trong các trường hợp khác, trang web có thể cố gắng kiểm tra loại file bằng cách xác minh các thuộc tính mà kẻ tấn công có thể dễ dàng thao tác được bằng các công cụ như Burp Proxy hoặc Repeater.
Cuối cùng, ngay cả các biện pháp xác thực mạnh mẽ cũng có thể được áp dụng không đồng nhất trên toàn bộ mạng lưới máy chủ và thư mục của trang web, dẫn đến các lỗ hổng có thể bị khai thác.
Trước đây, các trang web chủ yếu gồm các file tĩnh được cung cấp cho người dùng khi được yêu cầu. Do đó, đường dẫn của mỗi yêu cầu có thể được ánh xạ trực tiếp 1:1 với cấu trúc thư mục và file trên hệ thống máy chủ. Hiện nay, các trang web ngày càng trở nên động hơn và đường dẫn của yêu cầu thường không có mối quan hệ trực tiếp với hệ thống file nữa. Tuy nhiên, các máy chủ web vẫn xử lý các yêu cầu cho một số file tĩnh, bao gồm các stylesheet, hình ảnh, v.v.
Quy trình xử lý các file tĩnh này phần lớn vẫn như cũ. Tại một thời điểm nào đó, máy chủ sẽ phân tích đường dẫn trong yêu cầu để xác định phần mở rộng của file. Nó sẽ sử dụng thông tin này để xác định loại file được yêu cầu, thông thường bằng cách so sánh với danh sách các ánh xạ được cấu hình trước giữa phần mở rộng và loại . Những gì xảy ra tiếp theo sẽ phụ thuộc vào loại file và cấu hình của máy chủ.
Nếu loại file là không thực thi, như hình ảnh hoặc trang HTML tĩnh, máy chủ có thể chỉ cần gửi nội dung file cho client trong phản hồi HTTP.
Nếu loại file là thực thi, như file PHP, và máy chủ được cấu hình để thực thi các file loại này, nó sẽ gán các biến dựa trên các header và tham số trong yêu cầu HTTP trước khi chạy script. Kết quả đầu ra có thể được gửi lại cho client trong phản hồi HTTP.
Nếu loại file là thực thi, nhưng máy chủ không được cấu hình để thực thi file loại này, thông thường máy chủ sẽ phản hồi với lỗi. Tuy nhiên, trong một số trường hợp, nội dung của file vẫn có thể được cung cấp cho client dưới dạng văn bản thuần túy. Các cấu hình sai như vậy có thể bị khai thác để làm lộ mã nguồn và thông tin nhạy cảm khác.
Mẹo: Header phản hồi Content-Type
có thể cung cấp manh mối về loại file mà máy chủ nghĩ rằng nó đã phục vụ.
Nếu header này không được thiết lập rõ ràng bởi mã ứng dụng, nó thường chứa kết quả của ánh xạ phần mở rộng file và loại MIME.
Điều tệ nhất xảy ra là khi một trang web cho phép upload server-side script như PHP, Java, hoặc Python file và cũng được cấu hình để thực thi chúng dưới dạng code. Điều này giúp dễ dàng tạo ra web shell trên server
Web shell là một malicious script cho phép attacker thưc thi lệnh tùy ý trên web server từ xa chỉ bằng việc gửi HTTP request đến đúng endpoint.
Tác đông: Đọc ghi file tùy ý, trích xuất dữ liệu nhảy cảm, thậm chí sử dụng chính server để pivot attack vào cơ sở hạ tâng nội bộ +> Cơ bản là có toàn quyền kiểm soát server.
Ví dụ:
Đọc file tùy bằng PHP: Khi được upload, request sẽ trả về nội dung file mục tiêu trong phản hồi.
Thực thi lệnh tùy ý
Tập lệnh cho phép truyền system command tùy ý qua tham số
GET /example/exploit.php?command=id HTTP/1.1
Giải pháp:
Đăng nhập và upload file:
Khi gửi biểu mẫu (form) trên website, trình duyệt thường gửi dữ liệu bằng yêu cầu POST. Đối với dữ liệu văn bản đơn giản, định dạng application/x-www-form-urlencoded
là đủ. Tuy nhiên, đối với dữ liệu nhị phân lớn (như ảnh hoặc tệp PDF), định dạng multipart/form-data
được sử dụng.
Ví dụ, khi gửi biểu mẫu tải lên ảnh, mô tả và tên người dùng, yêu cầu có thể trông như sau:
Nội dung phản hồi được chia thành các phần riêng biệt, đều chứa Content-Disposition
header
Vấn đề với việc xác thực loại MIME
Một số website cố gắng xác thực tải lên tệp bằng cách kiểm tra tiêu đề Content-Type
của từng phần để đảm bảo nó khớp với loại MIME mong đợi (ví dụ: image/jpeg
hoặc image/png
).
Vấn đề: Nếu máy chủ tin tưởng tiêu đề Content-Type
mà không kiểm tra thêm nội dung thực tế của tệp, kẻ tấn công có thể dễ dàng vượt qua kiểm tra này. Bằng cách sử dụng công cụ như Burp Repeater, chúng có thể thao tác yêu cầu để tải lên các tệp loại bất kỳ, dẫn đến vi phạm an ninh.
Giải pháp:
Đăng nhấp và không thành công khi upload trực tiếp
Web chỉ cho phép image/jpeg và image/png
Gửi phản hồi này Repeater, chú ý đến Content-Type
Thử sửa thành Content-Type hợp lệ
Thành công upload. Tìm secret key trong phản hồi
Rõ ràng tốt nhất là ngăn file type nguy hiểm được upload, còn tiếp sau mới đến biện pháp ngăn chặn máy chủ thực thi bất kỳ tập lệnh nào lọt qua mạng.
Để phòng ngừa, các server thường chỉ chạy các script có loại MINE mà chúng đã được cấu hình để thực thi. Nếu không, chúng có thể chỉ trả về một số loại thông báo lỗi/nội dung file dạng clear-text(có thể leak source code nhưng vô hiệu hóa web shell).\
Kiểu cấu hình này thường khác nhau giữa các thư mục. Có thể với các thư mục mà hệ thống xem là ngoài tầm với của người dùng cuối sẽ cho phép upload script đồng thời thực thi nó.
Note: Thường có reverse proxy server như load balancer trước domain name sẽ tiền xử lý tất cả các request gửi đến domain đó, và có thể được cấu hình khác đi.
Giải pháp
Với tính năng upload avatar, ứng dụng không thực thi mà chỉ trả về nội dung file upload
Và có vẻ cả phần comment cũng không thành công.
Với các đường dẫn bị bảo vệ như này, có thể sử dụng path traversal nhằm upload file đến thư mục khác
Trong POST /my-account/avatar
sửa trường file name trong body request
File vẫn được upload trong thư mục ban đầu. Thử với URL encode: "..%2f"
Có vẻ đã thành công. Nếu ứng dụng duyệt thư mục trên thì file_upload.php sẽ nằm tại /file/file_upload.php
Với các trường hợp blacklist các phần mở rộng tệp có khả năng gây nguy hiểm như .php,
đôi khi có thể bypass bằng cách sử dụng phần mở rộng như .php5
, .shtml
, v.v.
Máy chủ thường sẽ không thực thi các tệp trừ khi chúng được cấu hình để thực hiện như vậy. Ví dụ, các máy chủ Apache để thực thi các tệp PHP do client yêu cầu có thể cần được cấu hình tại /etc/apache2/apache2.conf
như sau:
Nhiều máy chủ cũng cho phép các nhà phát triển tạo các tệp cấu hình đặc biệt trong các thư mục riêng lẻ để ghi đè hoặc thêm vào một hoặc nhiều cài đặt chung, như Apache là .htaccess
, máy chủ IIS thì sử dụng tệp web.config
Ví dụ trên web.config
cho phép các tệp JSON được phục vụ cho người dùng:
Giải pháp:
Đăng nhập và thử uploadfile
Lợi dụng điều này để chỉnh sửa .htaccess
nhằm cho phép thực thi file php.
Gửi POST /my-account/avatar
request tới Repeater và chỉnh sửa:
filename
thành .htaccess
.
Content-Type
thành text/plain
.
Thay thế nội dung của tệp bằng lệnh Apache sau:
AddType application/x-httpd-php .loilt8
Điều này ánh xạ một phần mở rộng tùy ý ( .loilt8
) tới kiểu MIME có thể thực thi application/x-httpd-php
. Khi máy chủ sử dụng mô dun mod_php
, nó đã biết cách xử lý điều này.
Thành công. Mở Response trong trình duyệt.
Sửa lại POST /my-account/avatar
request
Mở Response trong trình duyệt
Trở lại trang My Account và tìm đến avatar
Phần xác thực case sensitive nhưng sau đó ánh xạ file extension thành MINE type not case sensitive => Các tệp .pHp được xác thực rồi thực thi như các file .php
Cung cấp nhiều phần mở rộng, tùy thuộc vào các xử lý trên máy chủ (exploit.php.jpg
)
Sử dụng URL encode (hoặc double URL encode) cho . / \
(nếu giá trị không được giải mã khi xác thực phần mở rộng tệp, nhưng sau đó được giải mã ở phía máy chủ) => exploit%2Ephp
Thêm ;
hoặc ký tự null byte trước phần mở rông tệp: exploit.asp;.jpg
hoặc exploit.asp%00.jpg
(nếu xác thực được viết bằng ngôn ngữ cấp cao như PHP hoặc Java, nhưng máy chủ xử lý tệp bằng các hàm cấp thấp hơn trong C/C++)
Sử dụng các ký tự Unicode mutibyte, có thể bị chuyển đổi thành các byte null và dấu chấm sau khi chuyển đổi hoặc chuẩn hóa Unicode: \xC0\x2E
, \xC4\xAE
, hoặc \xC0\xAE
có thể được chuyển thành \x2E
(dấu chấm) nếu tên tệp được phân tích như một chuỗi UTF-8, nhưng sau đó lại được chuyển đổi thành các ký tự ASCII trước khi được sử dụng trong một đường dẫn.
Tạo các phần mở rộng để bypass việc ứng dụng xóa hoặc thay thế các phần mở rộng nguy hiểm mà không đệ quy: exploit.p.phphp (bypass việc xóa .php
khỏi tên tệp)
Giải pháp:
Đăng nhập và thử upload file
Chỉ JPG và PNG file được cho phép upload. Thử các biện pháp thêm vào sau tên tệp phần mở rộng hợp lệ sử dụng Repeater với POST /my-account/avatar
request
Với null byte trước phần mở rộng tệp, thành công upload tệp có phần mở rộng là php
Trở lại My Account. Tìm đến GET /file/avatars/...
và bỏ đi null byte
Thành công lấy được secret key
Thay vì chỉ ngầm tin tưởng vào thông tin Content-Type
, các máy chủ an toàn hơn sẽ cố gắng xác minh xem nội dung của tệp có thực sự khớp với những gì mong đợi hay không. Ví dụ:
Với upload hình ảnh thì xác minh một số thuộc tính của hình ảnh như kích thước
Với một số loại tệp luôn chứa một chuỗi byte cụ thể trong header hoặc footer (JPEG luôn bắt đầu với các byte FF D8 FF
)
Các công cụ như ExilTool có thể tạo JPEG chứa mã độc trong metadata
Giải pháp:
Đăng nhập và thử upload avatar
Có thể đoán rằng ứng dụng sẽ các minh nội dung tệp tải lên xem có là hình ảnh không. Tại đây sử dụng ExifTool
để tạo một polyglot PHP/JPG có chứa mã độc hại trong metadata của tệp đó.
Thêm trường comment vào metadata của ảnh này
Upload polyglot.php
Mở ảnh trong tab mới và tìm kiếm từ khóa START và END trong dữ liệu nhị phân của ảnh.
Các framework hiện đại đã tăng cường bảo mật khi tải lên tệp bằng cách sử dụng thư mục tạm thời và kiểm tra tính hợp lệ trước khi lưu tệp vào hệ thống chính. Tuy nhiên, khi lập trình viên tự xử lý quá trình này mà không dùng framework, có thể xuất hiện các điều kiện tranh chấp nguy hiểm. Ví dụ, nếu tệp được tải lên hệ thống chính và chỉ bị xóa sau khi không vượt qua kiểm tra, kẻ tấn công có thể tận dụng thời gian ngắn mà tệp tồn tại trên máy chủ để thực thi mã độc. Những lỗ hổng này rất tinh vi và khó phát hiện nếu không có mã nguồn.
Giải pháp:
Đăng nhập và thử với các các upload ở các lab trước đó đều không thành công
Dưới đây là gợi ý được đưa ra
Nhìn vào có thể thấy dù là tệp nào cũng được tải lên thư mục avatars/ của hệ thống rồi mới thực hiện kiểm tra FileType và Virus. Điều này cho ta một khoảng thời gian để truy cập file upload trên hệ thống tệp trước khi nó bị kiểm tra và xóa
Gửi cả 2 request POST File Upload và GET File Upload đến Intruder
Cấu hình như sau cho cả 2 request
Kiểm tra các response có status code là 200 để lấy secret
Race codition tương tự có thể xảy ra khi các chức năng cho phpes tải tệp bằng cách cung cấp URL. Trong trường hợp này, máy chủ phải tải tệp từ internet và tạo một bản sao cục bộ trước khi thực hiện bất kỳ kiểm tra tính hợp lệ nào.
Vì tệp được tải bằng HTTP, các nhà phát triển không thể sử dụng các cơ chế tích hợp sẵn của framework để kiểm tra tính hợp lệ một cách an toàn. Thay vào đó, họ phải tạo quy trình riêng để lưu trữ tạm thời và kiểm tra tệp, điều này có thể không đảm bảo an toàn.
Ví dụ, nếu tệp được lưu vào một thư mục tạm thời với tên ngẫu nhiên, về lý thuyết, kẻ tấn công sẽ không thể khai thác race condition nếu không biết tên thư mục. Tuy nhiên, nếu tên thư mục được tạo bằng các hàm ngẫu nhiên giả như uniqid()
của PHP), nó có thể bị tấn công brute-force.
Để thực hiện tấn công dễ dàng hơn, có thể kéo dài thời gian xử lý tệp (bằng cách tải tệp lớn hơn với payload ở đầu và đệm lượng lớn byte tùy ý theo sau)
Nếu file upload sau đó xuất hiện trên trang mà được truy cập bởi người dùng khác, trình duyệt của họ sẽ thực thi tập lệnh khi cố gắng hiển thị trang. Chú ý là do hạn chế về , các loại tấn công này sẽ chỉ có hiệu quả nếu tệp đã tải lên được phục vụ từ cùng nguồn gốc mà bạn đã tải lên
Đây là biện pháp cuối cùng khi có vẻ các tệp đã tải lên được lưu trữ và phục vụ an toàn. Ví dụ, nếu biết máy chủ phân tích các tệp dựa trên XML, chẳng hạn như Microsoft Office .doc
hoặc .xls
, đây có thể là một vectơ tiềm ẩn cho các cuộc tấn công tiêm XXE.
Một số web server có thể được cấu hình để hỗ trợ PUT
request, Nếu không có biện pháp phòng thủ phù hợp, đây có thể cung cấp môt phương tiện thay thế để file upload, ngay cả khi chức năng upload không khả dụng qua giao diện web
Tip: Gửi OPTIONS
requests tới các endpoint khách nhau để kiểm tra xem to có cái nào hỗ trợ phương thức PUT
không.
Kiểm tra phần mở rộng tệp bằng whilelist (hơn là blacklist)
Đảm bảo filename không chứa substring có thể bị thông dịch như là thư mục hoặc chuỗi duyệt ( ../
).
Đổi tên các tệp đã tải lên để tránh xung đột có thể khiến các tệp hiện có bị ghi đè
Không tải tệp lên hệ thống tệp cố định của máy chủ cho đến khi chúng được validate đầy đủ
Nếu có thể, hãy sử dụng một framework được thiết lập để xử lý trước các tệp tải lên
Thông thường các tệp cấu hình này không được phép truy cập bằng HTTP request, nhưng một số máy chủ đôi khi không ngăn người dùng tải lên
Ví dụ: Nếu có thể upload HTML file hoặc ảnh SVG, có thể sử dụng <script>
tag để tạo payloads.