File upload là một tính năng phổ biến trong các ứng dụng web, cho phép người dùng chia sẻ hình ảnh, tài liệu hoặc các tệp khác. Tuy nhiên, nếu không triển khai một cách an toàn, tính năng này có thể trở thành một rủi ro bảo mật đáng kể, có thể dẫn đến truy cập không được ủy quyền, việc vi phạm dữ liệu và thậm chí là thực thi mã từ xa.
Trong bài viết này, chúng ta sẽ liệt kê các vị trí và checklist có thể vượt qua cơ chế kiểm tra của hệ thống.
Lưu ý: Luôn cần tải lên một tệp chuẩn định dạng theo yêu cầu của hệ thống để vượt qua cơ chế kiểm duyệt ở phía front-end.
Mục lục
Check Content-Type ở chức năng File Upload
Phía back-end có thể xác thực kiểu file thông qua header Content-Type Sau khi bắt request bằng công cụ Burpsuite, chúng ta đổi giá trị của header Content-type thành một giá trị hợp lệ.
Ví dụ: Đoạn code dưới đây thể hiện cách xác thực tệp tải lên phía backend thông qua header Content-Type. Các loại Content-Type được chấp nhận bao gồm: image/jpeg, image/png, image/gif, application/pdf, application/zip, và audio/mpeg. Khi tải lên một tệp, hệ thống sẽ kiểm tra Content-Type của tệp đó. Nếu Content-Type không nằm trong danh sách được chấp nhận, tệp sẽ bị từ chối.
<?php
function isValidContentType($filePath) {
$allowedContentTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/zip', 'audio/mpeg'];
$fileContentType = mime_content_type($filePath);
return in_array($fileContentType, $allowedContentTypes);
}
Check File name ở chức năng File Upload
Case 1: Phía back-end chỉ check đuổi file extension
Đoạn code dưới đây thể hiện cách xác thực tệp tải lên phía back-end thông qua file extension. Các file extension được chấp nhận bao gồm jpg, png, gif. Khi tải một tệp lên, hệ thống chỉ kiểm tra file extension của tệp đó. Nếu file extension không nằm trong danh sách được chấp nhận, tệp sẽ bị từ chối. Tuy nhiên, có thể bypass kiểm tra này bằng cách đặt tên tệp như là shell.jpg.php.
function is_valid_extension($filename) {
$valid_extensions = ['jpg', 'png', 'gif'];
$file_extension = pathinfo($filename, PATHINFO_EXTENSION);
return in_array($file_extension, $valid_extensions);
}
Case 2: Phía back-end thực hiện loại bỏ các đuôi file không hợp lệ.
Đoạn code dưới đây thể hiện cách xác thực tệp tải lên phía back-end thông qua file extension. Khi tải một tệp lên, hệ thống chỉ kiểm tra file extension của tệp đó. Nếu file extension bao gồm php, php3, php4, php5, phtml, tệp sẽ bị từ chối. Tuy nhiên, có thể bypass kiểm tra này bằng cách đặt tên tệp như là shell.phphpp.
function remove_invalid_extension($filename) {
$invalid_extensions = ['php', 'php3', 'php4', 'php5', 'phtml'];
$path_parts = pathinfo($filename);
$extension = strtolower($path_parts['extension']);
if (in_array($extension, $invalid_extensions)) {
// Loại bỏ đuôi không hợp lệ
$filename = str_replace("." . $extension, "", $filename);
}
return $filename;
}
Case 3: Phía back-end có thể luôn luôn thêm đuôi file hợp lệ.
Đoạn code dưới đây không thực hiện xác thực file extension mà luôn thực hiện nối thêm file extension jpg ở cuối file. Đối với các phiên bản php 5.3.4 trở về trước ta thực hiện bypass dùng null byte. Ta có thể bypass bằng cách đặt tên tệp như là shell.php%00.
function add_valid_extension($filename, $valid_extension) {
return $filename . '.' . $valid_extension;
}
$filename = $_FILES['uploaded_file']['name'];
$valid_extension = 'jpg';
$filename_with_extension = add_valid_extension($filename, $valid_extension);
Case 4: Phía server có thể không kiểm tra tên file upload.
Đoạn code dưới đây không thực hiện việc kiểm tra file name. Chức năng file upload này có thể tồn tại lỗ hổng Path Traversal. Attacker có thể thực hiện được việc ghi đè lên 1 file khác. Nếu phía back-end không cấm thực thi tệp, attacker có thể tải tệp lên một đường dẫn khác và thực thi nó.
function add_valid_extension($filename, $valid_extension) {
return $filename . '.' . $valid_extension;
}
$filename = $_FILES['uploaded_file']['name'];
$valid_extension = 'jpg';
$filename_with_extension = add_valid_extension($filename, $valid_extension);
Case 5: Phía server sử dụng các hàm hệ thống để thao tác với file upload.
Đoạn code dưới đây thực hiện di chuyển file bằng lệnh hệ thống. Phía backend không thực hiện việc kiểm tra file name, chức năng file upload tồn tại lỗ hổng OS Command injection gây nguy hiểm rất lớn tới hệ thống.
$filename = basename($_FILES['uploaded_file']['name']);
$target_path = $upload_dir . $filename;
exec("mv " . $_FILES['uploaded_file']['tmp_name'] . " " . $target_path);
Check File header(Magic byte) ở chức năng File Upload
Magic byte là một giá trị nhận dạng đặc biệt được sử dụng ở đầu của một file hoặc một đoạn dữ liệu để xác định định dạng hoặc giao thức của nó. Magic byte giúp các chương trình phần mềm nhận ra kiểu của file hoặc dữ liệu ngay lập tức mà không cần đọc toàn bộ nội dung.
Đoạn code dưới đây thể hiện cách xác thực tệp tải lên phía back-end thông qua magic byte. Khi tải một tệp lên, hệ thống chỉ kiểm tra magic byte của tệp đó. Nếu magic byte không bao gồm ffd8ff(jpeg), 89504e470d0a1a0a(png), 47494638(gif), 25504446(pdf) tệp sẽ bị từ chối. Ta có thể bypass bằng cách giữ nguyên magic byte và thực hiện thay đổi nội dung file.
function isValidFile($filePath) {
$magicBytes = bin2hex(file_get_contents($filePath));
$validMagicBytes = [
'jpeg' => 'ffd8ff',
'png' => '89504e470d0a1a0a',
'gif' => '47494638',
'pdf' => '25504446'
];
foreach ($validMagicBytes as $type => $bytes) {
if (strpos($magicBytes, $bytes) === 0) {
return true;
}
}
return false;
}
Danh sách các Magic Byte của các kiểu file phổ biến
Bypass Extension với Web Server Apache
.htaccess là một file cấu hình phân tán được sử dụng bởi máy chủ web Apache để quản lý và kiểm soát các thiết lập ở mức thư mục. Tên gọi .htaccess là viết tắt của “Hypertext Access”.
.htaccess chỉ hoạt động với Apache Web Server và và không hoạt động trên các máy chủ web khác.
Lưu ý: Nội dung .htaccess phải viết đúng Syntax.Nếu sai Apache sẽ không xử lý được và báo lỗi 500 Internal Server Error
Apache cho phép người dùng tự tuỳ biến cấu hình Web mà không phải khởi động lại máy chủ thông qua file .htaccess
Lợi dụng .htaccess để yêu cầu Apache nhận dạng thêm *.cookie cũng là file php.
Dưới đây, ta sử dụng công cụ Burpsuite bắt request upload file. Ta thực hiện upload file .htaccess có nội dung “cấu hình file extension png cũng là 1 file php” .
Check Metadata của ảnh được upload lên hệ thống
Sau khi thực hiện Upload file thành công lên hệ thống. Phía back-end không thực hiện việc xóa metadata của ảnh. Những thông tin nhạy cảm của người dùng có thể bị tiết lộ. Mọi người có thể tham khảo ở bài nghiên cứu VẤN ĐỀ LỘ THÔNG TIN TỪ ẢNH TRÊN CÁC TRANG BÁO của bạn Tùng
Sử dụng công cụ Exif tool để kiểm tra metadata của ảnh:
Để giảm thời gian và công sức khi kiểm tra lỗ hổng trong chức năng tải tệp lên, chúng ta có thể sử dụng extension Upload Scanner trong công cụ Burpsuite. Extension này cung cấp khả năng tự động quét và phát hiện các lỗ hổng liên quan đến việc tải lên tệp, giúp chúng ta nhanh chóng xác định và khắc phục các vấn đề bảo mật.
Để hiểu rõ cách sử dụng extension này, bạn có thể tham khảo hướng dẫn chi tiết tại blog về Upload Scanner extension.
What do you think?
It is nice to know your opinion. Leave a comment.