Skip to content

Latest commit

 

History

History
86 lines (64 loc) · 5.26 KB

FILE_UPLOAD_02.md

File metadata and controls

86 lines (64 loc) · 5.26 KB

FILE_UPLOAD level 02

Một trang web có chức năng cho phép user upload file và lưu trữ nó lên server, ngoài ra ta có thể xem được source code của trang web. Thử xem source code của trang web thì thấy đầu tiên một đường dẫn upload sẽ được tạo dựa trên sesion của user:

session_start();
if (!isset($_SESSION['dir'])) {
    $_SESSION['dir'] = 'upload/' . session_id();
}
$dir = $_SESSION['dir'];
if ( !file_exists($dir) )
    mkdir($dir);

Tiếp là câu if để kiểm tra xem có file được upload lên hay không, nếu có thì sẽ move file đó đến đường dẫn dir được khởi tạo ban đầu. Sau khi upload thành công thì sẽ hiển thị lên link dẫn đến file đã upload. Khối if này cũng là đoạn code xử lý chính của web:

if(isset($_FILES["file"])) {
        $error = '';
        $success = '';
        try {
            $filename = $_FILES["file"]["name"];
            $extension = explode(".", $filename)[1];
            if ($extension === "php") {
                die("Hack detected");
            }
            $file = $dir . "/" . $filename;
            move_uploaded_file($_FILES["file"]["tmp_name"], $file);
            $success = 'Successfully uploaded file at: <a href="/' . $file . '">/' . $file . ' </a><br>';
            $success .= 'View all uploaded file at: <a href="/' . $dir . '/">/' . $dir . ' </a>';
        } catch(Exception $e) {
            $error = $e->getMessage();
        }
    }

Khác với level 1, anh lập trình viên ở level này đã add thêm một đoạn code kiểm tra file trước khi được upload để tránh bị mình RCE như bài trước:)

$extension = explode(".", $filename)[1];
if ($extension === "php") {
    die("Hack detected");
}

Tác dụng của hàm explode() là để tách các phần trong một chuỗi ngăn cách bởi một ký tự (trong trường hợp này là dấu chấm .) và trả về một mảng chứa các phần đó. Giả sử file được upload lên là shell.php thì phần code explode(".", $filename) sẽ trả về ["shell", "php"]explode(".", $filename)[1] sẽ trả về php. Mục đích của đoạn code là để kiểm tra xem đuôi file upload lên có phải là php hay không, nếu phải thì sẽ dừng thực thi và trả về đoạn text Hack detected

Vấn đề

Ở đây có 2 vấn đề, thứ nhất thật ra kết quả trả về từ hàm session_id() là một untrust data được kiểm soát bởi client.

Hàm session_id() sẽ trả về kết quả dựa trên giá trị của cookie PHPSESSID, trong trường hợp này là dfacd091c5443055c3ae34525887ce95. Nếu user thay đổi giá trị này thành chanh thì đường dẫn upload bây giờ sẽ thành upload/chanh, vậy nếu giá trị bị thay đổi thành ../ thì đường dẫn upload sẽ là: upload/../:

Dẫn đến việc file được upload bây giờ không còn nằm trong các directory con của upload nữa mà giờ đây nằm ngay bên trong directory này, dẫn đến một lỗ hổng path traversal. Tuy nhiên trong trường hợp này thì không gây ảnh hưởng quá nghiêm trọng.

Vấn đề thứ 2, mình đặt 3 giả thuyết cho phần kiểm tra đuôi file:

  • Một là ngoài sử dụng đuổi file là php thì liệu ta có thể sử dụng đuôi file nào khác mà server vẫn nhận diện là script php và thực thi hay không
  • Hai là nếu truyền tên file là shell.php thì hàm explode sẽ trả về ["shell", "php"], vậy nếu ta upload một file có dạng shell.jpg.php thì sao
  • Ba là extension của file được so sánh với chuỗi php, vậy nếu ta upload một file có đuôi PHP (php được viết hoa) thì sao

Tấn công

Với giả thuyết 1, mình lên trang https://book.hacktricks.xyz (đây là một trang khá hay và được recommend rất nhiều) và tìm kiếm về file upload, mình tìm ra các extension khác có thể được sử dụng thay cho php. Để kiểm chứng thử thì mình thử up một file .phar chứa shell script lên để thử:

Và kết quả:

Vậy là ta đã hoàn thành bài lab, nhưng hãy thử kiểm tra qua các giả thuyết khác.

Giả thuyết 2, ta sẽ thử upload lên một file tên shell.a.php:

Với tên file như trên thì đoạn code explode(".", $filename) sẽ trả về kết quả ["shell", "a", "php"] và khi truy cập đến vị trí thứ 1 của mảng này thì sẽ thu về phần tử a, không khớp với chuỗi php từ đó pass qua khối lệnh check và upload được file

Với giả thuyết 3 ta sẽ thử upload lên file shell.PHP để xem thế nào:

Yay upload lên rồi

Nhưng buồn là khi truy cập đến file, nội dung của file được in ra chứ không được thực thi do server không nhận diện được đuôi file .PHP