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.