php代码审计-文件安全(2)

php代码审计

梦想cms任意文件读取漏洞

image-20230723095830899

从危害等级来看,估计也是在后台,我们直接从后台来看一看

这里也是先给出文件读取相关的函数

在 PHP 中,文件读取相关的函数主要有以下几个:

1.fopen() 函数:用于打开一个文件,并返回一个文件指针。语法如下:

1
php复制代码$fp = fopen($filename, $mode);

其中,$filename 是要打开的文件名,可以是相对路径或绝对路径;$mode 是打开文件的模式,包括 “r”(只读)、”w”(只写)、”a”(追加)等多种模式。

2.fgets() 函数:用于从文件指针中读取一行数据。语法如下:

1
php复制代码$line = fgets($fp);

其中,$fp 是文件指针,可以是通过 fopen() 打开的一个文件句柄;$line 是从文件指针中读取到的一行数据,包括行末换行符(\n)。

3.fread() 函数:用于从文件指针中读取指定长度的数据。语法如下:

1
php复制代码$data = fread($fp, $length);

其中,$fp 是文件指针,可以是通过 fopen() 打开的一个文件句柄;$length 是要读取的数据长度,单位为字节;$data 是从文件指针中读取到的数据。

4.file_get_contents() 函数:用于一次性读取整个文件到一个字符串中。语法如下:

1
php复制代码$data = file_get_contents($filename);

其中,$filename 是要读取的文件名,可以是相对路径或绝对路径;$data 是读取到的文件内容。

需要注意的是,在实际编程中,应该谨慎处理文件读取操作,并进行错误处理和异常情况的处理。同时,还应该遵循最佳安全实践,例如对文件路径进行验证和过滤、限制文件访问权限、加密敏感信息等,以确保系统的稳定性和安全性。

5.file() 函数:用于将整个文件读入一个数组中。语法如下:

1
php复制代码$lines = file($filename, $flags);

其中,$filename 是要读取的文件名,可以是相对路径或绝对路径;$flags 是可选参数,用于指定读取方式和处理方法,例如忽略空行、保留换行符等。

6.fgets() 和 feof() 函数的结合使用:用于逐行读取文件,直到文件结束。语法如下:

1
2
3
4
5
6
php复制代码$fp = fopen($filename, "r");
while (!feof($fp)) {
$line = fgets($fp);
// 处理每一行数据
}
fclose($fp);

其中,$filename 是要读取的文件名,可以是相对路径或绝对路径;$fp 是通过 fopen() 函数打开的文件句柄;feof() 函数用于检测文件是否已经结束。

7.readfile() 函数:用于将文件内容输出到输出缓冲区。语法如下:

1
php复制代码readfile($filename);

其中,$filename 是要读取的文件名,可以是相对路径或绝对路径。readfile() 函数会自动将文件内容输出到输出缓冲区,并返回读取到的字节数。

这里我在vscode里面全局搜索一下(之前install文件已经被删除了,所以搜索到的可能少一些)

img

这里可以发现,一个在php文件中,一个在js文件中,肯定是在php文件中的可能性大一些,,进入php文件看一波

1
2
3
4
5
6
7
8
9
10
11
12
//获取文件内容
public static function getcon($path){
if(is_file($path)){
if(!$content = file_get_contents($path)){
rewrite::js_back('请检查【'.$path.'】是否有读取权限');
}else{
return $content;
}
}else{
rewrite::js_back('请检查【'.$path.'】文件是否存在');
}
}

具体来说,这个方法首先使用 is_file() 函数检查 $path 是否是一个文件,如果不是,则使用 rewrite::js_back() 方法返回一个 JavaScript 弹窗提示信息,内容为 ‘请检查【’.$path.’】文件是否存在’。如果 $path 是一个文件,则继续执行后续代码逻辑。

