[RITSEC CTF 2025] Crypto
这个忘打了,难度不小。
Alien Encryption 101
一个很小的RSA,略
Cuwves 2 Electric Boogaloo
已知p,在p^2下的两个椭圆曲线的j不变量,直接用函数
Mothership
AES_CBC加密给出密文和IV,通过调整IV来修改明文
import base64
import os
import signal
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
COORDS = open("coordinates.txt").read().strip()
def encrypt(message, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
padded = pad(message.encode(), AES.block_size)
ciphertext = cipher.encrypt(padded)
return base64.b64encode(iv + ciphertext).decode()
def validate(data, key):
try:
data = base64.b64decode(data)
iv = data[:16]
ciphertext = data[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(ciphertext), AES.block_size).decode()
return decrypted == "SHIP:FIRE"
except:
print("Invalid transmission.")
raise SystemExit(1)
def main():
print("=== Alien Transmission System ===")
print("Welcome to the transmission system.")
signal.alarm(11)
for i in range(200):
key = os.urandom(16)
iv = os.urandom(16)
print("\nSAFE TRANSMISSION:", encrypt("SHIP:SAFE", key, iv))
data = input("SEND TRANSMISSION: ")
if not validate(data, key):
print("Safe transmission received. Exiting.")
return
print(f"Attack transmission received ({i + 1}/200). Continue to confirm.")
print("Attack mode initiated. Ship coordinates:", COORDS)
if __name__ == "__main__":
main()
from base64 import b64encode,b64decode
from pwn import *
context.log_level = 'debug'
p = remote('mothership.ctf.ritsec.club', 31750)
for i in range(200):
p.recvuntil(b':')
enc = b64decode(p.recvline().strip().decode())
niv = xor(enc[:16], b'SHIP:FIRE'.ljust(16,b'\0'), b'SHIP:SAFE'.ljust(16,b'\0'))
p.sendline(b64encode(niv+enc[16:]))
p.recvline()
p.interactive()
不过这个远程有计时,而速度又很慢最多到195总是到不了200
Leaky ZKP
又一个脑筋急转弯的题。前一半看似DLP,p不是strong的,所以可以出来小因子,解出小模下的解,多次可以得到flag。后一半看是hnp (B*x+t = A)其中B自己输入,A给出。问题是这里没有取模,所以当B输入大值时,就能忽略t
#!/usr/local/bin/python
from os import urandom, getenv
from secrets import randbelow
from Crypto.Util.number import getPrime, bytes_to_long
FLAG = getenv('FLAG', 'MetaCTF{test_flag}').encode()
def main():
p = getPrime(512)
k = 32
x = bytes_to_long(FLAG + urandom(64 - len(FLAG)))
g = 3
h = pow(g, x, p)
print('Let me prove to you in *zero-knowledge* that I know the discrete log of h!')
print(f'{p = }')
print(f'{g = }')
print(f'{h = }')
# 1. Prover (me) chooses random r_i for i = 1, 2, ..., k and sends each g^r_i
R = [randbelow(p) for _ in range(k)]
print([pow(g, r_i, p) for r_i in R])
# 2. Verifier (you) chooses and sends random bits b_i for i = 1, 2, ..., k
B = [int(b_i) for b_i in input(f'Send b_1, b_2, ..., b_{k}: ').split(',')]
assert len(B) == k and all(b_i >= 0 for b_i in B)
# 3. Prover (me) computes z_i = r_i + b_i x for i = 1, 2, ..., k and sends each z_i
Z = [r_i + b_i * x for r_i, b_i in zip(R, B)]
print(Z)
# 4. Verifier (you) has sufficient information to be convinced that I truly know the discrete log!
print('With that, you can verify that I know the discrete log, and you will have learnt nothing about my secret!')
if __name__ == '__main__':
main()
输入 [2**512]+[1]*31拿第1个结果直接右移512位即可。
Bitstream Breach
这个就算没作完(代码太多,略)
给了一堆看不懂的代码。大概看懂以后加密分4部分
1,把64位key转为key1,再key1转为key2,再转为key3由于key已知所以这3个已知
2,把输入进行换位
3,作3轮 l,r=>r,r^k^l 每次用1个key
4,把结果进行第2次换位
看似不难,可转来转去,不知道该提交啥。
#keygen
key = 0xFEDCBA9876543210
skey = bin(key)[2:]
#keycompress 64->32
cp = [10,35,38,13,3,60,9,62,7,43,45,44,34,12,54,24,26,42,41,18,8,31,50,32,17,56,47,0,46,49,27,48]
#kp
kp = [31,11,22,25,21,28,0,19,12,14,17,10,6,9,20,18,24,1,7,26,23,15,27,4,29,5,2,3,30,16,13,8]
#ip
ip = [57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7,56,48,40,32,24,16,8,0,58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6]
#fp
fp = [39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25,32,0,40,8,48,16,56,24]
#31 30 ... 0 从高位到低位
kcomp_s = ''.join([skey[63-cp[i]] for i in range(32)])[::-1]
key1 = kcomp_s
krot1_s = kcomp_s[-21:]+ kcomp_s[:11]
kperm1_s = ''.join([krot1_s[31-kp[i]] for i in range(32)])[::-1]
key2 = kperm1_s
krot2_s = kperm1_s[-6:]+kperm1_s[:-6]
key3 = ''.join([krot2_s[31-kp[i]] for i in range(32)])[::-1]
def sxor(a,b):
return ''.join([str(int(a[i])^int(b[i])) for i in range(32)])
enc = 0x3EA8A2CD3A1C7DE221A48BAD307C7DDA
senc = bin(enc)[2:].zfill(128)
#0x920bd05154bc2173ee3b75d17d3c2193
后边就更看不懂了。