前言

1
2
$file = $_GET['file'];
include 'path/$file'.'.php';

一个CMS中出现上面这样的代码,首先想到的应该是php版本小于5.3.4中利用%00截断包含文件。那么,如果我们正常的区包含一个php文件,又有那些用法呢?

正文

包含shell文件

第一次做CMS审计的时候便遇到了这样的情况,那个CMS采用的是ZendFramework框架,只有根目录下的文件可访问执行,找到一个任意文件写入Shell后却无法访问到,正好看过ph的审计文章,于是我果断去找到了类似这么一处鸡肋文件包含点来帮忙,成功拿下

包含install.php

绝大多数的CMS安装后,均会创建一个锁文件,然后在install.php中写入判断代码防止重装。但是有很多代码是采用的判断锁文件相对路径,类似如下这样:

1
2
3
4
if(file_exists('./install.lock')){
die('had installed!');
}
//code to install...

这种情况下,如果我在其他目录下找到一个鸡肋文件包含点,对install.php进行包含,判断锁文件时,以包含点的文件出发,锁文件就被判断为不存在了,导致我们就可以执行后面的安装代码了

相应的操作类似如下这样:

img

虽说我们绕过了对锁文件的判断,但是实际会收到很大限制,最大问题的就是Install.php文件通常也会使用相对路径载入一些相关文件,文件不存在则会终止掉php脚本,除非引入相关文件使用的是include和include_once

这里拿metinfo的代码做演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
if(file_exists('../config/install.lock')){
exit('对不起,该程序已经安装过了。<br/>
如你要重新安装,请手动删除config/install.lock文件。');
}
deldir_in('../cache', 1);
switch ($action)
{
case 'apitest': {...}
case 'inspect': {...}
case 'db_setup':
{
if($setup==1){
$db_prefix = trim($db_prefix);
if (strstr($db_host, ":")) {
$arr = explode(":", $db_host);
$db_host = $arr[0];
$db_port = $arr[1];
}else{
$db_host = trim($db_host);
$db_port = "3306";
}
$db_username = trim($db_username);
$db_pass = trim($db_pass);
$db_name = trim($db_name);
$db_port = trim($db_port);
$config="<?php
/*
con_db_host = \"$db_host\"
con_db_port = \"$db_port\"
con_db_id = \"$db_username\"
con_db_pass = \"$db_pass\"
con_db_name = \"$db_name\"
tablepre = \"$db_prefix\"
db_charset = \"utf8\";
*/
?>";

$fp=fopen("../config/config_db.php",'w+');
fputs($fp,$config);
fclose($fp);

如果成功包含该文件,判断锁文件之前是metinfo自己写的很多安装用的函数,不会影响包含后进入下面的代码。install.php中的代码本身就存在很大的风险

就比如这里的配置文件写入,利用*/phpinfo();/*即可写入一个shell,可惜并没有一个好的方法创建一个完美的config文件夹供代码写入。总之,绕过锁文件后,就可能利用到其中的危险代码

其他

仔细想想,使用上面点还可以有很多骚操作,遇到再补充~

结尾

开发过程中,这样的点最好不要出现,有也得添加限制,另外,install目录这种东西不要出现在线上