PHP反序列化字符串逃逸

例题可看:https://www.cnblogs.com/v2ish1yan/articles/16118319.html

今天才学的,做个记录。

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

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

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

1.字符串增多

demo:

得到结果为:

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'。

例子:

';
$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";}"就不会被认为是序列化字符串的内容,从而执行了我们构造的";s:1:"b";s:3:"104";},即让一个成员b的值为104。

然后进行构造:

在上面,只要让'w'字符的数量按要求达到s:后面所要求的的数量(28)即可。

但是我们要根据实际情况来选择构造多少个w。

因为在filter函数中,一个q被换成了两个w,所以让q的数量等于";s:1:"b";s:3:"104";}的字符串长度就行了。因为";s:1:"b";s:3:"104";} 的字符串长度为21,让q的数量为21,反序列化后a的值的长度为就是q的数量加上";s:1:"b";s:3:"104";}  的长度(42),在filter()之后,w的数量就是刚好42,而我们添加上去的字符串就会被逃逸出来,会在反序列化的时候成功执行。【文笔不好】

';
$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));

PHP反序列化字符串逃逸_第1张图片

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

2.字符串减少

demo:

';
$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。

所以这样:

';
$r=filter(serialize($a));
var_dump($r);
print_r(unserialize($r));

就可以得到

PHP反序列化字符串逃逸_第2张图片

 看$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)

你可能感兴趣的:(web知识,php)