RITSEC CTF

记录这个假期做的一些题目

RITSEC CTF

Emails

email0.txt

1
2
3
4
5
6
7
8
Good morning,

How are you?
I've become concerned about the security of this email service. It's only a matter of time before your inbox gets leaked.
To deal with this, I suggest we encrypt our emails. If you have any further ideas, please let me know.

Thanks,
- Your Secret Conspirator

email1.txt

1
2
3
4
5
6
7
Good morning,

I need to send you the flag, but as I mentioned in my last email, I don't want to send it unencrypted.
Please continue to look into possible encryption methods.

Thanks,
- Your Secret Conspirator

email2.txt

1
2
3
4
5
6
7
Good evening,

I see you mentioned a One Time Pad. Looking into it, that might be useful.
It apparently is secure against infinite computational resources. Do you think we can use that?

Thanks,
- Your Secret Conspirator

email3.txt

1
2
3
4
5
6
7
Good afternoon,

Okay so I have developed a secure channel for sending the key to the one time pad.
The only problem is it's really slow. I'll send you the key, but I think we should limit the key size to 32 bytes.

Thanks,
- Your Secret Conspirator

email4.txt

1
2
3
4
5
6
Good evening,

It's simple. Just repeat the key over the whole message. That way you can encrypt the whole email with the smaller key.

Thanks,
- Your Secret Conspirator

email5.enc

1
2
[P蒊?S =檤?I僷MX[,?団?<S螰鱏L1F'議2鴁!7?釯ZSu昛楊曪鏩zS荍糞l1F'?Y蘦z??Gh;躠溅佯?,J鵛z
5?Y赥od?釪UE0蘚栴栴?<^萒?@d@t緊t?w&穈盻QT'堿妹電?t^菷醎(OLt畉&?R&鬤t:侳挧撴?n

从4份未加密的邮件可以知道考点是MTP,而且密钥长度是32bytes

我查了下密文刚好192长度,分为6组,套用MTP脚本即可

本题关键在于用邮件格式Good evening,然后利用know函数可以得到更多有意义的信息,然后不断猜测,不断利用know函数

最后我利用了32次才得到正确的明文,也许是我脚本用错了(欢迎师傅们指点)

exp.py

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import Crypto.Util.strxor as xo
import libnum, codecs, 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(' ')

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


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))

#这里传密文
f = open("email5.enc","rb").read()
# c = [codecs.decode(x.strip().encode(), 'hex') for x in open('0.txt', 'r').readlines()]
c = [b'[P\xc9I\xb2\x16S \x0f=\x99|\x7f\x931\x0cI\x83p\xffMX[,\xc0\x15\xab\xee\x87\xe2\xe7\x16', b"<S\xcfF\xf7SL1F'\xd7h2\xf8^!7\xaa9\xe2IZSu\x95Z\x97\xee\x95\xef\xe7Z", b"zS\xc7J\xbcSl1F'\xcd\x16Y\xcchz\x17\xad-\xc5\x0bGh;\xdca\xbd\xa6\xd1\xf0\xdd#", b',J\xf9X\xa7@z\n5\x04\x8a\x16Y\xdaTod\xb19\xe2DUE0\xcc\\\x96\xee\x96\xee\xf6\x12', b"<^\xc8T\xfd\x1d@d@t\xbeot\xed\x1bw&\xb7`\xb1_QT'\x89A\xc3\xc3\xeb\x8a\x88.", b't^\xc8F\xe1_(OLt\xaet&\xec\x1bR&\xa6k\xf4X\x14t:\x82F\x92\xa7\x93\xe6\xf6\x15']

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

getSpace()

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

# know(0, 24, 'r') #如果需要修正, 传入所在被改字母所在行和列,再输入替代的字母,例如alwa s 改为always
import string


know(0,0,'G')
know(0,1,'o')
know(0,2,'o')
know(0,3,'d')
know(0,4,' ')
know(0,5,'e')
know(0,6,'v')
know(0,7,'e')
know(0,8,'n')
know(0,9,'i')
know(0,10,'n')
know(0,11,'g')
know(0,12,',')
know(2,13,'R')
know(2,14,'S')
know(2,15,'{')
know(2,16,'T')
know(2,17,'h')
know(2,18,'4')
know(2,19,'T')
know(2,20,'\'')
know(5,21,' ')
know(5,22,'C')
know(5,23,'o')
know(5,24,'n')
know(5,25,'s')
know(5,26,'p')
know(5,27,'i')
know(5,28,'r')
know(5,29,'a')
know(5,30,'t')
know(5,31,'o')

