ASIS CTF Finals 2020 - babymd5
给出了一个可以连接的地址,试着连接得
让我们输入一字符串,长度要为15,且经过sha384加密后,最后六位字符为'd709bb',可根据这些写一个小小的脚本来找出符合这些条件的字符串
如下:
import hashlib import string,random for i in range(100000000000000,199999999999999): temp=hashlib.sha384(str(i).encode()).hexdigest() if temp[-6:]=='d709bb': print(str(i)) break
结果如下:
输入字符串后,又显示
输入B后,显示代码如下:
def babymd5(m, n, x_head, y_head, x, y): if x.startswith(x_head) and y.startswith(y_head): for _ in range(m): xhash = md5(x.encode('utf-8')).hexdigest() x = xhash for _ in range(n): yhash = md5(y.encode('utf-8')).hexdigest() y = yhash if xhash == yhash: return True return False
输入C后,显示代码如下:
| (m, n, x_head, y_head) = (202, 201, 'nPz', 'dead')
输入R后,提示让我们输入x
总结一下,流程大概就是已知一个函数babymd5和参数条件,即函数的参数前4个为(202,201,'nPz','dead'),让我们输入让函数babymd5返回结果为True的x和y
分析下函数babymd5的大概流程:
①判断x是否以x_head开头,y是否以y_head开头,若此条件不通过,则直接返回false
②将x进行md5加密,并对每次的结果进行循环加密,总加密次数为m次,最后加密结果为xhash
③将y进行md5加密,并对每次的结果进行循环加密,总加密次数为n次,最后加密结果为yhash
④若最后xhash与yhash恒相等,那么函数会返回True,否则返回False
这里难点就是如何找到这样的x和y,使得它们经过不同次数的md5加密后,值会相等,(我就被难倒了!参考了下wphttps://github.com/TalaatHarb/ctf-writeups/blob/main/asisctf2020/babymd5,写的很详细!)
函数中,很特殊的一个过程就是对结果反复进行循环加密,而y_head='dead','dead'又是一个合法的十六进制表示,且x加密循环的次数m>对y循环加密的次数n,故,我们可以把y看成x循环md5加密n次后的一个中间结果,即只要找到这样的一个x,对它进行循环解密n次后,它的结果temphashx恰以'dead'开头,而这个结果temphashx也就是我们需要的y。脚本如下:
import hashlib import string,random def babymd5(m, n, x_head, y_head, x, y): if x.startswith(x_head) and y.startswith(y_head): for _ in range(m): xhash = hashlib.md5(x.encode('utf-8')).hexdigest() x = xhash for _ in range(n): yhash = hashlib.md5(y.encode('utf-8')).hexdigest() y = yhash if xhash == yhash: return True return False dict=string.ascii_letters+string.digits+string.punctuation print(dict) counter=1 found=False length=32 x_head='nPz' y_head='dead' m=202 n=201 while not found: tmp=x_head+''.join(random.choice(dict) for _ in range(length)) possible_x=tmp res=tmp for _ in range(m-n): res=hashlib.md5(res.encode()).hexdigest() if res.startswith('dead'): possible_x=res x=tmp y=res print("x:",x) print("y:",y) found=babymd5(202, 201, 'nPz', 'dead',x,y) break if(counter%10000==0): print("attemp:"+str(counter)+'次') if(counter%100000==0): print("attemp:"+str(counter)+'次') counter=counter+1
得到结果:
输入对应的x和y后,得到flag!