这是一道典型的 PHP 代码审计与绕过题(通常出现在 CTF 比赛中)。题目核心在于通过 eval() 函数执行任意代码以获取 Flag。

执行点:
php
eval("echo new $v1($v2());");
但是v1v2都被正则限制
被禁用的字符包括:绝大多数特殊符号(包括括号 ()、分号 ;、美元符号 KaTeX parse error: Undefined control sequence: \、 at position 6: 、反斜杠 \̲、̲引号等)以及所有数字 [0-9...v1 和 $v2 中只能包含纯英文字母。
致命细节:注意到 v2 在 eval 中是以 v2() 的形式被调用的,而正则中禁用了括号 ()。因此,我们不能在 v2 的输入中自带括号,必须让它保持纯字母,依赖代码原本自带的 () 执行。例如,若 v2 = 'phpinfo',则会被解析执行为 phpinfo()
因为受到严格的字母限制无法使用 system() 等需要传参的函数,我们必须利用 PHP 的内置类 来读取文件
我们需要寻找一个满足以下条件的 PHP 内置类:
类名完全由纯字母组成(配合 $v1)。
其构造函数接受一个字符串参数。
或者是可以通过 echo 直接输出该对象的实例(即该类实现了 __toString() 魔术方法)。
核心武器:FilesystemIterator 或 GlobIterator
FilesystemIterator:用于遍历文件系统目录。
GlobIterator:可以通过匹配模式遍历文件目录(支持通配符 *)。
当使用 echo 打印这些类的实例时,它们会默认返回当前目录下的第一个文件名。
- 具体构造与构造链步骤
第一步:查看当前目录下的文件
由于 v2 会以 v2() 形式执行,我们需要找到一个不需要参数、返回值为字符串或可用路径的内置函数。
getcwd:这是一个完美的函数。getcwd() 不需要参数,返回当前工作目录的绝对路径(字符串)。
如果我们传入:
v1 = FilesystemIterator
v2 = getcwd
eval 实际执行的语句将是:
php
echo new FilesystemIterator(getcwd());

发现有一个文件名为fl36dga.txt的我们尝试访问
这里直接在原url后加上文件名就可以访问

在原 URL 后面加上 fl36dga.txt 就能直接访问,这并不是因为题目代码执行了什么逻辑,而是因为 Web 服务器(如 Apache、Nginx)的核心工作原理。
我们可以把这个过程拆解为两个层面:
- Web 服务器的"文件映射"机制(为什么能直接访问)
当你访问一个网站时(例如 http://example.com/),Web 服务器的后台其实对应着服务器硬盘上的一个具体文件夹(通常称为 Web 根目录,比如 /var/www/html/)。
当你访问 http://example.com/index.php 时,服务器就会去根目录下找到 index.php 这个文件,通过 PHP 解释器执行它,然后把结果发给你的浏览器。
同理,如果你在上一阶段通过漏洞发现了当前目录下还有一个叫 flag.php 的文件,你直接在浏览器输入 http://example.com/flag.php,Web 服务器就会绕过原本的 index.php,直接去读取并执行 flag.php。
这就是为什么你不需要再去研究怎么构造复杂的 Payload,直接修改 URL 就能访问它的原因。
- 为什么有时候直接访问 flag.php 却看不到 Flag?
虽然你可以直接访问它,但在实际的 CTF 比赛中,你大概率会遇到以下两种情况:
情况 A:页面是一片空白
原因:flag.php 内部的代码通常是这样写的:
PHP
<?php $flag = "flag{this_is_a_fake_flag}"; ?>
或者它只是把 Flag 赋值给了一个变量,但没有使用 echo 或 print 把它打印出来。
结果:Web 服务器确实执行了这个文件,但因为代码没有输出任何内容,所以你看到的浏览器页面是一片空白。
情况 B:权限被拒绝(403 Forbidden)或找不到(404 Not Found)
原因:出题人为了防止你"爆破文件名直接下载",通常会把 flag.php 放在 Web 根目录之外(例如放在 / 根目录下,或者 /var/ 目录下)。
结果:这时候,Web 服务器的 URL 根本无法直接映射到这个文件。你通过浏览器无论怎么输入 URL 都访问不到它。
总结:什么时候该用什么方法?
因此,在得到 Flag 的文件名或路径后,最稳妥的思路是:
先尝试直接访问:在 URL 后面直接改成 flag.php。如果出题人偷懒,Flag 直接写在 HTML 里面,或者直接 echo 出来了,你就能直接秒杀此题(右键查看网页源代码防止被浏览器隐藏)。
如果直接访问失败(空白或403):说明必须通过题目自带的漏洞去读取文件内容。这时候就需要用上一步提到的 SplFileObject 配合 session_id() 的方法,强行让后台代码把 flag.php 的内部源码读出来并打印在网页上。