-
-
[原创]2020网鼎杯 白虎组 b64 精析
-
2021-6-11 10:02 10855
-
扯淡时间
不懂出题的师傅是哪位,但猜测很大可能性不超过25岁。
最近又在搞CTF,但看着余弦等大佬都已转战区块链领域良久,不觉心慌慌,感觉自己再亿次被时代抛弃。
题目分析
题目很简练,类型:Crypto,最终解出人数是300队以内。
下载打开看是
密文:uLdAuO8duojAFLEKjIgdpfGeZoELjJp9kSieuIsAjJ/LpSXDuCGduouz
泄露的密文:pTjMwJ9WiQHfvC+eFCFKTBpWQtmgjopgqtmPjfKfjSmdFLpeFf/Aj2ud3tN7u2+enC9+nLN8kgdWo29ZnCrOFCDdFCrOFoF=
泄露的明文:ashlkj!@sj1223%^&*Sd4564sd879s5d12f231a46qwjkd12J;DJjl;LjL;KJ8729128713
几乎15分钟内就能看出,“泄露的密文”可能是个类似Base64的东西,把“泄露的明文”转换成base64编码看看:
1 | YXNobGtqIUBzajEyMjMlXiYqU2Q0NTY0c2Q4NzlzNWQxMmYyMzFhNDZxd2prZDEySjtESmpsO0xqTDtLSjg3MjkxMjg3MTM = |
注意:FoF=和MTM=
与泄露的密文对比后发现最后四位长得很像,猜测最后3位的加密过程肯定是M--->F,T---->o。
Vlookup
初步想法是先把“密文”按照替换法替换成明文(要注意Excel某些时候不区分大小写,不要直接Vlookup):
1 | = LOOKUP( 1 , 0 / EXACT(A:A,D2),B:B) |
解释:假如 D2和A:A列的某个项一致,则返回B:B列相应的项
至于1,0,Lookup啥意思,不知道。
明文的前半部分是不是很熟?基本上flag 的base64开头就是ZmxhZ
base64解码:flag{1e3a2。那接下来就很明显了。爆破下面六个字符对应的字母就可以了。
EIGsXz
爆破
字典构造
我们知道base64的字典一般是大小写字母和数字,加号和斜杠组成(共计64个)
如果用python写就是
1 2 | import string string.letters + string.digits + '+/' |
这个字典里要去掉参考明文的所有字母(这里需要思考一下),原因是:
参考密文当中不包含EIGsXz,假如 EIGsXz作为密文,明文肯定不是参考明文当中的字符。
所以字典64个字符要减掉参考明文中42个字符(注:不可用Excel 的自动去重功能,因为没区分大小写),共计22个。
1 2 3 4 5 | #用未被映射的字符构造字典 newDic = '' for x in dic: if (x not in b ): newDic + = x |
python解析base64
同时又知道python有个解base64的包。
1 2 | import base64 base64.b64decode( 'ZmxhZ3sxZTNhMm' ) |
进度条
所以可以直接爆破了(引入个进度条,不然等待很绝望)记得要是
1 | pip install progressbar2。 |
1 | bar = progressbar.ProgressBar(max_value = scipy.special.perm( len (newDic), len (unknow))) |
爆破核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | dic1 = newDic for E in newDic: dic2 = dic1.replace(E,'') for G in dic2: dic3 = dic2.replace(G,'') for I in dic3: dic4 = dic3.replace(I,'') for s in dic4: dic5 = dic4.replace(s,'') for X in dic5: dic6 = dic5.replace(X,'') for z in dic6: result = 'ZmxhZ3sxZTNhMm{E}lN{I}0xYz{G}yLT{E}mNGYtOWIyZ{I}{s}hNGFmYW{X}kZj{G}xZTZ{z}' . format (E = E,G = G,I = I,s = s,X = X,z = z) # '............. . E .. I .... G ... E ......... .Is..... .X ... G......z' # ZmxhZ3sxZTNhMm{E}lN{I}0xYz{G}yLT{E}mNGYtOWIyZ{I}{s}hNGFmYW{X}kZj{G}xZTZ{z} count + = 1 #进度条 bar.update(count) combineAndDecode(result) |
排列组合
1 | scipy.special.perm( len (newDic), len (unknow)) |
这一串是排列的意思,其实就是A22,6(22个字符中选择6个,有53721360种可能)。这个数字用于设计进度条。
正则验证
一般盲猜的base64解密,会出一堆乱码字符
所以前面一般加个可打印字符判断,如果是乱码直接下一个尝试了
1 2 3 4 5 | flag = base64.b64decode(result) for x in flag: if (x not in string.printable): flag = '' break |
然后再写个正则验证flag的符合性(根据其他题的flag,格式一般是)。
1 | re.findall(r 'flag{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}}' ,flag) |
字符串加工
因为要打出以下这串:
1 | ZmxhZ3sxZTNhMm{E}lN{I} 0xYz {G}yLT{E}mNGYtOWIyZ{I}{s}hNGFmYW{X}kZj{G}xZTZ{z} |
所以加了个代码
1 2 3 4 5 | for x in m: if (a.find(x) = = - 1 ): n + = '{' + x + '}' unknow + = x maskM + = x |
最终代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | # -*- coding: utf-8 -*- import requests import sys import string import base64 import re import progressbar import scipy.special reload (sys) sys.setdefaultencoding( 'utf8' ) #a(cypher_base64)--->b(plain_base64) a = 'pTjMwJ9WiQHfvC+eFCFKTBpWQtmgjopgqtmPjfKfjSmdFLpeFf/Aj2ud3tN7u2+enC9+nLN8kgdWo29ZnCrOFCDdFCrOFoF=' b = 'YXNobGtqIUBzajEyMjMlXiYqU2Q0NTY0c2Q4NzlzNWQxMmYyMzFhNDZxd2prZDEySjtESmpsO0xqTDtLSjg3MjkxMjg3MTM=' #m(cypher_base64)--->n(target_base64) m = 'uLdAuO8duojAFLEKjIgdpfGeZoELjJp9kSieuIsAjJ/LpSXDuCGduouz' # ZmxhZ3sxZTNhMm.lN.0xYz.yLT.mNGYtOWIyZ..hNGFmYW.kZj.xZTZ. n = '' maskM = '' unknow = '' dic = string.letters + string.digits + '+' + '/' #用未被映射的字符构造字典 newDic = '' for x in dic: if (x not in b ): newDic + = x print "newDic:" + str ( len (newDic)) print "newDic:" + newDic for x in m: if (a.find(x) = = - 1 ): n + = '{' + x + '}' unknow + = x maskM + = x else : n + = b[a.find(x)] maskM + = '.' print m print maskM print n #未知字符 unknow = "".join( set ( list (unknow))) def combineAndDecode(result): try : flag = base64.b64decode(result) #flag='flag{1e3a2de4-1c02-4f4f-9b2d-a4afabdf01e6}' for x in flag: if (x not in string.printable): flag = '' break if ( len (re.findall(r 'flag{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}}' ,flag))> 0 ): #print flag with open ( 'results.txt' , 'a+' ) as f: f.write(result + '\n' ) f.write(flag + '\n' ) #pass except Exception as e: pass count = 0 bar = progressbar.ProgressBar(max_value = scipy.special.perm( len (newDic), len (unknow))) dic1 = newDic for E in newDic: dic2 = dic1.replace(E,'') for G in dic2: dic3 = dic2.replace(G,'') for I in dic3: dic4 = dic3.replace(I,'') for s in dic4: dic5 = dic4.replace(s,'') for X in dic5: dic6 = dic5.replace(X,'') for z in dic6: result = 'ZmxhZ3sxZTNhMm{E}lN{I}0xYz{G}yLT{E}mNGYtOWIyZ{I}{s}hNGFmYW{X}kZj{G}xZTZ{z}' . format (E = E,G = G,I = I,s = s,X = X,z = z) # '............. . E .. I .... G ... E ......... .Is..... .X ... G......z' # ZmxhZ3sxZTNhMm{E}lN{I}0xYz{G}yLT{E}mNGYtOWIyZ{I}{s}hNGFmYW{X}kZj{G}xZTZ{z} count + = 1 #进度条 bar.update(count) combineAndDecode(result) |
跑的效果是这样:
大概5分钟内能跑完。
最终结果(21 flag):
(共计可能有21个flag)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ZmxhZ3sxZTNhMmJlNC0xYzAyLTJmNGYtOWIyZC1hNGFmYWRkZjAxZTZ9 flag{ 1e3a2be4 - 1c02 - 2f4f - 9b2d - a4afaddf01e6} ZmxhZ3sxZTNhMmJlNC0xYzAyLTJmNGYtOWIyZC1hNGFmYWVkZjAxZTZ9 flag{ 1e3a2be4 - 1c02 - 2f4f - 9b2d - a4afaedf01e6} ZmxhZ3sxZTNhMmJlNC0xYzAyLTJmNGYtOWIyZC1hNGFmYW5kZjAxZTZ9 flag{ 1e3a2be4 - 1c02 - 2f4f - 9b2d - a4afandf01e6} ZmxhZ3sxZTNhMmJlNC0xYzRyLTJmNGYtOWIyZC1hNGFmYWVkZjRxZTZ9 flag{ 1e3a2be4 - 1c4r - 2f4f - 9b2d - a4afaedf4qe6} ZmxhZ3sxZTNhMmJlNC0xYzRyLTJmNGYtOWIyZC1hNGFmYW5kZjRxZTZ9 flag{ 1e3a2be4 - 1c4r - 2f4f - 9b2d - a4afandf4qe6} ZmxhZ3sxZTNhMmJlNC0xYzVyLTJmNGYtOWIyZC1hNGFmYWRkZjVxZTZ9 flag{ 1e3a2be4 - 1c5r - 2f4f - 9b2d - a4afaddf5qe6} ZmxhZ3sxZTNhMmJlNC0xYzVyLTJmNGYtOWIyZC1hNGFmYW5kZjVxZTZ9 flag{ 1e3a2be4 - 1c5r - 2f4f - 9b2d - a4afandf5qe6} ZmxhZ3sxZTNhMmRlNC0xYzAyLTRmNGYtOWIyZC1hNGFmYWJkZjAxZTZ9 flag{ 1e3a2de4 - 1c02 - 4f4f - 9b2d - a4afabdf01e6} ZmxhZ3sxZTNhMmRlNC0xYzAyLTRmNGYtOWIyZC1hNGFmYWVkZjAxZTZ9 flag{ 1e3a2de4 - 1c02 - 4f4f - 9b2d - a4afaedf01e6} ZmxhZ3sxZTNhMmRlNC0xYzAyLTRmNGYtOWIyZC1hNGFmYW5kZjAxZTZ9 flag{ 1e3a2de4 - 1c02 - 4f4f - 9b2d - a4afandf01e6} ZmxhZ3sxZTNhMmRlNC0xYzJyLTRmNGYtOWIyZC1hNGFmYWVkZjJxZTZ9 flag{ 1e3a2de4 - 1c2r - 4f4f - 9b2d - a4afaedf2qe6} ZmxhZ3sxZTNhMmRlNC0xYzJyLTRmNGYtOWIyZC1hNGFmYW5kZjJxZTZ9 flag{ 1e3a2de4 - 1c2r - 4f4f - 9b2d - a4afandf2qe6} ZmxhZ3sxZTNhMmRlNC0xYzVyLTRmNGYtOWIyZC1hNGFmYWJkZjVxZTZ9 flag{ 1e3a2de4 - 1c5r - 4f4f - 9b2d - a4afabdf5qe6} ZmxhZ3sxZTNhMmRlNC0xYzVyLTRmNGYtOWIyZC1hNGFmYW5kZjVxZTZ9 flag{ 1e3a2de4 - 1c5r - 4f4f - 9b2d - a4afandf5qe6} ZmxhZ3sxZTNhMmVlNC0xYzAyLTVmNGYtOWIyZC1hNGFmYWJkZjAxZTZ9 flag{ 1e3a2ee4 - 1c02 - 5f4f - 9b2d - a4afabdf01e6} ZmxhZ3sxZTNhMmVlNC0xYzAyLTVmNGYtOWIyZC1hNGFmYWRkZjAxZTZ9 flag{ 1e3a2ee4 - 1c02 - 5f4f - 9b2d - a4afaddf01e6} ZmxhZ3sxZTNhMmVlNC0xYzAyLTVmNGYtOWIyZC1hNGFmYW5kZjAxZTZ9 flag{ 1e3a2ee4 - 1c02 - 5f4f - 9b2d - a4afandf01e6} ZmxhZ3sxZTNhMmVlNC0xYzJyLTVmNGYtOWIyZC1hNGFmYWRkZjJxZTZ9 flag{ 1e3a2ee4 - 1c2r - 5f4f - 9b2d - a4afaddf2qe6} ZmxhZ3sxZTNhMmVlNC0xYzJyLTVmNGYtOWIyZC1hNGFmYW5kZjJxZTZ9 flag{ 1e3a2ee4 - 1c2r - 5f4f - 9b2d - a4afandf2qe6} ZmxhZ3sxZTNhMmVlNC0xYzRyLTVmNGYtOWIyZC1hNGFmYWJkZjRxZTZ9 flag{ 1e3a2ee4 - 1c4r - 5f4f - 9b2d - a4afabdf4qe6} ZmxhZ3sxZTNhMmVlNC0xYzRyLTVmNGYtOWIyZC1hNGFmYW5kZjRxZTZ9 flag{ 1e3a2ee4 - 1c4r - 5f4f - 9b2d - a4afandf4qe6} |
总结
要解这题门道还是挺多的,以下方面要快速知道并投入使用:
1、 python解base64
2、正则表达式
3、字符串快速转置去重分析
4、进度条设计
5、排列组合知识
6、基本是盲猜,连base64原理是什么都可以不用知道。但知道一下base64原理也挺好。
参考链接
VLOOKUP函数不能区分大小写,该如何查找匹配?
https://cloud.tencent.com/developer/news/594528
附件下载(Excel和python文件)
https://github.com/8gg/BlogFile/issues/1
TODO
1、深入研究Excel Lookup如何匹配大小写
2、研究 Base64原理