php 在 ctf 中常见的特性

php的一些特性

谈谈一些在ctf中遇到的php的特性

php的弱比较

在php中有两个比较表达式

  1. ==
  2. ===

两个等号==是弱比较,使用==进行对比的时候,php解析器就会做隐式类型转换,如果两个值的类型不相等就会把两个值的类型转为同一类型进行对比

使用字符串与整型对比

"a"==0

image.png

原理是,当字符串开头是非数字的字符与数字时进行弱比较,php的解析器做隐式类型转换就会把非数字的字符转为int类型的0,再进行比较

image.png

image.png

这样就会相等

如果是数字开头的就不一样了

image.png

因为php的解析器会获取开头的字符来进行校验,如果开头的字符是非数字的就整个值转成int类型的值为0,数字开头的则以数字为准

image.png

image.png

三个等号===是强对比,使用===进行对比的时候,php解析器会校验两个值的类型是否相等,相等的时候再进行对比

再三个等号===这里就和==不相同,因为会先做类型校验

image.png

例题:

192.168.4.13/php_weak.php

image.png

代审:

接收一个GET参数,判断是否长度为5,然后使用switch函数对比,对比为4就打印flag

根据官方文档所说的switch表达式对比是松散的对比

image.png

所以根据上面的所说的特性php的解析器会获取开头的字符来进行校验,如果开头的字符是非数字的就整个值转成int类型的值为0,数字开头的则以数字为准, 传入一个4开头长度为5的字符串即可

image.png

php的hash弱比较

进行hash加密出来的字符串如果存在0e开头进行弱比较的话会直接判定为true

例题:

192.168.4.13/php_hash.php

image.png

代审:

接受两个GET参数,使用ctype_alpha判断参数a是否为纯字符串,不是就logined为false

使用is_numeric判断参数b是否为纯数字或者纯数字的字符串,不是就logined为false

然后判断参数a和参数b经过md5加密是否相等,不相等logined为false

logined为true则打印flag

因为使用的是弱比较,所以只要是md5加密后的字符串是0e开头的进行对比就会变成0==0然后对比成立就返回true从而绕过

image.png

以下是md5加密后为0e开头的字符串

QNKCDZO
0e830400451993494058024219903391

240610708
0e462097431906509019562988736854

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904 

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

根据代审参数a传入GNKCDZO参数b传入240610708

image.png

php的json弱比较

例题:

192.168.4.13/php_json.php

image.png

代审:

接受GET参数,判断参数是否为空,然后json_decode转码为json数据,然后判断json的键key映射的值是否为flag

这里比较使用的是弱比较,所以可以使用特性0于任意开头非数字的字符串对比为true的特性进行绕过

image.png

php的编码比较绕过

例题:

192.168.4.13/php_encode.php

image.png

代审:

接收两个GET参数,判断两个参数是否为空,然后依次对两个参数进行md5加密,sha1加密,base64编码然后再进行强对比,如果不相同chake变量就变为false

但是这些加密编码函数无法对数组进行加密或编码,返回值就会变成NULL,如果传入两个参数都是数组的话就就是两个NULL进行强对比,所以表达式成立,结果为true即可得到flag

image.png

所以参数传入数组即可绕过

image.png


php函数in_array弱比较

PHP: in_array - Manual

例题:

192.168.4.13/php_array.php

php的函数in_array,在第三个参数没有选择的时候,进行检索使用的是弱比较

image.png

image.png

代审:

接受GET参数,判断参数是否是数组,是则继续程序,循环遍历数组里的值,如果数组里的值是字符串则结束程序,如果数组里的值是flag则结束程序,然后转换数组里的值为数字,再判断数组里的值是否有存在flag,存在就打印flag

这道题很简单,根据上面所说的php弱比较的特性当字符串开头是非数字的字符与数字时进行弱比较,php的解析器做隐式类型转换就会把非数字的字符转为int类型的0,传入一个数组,里面的值为0即可

image.png

php函数strcmp

PHP: strcmp - Manual

例题:

192.168.4.13/php_strcmp.php

php的函数strcmp是用来做字符串比较的,如果两者相等返回0

image.png

image.png

代审:

接受一个GET参数与flag进行比较,结果为0就打印flag

这里使用的是弱比较,函数strcmp和md5这些函数一样无法对数组进行有效的处理,如果函数传入的参数为数组,结果返回会是NULL,NULL类型与0进行弱比较的话表达式会成立,结果为true

image.png

所以这一题也是传入一个数组即可

image.png

php可变变量

PHP: 可变变量 - Manual

image.png

image.png

这里的$$a等同于$hello,因为php是使用$来表明变量的,如果再$前再添加一个$就变为了可变变量,即$$a这个$a的值是hello$a解析后就是hello,这个hello再添加前面的$符就变成了$hello$$a 同等于$hello

image.png

例题:

192.168.4.13/php_web10.php

image.png

代审:

判断GET参数,是否为空,然后再正则匹配参数,如果是纯数字就退出程序,否则就打印可变变量

传入flag的字符串即可

image.png

192.168.4.13/php_web11.php

image.png

代审:

foreach函数遍历GET参数的的键值,强判断键为error退出程序,然后给值的参数命名的可变变量赋值给键的参数命名的可变变量,然后再使用相同的函数遍历POST参数的键值,如果参数的值为flag,则退出,然后给值的参数命名的可变变量赋值给键的参数命名的可变变量

因为这一题没有指定传参名,所以可以指定任意的参数名,这样可以利用它已经存在的变量名来进行绕过

image.png

指定传入的参数名为suces然后值为flag,再根据$$key=$$value1这样就变量$suces经过可变变量的改变变成了变量$flag,然后再传入POST参数键为error值为suces因为$$key=$$value2的原因变成了变量$suces但是经过了第一个$$key=$$value1的关系$suces已经变成了$flag所以最后的die($flag)打印了flag