ctfshow个人解析(PHP89~94)

本文详细讲述了如何通过绕过intval()函数的漏洞和利用强弱类型比较规则,以及正则表达式的技巧,在PHPWeb安全挑战中获取flag。方法包括八进制/十六进制绕过、数组和字符串技巧,以及小数点和换行符的应用。
摘要由CSDN通过智能技术生成

目录(PS:仅个人思路,不保熟🐔🦄🐔🦄🐔🦄🐔🦄🐔🦄🐔🦄🐔🦄🐔🦄🐔🦄🐔)

web89:

intval()绕过思路汇总一下intval()函数漏洞的绕过思路:

preg-match绕过总结:

web90:

强类型比较与弱类型比较的区别:

绕过方法:

web91:

PHP正则表达式修饰符的种类及介绍:

web92:

web93:

web94:

知识点:传入的参会自动转换为字符串

strpos()函数


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;
    }
}

主要流程:大概就是你要给它个“num”参数(get请求),绕过preg——match()函数和intval()函数之后就能拿到flag了

对于intval()函数的绕过我推荐这篇:PHP intval()函数详解,intval()函数漏洞原理及绕过思路_intval函数-CSDN博客

intval()绕过思路
汇总一下intval()函数漏洞的绕过思路:

1)当某个数字被过滤时,可以使用它的 8进制/16进制来绕过;比如过滤10,就用012(八进制)或0xA(十六进制)。
2)对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
3)当某个数字被过滤时,可以给它增加小数位来绕过;比如过滤3,就用3.1。
4)当某个数字被过滤时,可以给它拼接字符串来绕过;比如过滤3,就用3ab。(GET请求的参数会自动拼接单引号)
5)当某个数字被过滤时,可以两次取反来绕过;比如过滤10,就用~~10。
6)当某个数字被过滤时,可以使用算数运算符绕过;比如过滤10,就用 5+5 或 2*5
————————————

此处只要intval返回有值即可,而此处preg-match又过滤了所有的数字,则只需要过滤preg-match就可以获得flag了(intval没有受限制)

对于preg-match这里也是摘一篇文供大家详细了解:

https://www.cnblogs.com/iwantflag/p/15262445.html

preg-match绕过总结:


1,数组绕过     a[]=(想要传的参数) 

2,利用PCRE回溯次数绕过(100万次,不推荐)   

3,换行符绕过(在web传参时传入换行符"%0a",此处不知道为啥不行🤨🤨)

我使用的是第一种,写成“/?num[]=1”即可

tips:preg_match当检测的变量是数组的时候会报错并返回0。而intval函数当传入的变量也是数组的时候,会返回1


web90:

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){  
    $num = $_GET['num'];  //接受num(git参数)
    if($num==="4476"){    //强比较类型
        die("no no no!");
    }
    if(intval($num,0)===4476){ //对于intval($var,$base)第二个参数为空时,
        echo $flag;          //默认值是 0,会根据 $var 的格式来调整转换的进制。
    }else{
        echo intval($num,0);
    }
}

这题只有一个函数需要绕过。记一个知识点,强弱类型区别及绕过:

强类型比较与弱类型比较的区别:


强类型:===,比较值也比较类型

弱类型:==只比较值

绕过方法:

Tips:这样写感觉排版好一些,放到黑框框里单纯觉得好看,并无其他含义也不是代码

1、0e绕过

弱比较会把0exxxx当做科学计数法,不管后面的值为任何东西,0的任何次幂都为0

以下是一些字符串md5值以0e开头
QNKCDZO
240610708
s878926199a
s155964671a
s21587387a
payload:?a=QNKCDZO&b=240610708 即可绕过

2、数组绕过

因为php中md5(数组)返回空值

空值=空值返回ture

3、强类型绕过

(1)、哈希碰撞

4、双md5绕过,就是md5的值和双md5还是0e开头

这个是摘的,后面有道题会用到,到时候详细说,这里只做简单了解。

回顾本题,

第一种方法:我们采用进制转换。

在线进制转换网站(网上搜一下都有):在线进制转换器

        1),将4476转换为8进制,并在开头加上0让intval()函数知道我们传入的是8进制数并于4476进行对比,拿下flag。

        2),将4476转换为16进制,以0x开头,同上不再赘述。

第二种方法:采用浮点类型。

intval() 转换小数类型时,只返回个位数,不遵循四舍五入的原则。那么我们就可以传入4476.3来实现绕过

还有其他方法大家可以自己思考下。本题过。


web91:

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';
}

此处如果我们采取数组绕过“cmd[]=php”就无法行通了,应为我们必须要有“php”才能进入第一个if条件内,而第二个if条件我们又不能有“php”。对于PRCE回溯绕过应该是可行的,但我不hui~(抱歉哈)

因此这里我们只能利用代码特性来思考了。

首先对于preg-match()函数,我们就需要有一个全面的了解,这里摘这个网址:php正则表达式中preg_match函数的详解-php教程-PHP中文网

对于正则表达式的学习还是一个很艰难的过程(不推荐小白学,容易受挫),如果你想了解推荐这篇:​​​​​​正则表达式 – 语法 | 菜鸟教程

