PHP反序列化字符串逃逸

今天才学的,做个记录。

字符串逃逸分为两种,减少和增多。

主要是通过一个preg_replace()函数来进行字符串的减少和增多。

首先要知道逃逸的原理,就是反序列化时,是以}来进行结尾的,同时在字符串内,是以关键字后面的数字来规定所读取的内容。

1.字符串增多

demo:

<?php
class A{
    public $a='q';
    public $b='21';

}
$a=new A;
var_dump($a);

得到结果为:

string(45) "O:1:"A":2:{s:1:"a";s:1:"q";s:1:"b";s:2:"21";}"

要将反序列后$b的值变为我们想要的值。

我们还要有一个关键的函数。

function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}

这个就是将序列化后的值,将所有的'q'变为'ww'。

例子:

<?php
class A{
    public $a='qqqqqqq';
    public $b='21';

}function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}
$a=new A;
var_dump(serialize($a));
echo'<pre>';
$r=filter(serialize($a));
var_dump($r);

得到:

 

假设我们想要$b=104,构造的$b的值的序列化后为:

";s:1:"b";s:3:"104";}//";是用来闭合前面的,往下看就知道了

如何进行逃逸

我们先看看把上面的字符串加到$a后是什么样的。

 然后仔细看,如果我们把s:28后面的内容以字符串按要求填满了28个,那么s:1:"b";s:3:"104";}就会执行。而}”后面的内容,即;s:1:"b";s:2:"21";}"就不会执行了,从而达到了逃逸的目的。

然后进行构造:

只要让'w'字符的数量按要求达到s:后面所要求的的数量即可。

又因为在filter函数中,一个q被换成了两个w,所以让q的数量等于";s:1:"b";s:3:"104";}的字符串长度就行了

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqq";s:1:"b";s:3:"104";}';
    public $b='21';

}function filter($a){
    $filter='/q/i';
    return preg_replace($filter,'ww',$a);
}
$a=new A;
var_dump(serialize($a));
echo'<pre>';
$r=filter(serialize($a));
var_dump($r);

得到

string(87) "O:1:"A":2:{s:1:"a";s:42:"qqqqqqqqqqqqqqqqqqqqq";s:1:"b";s:3:"104";}";s:1:"b";s:2:"21";}"

string(108) "O:1:"A":2:{s:1:"a";s:42:"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:3:"104";}";s:1:"b";s:2:"21";}"

然后再进行反序列化就可以发现,$b的值变成了104。

接上面代码:

print_r(unserialize($r));

 

 

 

 总的就是说,让字符'w'占用了原本属于";s:1:"b";s:3:"104"}的位置,从而让";s:1:"b";s:3:"104"}逃逸出去而成功执行。

 

2.字符串减少

demo:

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
    public $b='20';

}
function filter($a){
    $filter='/qq/i';
    return preg_replace($filter,'w',$a);
}
$a=new A;
var_dump(serialize($a));
echo '<pre>';
$r=filter(serialize($a));
var_dump($r);

 

 由名字可知,这个就是让字符串变少。

那么要如何让字符串逃逸呢?

同上面字符串增加:如果要让$b=104,那么他的序列化后就是:";s:1:"b";s:3:"104";}

但是前面要加个东西,如:A";s:1:"b";s:3:"104";},那个A是用来闭合的。

我们先把$b=A";s:1:"b";s:3:"104";}

得到:

 

 这里可以看到,在序列化字符串里,有两个 s:1:"b",第一个是序列化得到的,第二个是我们自己构造的。

那么要如果让我们构造的104生效呢?

就要让s:1:"a":s:32:"读取到s:22:"A",这样s:22:"A就会变成$a的值了,后面的内容就可以执行,所以这个时候就要想如何使这些字符串在一个合理的数量了。

有filter可以知道,两个q会变成一个w,所以只要让w的个数等于黄色字符串的长度

"O:1:"A":2:{s:1:"a";s:44:"wwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:22:"A";s:1:"b";s:3:"104";}";}"

 

这个黄色字符串长度为17,所以qq的数量就为17,就有34个q。

所以这样:

<?php
class A{
    public $a='qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
    public $b='A";s:1:"b";s:3:"104";}';

}
function filter($a){
    $filter='/qq/i';
    return preg_replace($filter,'w',$a);
}
$a=new A;
var_dump(serialize($a));
echo '<pre>';
$r=filter(serialize($a));
var_dump($r);
print_r(unserialize($r));

就可以得到

 

 看$b变成了104。

与字符串增加的区别:

1.字符串增加:构造的序列化加在qqqq(就是值有很多qqqq的)那个变量里。字符串减少:构造的序列化加在另一个变量里。

2.字符串增加:字符串'qqqqxxx'的数量依照构造的那个序列化字符串的长度。字符串减少:字符串'qqqqxxx'的数量依照"O:1:"A":2:{s:1:"a";s:44:"wwwwwwwwwwwwwwwwwwwwww";s:1:"b";s:22:"A";s:1:"b";s:3:"104";}";}"中黄色字符串的长度。(只能意会)(doge)

posted @ 2022-04-07 17:17  v2ish1yan  阅读(244)  评论(0)    收藏  举报