前置
遍历文件类
filesystemiterator
遍历目录类
directoryItrerator
reg_match函数介绍
-
preg_match()
是 PHP 中的一个强大的正则表达式匹配函数。它用于在一个字符串中搜索匹配给定正则表达式模式的内容。如果找到匹配项,它可以返回匹配的次数(通常为 1,因为preg_match()
在第一次匹配成功后就会停止),并可以通过可选的参数获取匹配的内容。 -
preg_match当检测的变量是数组的时候会报错并返回0。
intval函数介绍
-
intval()
函数是 PHP 中的一个内置函数。它的主要作用是获取变量的整数值。例如,如果有一个包含数字的字符串或者一个浮点数,intval()
函数可以将其转换为整数。 -
基本语法是
intval ( mixed $var, int $base = 10 )
,其中$var
是要转换的变量,$base
是可选参数,用于指定转换的进制,默认是十进制。
-
参数解释
-
$var 参数
-
这个参数可以是多种数据类型。如果是字符串,函数会从字符串的开头提取整数部分。例如,
intval("123abc")
会返回123
。如果字符串是以非数字字符开头的,如intval("abc123")
,则会返回0
。 -
当
$var
是浮点数时,intval()
函数会将小数部分截断,只保留整数部分。比如intval(3.14)
会返回3
。 -
如果
$var
是布尔值,true
会被转换为1
,false
会被转换为0
。 -
对于数组或对象,
intval()
函数会先尝试将其转换为字符串,再按照字符串的规则进行转换。通常会返回0
,除非数组或对象在转换为字符串时有特殊的规则可以生成以数字开头的字符串。
-
-
$base 参数
-
当
$var
是一个字符串,并且这个字符串表示一个数字的时候,可以指定$base
来转换进制。例如,intval("10", 2)
会将二进制的10
转换为十进制,结果是2
。$base
参数的取值范围是从2
到36
,其中2
表示二进制,10
表示十进制,36
表示三十六进制。
-
-
Web89
preg_match 正则匹配函数
preg_match当检测的变量是数组的时候会报错并返回0。
intval 获取变量整数值
而intval函数当传入的变量也是数组的时候,会返回1
参数1 获取的值
参数2 获取整数的进制类型 2 8 10 16
Payload
?num[]=a
Web90
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:06:11 # @email: h1xa@ctfer.com # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==="4476"){ die("no no no!"); } if(intval($num,0)===4476){ echo $flag; }else{ echo intval($num,0); } }
intval($num,0)
-
当第二个参数(进制基数)为
0
时,intval()
函数会根据$num
的前缀自动判断进制。如果$num
以0x
或0X
开头,那么它会被当作十六进制数进行转换;如果以0
开头(但不是0x
或0X
),则会被当作八进制数进行转换;如果没有这些前缀,就会被当作十进制数进行转换。
绕过方法有多种:
-
字符串:4476 后面接入任意字符串 因为该函数只会截取字符串中数字。
-
其他进制:可以使用8进制 010574,16进制 0x117C
-
科学计数法:4476.0
Web91
<?php /* # -*- coding: utf-8 -*- # @Author: Firebasky # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:16:09 # @link: https://ctfer.com */ show_source(__FILE__); include('flag.php'); $a=$_GET['cmd']; if(preg_match('/^php$/im', $a)){ if(preg_match('/^php$/i', $a)){ echo 'hacker'; } else{ echo $flag; } } else{ echo 'nonononono'; }
第一个判断:if(preg_match('/^php$/im', $a))
-
正则表达式模式:
'/^php$/im'
-
^
:表示匹配字符串的开头。这意味着要匹配的内容必须从字符串的起始位置开始符合后续的模式要求。 -
php
:就是要精确匹配的文本内容,这里希望在字符串中找到的就是 “php” 这三个字符。 -
$
:表示匹配字符串的结尾。即匹配的内容必须到字符串的末尾位置都是符合前面模式要求的,也就是说整个字符串只能是 “php” 这三个字。 -
i
:是一个正则表达式的修饰符(flag),它使得匹配过程忽略大小写。所以无论是 “php”、“PHp”、“PhP” 等各种大小写组合形式,只要是这三个字符组成的字符串,都能满足该模式在大小写方面的要求。 -
m
:也是一个正则表达式的修饰符,它用于多行模式匹配。不过在这个具体的正则表达式中,由于我们只是要匹配整个字符串是否为 “php”,多行模式在这里实际上并没有起到特别的作用(如果是在匹配跨多行的文本内容且有相关匹配需求时,m
修饰符会更有用)。
-
而第二个判断却少了m参数,所以推测可能是换行绕过
整体逻辑如下:
-
第一个if判断字符串中有没有php字符,正则匹配的模式是 “从头到结尾不区分大小写同时匹配多行”
-
第二个if也是如上,但是没有参数m(匹配多行)
-
所以先输入随机字符串 xxxx然后输入换行符%0A最后输入PHP
-
这样第一个if会匹配到换行后的php,而第二个if却无法匹配到 导致绕过
URL换行符%0A
Payload
?cmd=xiao%0Aphp
Web92
<?php /* # -*- coding: utf-8 -*- # @Author: Firebasky # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:29:30 # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(intval($num,0)==4476){ echo $flag; }else{ echo intval($num,0); } }
这一关与90关的唯一不同就是在等于号上!
90关的等于号是=== 代表必须一模一样(包括类型,内容)
而本关的等于号是== 代表不用必须一模一样(包括类型,内容)只要有就行
绕过方法:
-
八进制、十六进制绕过
-
payload:?num=0x117C
Web93
<?php /* # -*- coding: utf-8 -*- # @Author: Firebasky # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:32:58 # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(preg_match("/[a-z]/i", $num)){ die("no no no!"); } if(intval($num,0)==4476){ echo $flag; }else{ echo intval($num,0); } }
照比上一关多了一个,不能使用字母
不用就不用!(¬︿̫̿¬☆)
我用8进制绕过
payload:?num=010574
Web94
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:46:19 # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==="4476"){ die("no no no!"); } if(preg_match("/[a-z]/i", $num)){ die("no no no!"); } if(!strpos($num, "0")){ die("no no no!"); } if(intval($num,0)===4476){ echo $flag; } }
呦呵!8进制和16进制都不能用了?
注意细节骚年:他这里等于号变成===全等于了,直接科学计数法绕过
payload:num=4476.0
Web95
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 16:53:59 # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if(isset($_GET['num'])){ $num = $_GET['num']; if($num==4476){ die("no no no!"); } if(preg_match("/[a-z]|\./i", $num)){ die("no no no!!"); } if(!strpos($num, "0")){ die("no no no!!!"); } if(intval($num,0)===4476){ echo $flag; } }
在8进制前面加个+
Web96
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 19:21:24 # @link: https://ctfer.com */ highlight_file(__FILE__); if(isset($_GET['u'])){ if($_GET['u']=='flag.php'){ die("no no no"); }else{ highlight_file($_GET['u']); } }
路径绕过比较
./flag.php
以下是来自AI的解答:
-
绕过原理
-
松散比较机制: 在 PHP 中,当使用
==
进行比较时,会进行自动的类型转换以尝试使比较能够成功。对于字符串的比较,它不仅仅看字符串的字面内容,还会在一定程度上对字符串进行 “规范化” 处理后再比较。 -
文件路径处理与比较: 当比较
$_GET['u']
(假设其值为./flag.php
)和flag.php
时,在松散比较的规则下,PHP 会忽略掉./
这样的相对路径表示部分。因为它主要关注的是文件名部分(这里都是flag.php
),经过这种自动的处理和比较逻辑,就会认为./flag.php
和flag.php
是 “相等” 的,从而绕过了原本预期的判断,使得后续的highlight_file($_GET['u']);
被执行,而不是输出"no no no"
并终止脚本执行
-
Web97
<?php /* # -*- coding: utf-8 -*- # @Author: h1xa # @Date: 2020-09-16 11:25:09 # @Last Modified by: h1xa # @Last Modified time: 2020-09-18 19:36:32 # @link: https://ctfer.com */ include("flag.php"); highlight_file(__FILE__); if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) if (md5($_POST['a']) === md5($_POST['b'])) echo $flag; else print 'Wrong.'; } ?>
md5函数是无法处理数组的,如果传入了两个数组就会变成null,而null=null
a[]=1&b[]=2