0%

2024-CISCN-Crypto-WP

古典密码:

Atbash -> base64 -> 栅栏:

AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9

直接CybeyChef就可以。

hash:

爆破用的必须得是Python2.7.

比较烦,就不想用itertools了,直接一个一个循环打吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import binascii
import hashlib
def to_bytes(i):return binascii.unhexlify(hex(i)[2:].zfill(2))

for i0 in range(255,-1,-1):
print(i0)
for i1 in range(256):
for i2 in range(256):
for i3 in range(256):
pt = to_bytes(i0)+to_bytes(i1)+to_bytes(i2)+to_bytes(i3) + b'\x01\x01\x01'
if str(hash(pt))[:4] == '7457':
for i4 in range(256):
pt = to_bytes(i0)+to_bytes(i1)+to_bytes(i2)+to_bytes(i3)+to_bytes(i4)+b'\x01\x01'
if str(hash(pt))[:13] == '7457312583301':
print 'finally!'
for i5 in range(256):
for i6 in range(256):
pt = to_bytes(i0)+to_bytes(i1)+to_bytes(i2)+to_bytes(i3)+to_bytes(i4)+to_bytes(i5)+to_bytes(i6)
if str(hash(pt)) == '7457312583301101235':
print int(hashlib.sha384(binascii.hexlify(pt)).hexdigest(), 16)

OvO:

e=65537+kp+(k+2)(p+1)(q+1)+1\ e=65537+(k+2)n+2(k+1)p+(k+2)q+k+3\ ep=65537p+(k+2)np+2(k+1) p^2+(k+2)n+(k+3)p\ 令k = e // 2 - 2

因为e的信息缺失,通过上式求根的办法只能得到q的高位,接下来还得利用q高位泄露的办法去解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
from Crypto.Util.number import *
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823

k = e//n-2
g = 65537 + (k+2)*n + (k+2) + 1
R.<x> = PolynomialRing(RealField(1024))
f = e*x - (2*(k+1)*x**2 + (k+2)*n + g*x)
MSBs = f.roots()
print(f'[+] MSB = {MSBs}')

for MSB in MSBs:
PR.<x> = PolynomialRing(Zmod(n))
print(f'[+] test = {int(MSB[0])}')
t = int(MSB[0])
f_= x+t
root = f_.small_roots(X=2**200,beta=0.4)
print(f'[+] find root = {root}')
try:
p = root[0]+t
if n%p==0:
print(f'[+] p={p}')
break
except:
pass

