### PHP 的 %00 截断的原理

当 PHP 脚本在调用某些文件操作函数（如 `include()`、`require()`、`file_get_contents()` 等）时，底层会调用 C 语言的库函数。在 C 语言中，字符串是以空字节（null byte）作为结束符的，即十六进制的 `0x00`。当 C 语言函数读取到 `0x00` 时，就会认为字符串已经结束

而 PHP 脚本在处理用户输入时，并不会像 C 语言那样将 `%00` 解析为空字节，它会将其当作普通的字符串。但是，当这个字符串被传入底层 C 语言函数进行文件操作时，C 语言会截断这个字符串，只处理 `%00` 之前的部分

假设服务器上有一个 PHP 脚本，其代码如下：

    <?php
    $file = $_GET['file'];
    include($file . ".php");
    ?>

这段代码的本意是让用户通过 `file` 参数指定一个文件名，然后脚本会在文件名后面自动加上 `.php` 后缀，再包含这个文件

现在，如果攻击者想要利用这个漏洞来包含一个图片文件 `shell.jpg`（其中包含恶意 PHP 代码），他可以构造一个带有 `%00` 截断的 URL：

    http://example.com/index.php?file=shell.jpg%00

当 PHP 脚本接收到这个 URL 时：

1. PHP 层：
   - `$file` 的值是 `shell.jpg%00`
   - `$file . ".php"` 拼接后的字符串是 `shell.jpg%00.php`
2. C 语言底层：
   - 当 `include()` 函数将 `shell.jpg%00.php` 这个字符串传递给底层的 C 语言文件操作函数时，C 语言会把 `%00` 识别为空字节（`\0`）
   - 根据 C 语言的字符串处理规则，它会认为字符串在 `shell.jpg` 处就已经结束了
   - 最终，操作系统实际打开的文件名是 `shell.jpg`，而不是 `shell.jpg.php`

这样一来，攻击者就成功绕过了 `.php` 后缀的限制，实现了对 `shell.jpg` 的文件包含，从而执行了图片中的恶意代码