PHP中弱类型的转化漏洞

官方文档中的几句话已经说的很清楚了

==是弱类型漏洞的罪恶根源
在==中,数值和字符串比较,则字符串会被转换为数值并且比较按照数值来进行。两个可以完美转化为数值型的字符串(0e123,0x123 但0e4fe,12f3不可),将转化为数值比较


当用 === 或 !== 进行比较时则不进行类型转换,因为此时类型和数值都要比对,基本不会出现弱类型比较的漏洞


对了,这些规则经过测试,在mysql的比较中是一样的


从几个例子中学习字符型是如何转换为数值的:

1
2
3
4
5
6
7
8
其中0代表转化失败,转化成功即为对应的数值
'xie'=>0
'0xff'=>0xff
'0xfz'=>0xf
'0xzf'=>0 这个比较有趣,0是转化成功的结果,而不是转化失败的意思
'x1'=>0
'1x'=>1
'0e123456'=>0 很神奇,0e123这种数值代表幂写法,已经好几次碰到了


php弱类型漏洞的应用场景

  • 对不同类型的比较,在使用==时,php会进行转化后再比较
  • 判断中即使两端都是字符型的,但一些情况下仍然做出数值型的比较,将因数值型的比较特性导致某些判断被绕过,测试如下:

    1
    2
    3
    4
    5
    6
    7
    数值型的比较特性:
    0e0 == 0 基于科学计数法的转换
    0x80 == 128 基于进制转换
    那么如下比较将成立
    '0e0' == '0'
    '0x80' == '128'
  • 一些其他的比较场景

    1
    2
    0 == NULL
    flag{xxx}=''=''
  • 类型的运算的结果都是数值型的,如果参数有字符型的话,就按照上述的转换方式来转换

    1
    2
    3
    4
    'flagpig'+1 = 1
    '11zip'+1=12
    '0'+'1'+'0'=1
    'xie'+'fei'=0


记录比赛中关于判断的一些例子

  • md5(password)==md5(username)
    基于转后后是十六进制数值,利用两个数值的幂写法进行了绕过。。。
  • 使用strcmp进行比较的判断中,文档中给出:int strcmp ( string $str1 , string $str2 ),如果一个参数是数组,将产生NULL结果,若对结果进行strcmp()==0判断,将通过
  • 使用一个很有意思的逻辑:任意字符串+0 = 任意字符串,这样就可以把字符串转化为0而通过所有与字符串比较的弱类型判断
  • 数据库的题目,可以使用where “xie”=”meng”=”fei”来实现判断或者经常使用的passwd=’’=’’
  • 两个数值的相等判断,可以使用幂的表示方法:0e123==0e456
  • 返回结果==false时,因为0==false,除0外的所有数字==true,这样可能实现绕过。但如果是使用返回结果===false时,就没法伪造返回结果为数字,因为此时要求比较的类型也是相同的,只有真正的返回结果可以做到
  • 利用’0’+’1’的结果是数值型,这种利用可以用在mysql注入中,这样可以把预定的sex=’xx’转化为sex=数值型对象,接下来就是判断中类型转化的原理了
    应用:sex=’0’+’1’+’0’ 第一个0用于闭合句式中的前引号,最后一个0用于闭合句式中的后引号,中间的将用于盲注,是0是1将影响输出结果 本题将有两个结果:sex=0 or sex=1 产生两种不同情况以作为盲注判断条件
  • 使用这样一种判断:$req['number']==strval(intval($req['number'])),之前一直担心先intval再strval会把进制与科学记数法的姿势限制住,测试后才意识到两边都是字符型的数值下,会进行转换的,因此req[‘number’]=0e00是没有问题的,可以通过比较
  • 一般弱类型语言都会有浮点数精度问题,像python,php都存在的。
    所以if(“0.999999999999999999999999” == 1)是成立的,
    同理if(“1.00000000000000000000001” == 1)也是成立的
  • 1e-324 == 0成立 (int)1e-324 > 0成立 利用的应该也是精度问题