虽然PHP是世界上最好的语言,但是也有一些因为弱类型语言的安全性问题出现。WordPress历史上就出现过由于PHP本身的缺陷而造成的一些安全性问题,如CVE-2014-0166 中的cookie伪造就是利用了PHP Hash比较的缺陷。 当然一般这种情况实战中用到的不是很多,但是在CTF竞赛中却是一个值得去考察的一个知识点,特此记录总结之。
在用PHP进行浮点数的运算中,经常会出现一些和预期结果不一样的值,这是由于浮点数的精度有限。尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由于取整而导致的最大相对误差为 1.11e-16。非基本数算可能会给出更大误差,并且要考虑到进行复合运算时的误差传递。下面看一个有趣的例子:
以十进制能够精确表示的有理数如 0.1 或 0.7,无论有多少尾数都不能被内部所使用的二进制精确表示,因此不能在不丢失一点点精度的情况下转换为二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.1118…。
问鼎杯2017 老眼昏花网上很多write-up感觉就像是看着答案写write-up,个人感觉真正的write-up中应该体现自己的思考在里面。
有提示了,说明year这个参数是对的,但是2017中不可以出现7,这里如果不了解php精度的线进行各种编码绕过,但是这里对编码也进行过滤了:
PHP提供了is_numeric函数,用来变量判断是否为数字。PHP弱类型语言的一个特性,当一个整形和一个其他类型行比较的时候,会先把其他类型intval数字化再比。
分析下代码:首先对GET方式提交的参数id的值进行检验。id通过is_numeric函数来判断是否为数字,如果为数字的话,GG。如果不是数字的线进行比较,id的值大于665的时候输出flag。
乍看上去又好像不可能这里,但是如果知道PHP弱类型语言的一个特性,当一个整形和一个其他类型行比较的时候,会先把其他类型intval数字化再比。这个特性的话就可以很好的绕过。
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行
PHP 会根据变量的值,自动把变量转换为正确的数据类型。这一点和C 和 C++ 以及 Java 之类的语言明显不同。虽然这样PHP方便了程序员,但是随之而来却会带来一些安全性的问题。
0与gg进行松散性质的不严格比较,会将gg转换为数值,强制转换,由于gg是字符串,的结果是0,所以 输出 true
0与gg进行严格 性质的严格比较,这里的gg是字符串类型,和int类型的0不相等,所以输出 lse
0与gg进行松散性质的不严格比较,会将gg转换为数值,强制转换,由于gg是字符串,的结果是0,不等于1,所以输出 lse
1与1gg进行松散性质的不严格比较,这里1gg被强制转换为int类型的时候会从字符串的第一位开始做判断进行转换,这里的1gg第一位是1,所以这里1gg被转换为1,所以输出 true
1与gg1进行严格 性质的严格比较,字符串gg1的第一位不是数字,所以它被强制转换为0,所以输出 lse
当一个字符串欸当作一个数值来取值,其结果和类型如下:如果该字符串没有包含.,e,E并且其数值值在整形的范围之内 该字符串被当作int来取值,其他所有情况下都被作为float来取值, 该字符串的开始部分决定了它的值,如果该字符串以的数值开始,则使用该数值,否则其值为0。
0e123与0e456相互不严格性质比较的时候,会将0e这类字符串识为科学技术法的数字,0的无论多少次方都是零,所以相等,输出 true
0e123与0eabc相互进行不严格性质比较的时候,本应该将0e这类字符串识为科学技术法的数字,但是这里的0e后面跟着的是abc,数学中科学计数的指数不可以包含字母。所以这里字符串中虽然是0e开头,但是后面的abc却不符合科学技法的规范,所以输出是 lse
md5绕过(Hash比较缺陷)南京邮电大学网络攻防训练平台中一道比较经典的md5 collision题,关于这道题目的WriteUp网上很多,但是真正深入分析的少之又少~~
从源码中可以得输入一个a的参数的变量,a首先不等于QNKCDZO并且a得md5值必须等于QNKCDZO加密后的md5值。 乍一看好像不可能存在这样的值,但是这里QNKCDZO加密后的md5值为0e 这里是0e开头的,在进行等于比较的时候,PHP把它当作科学计数法,0的无论多少次方都是零。 所以这里利用的弱类型的比较的缺陷来进行解题:?a=s155964671a
这个乍看起来这是不可能的,但是这里利用sha1()函数在处理数组的时候由于无法处理将返回NULL可以绕过if语句的验证,if条件成立将获得flag。 构造语句如下:
经过验证,不仅sha1()函数无法处理数组,这里md5()函数也有同样的问题,在处理数组的时候,都将返回NULL
这个函数接受到了不符合的类型,例如数组类型,函数将发生错误。但是在5.3之前的php中,显示了报错的信息后,将return 0 !!!! 也就是虽然报了错,但却判定其相等了。
这里使用了==松散比较了$flag和通过GET方式提交的password的值,如果想等的话,拿到flag。这里用的是==松散性质的比较,再利用字符串处理数组时将会报错,在5.3之前的php中,显示了报错的信息后,将return 0。所有这里将password参数指定为数组,利用函数漏洞拿到flag:
除了strcmp()函数外,ereg()和strpos()函数在处理数组的时候也会异常,返回NULL。测试代码如下:
ereg()函数是处理字符串的,传入数组后返回NULL,NULL和 FALSE,是不恒等(===)的,满足第一个if条件;而strpos()函数也是处理字符串的,传入数组后返回NULL,NULL!==FALSE,满足条件,拿到flag:
parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量。
因为这里用到了parse_str函数来传递b,if的语句的条件是拿$a[0]来比较的,有因为这里的变量a的值已经三是固定的了:
这里其实是我博客的地址~~ 不过不重要。 整体代码乍看起来又不可能,但是利用变量覆盖函数的缺陷这里可以对a的变量进行重新赋值,后面的的if语句再利用本文前面提到的md5()比较缺陷进行绕过:
网友评论 ()条 查看