CUMTCTF第三次双月赛Writeup-crypto

五一假期期间举行CUMT第三次双月赛,一共五道密码题,我出的是后三道题。考虑到避免被锤17级18级同学,题目不是很难,但从实际情况来看,能全部做出来的队伍并不多。这里提供wp及一些出题思路

比赛平台219.219.61.234(需挂VPN)

古典密码签到

题目
6A757474616967796B68706D6A7972656361
key=63756D74

分析
在密文中发现6数字最多 —> ascii码中的16进制,转化密钥和密文
具有密钥的古典密码 —> 维吉尼亚

解密脚本

1
2
3
4
5
6
7
import binascii
m = '6A757474616967796B68706D6A7972656361'
c = '63756D74'
m = binascii.a2b_hex(m)
c = binascii.a2b_hex(c)
print(m)
print(c)

1
flag{hahayoufindtheflag}

现代密码签到

题目
zSLWE5Fk7Sg3mlltw9l2N7dhuADvk2HvWYU=
key=WTNWdGRHWnNZV2M9

分析
一时半会儿没看出这是个什么玩意儿…
key尝试两次base64发现是cumtflag
使用的是RC4对称密码加密,utf8编码,在线解密网站进行解密RC4解密

1
flag{CumT_D0uB13_MooN_cTf}

easyxor

出题的时候觉得不是很难,但题目放出一天后发现没有队伍做出,于是直接放出了关键一步的提示
Decryption is equivalent to continuing encryption

题目
enc.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import libnum
flag = 'flag{**************************}'

def crypt(n):
msg = libnum.s2n(n)
k = 0
for i in bin(msg)[2:]:
k = k << 1
if int(i):
k = k ^ msg
if k >> 256:
k = k ^ 0x10000000000000000000000000000000000000000000000000000000000000365L
return str(k)


print crypt(flag).encode('base64')

cipher.txt

1
2
MTEzNDkzNzQwMjcwNDkyMDg3MzgxNjE5MzYxMTAyMzExNjM1MTc3NTU0ODM0NTI2OTMyMTY0MDkw
MjgyNjM1ODU4NDE5MDczNjU1Njcw

分析
代码里同时有移位和异或容易被迷惑,但实际上解密过程只要利用crypt继续进行加密,再根据flag关键字进行爆破,稍微更改下代码就可以了

解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def crypt(msg):
k = 0
for i in bin(msg)[2:]:
k = k << 1
if int(i):
k = k ^ msg
if k >> 256:
k = k ^ 0x10000000000000000000000000000000000000000000000000000000000000365L
return k

flag = int(base64.b64decode('MTEzNDkzNzQwMjcwNDkyMDg3MzgxNjE5MzYxMTAyMzExNjM1MTc3NTU0ODM0NTI2OTMyMTY0MDkwMjgyNjM1ODU4NDE5MDczNjU1Njcw'))
for i in range(10000000):
flag = crypt(flag)
if '666c6167' == str(hex(flag))[2:10]:
print i
print hex(flag)[2:-1].decode('hex')

即可得到flag

1
flag{ec33f669d2d659e2bc27dbffdf}

encode

这个算是签到难度的题目,是adworld上的原题主要是懒,目的是想让还没怎么用过python的同学尝试写一下脚本&知道pyc是可以反编译(好吧室友说她是手算出来的…)

题目
1.pyc
运行出来是这样的

分析
作为脚本语言,只要拿到了pyc或者pyo相当于就拿到了源码。因此对pyc文件进行反编译,使用uncompyle6或者在线反编译

1
2
pip install uncompyle6
uncompyle6 crypto11.pyc

反编译代码

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

def encode1(ans):
s = ''
for i in ans:
x = ord(i) ^ 36
x = x + 25
s += chr(x)

return s


def encode2(ans):
s = ''
for i in ans:
x = ord(i) + 36
x = x ^ 36
s += chr(x)

return s


def encode3(ans):
return base64.b32encode(ans)


flag = ' '
print 'Please Input your flag:'
flag = raw_input()
final = 'UC7KOWVXWVNKNIC2XCXKHKK2W5NLBKNOUOSK3LNNVWW3E==='
if encode3(encode2(encode1(flag))) == final:
print 'correct'
else:
print 'wrong'

代码逻辑很清晰,三层加密一层一层逆运算

解密脚本

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

