NPC 2025复现

river

class LFSRStreamCipher: def init(self, key: int): if not (0 <= key < 2**16): raise ValueError(“Key must be a 16-bit integer”) self.state = key self.poly = 0b1010000000000101 # 反馈多项式: x^16 + x^14 + x^13 + x^11 + 1

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
def lfsr_step(self) -> int:
feedback = self.state & 1
self.state >>= 1
if feedback:
self.state ^= self.poly
return feedback

def generate_keystream(self, length: int) -> bytes:
keystream = bytearray()
for _ in range(length):
byte = 0
for i in range(8):
byte |= self.lfsr_step() << i
keystream.append(byte)
return bytes(keystream)

def encrypt(self, plaintext: bytes) -> bytes:
"""使用密钥流加密"""
keystream = self.generate_keystream(len(plaintext))
return bytes(p ^ k for p, k in zip(plaintext, keystream))

def decrypt(self, ciphertext: bytes) -> bytes:
"""使用密钥流解密(加密与解密是相同的)"""
return self.encrypt(ciphertext)



key = 0b1101011010110101
cipher = LFSRStreamCipher(key)


ciphertext = cipher.encrypt(flag)



print("Ciphertext:", ciphertext.hex())



#bd8b802f4a05ed77abace36b6cf9adbe627d3632edff818c556120ad131b50dbedd0f4af4483


常规的LFSR题目,加密方式和反馈多项式都给了,并且因为异或具有可逆性,所以只需要再将密文按照这个逻辑即可解密。需要注意的是要在初始化的时候将LFSR内部重置一下。

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


class LFSRStreamCipher:
def __init__(self, key: int):
if not (0 <= key < 2**16):
raise ValueError("Key must be a 16-bit integer")
self.initial_key = key
self.poly = 0b1010000000000101
self.reset()

def reset(self):#重置,确保密钥和解密开始时状态相同
self.state = self.initial_key

def lfsr_step(self) -> int:
feedback = self.state & 1
self.state >>= 1
if feedback:
self.state ^= self.poly
return feedback

def generate_keystream(self, length: int) -> bytes:
keystream = bytearray()
for _ in range(length):
byte = 0
for i in range(8):
byte |= self.lfsr_step() << i
keystream.append(byte)
return bytes(keystream)

def decrypt(self, ciphertext: bytes) -> bytes:
self.reset()
keystream = self.generate_keystream(len(ciphertext))
return bytes(p ^ k for p, k in zip(ciphertext,
keystream))

key = 0b1101011010110101
cipher = LFSRStreamCipher(key)

ciphertext = 0xbd8b802f4a05ed77abace36b6cf9adbe627d3632edff818c556120ad131b50dbedd0f4af4483


decrypted = cipher.decrypt(long_to_bytes(ciphertext))

print("Decrypted:", decrypted)

#Decrypted: b'flag{two_dift3rs_0ff_t0_s33_th3_w0rld}'

全网呼叫密码人

刚好锻炼一下我简直为0的码力

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
from Crypto.Cipher import AES
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
"""
Dinzheng先生准备去买一根RuiKeV电子烟,在付款的时候忘记了它的支付密码。
还好他的朋友早有准备,留下了若干个密保问题,你能从中获取秘密的信息(flag)吗?
"""
flag=b"flag{?????}"

assert len(flag)==64

piece=[flag[i:i+8] for i in range(0,64,8)]

#-----密保问题----- : 李唐王有可能是凯撒,但李唐王是凯撒不大可能
print(''.join(chr(piece[0][i]-2) for i in range(8)))
"""
dj_ey//)
"""

#-----密保问题-----: 是谁来着...维十戴尔?王维那?哦哦哦!是维吉尼亚
"""
Ofqi ht wj, fdpsxvp, ityg cgux tqi egtbvvb. Lx ypfu iaov flt woa nc bngv ugt, uiv lqjtznp ut iweksgx hjrr stm cj dpk wp kft yivlpt. Pvge ut tfg zl qncarli asccrw, wsckf xl onc zjm ipzkpzwprzax. Kg jcawco kfxgy qw gi. Mvg uynl gvicivv qlr xg op vlsesuj txlhc. Jm lx uq rzdnh qlp exhvp rplyu, yygwza rupks qw mjk zkjraxgu rribhwuc ihkcib abtg.Rls mvg jcrhbf ggtvs kj "ztewg5!_"
"""

#-----密保问题----- : Avemujica rosElia raS
key =iv = b'1234567890123456';cipher = AES.new(key, AES.MODE_CBC, iv);ppiece = pad(piece[2], AES.block_size);print(cipher.encrypt(ppiece))
"""
b"'*\xc0m\xd0&\xcb\x18\xf3z\xfa\xf0n\xc9<\xf1"
"""

