这个打开就是一段代码:
不太会php,查了一下,知道了:
assert()是一个断言函数,如果条件判断错误会终止程序;
die() 函数输出一条消息,并退出当前脚本。
然后还有一个intval()函数,他是用来获取变量的整数值。其实可以看出来,有两个对num值的判断,且都要为真才能达到flag,那么就可以利用intval()函数的一些特点进行绕过。
这里利用的是加法绕过:intval()函数中用字符串方式表示科学计数法时,函数的返回值是科学计数法前面的一个数,而对于科学计数法加数字则会返回科学计数法的数值;也就是说如果是加法形式,它会返回加完的和的值。
我们设置payload:
?num=114514+1805296
这样,在if判断中是弱类型比较,那么比较时取的是整个num字符串中加号之前的值(数字开始,非数字结束);在intval()函数中取到的是和的值;就可以绕过两次判断。我们使用max hackbar插件吧payload写进去,然后执行请求,结果如下图:
intval()还有一些特性和可利用的绕过方式,其他的大家可以自行了解总结一下。
另外,看了一下其他的wp,还有绕过方法,比如针对assert()断言函数的绕过方法:将传入num的值设为:
num=114514);(19199810
num=114514)==1 or system('ls');#
这样就可以构造出恶意的闭合,绕过判断,让代码顺利执行。
这个相比上一个就是多了一些过滤,去掉了字母,分号,括号以及双引号。可以注意到没过滤加号,所以就还是利用intval()函数的特点进行绕过就可以了。
是个小游戏,先玩了玩,没发现什么 ,于是扫了一下,也没发现什么;最后就想着抓包看看吧,但是发现玩游戏时没有数据包,应该都是和前端交互,那就看一下前端代码吧(好多,眼花缭乱):
ctrl+F搜索了一下flag也没有;看这些代码都有注释,主要的逻辑实现应该在logic&brain下面的代码里,于是打开看一下吧。在里面发现了一段区别于正常代码,类似base64加密的字符串:
使用cyberche飞(在线加解密工具)进行base64解密后发现是:
于是访问此路径,拿到flag:
早知道多坚持玩几关了*-*,于是我又按照代码的逻辑玩到21关试了一下(这该死的胜负欲):
看代码是个反序列化:
首先序列化主要就是将对象转化为字符串的形式,使其可存储或可传输;而反序列化就是将字符串形式的对象在转换到原来的形式。( 详细了解反序列化可以看一下这篇文章https://www.freebuf.com/articles/web/241998.html)
举个例子:
得到的序列化后的结果是:
O:9:"DemoClass":2:{s:4:"name";s:5:"admin";s:3:"age";i:18;}
对象类型:长度:“类名”:变量数量:{类型:长度:“值”;类型:长度:“值”;...}
可以发现没有类,只有变量。而且其中的字符都代表着不同的意思:
反序列化漏洞就是当反序列的对象可控时,不正当的利用一些魔法函数,将自己想要的命令得到执行。
//魔法函数
__wakeup() //执行unserialize()时,先会调用这个函数
__sleep() //执行serialize()时,先会调用这个函数
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据或者不存在这个键都会调用此方法
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当尝试将对象调用为函数时触发
__construct() //对象初始化时会调用此方法
了解了这些,就可以知道主要是构造反序列化的字符串传给cmd,之后在代码进行反序列化时就会调用construct()函数,进而执行init()函数,对cmd进行过滤后在执行命令返回结果。
那么针对如何绕过flag过滤的问题,我们可以看到它过滤掉了flag且不区分大小写,那么我们在设置payload的时候可以把命令写为:cat fla*做一个模糊查询,这样就可以绕过过滤了。
执行后页面没有任何信息,但是打开代码,就可以看到flag了: