一道有点心思的Re题目,我也被最后一步坑了。
程序总体流程:
获取第一次输入,并且输入只能是6位的数字,并拼接上"@DBApp"调用win32API进行加密,第一次选择的是sha1加密,加密完成后与一个hash值进行比较,注意这给是值比较不是字符串比较,因此写脚本的时候要注意一下大小写。
第二次,故技重施,不同的是这次的输入只是将长度限制位6个字符而不仅限于数字,并且拼接上sha1爆破出来的结果,随后再次调用WIN32 api进行加密,这次是进行md5加密。不过因为,这次由于第二次输入条件的宽松限制,md5爆破不太实际,后面md5校验通过后其实还进行了一次检查,看看有什么东西。
发现加载了资源表中一个叫做AAA的资源,并将该资源区域的所有值参与了最终密码的异或运算。然后创建一个dbapp.rtf的文件,同时将异或的结果写入该文件。看到这里,我其实不太懂怎么利用,不过看了其他师傅的WP说,写入rtf文件必定有rtf文件头,嗯…这个我是觉得文件后缀与文件内容没有必然的联系,不过这样的推测也站得住脚,而且题目名字也是crackRTF,这也显得很合理。我看有些人对为什么最终的异或运算取文件头6给字符有疑惑,这个是因为第二次输入的6个字符与dbapp.rtf的前6个字节进行的异或。
脚本如下:
import hashlib
passwd1 = "6e32d0943418c2c33385bc35a1470250dd8923a9"
passwd2 = "27019e688a4e62a649fd99cadaafdb4e"
suffix = "@DBApp"
aaa = [0x5, 0x7d, 0x41, 0x15, 0x26, 0x1] #AAA资源的前6个字节
rtf_header = [0x7b, 0x5c, 0x72, 0x74, 0x66, 0x31] # RTF文件头前6给字节
pass1 = ""
pass2 = ""
for i in range(100000,1000000):
instr = str(i) + suffix
res = hashlib.sha1(instr.encode('utf-8')).hexdigest()
if res == passwd1:
pass1 = str(i)
print("passwd1 = ", pass1)
break
for i in range(6):
res = aaa[i] ^ rtf_header[i]
pass2 += chr(res)
print("passwd2 = ", pass2)
注意:hash函数族通常只能爆破。