2023古剑山杯

guess the key

题目

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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
if (argc != 3) {
printf("USAGE: %s INPUT OUTPUT\n", argv[0]);
return 0;
}
FILE* input = fopen(argv[1], "rb");
FILE* output = fopen(argv[2], "wb");
if (!input || !output) {
printf("Error\n");
return 0;
}
char key[] = "guessthekey";
char d, q, t = 0;
int ijk = 0;
while ((q = fgetc(input)) != EOF) {
d = (q + (key[ijk % strlen( key )] ^ t) + ijk*ijk) & 0xff;
t = q;
ijk++;
fputc(d, output);
}
return 0;
}

题解

加密函数如下:

1
2
3
4
5
6
while ((q = fgetc(input)) != EOF) {
d = (q + (key[ijk % strlen( key )] ^ t) + ijk*ijk) & 0xff;
t = q;
ijk++;
fputc(d, output);
}

给了四个文件,加密脚本,明文1和对应的密文,flag的密文

我们需要写一个求key的脚本来还原key,然后再用key去解密flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# python
# 求密钥
with open("msg01.enc", "rb") as f:
result = f.read()
cipher = []
for i in result:
cipher.append(i)
with open("msg01","rb") as f:
result1 = f.read()
message = result1.decode()
key = ''
for i in range(len(message)):
if i == 0:
key = key + chr((cipher[i] - ord(message[i])) & 0xff)
else:
key = key + chr(((cipher[i] - i * i - ord(message[i])) ^ ord(message[i - 1])) & 0xff)
print(key)
# VeryVeryLongKeyYouWillNeverKnowVeryV

然后就是解密flag,主要考察对代码的逆行分析

1
2
3
4
5
6
7
8
9
10
11
12
key = "VeryVeryLongKeyYouWillNeverKnow"
with open("msg02.enc", "rb") as f:
result = f.read()
cipher = [i for i in result]
new_flag = ""
for i in range(len(cipher)):
if i == 0:
new_flag = new_flag + chr((cipher[i] - ord(key[i % len(key)])) & 0xff)
else:
new_flag = new_flag + chr((cipher[i] - i * i - (ord(key[i % len(key)]) ^ (ord(new_flag[i - 1])))) & 0xff)
print(new_flag)
# She had been shopping with her Mom in Wal-Mart. She must have been 6 years old, this beautiful brown haired, freckle-faced image of innocence. It was pouring outside. The kind of rain that gushes over the top of rain gutters, so much in a hurry to hit the Earth, it has no time to flow down the spout.flag{101a6ec9f938885df0a44f20458d2eb4}

Vigenere+++

题目

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
import sys
from secret_file import *
def _l(idx, s):
return s[idx:] + s[:idx]
def main(p, k1, k2):
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
t = [[_l((i+j) % len(s), s) for j in range(len(s))] for i in range(len(s))]
i1 = 0
i2 = 0
c = ""
for a in p:
c += t[s.find(a)][s.find(k1[i1])][s.find(k2[i2])]
i1 = (i1 + 1) % len(k1)
i2 = (i2 + 1) % len(k2)
return c

flag="flag{************************}"
key="**********"

# * 为马赛克,长度为1。
# hint: 可以自己尝试下运行加密函数,看看秘钥对加密结果的影响。
# hint: 首先根据线索求秘钥,秘钥不唯一,找到一个有效的,就能爆破flag了。
print main(flag, key, key[::-1])

