目录

  1. 安全级别Low
    1. 源码分析
    2. 漏洞复现
  2. 安全级别Medium
    1. 源码分析
    2. 漏洞复现
  3. 安全级别High
  4. 安全级别Impossible

  当我们在编写较大工程时,往往会将功能函数封装在单独的文件中,方便多次调用,调用文件的过程就是文件包含。如果不对文件来源进行审查,可能就会导致任意文件读取或者任意命令执行,这就是文件包含漏洞。
  文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞。在php中alLow_url_fopen选项开启后,服务器允许包含远程的文件,就会造成远程文件包含漏洞。
  php常见文件包含函数如下:

1
2
3
4
5
6
7
8
Include()
/*当包含并运行指定文件时,包含的外部文件发生错误,系统会给出警告,但整个php文件还会继续执行。*/
Require()
/*require()与 include()的区别在于 require()执行如果发生错误,函数会输出错误信息,并终止脚本的运行。*/
include_once()
/*和include没有什么区别,只是在导入函数之前先检测下该文件是否被include过,如果已经执行了一遍,那么就不在进行第二次的include操作。*/
require_once()
/*功能与 require()相同,区别在于当重复调用同一文件时,程序只调用一次*/

安全级别Low

源码分析

1
2
3
4
5
6
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

?>

  直接跳过GET获取page参数,未经检查和过滤,直接执行。
  页面显示如下:

漏洞复现

  页面中有三个file,点击第一个文件,显示如下:

  点击file1时,服务器会包含file1并执行,同时观察url,page=file1.php,因此是直接通过page传递参数,可以直接在url上修改文件路径。
  在file1、2、3同文件夹下有一个隐藏文件file4.php和我自己编写的flag文件,通过page=file4.php、page=flag获取文件内容:


  当文件类型为php时,文件会执行并显示信息。而不是php文件时,如上图flag,会直接显示文件内容。
  如果我们知道服务器的文件路径,可以通过相对路径(如../../phpinfo.php)和绝对路径的方式包含文件。若要远程包含文件,输入完整的url路径即可:


安全级别Medium

源码分析

1
2
3
4
5
6
7
8
9
10
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );

?>

  此处添加了一些字符过滤,将“http: //”、“https: //”、 “../”、“..\”替换为空,阻挡一些路径文件的访问。

漏洞复现

  对于“../”、“..\”这样的相对路径,若知道了服务器完整的文件路径,可以使用绝对路径来代替。
  可以采用复写的方式来绕过,如“ht http:// tp://”,“ht https:// tps://”,字符串中的“http: //”、“https: //”被替换为空,因此前后的字符串又拼接起来成http。同样也使用”…/./“、”….\”来绕过:


安全级别High

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}

?>

  源码中使用了file协议,限制路径开头必须为file。
  file协议是本地文件传输协议 ,主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样。 要使用file协议,基本的格式如下:file:///文件路径。
  因此我们只能使用绝对路径来包含文件:

安全级别Impossible

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

// The page we wish to display
$file = $_GET[ 'page' ];

// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}

?>

  源码对文件名实行白名单机制,只有file1.php、file2.php、file3.php可以被包含,彻底修复了任意文件包含漏洞。