[SWPUCTF 2021 新生赛]fakebase | NSSCTF
前言
很有意思的一道python题,逆向。
题解
下载附件,得到py文件,直接打开分析
flag = 'xxxxxxxxxxxxxxxxxxx'
s_box = 'qwertyuiopasdfghjkzxcvb123456#$'
tmp = ''
for i in flag:
tmp += str(bin(ord(i)))[2:].zfill(8)
b1 = int(tmp,2)
s = ''
while b1//31 != 0:
s += s_box[b1%31]
b1 = b1//31
print(s)
# s = u#k4ggia61egegzjuqz12jhfspfkay
分析
flag每位字符经for循环转化为8位的2进制后以字符的形式统一存放放在tmp中,随后将tmp字符串转化为2进制。while循环中是将转化后的值不断处理,最终得到密文s。处理方式是不断对31整除,余数转化为字符的形式保存在s中。需要注意的是,由于循环的的退出条件是b1//31==0,所以b1小于31时的值不会被保存的值不会被保存在s中。
思路
制作脚本对密文回溯。
由以上分析易知,只要将b1最后的值不断 *31 后 +对应一位密文ASCII码值,
for str1 in reversed(s):
n = n*31 + s_box.find(str1)
得到“b1”,将b1转化为二进制后各自拆分为8位,最后不足8位时前补0,
n_str = str(bin(n))[2:]
if len(n_str)%8:
n_str = '0'*(8-len(n_str)%8) + n_str
n_list = [n_str[x:x+8] for x in range(0,len(n_str),8)]
再转化为字符类型。
n_list = [n_str[x:x+8] for x in range(0,len(n_str),8)]
print(''.join([(chr(int(i,2))) for i in n_list]))
但是,由于第一个值未知,无法计算,所以此处需要爆破。即从0到31依次尝试,flag必然在其中。(看到某位大佬的wp上说这个爆破的范围可以缩到0~5,但是我不是很理解,就先不说啦,理解后再更新)
exp
s = 'u#k4ggia61egegzjuqz12jhfspfkay'
s_box = 'qwertyuiopasdfghjkzxcvb123456#$'
flag = ''
for i in range(31):
n = i
for str1 in reversed(s):
n = n*31 + s_box.find(str1)
n_str = str(bin(n))[2:]
if len(n_str)%8:
n_str = '0'*(8-len(n_str)%8) + n_str
n_list = [n_str[x:x+8] for x in range(0,len(n_str),8)]
print(i,''.join([(chr(int(j,2))) for j in n_list]))