运维开发网

php反序列化的字符串转义详细介绍

运维开发网 https://www.qedev.com 2022-07-08 23:06 出处:网络
这篇文章主要为大家详细介绍了php反序列化之字符串逃逸,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

这篇文章主要为大家详细介绍了php反序列化之字符串逃逸,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助


php反序列化ndash;字符串逃逸

PHP反序列化字符串转义有两种情况。一个是过滤后字符串多了,一个是过滤后字符少了(本文默认有反序列化的知识库)。


过滤后字符串变多

以ctfshow-web262为例进行说明:

error_reporting(0);class message{ public $from; public $msg; public $to; public $token='user'; public function __construct($f,$m,$t){ $this-gt;from = $f; $this-gt;msg = $m; $this-gt;to = $t; }}$f = $_GET['f'];$m = $_GET['m'];$t = $_GET['t'];if(isset($f) amp;amp; isset($m) amp;amp; isset($t)){ $msg = new message($f,$m,$t); $umsg = str_replace('fuck', 'loveU', serialize($msg)); setcookie('msg',base64_encode($umsg)); echo 'Your message has been sent';}highlight_file(__FILE__);

在这段代码中,首先获取传入的三个参数,然后序列化包含这三个参数的msg函数,然后用loveU替换其中包含的fuck字符串,重新赋给umsg变量,将变量base64编码设置为cookie。

根据题目中的注释,得到message.php的内容,即

highlight_file(__FILE__);include('flag.php');class message{ public $from; public $msg; public $to; public $token='user'; public function __construct($f,$m,$t){ $this-gt;from = $f; $this-gt;msg = $m; $this-gt;to = $t; }}if(isset($_COOKIE['msg'])){ $msg = unserialize(base64_decode($_COOKIE['msg'])); if($msg-gt;token=='admin'){ echo $flag; }}

如果设置了cookie,并且msg中的令牌是admin,则可以输出该标志

从index.php的内容中可以看出,执行了一个replace步骤,这导致为每个他妈的输入多生成一个位,所以我们可以利用这个特性对字符串进行转义。首先,在本地尝试。

从问题中可以看出,我们需要将原来class类中的token值修改为admin,然后一起传入三个参数,F,M,t,我们可以使用其中一个,这里使用的参数是M,为了避免需要转义的字符串太多,可以先写f t参数,在本地传入值,输出序列化结果。

在下图中quot;学生2:quot;toquot;学生1:quot;1quot;学生5:quot;tokenquot;学生5:quot;adminquot;}是我们要转义的部分,一共44个字符,所以需要M输入44 fuck进行转义。



转义成功,上下串都是正常序列化的字符串,复制有效载荷执行。



字符串变多原理详解

这个问题利用了php反序列化中字符串转义的知识。

先看本地实验的正常回报结果。


当x被传入时,定义的替换函数,用两个x替换一个x,得到o l d的值为lsquoa:2:I:0;学生4:quot;h a n x x quot;I:1;学生7:quot;我是m 11 quot;lsquo如果长度不匹配,会报错,导致old进一步反序列化失败。


当然,如果我们能把hanx的字符串长度从4改成5,那么就会正常执行,虽然一开始输入的是4个字符,名字也会从hanx改成hanxx。

PHP反序列化时,底层代码从;作为字段的分隔,以}(字符串除外)结尾,根据长度判断内容。同时,在反序列化过程中,必须严格遵循序列化规则,才能成功实现反序列化。

从上面的输出结果中,我们可以看到X已经被xx替换,但是序列化结果中的值仍然是原来的4。我们可以根据过滤功能后字符串变多的特点来发现漏洞。

漏洞原理:我们可以使用可以用来封闭数据的等长字符串,假设我们需要以woaini的身份传入年龄,那么我们可以使用quot;I:1;学生6:quot;woainiquot;}这个字符串,一共20位。我们可以通过补充20个x来实现字符串转义,最终构造的有效载荷如下:

name = Mao xxxxxxxxxxxxxxxxxxxx quot;;I:1;学生6:quot;woainiquot;}

因为在题目中知道一个X会被两个X代替,所以我们可以使X的个数等于quot在上面的有效载荷中。;I:1;学生6:quot;woainiquot;}相等,既满足序列化前name长度为40(不算前面的毛),又满足替换后X翻倍,导致引号闭合,所以长度还是40位,但是我们通过字符串转义,传入age的期望值。


从图中可以看出,传入的age值溢出成功,字符串转义成功!


过滤后字符串变少


本地测试如上。开头没有赋值名字和符号,编号是2020,所以存在字符串转义漏洞。如果我们通过构造一个反序列化的字符串转义成功地将数字值从2020更改为2002,我们可以尝试构造一个序列化的字符串。

在代码中,首先通过get传入name和sign参数,然后进行反序列化,反序列化的结果用字符串替换,输出替换后的结果。将反序列化后的结果赋值为fake,分别输出修改后的name、sign和number的值。

正常输入获得正常输出:


当输入包含lemon或shy时,会被替换为空,字符串会被缩短,导致代码中反序列化失败,输出错误:


在上面反序列化的字符串中,控制数字值的字符串是quot;学生6:quot;numberquot;学生4:quot;2020quot;}总长度为27,所以我们需要将name变量中过滤掉的字符设置为set 空。set 空部分的字符串需要保证我们在第二个变量中输入人工补充的序列化字符串时,位数刚好,不报错。


输入的符号YKingquot这里;学生4:quot;signquot;学生4:quot;evanquot;学生6:quot;numberquot;学生4:quot;2002quot;}其中,YKing用于对字数进行四舍五入,补充前面名称变量的长度,以保证能够正常反序列化。然后,输入并分配一个手动构造的符号变量。值是什么并不重要,这样序列化才是正确的。最后把我们想要的数值2002加到sign变量中,用}封闭,让原标题中的2020无法反序列化,实现了数值的覆盖。

name变量的长度确保它可以正常反序列化。然后,输入并分配手动构造的符号变量。值是什么并不重要,这样序列化才是正确的。最后将我们想要的数值2002加入到sign变量中,用}封闭,导致原标题中的2020无法反序列化,从而实现了数值的覆盖。


总结

本文到此为止。希望能帮到你

0

精彩评论

暂无评论...
验证码 换一张
取 消