def decode1(ans):
s = ''
for i in ans:
i = chr((ord(i)-25)^36)
s += i
return s

def decode2(ans):
s = ''
for i in ans:
i = chr((ord(i)^36) - 36)
s += i
return s

def decode3(ans):
return base64.b32decode(ans)

flag = 'LOQ2NJFYU5YH2WTUU5VHJIDXLJNVW2LQO52WS2L6PVUVW2TQLJNVSWLJUBN3E==='

flag = decode3(flag)
flag = decode2(flag)
flag = decode1(flag)
print flag

1
flag{b38e7b57c2eff432044984f53efdd4cf}

RSA

考察RSA基本攻击方法及openssl证书格式,掌握基本openssl命令

题目
public.pem

1
2
3
4
5
6
7
8
9
-----BEGIN PUBLIC KEY-----
MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKBgQKBPJR+6zDQPEK6ZY+xAdHS
/Sw69BJG2IrKGOMQ7mk6vdpFlR0F2ZuqiYy6MEXG+KDv9yCrayeV0Yw+JwoNozIB
rTl74KXVk84FHmn6iYQceqtGjcb2frmkID0SBXgNBti1CNUOe/v6GeyXl0j3JPmn
B1wy9BldH3vSS9FJr6DGIwKBgQGtbGUOVzO5qyoOMo+/bdqnxqA4NHjUciH+GDaU
yKgjp4X47PFyHYc6HI0tyMmjxmo/nUXV7MTGVnk2lYoLuuSM8aNWyBgCdGf0bVxw
UtmMyDqr6Z7GL6djTSiUtWIyi0duMsGrPPxOTfZRkbVgj/r0OopZIDbc+zDxHsNU
wl2PXQ==
-----END PUBLIC KEY-----

flag.enc
flag.enc是使用公钥加密后的文件,需要私钥文件进行解密,Notepad打开后是乱码

分析
读取公钥命令

1
openssl rsa -pubin -text -modulus -in public.pem


明显e太大了,可知是wiener’s attack
在github上找到脚本

1
https://github.com/pablocelayes/rsa-wiener-attack

解出d的值为6355806618953128975353025351520924428881476657739441224888205915909580172245
需要自己写私钥证书对flag.enc进行解密

解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import math
import sys
from Crypto.PublicKey import RSA

keypair = RSA.generate(1024)

keypair.d = 6355806618953128975353025351520924428881476657739441224888205915909580172245

keypair.n = 450291682463471937994633961909225780739111573469355415549857153062096131780128537301094125311530341986868085649051979562164031270810233409398782674315229431165863308524798327389365660506329953669670981402058028057030562557523161350542930244129458811144567026261446438510035529368985188386448812933930064856611

keypair.e = 301551378389245888888469054776006575695350293556518354997081808339383084975027769316897489065835176847359431297124389026295666786219073195887657189709948336725694600924636831531927842364420562594497676000153230959659757547215533979542050631538309935222397525529633209216686332769439565646119704647425991741277

private = open('private.pem','w')
private.write(keypair.exportKey())
private.close()

1
openssl rsautl -decrypt -in flag.enc -inkey private.pem -out flag.txt

采用私钥文件private.pem来解密文件flag.enc,结果保存到flag.txt中
解得flag

1
flag{62fe8a611728ca62b6a7cba837abacae}

出题总结
事实上当 $\small \mathrm{p\geq 1024 bits\wedge q\geq 1024 bits} $ 时,n便不能被yafu和在线网站分解了,因此使用随机函数生成符合位数的p和q很重要

另附生成公钥代码

1
2
3
4
5
6
7
8
9
10
11
12
import math
import sys
from Crypto.PublicKey import RSA

keypair = RSA.generate(1024)

keypair.n = 450291682463471937994633961909225780739111573469355415549857153062096131780128537301094125311530341986868085649051979562164031270810233409398782674315229431165863308524798327389365660506329953669670981402058028057030562557523161350542930244129458811144567026261446438510035529368985188386448812933930064856611
keypair.e = 301551378389245888888469054776006575695350293556518354997081808339383084975027769316897489065835176847359431297124389026295666786219073195887657189709948336725694600924636831531927842364420562594497676000153230959659757547215533979542050631538309935222397525529633209216686332769439565646119704647425991741277

public = open('public.pem','w')
public.write(keypair.publickey().exportKey())
public.close()

-------------end ♥-------------