q = int(n//int(p))
phi = (q-1)*(p-1)
assert isPrime(int(k))
k = int(k)
print(f'k = {k}')
print(f'p = {p}')
print(f'q = {q}')
print(f'c = {c}')
#拿参数

解密:

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import *
p=9915449532466780441980882114644132757469503045317741049786571327753160105973102603393585703801838713884852201325856459312958617061522496169870935934745091
q=11287710353955888973017088237331029225772085726230749705174733853385754367993775916873684714795084329569719147149432367637098107466393989095020167706071637
n=q*p
c=14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
k = 331118458487559161870846961263454730637
e = 65537 + k*p + (k+2) * ((p+1) * (q+1)) + 1
phi = (q-1)*(p-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
#b'flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}'

Mouth:

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
from datetime import datetime, timedelta
from pickle import loads
from hashlib import md5
from requests import *
from math import floor
from libnum import n2s
import time
A = md5(b'A').hexdigest()[:16]
B = md5(b'B').hexdigest()[:16]
S = md5(b'S').hexdigest()[:16]
delta_8_hours = timedelta(hours=8)
url = 'http://8.147.131.163:15917'
token_A = A
token_B = B

def regist(url,token):
print(f'[+] use token : {token}')
prefix = '/register'
params = {'token':token}
result = get(url+prefix,params)
#cur_key_token
print(result.text)
cur_key = eval(result.text)["key_to_server"]
print(f'[+] get key : {cur_key}')
return cur_key
#时间少八小时
def send_msg(url,token,target_token,target,cur_key_token):
#source就是我们要控制的token
#cur_key_token = regist(url,token)
prefix = '/send_message'
#friend 也就是source由我们构造,之后通讯的cur_key,也是由我们构造,24秒内通过构造就行

timestamp_minus_8_hours = datetime.fromtimestamp(time.time()) - delta_8_hours
t = timestamp_minus_8_hours.timestamp()
#t = bytes.fromhex(hex(floor(t))[2:].zfill(32))
t = n2s(int(t)).rjust(16, b'0')
source = bytes.fromhex(target_token)
key = b'\x00' * 16
pad = b'\x00' * 8
msg = t + source + key + pad

Cipher = AES.new(bytes.fromhex(cur_key_token), AES.MODE_ECB)
message = Cipher.encrypt(msg) #记得传的时候是hex字符串
payload = message.hex()
assert len(payload) == 16 * 3 * 2
if not len(payload) == 16 * 3 * 2:print('?')
params = {'token':token,'to':target,'message':payload}
result = get(url+prefix,params)
return result.text

def send_flag(url,token):
prefix = '/send_flag'
params = {'token':token}
result = get(url+prefix,params)
return result.text

def exchange(url,token):
prefix = '/A_and_B'
params = {'token':token}
result = get(url+prefix,params)
return result.text

def view_history(url,token):
prefix = '/view_history'
params = {'token':token}
result = get(url+prefix,params)
return(result.text)

'''
#打法一,直接伪造A对B的发信密钥,让A和B交换一次会话密钥,用发信密钥解密,之后通话就随便监听了

A_key = regist(url,A)
#B_key = regist(url,B)

print(f'A_key={A_key}')
#print(f'B_key={B_key}')

exchange(url,A)
#view_history(A)
send_flag(url,A)
print(view_history(url,A))
'''
'''
#打法二,利用send_message函数去控制双方的会话密钥,强行让他们相等
A_key = regist(url,A)
send_msg(url,A,B,'A',A_Key)
send_msg(url,A,A,'B',A_Key)
send_flag(url,A)
print(view_history(url,A))
#凭记忆写的,可能流程不太对,大致这个思路能过,好处是直接一次性拿下会话密钥。
'''


#拿到密文之后,手动解一下密
'''
print(A)
key = '5fa11352bb62df887404c4da9a8357c9'
Cipher = AES.new(bytes.fromhex(key),AES.MODE_ECB)
orin_key_cipher = 'ad6c4e00649df28c1e89ea2c19ed49c8257e4cf9d66ed7b76fc76b17254fd5859c10b0c5983f4b3d35e78ac8d2649594'
print(bytes.fromhex(orin_key_cipher))
key_ = Cipher.decrypt(bytes.fromhex(orin_key_cipher))
print(key_)
print(key_[32: 48].hex())

key0 = 'b5768d25a0c3a76516136dc81e852300'
Cipher = AES.new(bytes.fromhex(key0),AES.MODE_ECB)
orin_cipher = '90ceb8ced60d9ed6d244edb9345505273ec51c9e32ff15bfd4bba14b0b1cbefdeb699c3a18affbf5fab5b91051f893f6'
flag = Cipher.decrypt(bytes.fromhex(orin_cipher))
print(flag)
'''

很烦,一开始做的时候用的send_message的接口,本地能通,远程的服务器根本通不了,原因在于time check这步,我们不知道服务器的时间,导致根本没办法主动去控制send_flag的会话密钥。经过测试,去调到服务器的时间也不行,不知道说什么好了。浪费时间。

EzRSA

证书是加密过的,要拿到泄露的信息有点麻烦。

先进函数库里面下Hook,把import key这个函数的解密拿来用,这样就不用造轮子去解析密钥了。

1
2
3
4
Python312\Lib\site-packages\Crypto\Util\asn1.py
在Class BytesIO_EOF里面的Read函数下个:
print(self._buffer[self._index:new_index].hex())
这样就能直接解析错误的证书。

接下来去爆解密的口令:

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
from tqdm import tqdm
#range(316999+166584,316999+166586)
for i in tqdm(range(100000,999999)):
try:
with open("priv.pem", "rb") as f:
data = f.read()
key = RSA.import_key(data, passphrase=str(i).encode())
except:
continue

直接在console里面看打出来的结果哪个正确就可以,经过二分查找得到口令483584

读密钥:

1
2
3
4
passw = b'483584'
with open("priv.pem", "rb") as f:
data = f.read()
key = RSA.import_key(data, passphrase=passw)

手动解析一下:

1
2
3
4
5
6
7
8
n = 0xa18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 0x010001
what = 0x6a033064c5a0dffc8f2363b340e502405f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
d_low = what>>512
p_q = what - (d_low<<512)
print(n)
print(d_low)
print(p_q)

具体手撕方案参考 : PEM与DER格式解析

撕完参考蓝帽杯的题:这个

直接抄脚本解就可以。

我感觉在做的是杂项,而不是密码

最后:

可信计算?三月七都不做。

可能太久没做题了,做的真不爽。