strcmp(a1,a2)函数用来比较两个字符串是否相等的,
比较的是对应字符的ascii码,如果相等返回0,
当a1的ascii大于a2的返回小于0,a1的ascii码小于a2的,返回大于0.
但是这个函数是存在漏洞的,我们知道这个函数是用来比较字符串的,
但是当我们传入为数组是,那变成字符串和数组进行比较了,
因此php在5.2之前,默认返回的-1,5.2版本之后返回0.
因此有时我们便可以利用这个漏洞。
函数期望传入的类型是字符串类型的数据,要是我们传入非字符串类型的数据的话,这个函数将发生错误
传入一个 ?a[],就得到了flag
题目
由题目容易知道该代码是对GET的id值二次编码,第一次是浏览器默认对传入参数进行一次解密,
由代码
$_GET[id] = urldecode($_GET[id]);
可知,又进行了一次解码
所以我们必须将id值进行二次编码后,才能符合最后的if条件
我利用了里面的其中一个字母J编码第一次编码是%4A,第二次编码是%254A,对其绕过:
分析:
构造?id=hackerD%254A
第一次浏览器先解码,将%25解码为%,变为id=%68ackerDJ;
第二次urldecode()函数解码,将%68解码为h,最后变为id=hackerDJ;
从而最后满足if条件,输出flag。
函数 eregi()
eregi()函数在一个字符串搜索指定的模式的字符串。搜索不区分大小写。Eregi()可以特别有用的检查有效性字符串,如密码。
可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组,如果匹配成功返回true,否则,则返回false。
根据题目提示,我去查了一下md5函数,发现它的php特性漏洞——不能处理数组
于是利用MD5函数不能处理数组进行构造payload
满足两个条件:
根据题目提示,尝试一下数组绕过,成功了
“[A-Za-z0-9]"
方括号表示字符集,[A-Za-z0-9]匹配大小写字母和数字其中一个字符
"^[A-Za-z0-9]$"
^表示字符串开始,$表示字符串结束 ,这个匹配只有一个大小写字母和数字字符的字符串
`“^[A-Za-z0-9]+$"`
+号表示重复1到多次,匹配由多个数字大小字母组成的字符串
阅读代码,本题需要满足的条件:
必须以数字或者字母开头(其实看到ereg就可以想到%00截断);
必须在password参数中找到–。
所以得到
index.php?password=a%00--
但是:
ereg只能处理字符,而你是数组,所以返回的是null,三个等号的时候不会进行类型转换。所以null不等于false。
strpos的参数同样不能够是数组,所以返回的依旧是null,null不等于false也是正确。
即:倘若函数的参数不符合其函数要求的时候返回的是null值
因此得到playload:
?password[]=0
strpos()函数语法:
strpos — 查找字符串首次出现的位置
int strpos( string $haystack, mixed $needle[, int $offset = 0] )
返回 needle 在 haystack 中首次出现的数字位置。
参数
haystack 在该字符串中进行查找。
needle 如果 needle 不是一个字符串,那么它将被转换为整型并被视为字符的顺序值。
offset 如果提供了此参数,搜索会从字符串该字符数的起始位置开始统计。如果是负数,搜索会从字符串结尾指定字符数开始。
返回值
返回 needle 存在于 haystack 字符串起始的位置(独立于 offset)。同时注意字符串位置是从0开始,而不是从1开始的。
如果没找到 needle,将返回 FALSE。
这里就是先判断是不是数字。
然后再判断这个数字是不是大于1336。
但是两者相矛盾,需要传入一个 password 的值 不是数字 又得大于 1336
在后面随便加个符号让他构不成数字
?password=1337*
即可得到flag
又尝试一下数组绕过,也成功了
is_numeric()函数
语法:
is_numeric — 检测变量是否为数字或数字字符串
bool is_numeric( mixed $var)
如果 var 是数字和数字字符串则返回 TRUE,否则返回 FALSE。
如果知道MD5碰撞的概念,同时知道了在PHP中的MD5中的0e的比较,这道题目就十分的简单。
如果md5的值是以0e开头的,那么就与其他的0e开头的Md5值是相等的。
例子如下:
md5(‘s878926199a’)=0e545993274517709034328855841020
md5(‘s155964671a’)=0e342768416822451524974117254469 //可以看到两者的md5值都是以0e开头的,则 md5(‘s878926199a’)==md5(‘s155964671a’) //就是True
php关于==号是这样处理的,如果一边是整型,另一边也需要是整型。
($a != ‘QNKCDZO’ && $md51 == $md52)
发现 $a != ‘QNKCDZO’ 并且 $md51 == m d 52 因 为 md52 因为 md52因为md51 = md5(‘QNKCDZO’)=0e830400451993494058024219903391
根据上文介绍,我们发现只要满足md5加密后为 "0e***************"就可以
所以随便挑一个0e开头的md5对应的原码 构造 playload即可
比如 ?a=s878926199a
首先分析代码,变量temp不能存在1~9之间的数字,
又要求temp=3735929054
这本来是自相矛盾的,但php在转码时会把16进制转化为十进制.
于是把3735929054转换成16进制为0xdeadc0de
最后需要number==temp是才可以输出flag
然后对password赋值,根据题目提示,直接将password赋值为number的十六进制
代码里有两个函数需要注意ereg() 和strpos()
先去查了一下PHP里的strpos() 函数用法:
strpos() 函数查找字符串在另一字符串中第一次出现的位置(区分大小写)
可以先尝试利用数组绕过这两个函数
ereg() 和strpos() 的参数不能够是数组,返回的是null,null!==false。
根据题目提示,可以用另一个方法——%00截断绕过正则匹配
ereg() 正则限制了password格式,只能是一个或者多个数字、大小写字母,strpos() 查找某字符串需要出现*-*
两者矛盾,所以要%00截断绕过
并且长度得是长度<8且大小要>9999999,所以用科学记数法1e9即1*10^9
大致看了一下代码,依旧先尝试了一下数组,成功得到flag
http://123.206.87.240:9009/15.php?ctf[]=1
再细看代码要求,和上一题有点相似
要求get传参ctf,只能是1~9,strpos() 查找某字符串需要出现#biubiubiu
两者矛盾,所以要%00截断绕过
尝试payload,一直不对,发现#并没被自动转码为%23
http://123.206.87.240:9009/15.php?ctf=3%00#biubiubiu
于是我手动更改了一下,成功得到flag
http://123.206.87.240:9009/15.php?ctf=3%00%23biubiubiu
搜了一下write up
直接post一下flag就可以,不明白为什么,,,
看了一下另一个人的:
题目的代码倒是挺长,但是while (TRUE) 后面貌似没有用到
满足:
if (0 >= preg_match('/^[[:graph:]]{12,}/',password)) //preg_match — 执行一个正则表达式匹配
{
echo 'flag';
exit;
}
即可得到flag
preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE
也就是随便构造不匹配就行了吧