PHP特性利用 | ISCTF2024 | Web 小蓝鲨的冒险
2024年12月10日约 688 字大约 2 分钟
原题
<?php
error_reporting(0);
highlight_file(__FILE__);
$a = "isctf2024";
$b = $_GET["b"];
@parse_str($b);
echo "小蓝鲨开始闯关,你能帮助他拿到flag吗?<br>";
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
$num = $_POST["num"];
echo "第一关有惊无险!小蓝鲨壮着胆子接着继续往下走!<br>";
if($num == 2024){
die("QAQ小蓝鲨误入陷阱,不怕,再接再厉!");
}
if(preg_match("/[a-z]/i", $num)){
die("陷阱太多QAQ");
}
if(intval($num,0) == 2024){
echo "到这了难道还要放弃吗?<br>";
if (isset($_GET['which'])){
$which = $_GET['which'];
echo "小蓝鲨貌似在哪里见过这个陷阱O.o?继续加油,还差最后一步了!";
switch ($which){
case 0:
print('QAQ');
case 1:
case 2:
require_once $which.'.php';
echo $flag;
break;
default:
echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
break;
}
}
}
}
第一关
如果$a[0] != 'QNKCDZO'
而且md5($a[0]) == md5('QNKCDZO')
则成立。该部分运用到 PHP 的特性。
md5 的碰撞,在 PHP 的数的处理中,0 开头的字符串会被转换成 0,所以才会有 md5 碰撞。
[[MD5-collision]]
所以只要传入 MD5 值为0e
开头的字符串,且不等于题目中的字符串,则条件成立。
$a[0]
取$a
的第一个元素,如果传入字符串,则将会取第一个字母。所以我们需要传入一个数组。parse_str
用于解析$b
并将里面的东西转为变量,而@
将会忽略转换的错误。如果 $b
的值是 "foo=bar&baz=qux"
,那么执行 parse_str($b);
后,PHP 将创建两个新的变量 $foo
和 $baz
,它们的值分别是 "bar"
和 "qux"
。
示例:
?b=a[0]=s878926199a
第二关
PHP 中post
请求参数num
, 有以下要求:
$num
不能等于数字 2024。$num
不能包含任何字母(无论是小写还是大写。- 当使用
intval($num, 0)
转换$num
为整数时,结果等于 2024。
尝试传入八进制数字03750
,可以通过校验。
要使用八进制表达,数字前必须加上
0
(零)。 PHP 8.1.0 起,八进制表达也可以在前面加上0o
或者0O
。 要使用十六进制表达,数字前必须加上0x
。要使用二进制表达,数字前必须加上0b
。
[[PHP Hypertext Preprocessor]]
第三关
if (isset($_GET['which'])) {
$which = $_GET['which'];
echo "小蓝鲨貌似在哪里见过这个陷阱O.o?继续加油,还差最后一步了!";
switch ($which) {
case 0:
print('QAQ');
case 1:
case 2:
require_once $which . '.php';
echo $flag;
break;
default:
echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
break;
}
}
PHP 转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,若无则输出 0。
具体请查阅: php 里,为什么 0 == 'abc'是成立的? - SegmentFault 思否
尝试传入flag
字符串返回了 flag.