print(''.join([''.join([chr(c) for c in x]) for x in msg]))

key = xo.strxor(c[5], ''.join([chr(c) for c in msg[5]]).encode())
"""
Good evening,

Finally, I feel like it's safe to send you the flag. It's:
RS{Th4T's_n0T_h0w_Y0u_u53_OTP}
Don't share it with anyone!! It's very secret!

Thanks,
- Your Secret Conspirato
"""

Failed File Transfer

file1.txt

1
2
3
Y�/㵫	%��9K��5wT��=�Tg�s��w��BƲId�U��X����^�k���*�uNBNrS�|,Td0��~y��.b�Xt����FgC�	�N@���K'�S�7�����-wJ�G��?"�
4Lc���l!e̮Sh�$�������l�[i-��E�O�*��ld�G
x(W��r| ��o��6�)c�Fi X'����?!��#Q0��*�0�!8�8�2/n���=��$�ü�P�w

file2.txt

1
2
3
4
.ϫ������y^8��Q6�;�5��$�h<]F��>2��5Y�2r<�^~��������{��,�$�x�B��,�$�^E�x���K��7�����s�*��3��+� x
��斎�g�v�
E�|u|e�'�Og���S�>f��
��h{�h�v0L�]��hB��l/�J�Ħ�Me���k�� '�E(U

file3.txt

1
2
3
���81a���V� ��.�0S��&Z���«��T���Zj���<�}����u}��)��#���M�*r�Weyh��E�k:�k"\w��*2��n2�b�9����c�HT�\�P�qИ������Ē7����X5E��9
'��_3^М
B㋅zPX�Г�}U�Vˎ�٘�t� <f�.���ЄJY�u.�J�y�ٽd��x,2]*� �S��sӂ�ʨ�|Fͷ����'_붷��Wk�U�����P�FD��A[n�

pk1.pem

1
2
3
4
5
6
7
8
9
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA4Gb3gDFSDx3Xr/XsXVnN
eqaOzUw5Sh7JeSzxeeJMM/WayFbmGDbHqjSjYXMWYV9YdDuUAVB6QjhTqjHF/LhU
PpncI6Ur8JzGVxRAZFjJEs+5zD2vQfEiEpRwOEZGX5K3R/48suhETKzzjs9fr3jE
IHVp7K6R2Y7KEy4sFb9v3VHTmf6KZFtpwBzcomBK6UNLrNbDsr9BtNQUFUJfwNWQ
4FeZNccj/aCIdSi/IMit4G5/+W/QdVaUrpUB+QU2P0SKVUbgg6HtyQH77RFW5Ruw
lTiOvlZy9pWzlaIzT/FWpt0XCp1u3VjkQVq0N+DWpcIMFcuUYIGs26muGQRmiiCU
pwIBEQ==
-----END PUBLIC KEY-----

pk2.pem

1
2
3
4
5
6
7
8
9
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Gb3gDFSDx3Xr/XsXVnN
eqaOzUw5Sh7JeSzxeeJMM/WayFbmGDbHqjSjYXMWYV9YdDuUAVB6QjhTqjHF/LhU
PpncI6Ur8JzGVxRAZFjJEs+5zD2vQfEiEpRwOEZGX5K3R/48suhETKzzjs9fr3jE
IHVp7K6R2Y7KEy4sFb9v3VHTmf6KZFtpwBzcomBK6UNLrNbDsr9BtNQUFUJfwNWQ
4FeZNccj/aCIdSi/IMit4G5/+W/QdVaUrpUB+QU2P0SKVUbgg6HtyQH77RFW5Ruw
lTiOvlZy9pWzlaIzT/FWpt0XCp1u3VjkQVq0N+DWpcIMFcuUYIGs26muGQRmiiCU
pwIDAQAB
-----END PUBLIC KEY-----

pk3.pem

