网页提示他备份过网站,因此服务器中应该有网站文件的备份信息
我们使用/www.zip看能不能得到(或者使用dirsearch、御剑等工具扫描后台)
成功得到一份备份信息
我们可以审计一下代码,看看内容
Index.php:
总的来说,网页可以被传递一个变量select
然后用res变量接受反序列化的select
Flag.php:
里面是一个虚假的flag,但是我们可以猜测,真正的网站上flag.php中有真正的flag
既然有真正的flag那我们为什么不直接去/flag.php下拿他呢
输入后发现,返回的是一个空网页
我又想,他给我的flag.php是以php代码写的,在html中并不会显示
因此方法无效
Class.php:
写了一个类的脚本
主要作用为:
定义两个私有变量username和password
对象如果使用这两个参数,则会执行_construct这个魔术方法,修改当前的属性值
_wakeup函数表示反序列化成功后执行下面操作
_destruct函数表示在一个函数生命周期结束时自动执行以下操作
如果password不是100就会直接结束脚本
如果password是一百,并且username等于admin,那么会给flag
我们再看index.php
它可以让我们传递一个参数,并且提示我们这个参数要进行反序列
那么我们首先想到的就是对class进行序列化
然后得到一个序列,付给select,最后在进行反序列化,执行
最后即可得到flag
我们找到class类里对我们有用的部分,然后给Name类两个参数
a作为Name的类对象
$b赋值为$a的序列
然后查看序列化后的$a为:
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
查阅网络资料可知:
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字
段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
因此,我们真正传参时应该加上\0,这样应该会使它可见
O:4:"Name":2:{s:14:"\0Name\0username";s:5:"admin";s:14:"\0Name\0password";i:100;}
而这又会带来另一个问题,\0会截断字符,导致字符后的内容无法被输出
因此我们要用%00来代替\0,他既有了\0的功能,又不会因为\0的特性而截断字符,因此,select应为:
O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
但现在还有一个问题,就是反序列操作完成后会自动执行_wakeup这个代码,修改username值,导致在下面的if语句中被拦截,拿不到flag
因此我们需要修改序列的总属性量,改为比原有属性要大的数,这就会触发一个反序列漏洞,导致代码逻辑异常,自动略过_wakeup,有点像卡bug
这是最终的select:
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
我们通过?传参,即可获得flag
本人为大一新生,上述解答仅为个人理解,若有错误请多指教,非常感谢!
标签:web,Buuctf,14,序列化,flag,100,Php,php,Name From: https://blog.csdn.net/2401_86312572/article/details/144855131