PHP代码审计——Day 10-Anticipation
漏洞解析
extract($_POST);
function goAway() {
error_log("Hacking attempt.");
header('Location: /error/');
}
if (!isset($pi) || !is_numeric($pi)) {
goAway();
}
if (!assert("(int)$pi == 3")) {
echo "This is not pi.";
} else {
echo "This might be pi.";
}
问题所在:当检测到攻击时,虽然有相应的防御操作,但是程序未立即停止退出,导致程序继续执行的问题。
extract
:(PHP 4, PHP 5, PHP 7)
- 功能 :将关联数组中的键名作为变量名,对应的值作为变量值,将它们导入到当前的符号表
- 定义 : int extract ( array &$array [, int $flags = EXTR_OVERWRITE [, string $prefix = NULL ]] )
$data = array("name" => "John", "age" => 30, "city" => "New York"); extract($data); echo $name; // 输出 "John" echo $age; // 输出 30 echo $city; // 输出 "New York"
回到有问题的代码。
程序对 pi 变量进行简单的验证,如果不是数字或者没有设置 pi 变量,程序就会执行 goAway 方法,即记录错误信息并直接重定向到 /error/ 页面。这里是对非法的操作进行了一定的处理。但是关键在于,程序在处理完之后,没有立即退出,没有exit()或die(),这样程序又会按照流程执行下去,也就到了assert语句。由于前面 pi 变量可以被用户控制,所以在这一行存在远程代码执行漏洞。assert()能够执行"中的代码,如assert("(int)phpinfo()")
;
构造payload:POST提交pi=phpinfo()
实际上,这种案例在真实环境下不少。例如有些CMS通过检查是否存在install.lock文件,从而判断程序是否安装过。如果安装过,就直接将用户重定向到网站首页,却忘记直接退出程序,导致网站重装漏洞的发生。