# 程序运行结果(即密文为):
kY0awfsdlY1FFL8C3bi4GSYCF{8W_E

题解

又是考察对代码的理解,先生成一个三维数组,然后根据索引变化进行替换,以下有三个详解

SECCON2017_online_CTF

2017-seccon-vigenere3d

SECCON -Vigenere3d - 简书 (jianshu.com)

原题exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz_{}"
p = "flag{"
c = "kY0awfsdlY1FFL8C3bi4GSYCF{8W_E"
k = []
for i in range(len(p)):
P = s.find(p[i])
C = s.find(c[i])
if P <= C:
k.append(C - P)
continue
k.append((len(s) - P) + C)
k += k[::-1]

p = ""
for i in range(len(c)):
num = s.find(c[i]) - k[i % len(k)]
if num < 0:
num = len(s) + num
p += s[num % len(s)]
print(p)
# flag{kynFTW2PRdH9lCZBf8IKDe6U}

babyrsa

题目

1
2
3
4
p=99953143645521177803735736579862987978862371986511271698200985860201988406992228386886156846586231189239404587468167638582713706975074975095727260756176495410112202900481714278106482237042151820865564725276149585814994889786992973857194861525113159772858254617684500040455709375098668578359761863035737111267
q=144415372074346358936965217477364683051506736832213069585643471901123120042657943921784778727610246832089508711511238996211478269698835592459553943833822992073553406476612087363775487608432193298596184833040136548627895587404676857891089403674492469390040235812377341690429548455672577876836346349155761346539
e=33
c=4680829915415870812281211152563428503064428938545028703923300734232338068354295969972680757130810558048976936545188308560554377453985439453266037425448718819398465160447125914374998787262482155999561262960844933980653294627047305816081836575351082731041044949829430251347574643312482000741462798688236290589605488420424275245156052958633122356128869507698293504468309282445294456290016179763445958393524340855750009260045863820907397341573311035964124325775286456112377652121280951592885961330916279791805340581920797766244059325031828233048008219032638906348454752719287896458438932064109933805037308289230985109854

题解

题目还给了服务端口,但是那个是判断输入值为奇数还是偶数,不知道和题目有什么关联

既然给了p和q,直接求解就行,但是这里e=33,和n的欧拉函数不互素,考虑在模p和模q上进行有限域开放,然后再利用中国剩余定理求真正的明文

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
# sage
from Crypto.Util.number import *
from gmpy2 import *

p=99953143645521177803735736579862987978862371986511271698200985860201988406992228386886156846586231189239404587468167638582713706975074975095727260756176495410112202900481714278106482237042151820865564725276149585814994889786992973857194861525113159772858254617684500040455709375098668578359761863035737111267
q=144415372074346358936965217477364683051506736832213069585643471901123120042657943921784778727610246832089508711511238996211478269698835592459553943833822992073553406476612087363775487608432193298596184833040136548627895587404676857891089403674492469390040235812377341690429548455672577876836346349155761346539
e=33
c=4680829915415870812281211152563428503064428938545028703923300734232338068354295969972680757130810558048976936545188308560554377453985439453266037425448718819398465160447125914374998787262482155999561262960844933980653294627047305816081836575351082731041044949829430251347574643312482000741462798688236290589605488420424275245156052958633122356128869507698293504468309282445294456290016179763445958393524340855750009260045863820907397341573311035964124325775286456112377652121280951592885961330916279791805340581920797766244059325031828233048008219032638906348454752719287896458438932064109933805037308289230985109854
n=p*q

R.<x> = Zmod(p)[]
f = x ^ e - c
f = f.monic()
res1 = f.roots()

R.<x> = Zmod(q)[]
f = x ^ e - c
f = f.monic()
res2 = f.roots()


# b是密文列表 m是模数列表
def crtcrt(b, m):
# 传入的参数分别为密文 和 模数n
# 乘积计算
M = 1
for i in range(len(m)):
M *= m[i]

Mm = []
# 求余数 M/m[i]
for i in range(len(m)):
Mm.append(M // m[i])

# 求Mm[i]的乘法逆元
Mm_ = []
for i in range(len(m)):
t, a, _ = gmpy2.gcdext(Mm[i], m[i])
Mm_.append(int(a % m[i]))

# 求的累加
y = 0
for i in range(len(m)):
y += (Mm[i] * Mm_[i] * b[i])
y = y % M
return y, M


for i in res1:
for j in res2:
# 普普通通中国剩余定理
m = crtcrt([int(i[0]),int(j[0])],[p,q])[0]
print(long_to_bytes(int(m)))
# flag{9cddd5588513a46a54f02ef72330eaed}