文件包含

什么是文件包含

和sql注入攻击方式类似,文件包含本质上就是输入一段用户能够控制的脚本或者代码,并让服务器执行。

许多脚本支持使用包含文件(include file),这种功能允许开发者把可使用的代码或脚本插入到单个文件中,然后包含文件中的代码被解释并执行,就好像直接插入到包含指令的位置一样。

以PHP为例,常用的文件包含函数有以下四种:include()require()include_once()require_once()

区别如下:

require(),找不到被包含的文件时会产生致命错误,并停止脚本运行。
include(),找不到被包含的文件时只会产生警告,脚本将继续运行。
include_once()与include()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
require_once()与require()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

参考链接

本地文件包含

  • include.php
<?php
    if(isset($_GET['file'])){
        $a = $_GET['file'];
        include($a.'.php');
    }else{
        highlight_file(__FILE__);
    }
  • payload:url/?file=flag

可以嵌套包含文件,例:url/?file=flag/../flag(此payload等价于上面的payload)

  • %00截断

条件

magic_quotes_gpc = Off

php < 5.3.4

  • 路径长度截断

条件

php < 5.2.8

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

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

PHP伪协议

  • 原理:事实上是支持的协议与封装协议

php://

  • 作用:访问各个输入/输出流

  • 条件:

allow_url_fopen:On/Off

allow_url_include:仅php://input,php://stdin,php://memory,php://temp需要on

php://input

  • 条件:

allow_url_fopen: On/Off

allow_url_include: On

PHP < 5.3.0

  • 用法:用于执行php代码

    可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分,在enctype="multipart/form-data"的时候php://input 是无效的。

  • 演示:

    <?php
        #test.php
        $a = $_GET['a'];    
        include($a);

php://filter

  • 条件:

    allow_url_fopen: Off/On

    allow_url_include: Off/On

  • 用法:主要用于读取文件源码或者写入源码

    名称 描述 备注
    resource=<要过滤的数据流> 指定了你要筛选过滤的数据流 必选
    read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符( )分隔
    <;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链 可选

    read参数可为

    string.strip_tags: 将数据流中的所有html标签清除

    string.rot13:将数据流中的内容rot13变换

    string.toupper: 将数据流中的内容转换为大写

    string.tolower: 将数据流中的内容转换为小写

    convert.base64-encode: 将数据流中的内容转换为base64编码

    convert.base64-decode: 将数据流中的内容转换为base64解码

  • 演示:

    <?php
        #test.php
        $a = $_GET['a'];    
        include($a);

data://

  • 条件:

    allow_url_fopen: On

    allow_url_include: On

    PHP >= 5.2.0

  • 用法:数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。

    data://text/plain;base64,your source (或者 data:text/plain;base64,your source

    data://text/plain,your source or data:text/plain,your source

  • 演示:

    <?php
        #test.php
        #<?php phpinfo(); ===base64===>  PD9waHAgcGhwaW5mbygpOw==
        $a = $_GET['a'];    
        include($a);

file://

  • 条件:

    allow_url_fopen: Off/On

    allow_url_include: Off/On

  • 用法:用于访问本地文件系统

    file://文件的绝对路径和文件名
    a=file://D:phpstudy_pro/www/phpinfo.php

    文件的相对路径和文件名 a=./test.php

    http://网络路径和文件名
    a=http://127.0.0.1/phpinfo.php

  • 演示:

    <?php
        #test.php
        $a = $_GET['a'];    
        include($a);

日志文件包含

  • 原理:对网站进行访问时,日志文件会记录相关的信息(UA头中的信息)
  • 要求:知道日志文件的路径并且能够包含
  • 步骤:
    1. 访问网站,在UA头里写马
    2. 通过post检查代码是否执行
    3. 成功后蚁剑连接反弹shell

Session文件包含

  • Session:

    Session就是保存在服务器的文本文件。 默认情况下,PHP.ini 中设置的SESSION 保存方式是 files(session.save_handler = files),即使用读写文件的方式保存 SESSION 数据,而 SESSION 文件保存的目录由 session.save_path 指定,文件名以 sess_为前缀,后跟 SESSION ID,文件中的数据即是序列化之后的 SESSION 数据

  • 原理:由于Session保存的文件名没有经过严格的过滤或者限制,从而可以被用户控制,执行任意代码

  • 要求:

    PHP >= 5.4.0

    必须先启动,在PHP中先调用session_start(void),注意,此函数前不能有任何输出

    如果在PHP.ini中session.auto_start已经开启则不用,但默认情况下是关闭的

  • 配置

    • session.auto_start:在php接收请求的时候自动初始化Session,不需要再执行session_start(),默认情况下关闭
    • session.save_path:Session存储的位置,我这里就是D:\phpstudy_pro\Extensions\tmp\tmp
    • session.serialize_handler
      • php:一直都在(默认方式) 它是用 |分割
      • php_serialize :php5.5之后启用
        它是用serialize反序列化格式分割
    • session.upload_progress:php5.4添加的。最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中(包含用户可控的值),即使此时用户没有初始化Session,PHP也会自动初始化Session。
      而且,默认情况下session.upload_progress.enabled是为On的,也就是说这个特性默认开启
      • session.upload_progress.enabled:默认开启,表示upload_progress功能开始,php能在每一个文件上传时监测上传进度,这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态
      • session.upload_progress.cleanup:默认开启这个选项,表示当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要。
      • session.upload_progress.prefixsession.upload_progress.name:当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name变量同名(PHP_SESSION_UPLOAD_PROGRESS)时(这部分数据用户可控),上传进度可以在SESSION中获得。当PHP检测到这种POST请求时,它会在SESSION中添加一组数据(系统自动初始化session),
        索引是session.upload_progress.prefixsession.upload_progress.name连接在一起的值
      • session.upload_progress.freq
        session.upload_progress.min_freq
        :选项控制了上传进度信息应该多久被重新计算一次。
        通过合理设置这两个选项的值,这个功能的开销几乎可以忽略不计
    • session.use_strict_mode:默认为0,用户可以自己定义Session ID。比如,我们在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:sess_flag
  • 演示

    #test.php
    <?php
        $test = $_GET['test'];  
        include($test);
    #session.php
    <?php
        session_start();
        $file = $_POST['file'];
        $_SESSION['file'] = $file;

    恶意写session文件马

    包含session文件,成功执行命令