#-----密保问题----- : 密码人不语,只是一味的梭哈RSA。
print(long_to_bytes(pow(bytes_to_long(piece[3]),3,getPrime(512)**2)))
"""
b'\x0f\xe5Q\xa5_\x16q\xb0\x11\xbd\xdbO\xe803\xf7\xbf\x16R\xdd\xac\x1a\x96\xf9'
"""

#-----密保问题----- : 但是,RSA vs PACK,你知道吗?什么?不会吧?真的吗?怎么可能?
print(long_to_bytes(sum(int(str(bin(bytes_to_long(piece[4]))[2:])[i]) * [3**i for i in range(80)][i] for i in range(63))))
"""
b'\x07)\x19\x12D\x18\xdc\xf7r\xe1\x7f\xb0}'
"""

#-----密保问题----- : 你的 N 我的 TRU
g=2**521-1;f=2*555;p=2**607-1;h=g*inverse(f,p)%p;c=(114514*h+bytes_to_long(piece[5]))%p;print(long_to_bytes(c))
"""
b'v\x8bM\x07\xd7h\xb4\xd0}wY\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\xe5\x9d\x86\xd2\xe4\xd0\x06\xed'
"""

#-----密保问题----- : 我的基地的核心用了64次加密
"""
Z2VfYW5kX2g=
"""

#-----密保问题----- : 你出的什么78密码?
"""
b'ave_fun}'
"""

第一部分,变异凯撒移位密码,倒着移回来就好了

1
2
3
4
5
6
7
8
#1凯撒
encrypt = "dj_ey//)"
decrept = ""
for char in encrypt:
decrept += chr(ord(char) + 2)

print(decrept)
#flag{11+

第二部分,维吉尼亚,在线工具爆破就好了

Vigenere Solver | guballa.de

第三部分,一个关于AES CBC解密库的调用

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

key = b'1234567890123456'
iv = b'1234567890123456'
data = b"'*\xc0m\xd0&\xcb\x18\xf3z\xfa\xf0n\xc9<\xf1"
cipher = AES.new(key, AES.MODE_CBC, iv)
m = cipher.decrypt(data)
print(f"m: {m}")
#b'U_are_th\x08\x08\x08\x08\x08\x08\x08\x08'

第四部分,一个RSA攻击,将密文转成10进制然后测了一下就知道位数不够,实际上根本没模,直接小明文开方即可

1
2
3
4
5
6
7
8
9
10
11
#小明文
from Crypto.Util.number import *
piece = b'\x0f\xe5Q\xa5_\x16q\xb0\x11\xbd\xdbO\xe803\xf7\xbf\x16R\xdd\xac\x1a\x96\xf9'
m = bytes_to_long(piece)
print(m)
x=389763319625032856717372467276348186270377284511452534521
print(x.bit_length())
from gmpy2 import *
print(long_to_bytes(gmpy2.iroot(x, 3)[0]))


第五部分,一个背包加密超递增序列

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import *
m2 = b'\x07)\x19\x12D\x18\xdc\xf7r\xe1\x7f\xb0}'
N = bytes_to_long(m2)
recover = ['0'] * 63
for i in range(62, -1, -1):
pwoer = 3**i
if N >= pwoer:
recover[i] = '1'
N -= pwoer
recover2 = "".join(recover)
recover10 = int(recover2, 2)
print(long_to_bytes(recover10))

第六部分,一个NTRU加密 h = gf−1 (mod  p)

c = r ⋅ h + m (mod  p)

解密 c ⋅ f = r ⋅ g + m ⋅ f (mod  p)(rg + mf < p)

a = rg + mf = c ⋅ f

m = af−1 (mod  g)

1
2
3
4
5
6
7
8
9
10
from Crypto.Util.number import *
m=b'v\x8bM\x07\xd7h\xb4\xd0}wY\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\xe5\x9d\x86\xd2\xe4\xd0\x06\xed'
c= bytes_to_long(m)
g=2**521-1
f=2*555
p=2**607-1
h=g*inverse(f,p)%p
a=c*f%p
print(long_to_bytes(a*inverse(f,g) % g))

第七部分,base64解密

1
2
3
4
5
6
from base64 import b64decode
code = "Z2VfYW5kX2g="
decoded = b64decode(code)
print(decoded)
#ge_and_h

EXP
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
#1凯撒
encrypt = "dj_ey//)"
decrept = ""
for char in encrypt:
decrept += chr(ord(char) + 2)

print(decrept)
#flag{11+


#维吉尼亚
#belie5!_

#AES CBC解密
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

key = b'1234567890123456'
iv = b'1234567890123456'
data = b"'*\xc0m\xd0&\xcb\x18\xf3z\xfa\xf0n\xc9<\xf1"
cipher = AES.new(key, AES.MODE_CBC, iv)
m = cipher.decrypt(data)
print(f"m: {m}")
#b'U_are_th\x08\x08\x08\x08\x08\x08\x08\x08'


