Automne's Shadow.

ASIS CTF 2019 A delicious soup WriteUp

2019/04/23 Share

Crypto

时间有限,只做了这个比赛的密码学签到题,签到题都这个难度,我枯了。

给了flag.enc文件和加密文件。

flag.enc内容:

11d.3ilVk_d3CpIO_4nlS.ncnz3e_0S}M_kn5scpm345n3nSe_u_S{iy__4EYLP_aAAall

加密的脚本如下:

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
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import random
from flag import flag

def encrypt(msg, perm):
W = len(perm)
while len(msg) % (2*W):
msg += "."
msg = msg[1:] + msg[:1]
msg = msg[0::2] + msg[1::2]
msg = msg[1:] + msg[:1]
res = ""
for j in xrange(0, len(msg), W):
for k in xrange(W):
res += msg[j:j+W][perm[k]]
msg = res
return msg

def encord(msg, perm, l):
for _ in xrange(l):
msg = encrypt(msg, perm)
return msg

W, l = 7, random.randint(0, 1337)
perm = range(W)
random.shuffle(perm)

enc = encord(flag, perm, l)
f = open('flag.enc', 'w')
f.write(enc)
f.close()

然后就是阅读代码,密文cipher其实是encord(flag, perm, l)的输出

flag未知
perm是range(7)生成的列表,再经过random.shuffle(perm)打乱顺序,这种组合其实不多,可以爆破
l是random.randint(0, 1337)生成的随机数,也是可以爆破的

接着再看encord()函数,这个函数其实就是执行了l次的encrypt(msg, perm)

分析这个函数可以看到首先判断如果不能被14整除就添加.

1
2
while len(msg) % (2*7):
msg += "."

然后做了一些替换操作

1
2
3
msg = msg[1:] + msg[:1]
msg = msg[0::2] + msg[1::2]
msg = msg[1:] + msg[:1]

最后就是将上面生成的msg信息每7位一组,按照perm里的排序重新组合

1
2
3
4
5
6
res = ""
for j in xrange(0, len(msg), 7):
for k in xrange(7):
res += msg[j:j+7][perm[k]]
msg = res
return msg

代码逻辑分析清楚后,整个过程其实除了加了.号之外,msg的长度其实没变,因此有flag.enc的长度为70,且包含了两个.可知,flag的长度为68位。

开始写逆向代码。

有几点需要注意,首先:

  1. msg = msg[1:] + msg[:1]的逆向过程是msg = msg[-1:] + msg[:-1]
  2. 调用iter = itertools.permutations(perm0,7)去生成7位的组合
  3. 使用perm.index(k)去获取k的索引

ok,最后给出爆破脚本:

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
#encoding=utf-8

import itertools
import random
import time
import sys


def decrypt(cipher,perm):
msg = ""
msg2 = ""
for j in xrange(0,70,7):
for k in xrange(7):
msg += cipher[j:j+7][perm.index(k)]
#print msg + "$$$$$$$$$$$$$"
#print len(msg)
msg = msg[-1:] + msg[:-1]
for m in xrange(35):
msg2 += msg[m::35]
msg3 = msg2[-1:] + msg2[:-1]
#plaintext = msg[:-2]
#print len(msg)
return msg3


def brute():
perm0 = range(7)
list1 = []
iter = itertools.permutations(perm0,7)
list1.append(list(iter))
for i in xrange(len(list1[0])):
cipher = "11d.3ilVk_d3CpIO_4nlS.ncnz3e_0S}M_kn5scpm345n3nSe_u_S{iy__4EYLP_aAAall"
#print n
perm = list(list1[0][i])
print perm
for m in xrange(1338):
#print cipher
#print m
cipher = decrypt(cipher,perm)
print cipher
if cipher.startswith('ASIS{') and cipher.endswith('}..'):
print cipher
print m
print perm
sys.exit(0)
print "Nothing Found"
print "All down."

if __name__ == "__main__":
brute()

几分钟后即可得到flag:

automne

CATALOG