复现一下2022angstromctf

Crypto

[复现]Vinegar Factory

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
#!/usr/local/bin/python3

import string
import os
import random


alpha = string.ascii_lowercase

def encrypt(msg, key):
ret = ""
i = 0
for c in msg:
if c in alpha:
ret += alpha[(alpha.index(key[i]) + alpha.index(c)) % len(alpha)]
i = (i + 1) % len(key)
else:
ret += c
return ret

inner = alpha + "_"
noise = inner + "{}"

print("Welcome to the vinegar factory! Solve some crypto, it'll be fun I swear!")

i = 0
while True:
if i % 50 == 49:
fleg = flag
else:
fleg = "actf{" + "".join(random.choices(inner, k=random.randint(10, 50))) + "}"

start = "".join(random.choices(noise, k=random.randint(0, 2000)))
end = "".join(random.choices(noise, k=random.randint(0, 2000)))
key = "".join(random.choices(alpha, k=4))

print(f"Challenge {i}: {start}{encrypt(fleg + 'fleg', key)}{end}")
x = input("> ")
if x != fleg:
print("Nope! Better luck next time!")
break
i += 1

题目的意思是远端随机产生一个fleg,其被actf{}括起来,以及一个key,用key加密fleg+”fleg”字符串,并且将其仍到上千个字符中,并且服务端会在未输入的20秒之内关闭,在循环次数为50次的时候会将真正的flag放到noise字符串中。

代码参考

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
import string
from pwn import *

alphabet = string.ascii_lowercase

s = remote("challs.actf.co",31333)

for count in range(51):
s.recvuntil("Challenge")
noise = str(s.recvuntil('\n'))
print(noise)

output_file = open("output.txt","w")
length = len(noise)
print(length)
for i in range(0, length - 50):

# 如果连续四个字符是字母
if noise[i] in alphabet and noise[i + 1] in alphabet and noise[i + 2] in alphabet and noise[i + 3] in alphabet:
if noise[i + 4] == '{': # 并且第五个是"{"
a = noise[i:i + 6]

# 开始往后循环,碰到"{"就停止,
while noise[i + 5] != '}' and noise[i + 5] != '{' and noise[i + 5] != '\n':
i = i + 1
a = a + noise[i + 5]
if noise[i + 5] == '{':
continue
# 碰到"}"并且后面的四个字符是字母,就放到文件中等待下一步读取
if noise[i + 6] in alphabet and noise[i + 7] in alphabet and noise[i + 8] in alphabet and noise[i + 9] in alphabet:
a = a + (noise[i + 6:i + 10])
output_file.write(a+'\n')
else:
continue
else:
continue
output_file.close() #文件关闭

#打开文件待进一步的筛选
with open('output.txt') as fp:
line = fp.readline()
while line:
noiseflag = line.strip()
enc = line
dec = 'actf'
k = ''

# 前四位加密前应为"actf",由此逆出key
alphabet = string.ascii_lowercase
for i in range(0, 4):
need_index = (alphabet.index(enc[i]) - alphabet.index(dec[i]) + 26) % 26
k = k + alphabet[need_index]
msg = ''

# 定义vinegar解密算法
def decrypt(ciph, key):
ret = ''
i = 0
for m in ciph:
if m in alphabet:
ret = ret + alphabet[(alphabet.index(m) - alphabet.index(key[i])) % len(alphabet)]
i = (i + 1) % 4
else:
ret = ret + m
return ret

# 如果后四位能被求出的key解密,结果位"fleg",则表示筛选成功
if decrypt(noiseflag, k)[-4:] == 'fleg':
dec_input = decrypt(noiseflag, k)

# 未成功则再读取一行
line = fp.readline()

# 输出解密出来的fleg字符串
print(count+1,end = " : ")
print(str(dec_input.encode()[:-4]))

# 向服务器发送解密后的fleg字符串,进入下一轮解密
s.sendline(dec_input.encode()[:-4])

代码功能:

  1. 连接远端,提取noise字符串

  2. 粗略筛选匹配的字符串到文本文件中

  3. 在文本文件中,一行一行读取字符串,求出key,并且验证尾部的字符串是否是”fleg”,因为key一致

  4. 筛选完成后向服务端发送解密后的fleg

太强了,涉及到字符串的算法……

reverse