emmmmmm再就是正则表达式休止符“/”后面加的参数(仅限PHP语言):php preg match i,PHP中preg_match正则表达式 /i, /is, /s, /isU等含义-CSDN博客

摘录出要用的知识点:

PHP正则表达式修饰符的种类及介绍:

◆i :如果在修饰符中加上"i",则正则将会取消大小写敏感性,即"a"和"A" 是一样的。

◆m:默认的正则开始"^"和结束"$"只是对于正则字符串如果在修饰符中加上"m",那么开始和结束将会指字符串的每一行:每一行的开头就是"^",结尾就是"$"。

综上,对于这题的解法也就有了。

现明确下目标:

我们要传入一个参数,需要拥有“php”关键字以便进入第一个if,在之后绕过第二个preg-match()使其识别不到php。

思路:

既然第一个preg-match()   (后面简写preg)修饰符为“im”即匹配每一行,而另一个preg修饰符为“i”即对大小写不敏感(无用,两个preg都有该修饰符),其没有“匹配每一行”的能力,那么我们就可以这样做


php

使用换行符来绕过第二个preg而又不会影响到第一个preg的判断。

Tips:url传参时,换行符的编码为“%0a”

本题过。


web92:

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);
    }
}

此处和Web90题类似。

先分析,传入参数还是$num,第一个if我们要绕过(使其无法匹配我们的4476),第二个if我们要使之成立,拿到flag。

这里直接就说方法了,详细内容前面都有的。

对于intval()它有一个特性,就是会自动进行进制转换,而且它第二个参数也是“0”,开启了这个功能 。那么方法如之前Web90一样(①转换进制,②小数点),这里放一个传送门,可以去看。

绕过方法:(传送门)


web93:

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);
    }
}

emmm再次看到相同(几乎)的代码,不知道用意何在。。。难道是防止字符串绕过吗?这里的preg_match()前面也有说过preg-match绕过总结:这里相信大家也能看懂,就是加了一个防止字符串的限制,i修饰符是不区分大小写(即“a”与“A”一样)

我想这是为了限制字符串绕过intval()函数,特此我还去web92试了一下,字符串是绕不过的

对于第一个if,它会检索到你传入的4476然后停止后续判断,这样你的intval()根本就如法解析(传不过去)你传入的参数,所以我还是不明白用意何在🤨🤨绕过同样是采用进制转换(但是这里无法使用16进制,因为你的“0x”中“x”会被检索到)和浮点型绕过。


web94:

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;
    }
}

这道题就太简单了啊,尽然使用了强类型转换。那么只要类型不一致就ok了(对于第一个if),第二个if还是限制了字母的出现;至于第三个if,等会介绍strpos()函数时说;接下来看第四个if,首先要知道intval函数输出的类型就是整型(int)那么这个强类型比较在类型比较方面就无用了,它只能判断数值是否相同。目前算是简单的分析完了,之后我们再来细看一下,在第一个if中($num==="4476")是将我们传入的参与字符串类型的“4476”做强类型比较。

知识点:传入的参会自动转换为字符串

这里我们需要知道一个东西啊,在我们传参时,emmm专业术语不太会,反正就是在服务器接受该参数时会自动带上双引号,帮助我们转换成字符串格式,所以传参一般不加双引号,如果加了呢也是把双引号传过去,而不是转换字符串。

而对于前面几道题,我们可以发现它的写法是这样的($num==4476

为什么这里不是与("4476")这种形式做比较呢?是因为对于弱类型比较,不会去比较类型,只比较数值,所以没有这样写。

strpos()函数

前两个if说完了我们来了解下strpos()函数(摘一篇其他人的)了解函数的话我这里只帮你们找,就不做重复叙述,看就行了。

    if(!strpos($num, "0")){
        die("no no no!");

对于这里为了方便理解,我们先处理“!”,这个符号的意思是取反,如果你是Ture那么就会当作Flase看待,如果是Flase就被当作Ture看待。这里我们是为了跳过if的,也就是说if判断的条件应是Flase,那么经过“!”,我们就得让后面的函数输出Ture或者说是有值输出

但这里就会有一个陷阱。我们知道,这题同以前一样还是呢两种方法绕过,而对于进制转换,由于prag-match()我们失去了转16进制的方法,而剩下的转8进制,需要最前面是0。陷阱就在这里!可以设想下当我们传入010574时,strpos()函数会检测到“0”并输出第一次“0”所出现的位置,这就相当于strpos()函数输出值为0,而在布尔类型中(Ture和Flase)0代表Flase,1代表Ture。这就相当于我们输出了Flase一样,经过“!”绕过就失败了!所以,这里把8进制绕过法也限制了!

Tips:在字符串中,字符的序号是从0开始排起的,eg:"abcd"中a的序号就是0,c的序号就是2。

因此,我们就只剩下了小数点绕过,但注意我们要保证传入的参数中有0但0又不能在第一个位置上。你可以是4476.0或4476.12312412301231241。只要保证上述条件即可。

本篇就写到这了,也有小5000字了😛😛😛纯纯个人码出来的,其中可能会有错误,毕竟我也是小白🤣,后续还会有。

感谢参考

🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲🐲

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值