1
2
3
4
5
6
7
8
9
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAuDtycwPMqViaKiua9QGM
lfeQYIYR74Zs+aTEGKDX3vjT+Osd208gm+2XOQO4FbuufFUoZWJlIX32jVTWmcqL
HlONxjM2gYNaCzfzBAhF48zmayRqsshdrpIklSfjcPQCXAMoeA9nNCKwb1CFH45U
Hw8KRPw7GWvE4auMaCKYdEVVXcL1lQvxMeoAANdVcjEYN7UreHjTqV58btJQZIG1
2l4vlYrUybb17MtadFMIcTpP7YB1/JG88rTyGmknVeV4BnhQGd71orJo6lFffJjV
8NnWAfcftN+cRHvbKqQeKX0r2m6jVCzSOzNVAAy4uIlp6GgxtoTl2fF+tXXtGp1L
wQIBAw==
-----END PUBLIC KEY-----

提取公钥发现e1 = 17,e2 = 65537,e3 = 3,而且n1 = n2

共模攻击即可

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.PublicKey.RSA import import_key
from Crypto.Util.number import *
from sympy.ntheory.modular import crt
import gmpy2

key1 = import_key(open("pk1.pem","r").read())
n1 = key1.n
e1 = key1.e
c1 = bytes_to_long(open("file1.txt","rb").read())

key2 = import_key(open("pk2.pem","r").read())
n2 = key2.n
e2 = key2.e
c2 = bytes_to_long(open("file2.txt","rb").read())

key3 = import_key(open("pk3.pem","r").read())
n3 = key3.n
e3 = key3.e
c3 = bytes_to_long(open("file3.txt","rb").read())

_,x,y = gmpy2.gcdext(e1,e2)
m = pow(c1,x,n1)*pow(c2,y,n1) % n1
print(long_to_bytes(m))
# RS{Y0U_C4NT_R3AD_M3_R1GHT??}

这明文长度估计直接开3次方也能出

Dastardly Evil Scientists

task.py

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
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad
from secret import KEY, FLAG

BLOCK_SIZE = 64

key = bytes.fromhex(KEY)
cipher = DES.new(key, DES.MODE_ECB)
flag = cipher.encrypt(pad(bytes(FLAG, "utf-8"), BLOCK_SIZE))

print("Here's the flag (in hex):", flag.hex())
print("=" * 64)
print("Encrypt something if you want, you can choose the key and the plaintext :)")
while True:
try:
key = bytes.fromhex(input("Key (in hex): "))
plaintext = bytes.fromhex(input("Message to encrypt (in hex): "))
print("=" * 64)
cipher = DES.new(key, DES.MODE_ECB)
ciphertext = cipher.encrypt(pad(plaintext, BLOCK_SIZE))
print("Here's your message! (in hex):", ciphertext.hex())
print("Here's your message! (in bytes):", ciphertext)
print("=" * 64)
except KeyboardInterrupt:
break

题目给的交互没什么用,因为要我们自己输入密钥。疑惑了很久,在鸡块师傅指导下得知当密钥是弱密钥的时候加密密文即可恢复明文(说来也惭愧,最近学校课程就在上DES的内容,而我却不知道这些),参考DES弱密钥-CSDN博客,弱密钥有以下这些

1
2
3
4
5
6
7
8
0x0101010101010101
0xFEFEFEFEFEFEFEFE
0xE0E0E0E0F1F1F1F1
0x1F1F1F1F0E0E0E0E
0x0000000000000000
0xFFFFFFFFFFFFFFFF
0xE1E1E1E1F0F0F0F0
0x1E1E1E1E0F0F0F0F

一个一个试就可以了

Forensics

read.txt

1
2
3
4
5
6
7
8
9
10
-----BEGIN BITCOIN SIGNED MESSAGE-----
Your invention has been taken.
If you ever want to see it again send 10 BTC to this address:

bc1qd7qtdayjnl382qmfl4tl4yaejuv5py0n3uwq6p

You have 3 days.
-----BEGIN BITCOIN SIGNATURE-----
H3zAMJyVW2j1+Y7A+w8wflZRUmggR+Sn532ZuAGtGLcxEERvymcPrtnXVkB+0mBqCUAb0AQwyPFJfGxvIeQDPpE=
-----END BITCOIN SIGNATURE-----

查询这个地址找交易记录

把这串16进制转字符得到I have the invention and expect full payment -Z RS{26f9c2fcdfe8e86804eb}

SwampCTF

Jank File Encryptor

task.py

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
import random