接下来,使用 file_get_contents() 函数读取文件内容,并将结果存储到 $content 变量中。如果读取失败,则使用 rewrite::js_back() 方法返回一个 JavaScript 弹窗提示信息,内容为 ‘请检查【’.$path.’】是否有读取权限’。否则,该方法返回读取到的文件内容。

到这里有两种思路,是看传参还是看函数的调用,但是仔细看一下代码,我们会发现没有可以控制的变量,所以直接在网页传参测试是不可以的,于是我选择看一下函数的调用

img

我们在全文搜索一下getcon

注意要全字匹配,不然会出现很多

img

这里在两个地方发现了getcon,一个是本身,一个是temp那个地方调用了,我们去一下temp看一下

img

在这里我们找到了可控变量dir

在注释中我们看到了很多模板这种字样,估计是在模板功能里面我们找一下就找到了相关链接

img

点击编辑之后会传递以下的url

http://127.0.0.1:8081/lmxcms1.4/admin.php?m=Template&a=editfile&dir=default/error.html

问题来了,我们需要知道$this->config[‘template’]的值是多少,因为查看文件的路径是这样的

$this->config[‘template’].$dir

后面的dir部分是可控的,但是前面的$this->config[‘template’]部分我们不知道值是什么,来解决这个问题

img

我们稍微修改一下源码,本来的源码是下面这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public function editfile(){
$dir = $_GET['dir'];
//保存修改
if(isset($_POST['settemcontent'])){
if($this->config['template_edit']){
rewrite::js_back('系统设置禁止修改模板文件');
}
file::put($this->config['template'].$dir.'/'.$_POST['filename'],string::stripslashes($_POST['temcontent']));
addlog('修改模板文件'.$this->config['template'].$dir);
rewrite::succ('修改成功','?m=Template&a=opendir&dir='.$dir);
exit();
}
$pathinfo = pathinfo($dir);
//获取文件内容
$content = string::html_char(file::getcon($this->config['template'].$dir));
$this->smarty->assign('filename',$pathinfo['basename']);
$this->smarty->assign('temcontent',$content);
$this->smarty->assign('dir',dirname($_GET['dir']));
$this->smarty->display('Template/temedit.html');
}

我们来稍稍修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public function editfile(){
$dir = $_GET['dir'];
//保存修改
if(isset($_POST['settemcontent'])){
if($this->config['template_edit']){
rewrite::js_back('系统设置禁止修改模板文件');
}
file::put($this->config['template'].$dir.'/'.$_POST['filename'],string::stripslashes($_POST['temcontent']));
addlog('修改模板文件'.$this->config['template'].$dir);
rewrite::succ('修改成功','?m=Template&a=opendir&dir='.$dir);
exit();
}
$pathinfo = pathinfo($dir);
//获取文件内容
$content = string::html_char(file::getcon($this->config['template'].$dir));
echo $this->config['template'].$dir;
$this->smarty->assign('filename',$pathinfo['basename']);
$this->smarty->assign('temcontent',$content);
$this->smarty->assign('dir',dirname($_GET['dir']));
$this->smarty->display('Template/temedit.html');
}

我们来访问一下下面这个构建好的链接,弹出了$this->config[‘template’]的值

http://127.0.0.1:8081/lmxcms1.4/admin.php?m=Template&a=editfile&dir=1

img

ok这样子我们就知道了前面的值是什么了

D:/phpstudy_pro/WWW/lmxcms1.4/template

访问下面的链接,就可以得到指定文件的内容

http://127.0.0.1:8081/lmxcms1.4/admin.php?m=Template&a=editfile&dir=../inc/db.inc.php

img

该文件不仅可以查看,还可以修改,那就是有文件写入的地方,可能存在任意文件写入漏洞?

这个1day放在下一篇文章继续讲

到这里该1day就审计结束了


php代码审计-文件安全(2)
https://zzhnohikari.github.io/2023/07/23/php代码审计-文件安全2/
作者
John Doe
发布于
2023年7月23日
许可协议