EZPHP
php
<?php
show_source(__FILE__);
include("flag.php");
$a=@$_GET['a'];
$b=@$_GET['b'];
if($a and $a==0){
if(is_numeric($b)){
exit("nono");
}else{
if($b>2026){
echo $flag;
}
}
}else{
exit("no");
}
?>
在 PHP 8.0 之前的版本中,当一个不以数字开头的字符串 与整数进行 == 比较时,PHP 会尝试将字符串转换为数字。因为字符串无法转换,就会被当成 0 处理。
- 如果传入
a=abc:if("abc")成立(非空字符串为真)。"abc" == 0成立("abc" 转换成数字是 0,0 == 0为真)。
参数b同样利用 PHP 的弱类型特性。当一个以数字开头但包含字母的字符串与数字进行比较时,PHP 会截取前面部分作为数字来计算。
- 如果传入
b=2027a:is_numeric("2027a")为false(因为包含字母 'a',不是纯数字)。"2027a" > 2026时,PHP 会将"2027a"隐式转换为2027,此时2027 > 2026成立。
Payload 建议: &b=2027a (数字部分大于2026,后面随便跟一个字母即可)。

EZPHP_1
php
<?php
show_source(__FILE__);
include("flag.php");
if (!isset($_GET['qc']) || $_GET['qc'] === '') exit("no");
$qc = (array)json_decode($_GET['qc'], true);
$key = array_search("QCCTF", $qc);
if($key === 1){
echo $flag;
}else{
exit("no");
}
?>
这里调用 array_search() 时没有传入第三个参数 true。这意味着它使用的是松散比较 ( ==) 。 它会遍历 $qc 数组,拿每一个"值"去和字符串 "QCCTF" 做 == 比较,一旦匹配成功,就返回对应的"键(Key)"。 我们需要让 array_search() 返回的键名严格等于整数 1。
在 PHP 中(无论 PHP 7 还是 PHP 8),布尔值 true 与任何非空字符串做 == 比较,结果都是 true 。因为这里用了json_decode()函数,json_decode() 是一个极其严格的"翻译官"。如果传入的字符串不符合 JSON 的语法规范,它就会直接罢工,返回 null。因此构造payload:
plain
?qc={"1":true}
//or
?qc={"1":"QCCTF"}

EZPHP_2
php
<?php
show_source(__FILE__);
include("flag.php");
if (!isset($_GET['qc']) || $_GET['qc'] === '') exit("no");
$qc = (array)json_decode($_GET['qc'], true);
if (!isset($qc["n"]) || !is_array($qc["n"]) || empty($qc["n"])) die("no");
if (array_search("QCCTF", $qc) === false) die("no...");
if (array_search("QCyyds", $qc["n"]) === false) die("no...");
foreach ($qc["n"] as $val) {
if ($val === "QCyyds") die("no......");
}
echo $flag;
这题可以说是上一道的升级版了
php
if (!isset($qc["n"]) || !is_array($qc["n"]) || empty($qc["n"])) die("no");
要求: 传入的 JSON 必须包含一个名为 "n" 的键,且这个键的值必须是一个非空的数组。
php
if (array_search("QCCTF", $qc) === false) die("no...");
要求: $qc 的第一层级(Top-level)的值里面,必须有一个能和 "QCCTF" 产生松散匹配(==)。
php
if (array_search("QCyyds", $qc["n"]) === false) die("no..."); // 第三关
foreach ($qc["n"] as $val) { // 第四关
if ($val === "QCyyds") die("no......");
}
- 要求: 在
$qc["n"]这个子数组里,必须通过array_search找到"QCyyds"(使用==松散比较)。 - 要求: 紧接着遍历这个子数组,里面绝对不能 出现严格等于
"QCyyds"的值(使用===严格比较)。
这就形成了一个经典的 CTF 悖论: > 既要在数组里"找到"这个字符串,又"不能真的把这个字符串放进去"。 依旧用布尔值true构造payload:
plain
?qc={"n":[true],"1":"QCCTF"}

EZPHP_3
php
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_GET['qc'])&&preg_match('/^Welcome to QingCen 2026!$/i', $_GET['qc']) && $_GET['qc'] !== 'Welcome to QingCen 2026!') {
if (intval($_GET['lover']) < 2025 && intval($_GET['lover'] + 3) > 2026) {
if (isset($_POST['Q']) && $_POST['C']) {
$array1 = (string)$_POST['Q'];
$array2 = (string)$_POST['C'];
if (sha1($array1) === sha1($array2)) {
if (isset($_POST['ZJZ_QingCen.2026']) && $_POST['ZJZ_QingCen.2026'] === "Happy to see you!") {
echo $flag;
} else {
echo "再绕最后一步吧";
}
} else {
echo "好哩,快拿到flag啦";
}
} else {
echo "这里绕不过去,QingCen可不答应了哈";
}
} else {
echo "嘿嘿嘿,你别急啊";
}
}else {
echo "不会吧不会吧,不会第一步就卡住了吧,ZJZ会瞧不起你的!";
这道题和我之前做的一道题很像:极客大挑战2023-web-easy_php-CSDN博客,只是在intval函数的处理上有所不同:
虽然在旧版 PHP 中,科学计数法结合 intval 和加法会发生奇妙的类型转换(intval('1e8')=1,'1e8'+3=100000003),但在 PHP 8.0 及以上版本 中,PHP 增强了类型的严格性。将包含字母的字符串(即使是科学计数法格式)直接进行数学加法运算(+ 3),可能会导致异常或被严格判定从而返回 False。
这道题不需要用科学计数法去绕,直接传一个最普通的数字就可以完美满足条件,比如传 2024 甚至是 2024.5
