PHP文件包含,文件读取的利用思路,以及配合伪协议的trick

PHP的文件包含函数有两类,分三种:

1
2
file_get_contents()
include()/include_once() require/require_once()

第一种用于获取文件的数据,第二种用于包含并执行代码与读取文件两种功能

php写文件的函数

1
file_put_contents()

基本的思路就是用来写shell吧,不过会有各种限制,但是结合伪协议就可以简单绕过了

file_get_contents()

这个函数经常用于获取文件内容,尤其是php文件的代码,配合伪协议中的元封装器php://filter/convert.base64-encode/resource=class.php
几乎已经成了公认的文件获取姿势

include() / require()

首先说下两者的唯一不同

  1. include是当代码执行到它的时候才加载文件,发生错误的时候只是给一个警告,然后继续往下执行
  2. require是只要程序一执行就会立即调用文件,发生错误的时候会输出错误信息,并且终止脚本的运行

此函数利用的原理
把参数作为一个php文件去运行,所以基本使用方法有拿运行环境与拿输出代码两种作用

这种文件包含利用的目的无外乎以下几种:

  • 使用php://filter/convert.base64-encode/resource=xxx来读文件源码
  • 包含shell代码文件(自己上传的,写的等各种方式),使代码具有php的执行环境
  • 包含使用伪协议自定的数据流,常用于写shell
  • 包含关键文件,获得该文件的输出结果与执行环境(就比如说关键文件中的变量引入)

file_put_contents()

用来写文件进去,其中文件名参数是支持伪协议的,用于将第二个参数content进行过滤器后再写进文件里面去

1
file_put_contents($_POST['filename'], "<?php system($_GET['c']);?>");

以上函数有许多种利用姿势,结合伪协议又可以实现各种检测的绕过,在这里做出统计

1、

1
2
3
4
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

写文件的时候在之前加上了exit函数,可以使用伪协议的base64,rot13,strip_tags来处理下

2、包含form-data形式下php创建的临时文件

3、文件包含函数的参数有固定的后缀

1
2
$file = $_GET['file'].'.php';
include($file);

考虑使用phar://或zip://伪协议来绕过

4、压缩文件上传后再解压文件读取,可以考虑软连接的形式

1
2
ln -s /etc/passwd 1.txt
tar -czvf test.tar.gz 1.txt

5、使用伪协议php:// data:// 构造输入流

6、包含session文件
session文件一般在/tmp目录下,格式为sess_[phpsessid]

7、文件包含函数参数有其他样式的后缀,

%00截断
/etc/passwd%00
(需要 magic_quotes_gpc=off,PHP小于5.3.4有效)

 路径长度截断:
/etc/passwd/././././././.[…]/./././././.
(php版本小于5.2.8(?)可以成功,linux需要文件名长于4096,windows需要长于256)

点号截断:
/boot.ini/………[…]…………
(php版本小于5.2.8(?)可以成功,只适用windows,点号需要长于256)

8、远程文件包含shell,这个在5.6下测试过了,php代码可以正常执行,但是不知为什么马运行不了,莫非是权限问题???好像记得ph师傅说过远程文件包含默认是禁用的。
9、包含日志文件