#小明文
from Crypto.Util.number import *
piece = b'\x0f\xe5Q\xa5_\x16q\xb0\x11\xbd\xdbO\xe803\xf7\xbf\x16R\xdd\xac\x1a\x96\xf9'
m = bytes_to_long(piece)
print(m)
x=389763319625032856717372467276348186270377284511452534521
print(x.bit_length())
from gmpy2 import *
print(long_to_bytes(gmpy2.iroot(x, 3)[0]))


#背包密码
m2 = b'\x07)\x19\x12D\x18\xdc\xf7r\xe1\x7f\xb0}'
N = bytes_to_long(m2)
recover = ['0'] * 63
for i in range(62, -1, -1):
pwoer = 3**i
if N >= pwoer:
recover[i] = '1'
N -= pwoer
recover2 = "".join(recover)
recover10 = int(recover2, 2)
print(long_to_bytes(recover10))

#NTRU
from Crypto.Util.number import *
m=b'v\x8bM\x07\xd7h\xb4\xd0}wY\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\x86:\x1eqxc\xa1\xe7\x17\xe5\x9d\x86\xd2\xe4\xd0\x06\xed'
c= bytes_to_long(m)
g=2**521-1
f=2*555
p=2**607-1
h=g*inverse(f,p)%p
a=c*f%p
print(long_to_bytes(a*inverse(f,g) % g))

#base64解码
from base64 import b64decode
code = "Z2VfYW5kX2g="
decoded = b64decode(code)
print(decoded)
#ge_and_h

#b'ave_fun}'

#flag{11+belie5!_U_are_the_best_in_crypto_challenge_and_have_fun}

OTP?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
from pwn import *

plain = """**************************"""

flag = 'flag{*********}'

length = len(flag)

block = [plain[i:i + length] for i in range(0, len(plain), length)]
c = []
for i in block:
result = ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(flag, i))
c.append(result.encode())
b = []
for i in c:
b.append(hex(bytes_to_long(i)))

with open("c.txt","a") as f:
for i in b:
f.write(i+"\n")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
0x250314151228131d593026490211373513442c54102a14104e4c18
0x70212471a3f044e1730204903003a3404007f451c7f12070f4f0e
0xb0515471028181d557f270003063a7000443254002c07120b011e
0x70241051e6d04001a36240108173a3441112c581d384614000118
0x80f131e0b390801177f3f0c14452f25030836521f2646070b5718
0x70004035b2f184e0d373149040b2b350f003a55532d0316075114
0x30215495b020f02007f3c0c4d063e3e41003a521a2f0e101c0109
0xe09410a1e3e120f1e3a78491e0c31330444305f1f26461d0b0116
0x80316145b39090b593c3b1b1f002c200e0a3b581d3846110b420f
0x1f1c150e142341051c267a284d083a2312053854533c071b4e4318
0x464e120e1c23040a5b7f211a040b387000442f431a2907010b4d04
0x4b04040b1f6d050b1a2d2d19190c303e410f3a485d7f271b174e13
0x34c0206156d170b0b3632104d11373912442c58143107011b5318
0x4619120e152a411a113a740a02172d351214305f173608124e5108
0x40008041734411c1c29310801003b70040a3c430a2f121c014f5d
0xd0918495b1e0809173e201c1f002c700205315f1c2b46170b011b
0x91e06021f61410f173b74084d1636370f012d11103e081b01555d
0xa0d1502096d050b1726741d05007f26000836551a2b1f5501475d
0xe05124708240600182b211b084b7f04090d2c111b3e155501430b
0xf0314145b2c111e15363708190c303e1244365f537d03190b4209
0x14030f0e186d0c0f103376490c0b3b7043013354102b141a00481e
0x460a14091f3e411a0b3e3a1a0b002d7241172642073a0b06400f53

MTP多次一密加密

Many-Time-Pad 攻击

一个小写的英文字母(例如{b = 0x62}),异或上空格(0x20),则会变成一个大写的英文字母{B = 0x42}。 对于 p1 xor p2 = c1 xor c2p 为明文,c 为密文),如果其中某个位置的异或结果 是一个大写的小写字母,那么有很大概率另一个明文字符就是空格(0x20),通过多个样本进行统计,可以近乎 100% 的概率确定此处是否为空格,进而能够获取到这个位置的密钥字节。 剩余部分,只需再结合人工分析,即可恢复出所有的密钥,进而完成解密。

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
from Crypto.Util.number import *
import Crypto.Util.strxor as xo
import numpy as np


def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False


def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')


dat = []


def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x != y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))

b = []
with open("c.txt","r") as f:
for i in f:
b.append(i)
c = []
for i in b:
c.append(long_to_bytes(int(i,16)))

msg = np.zeros([len(c), len(c[0])], dtype=int)

getSpace()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))# 此时解出来的还会存在部分词汇乱码,需要根据语句情景来恢复

print(''.join(chr(ord(a) ^ ord(b)) for a, b in zip(long_to_bytes(int("0x250314151228131d593026490211373513442c54102a14104e4c18",16)).decode(), "Couriers or other secure me")))
flag{Many_Time_Pad_1s_fun!}