概述
此题源于一个简单算法题的改编,在做这个算法题的时候,突然发现可以拿来做一个简单的密码题,在此分享一下分析思路。
1.题目概述
- 一个简单的Python加密,需要分析代码逆运算得出flag。
from flag import flag
import base64
print(len(flag))
table=sorted(flag)
for i in table:
print(ord(i),end="")
print()
passwd=[]
for i in range(len(flag)-1):
passwd.append((ord(flag[i])-64)^(ord(flag[i+1])-64))
print(base64.b64encode(bytes(passwd)))
'''
控制台输出如下:
27
656667686970717273747576777879808182838485868788899091
b'BhIXBg0MHAYfERIXAgEPAgEHFgIbFRQMAxY='
'''
2.题目分析
-
分析python代码,发现主要的步骤如下:
- 输出flag的长度为
27
。 - 对flag进行排序,输出flag每一位的ASCII码,得到
656667686970717273747576777879808182838485868788899091
。 - 定义列表
passwd
,其中
passwd[i] = (ord(flag[i])-64)^(ord(flag[i+1])-64)
。
- 输出flag的长度为
-
分析其具体的步骤,可以发现如下特点:
- 1.flag长度27。
- 2.flag的ASCII范围是
65-91
。 - 3.flag的所有位不重复。
- 4.
ord(flag[i] -64)
的范围为1-27
。
-
基于以上分析,可以将问题抽象为:
- 一个整数数组a,由前27个正整数组成,经过加密后得到长度为26的数组b,且加密的算法为:
b[i] = a[i] ^ a[i+1]
。 - 现在我们得到了base64编码后的b数组,需要求得a数组,进而可以求出flag。
- 一个整数数组a,由前27个正整数组成,经过加密后得到长度为26的数组b,且加密的算法为:
-
公式推导思路:
- 如果我们不考虑任何边界情况,单独从
b[i] = a[i] ^ a[i+1]
这个加密算法来看,可以得出b[i-1] = a[i-1] ^ a[i]
,接下来需要推导出a[i]
的公式。 - 原式两边同时对
a[i-1]
异或,得到b[i-1] ^ a[i-1] = a[i-1] ^ a[i] ^ a[i-1]
。 a[i-1] ^ b[i-1] = a[i-1] ^ a[i-1] ^ a[i]
。a[i-1] ^ b[i-1] = 0 ^ a[i]
。a[i] = a[i-1] ^ b[i-1]
。- 从上面的推导,我们已经可以得到
a[i]
的具体公式,但是上面这个公式其实只对i >= 1
的情况适用,当i==0
时,这个公式就不再适用,所以我们得先求出a[0]
的值。
- 如果我们不考虑任何边界情况,单独从
-
求
a[0]
的思路:- 对
a[0]
,如果我们知道整个a
数组的异或结果,并且知道除了a[0]
整个数组的异或结果,就可以得出a[0]
的值,设a
数组的异或结果为all
,设除了a[0]
外的所有异或结果为not0
,那么a[0] = all ^ not0
。 - 对于
all
,由于a
数组由1-27
的不同数字组成,所以可以很容易的得到。 - 对于
not0
,由于b
数组是26位,且有b[1] = a[1] ^ a[2]
,b[3] = a[3] ^ a[4]
,b[5] = a[5] ^ a[6]
,依次类推,可以得到not0 = b[1] ^ b[3] ^ b[5] ... ^ b[25]
。b数组已知,not0
就可以很容易的得到。 - 综合上面三个步骤,我们就可以得出
a[0]
的值。
- 对
-
综合上述所有的思路,我们得到最终的求解思路:
- 对输出结果进行base64解码,得到encode数组。
- 求出
1-27
的异或结果,求出encode[1] ^ encode[3] ^ encode[5] ... ^ encode[25]
的结果,从而得到flag[0]
的值。 - 利用公式
flag[i] = flag[i-1] ^ encode[i-1]
得到flag
数组其它元素。 - 对
flag
数组每位加上64
,得到最终的代码。
3.密码逆运算
- 解密Python脚本如下:
import base64
# 异或逆运算解密
def decode(b):
a=[]
all = 1
# 求a中所有异或值
for i in range(2,28):
all ^= i
not0=b[1]
# 求a中除了第一个元素的所有异或值
for i in range(3,len(b),2):
not0 ^= b[i]
# a[0]
a0 = all ^ not0
a.append(a0)
# a剩余元素的值
for i in range(1,27):
a.append(a[i-1] ^ b[i-1])
return a
passwd = 'BhIXBg0MHAYfERIXAgEPAgEHFgIbFRQMAxY='
passwd = base64.b64decode(passwd)
encode = []
for i in passwd:
encode.append(i)
flag = decode(encode)
for i in flag:
print(chr(i+64),end="")
- 解得最后flag为:
QWERTYUIOPASDFGHJKLZXCVBNM[
这个题目到这里就结束了,仔细想想还是很有意思的,让人体会到了异或运算的巧妙之处,也可以用于简单的CTF密码学题目之中。
此题仅展示这种异或的思路,单就此题来说,可以爆破缺失的那一位,但不是本题的初衷,实际出题可以考虑使用多层异或,直至达到无法爆破的程度。
ATFWUS 2021-05-11
最后
以上就是无情小懒虫为你收集整理的【解码异或排列】一个简单有趣的异或逆运算密码题1.题目概述2.题目分析3.密码逆运算的全部内容,希望文章能够帮你解决【解码异或排列】一个简单有趣的异或逆运算密码题1.题目概述2.题目分析3.密码逆运算所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复