# File to encrypt
file_name = input("Please input the filename: ")

# Choose whether to encrypt or decrypt the file
choice = input("Enter 'encrypt' or 'decrypt' to preform the respective operation on the selected file: ")

# Open the file
f = open(file_name, mode="rb")

# Read the file
data = f.read()

if choice == "encrypt":
# Generate random numbers for the LCG
seed = random.randint(1, 256)
a = random.randint(1, 256)
c = random.randint(1, 256)
modulus = random.randint(1, 256)

print(f"Seed: {seed}")
print(f"A: {a}")
print(f"C: {c}")
print(f"Modulus: {modulus}")

# Pad the file out with some filler bytes to obscure it's size
arr = bytearray(data)
arr += bytearray([0x41] * 1000)

save = bytearray()

# Encrypt the files contents with the LCG
for i in arr:
seed = (a * seed + c) % modulus
save.append(i ^ seed)

f.close()

# Write the encrypted file back to the disk
with open(f"{file_name}.enc", "wb") as binary_file:
binary_file.write(save)

elif choice == "decrypt":
seed = int(input("Seed: "))
a = int(input("A: "))
c = int(input("C: "))
modulus = int(input("Modulus: "))

# Remove the padding bytes
arr = bytearray(data[:len(data)-1000])

save = bytearray()

# Decrypt the files contents with the LCG
for i in arr:
seed = (a * seed + c) % modulus
save.append(i ^ seed)

# Write the encrypted file back to the disk
with open(f"{file_name}.dec", "wb") as binary_file:
binary_file.write(save)

很简单的LCG恢复参数题型,恢复完seed逐个异或回去即可,exp不小心删了,最后得到的是

1
2
3
4
5
6
It is super important that this flag be kept secret! I wouldn't want anyone to find it!!!
Thankfully my encryption scheme is simply IMPENETRABLE!!! MUHAHAHAHAHAHAHA

swampCTF{d0nt_l3ak_ur_k3ystr3am5}

Nobody will ever find this here!

Copper Crypto

task.py

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

from Crypto.Util.number import *

with open('flag.txt', 'rb') as fin:
flag = fin.read().rstrip()

pad = lambda x: x + b'\x00' * (500 - len(x))

m = bytes_to_long(pad(flag))

p = getStrongPrime(512)
q = getStrongPrime(512)

n = p * q
e = 3
c = pow(m,e,n)

with open('out.txt', 'w') as fout:
fout.write(f'n = {n}\n')
fout.write(f'e = {e}\n')
fout.write(f'c = {c}\n')
"""
n = 119604938096697044316047691964929805828918626075093639662825464535827900362132954794317391864822750976662931603966282850021396173045319251883406363073183189808699680701857953334587328906486229075428157995555693476599232724728486400143213284483622313607354815609215059406863340823255111036033446109329593686949
e = 3
c = 91149569482452486003218449809382430813144791805261257903556643652008332135606236690176360090659938752235745771493858775509562950906764411011689366104109528195425590415243479424000644174707030408431768079041029193109110970032733391052611637831168097556118005523386390422929265528589660737843901941464809893959
"""

可以写为
$$
c \equiv (flag\times pad)^e \mod n
$$

$$
flag^e \equiv c \times (pad^e)^{-1} \mod n
$$

这个填充可以枚举,然后开三次方即可

exp.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Util.number import *
import gmpy2

n = 119604938096697044316047691964929805828918626075093639662825464535827900362132954794317391864822750976662931603966282850021396173045319251883406363073183189808699680701857953334587328906486229075428157995555693476599232724728486400143213284483622313607354815609215059406863340823255111036033446109329593686949
e = 3
c = 91149569482452486003218449809382430813144791805261257903556643652008332135606236690176360090659938752235745771493858775509562950906764411011689366104109528195425590415243479424000644174707030408431768079041029193109110970032733391052611637831168097556118005523386390422929265528589660737843901941464809893959

for i in range(500):
pad = b"\x01" + b"\x00"*(500 - i)
pad = bytes_to_long(pad)
cc = c * gmpy2.invert(pad**3,n) % n
m = gmpy2.iroot(cc,3)
if m[1]:
print(long_to_bytes(m[0]))
break
# swampCTF{pycryp70d0m3_h45_4_p4dd1n6_func}
-------------已经到底啦!-------------