Bugku CTF 代码审计 writeup(未完待续)
Bugku CTF 代码审计 writeup
0x01extract变量覆盖
extract()函数功能:从数组中将变量导入到当前的符号表。使用数组键名作为变量名,使用数组键值作为变量值。
extract(array,extract_rules,prefix)
题中给出extract($_GET),相当于:
$shiyan = $_GET[‘shiyan’]
$flag = $_GET[‘flag’]。
另外,isset()函数判断$shiyan变量是否设置,
像这样,即使变量为空,isset()函数也为true。 payload:?shiyan=&flag=
或者利用php://伪协议:payload:?shiyan=&flag=php://input
0x02strcmp比较字符串
strcmp(str1, str2)比较两个字符串大小,若是非字符串(例如数组)比较,则会出错。在5.3之前的php中,显示了报错的警告信息后,将return 0。 payload:?a[]=1
0x03urldecode二次编码绕过
eregi()在一个字符串中搜索指定的模式的字符串,搜索不区分大小的正则匹配。
urldecode()解码以编码的URL字符串,但是$_GET[]会将参数解码一次。
若本题将“hackerDJ”进行两次URL编码,在eregi()中比较”hackerDJ”与$_GET[id]是否相同,$_GET会解码一次,从二次URL编码变成一次URL编码;urldecode()会将$_GET[id]从二次URL编码变成一次URL编码,赋值给$_GET[id],当$_GET[id]与“hackerDJ”比较时,$_GET[id]再从一次URL编码解码,最后比较相等得到flag。
将“hackerDJ”进行两次URL编码。 payload:?id=%25%36%38%25%36%31%25%36%33%25%36%62%25%36%35%25%37%32%25%34%34%25%34%61
0x04md5()函数
md5()计算字符串的MD5散列值。
md5()函数不能处理数组,使用数组绕过,md5(array)会返回null。 payload1:?username[]=1&password=2
0x05数组返回NULL绕过
strpos(string, find[, start])查找字符串在另一字符串中第一次出现的位置。
ereg()正则匹配,需使password中只含有英文字母和数字,又因为strpos()需要匹配“–”才能得到flag,可以使用数组绕过ereg()和strpos()。
ereg()只能处理字符,而password是数组,所以返回的是null,三个等号的时候不会进行类型转换。所以null!==false。
strpos()的参数同样不能够是数组,所以返回的依旧是null,null!==false也是正确。 payload:?password[]=1
思路二:ereg()可以进行%00截断,绕过正则匹配。 payload:?password=1%00--
0x06弱类型整数大小比较绕过
is_numeric(var)检测变量是否为数字或数字字符串,是则返回true,否则返回false。
is_numeric()对于空字符%00,无论%00放在前面还是后面都可以判断为非数值,而空格%20只能放在数值后面,实质上都是弱类型转换。 payload1:?password=1337%00
payload2:?password=1337%20
payload3:?password=1337a
0x07sha()函数比较绕过
同md5()一样,sha1()函数也无法处理数组,因此可以构造数组绕过。 payload:?name[]=1&password=2
0x08md5加密相等绕过
md5生成的以“0e”开头的哈希值都解释为0,所以PHP在判断时会认为相同。 payload:?a=240610708
0x09十六进制与数字比较
ord()返回字符串中首个字符的ASCII值。
题目中会要求输入的password中不能有0~9数字,并且还需要判断$number==$_GET[password]。所以将$number=3735929054转换为16进制“deadc0de”,再在前面加上0x表示16进制。 payload:?password=0xdeadc0de
0x10ereg正则%00截断
题目通过ereg()函数判断password中是否只含有字母或数字,进而限制password长度小于8,并且值小于9999999;在此前提下用strpos()函数搜索password中是否含有“-”,若是则输出flag。
解法一,利用数组绕过strpos()函数。 payload:?password[]=9999999999
解法二,利用ereg()%00截断漏洞,在用科学记数法来构造1e9满足strlen($_GET[‘password’]) < 8 && $_GET[‘password’]> 9999999这个条件,再加上“-”来满足strpos()的条件。 payload:?password=1e9%00*-*
0x11strpos数组绕过
构造数组绕过,并且值含有数字。 payload:?ctf[]=1
0x12数字验证正则绕过
直接POST一个password就可以,并且小于12个字符。 payload: POST:password=1