20230xGame

20230xGame——Crypto——Wp

!!!看看密码题的解答就好,其他方向是瞎做的

Week1

Crypto

BabyRSA

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
from Crypto.Util.number import *
from random import getrandbits
from secret import flag

def getN():
N = 1
for i in range(16):
tmp = getPrime(32)
N *= tmp
return N

mask = getrandbits(256)
e = 65537
n = getN()
m = bytes_to_long(flag)
c = pow(m*mask,e,n)
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
print(f'mask = {mask}')


'''
n = 93099494899964317992000886585964221136368777219322402558083737546844067074234332564205970300159140111778084916162471993849233358306940868232157447540597
e = 65537
c = 54352122428332145724828674757308827564883974087400720449151348825082737474080849774814293027988784740602148317713402758353653028988960687525211635107801
mask = 54257528450885974256117108479579183871895740052660152544049844968621224899247
'''

主要利用sagemath的factor函数,然后最后记得除mask

exp:

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

n = 93099494899964317992000886585964221136368777219322402558083737546844067074234332564205970300159140111778084916162471993849233358306940868232157447540597
c = 54352122428332145724828674757308827564883974087400720449151348825082737474080849774814293027988784740602148317713402758353653028988960687525211635107801
mask = 54257528450885974256117108479579183871895740052660152544049844968621224899247

phi = 1
for i in factor(n):
phi *= i[0] - 1

d = gmpy2.invert(65537,phi)
m1 = pow(c,d,n)
#m = m1 // mask
m = 334526535497992378634036751902245187892235112866317344720327978830278781
print(long_to_bytes(m))
#0xGame{Magic_M@th_Make_Crypt0}

有个店很怪,不能直接把m // mask,我的解决方法是把m打印出来,用数值进行相除

最后m =334526535497992378634036751902245187892235112866317344720327978830278781

Take my bag!

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

def encrypt(m):
m = str(bin(m))[2:][::-1]
enc = 0
for i in range(len(m)):
enc += init[i] * int(m[i]) % n
return enc

w = getPrime(64)
n = getPrime(512)
init = [w*pow(3, i) % n for i in range(512)]

c = encrypt(bytes_to_long(flag))

print(f'w={w}')
print(f'n={n}')
print(f'c={c}')

'''
w=16221818045491479713
n=9702074289348763131102174377899883904548584105641045150269763589431293826913348632496775173099776917930517270317586740686008539085898910110442820776001061
c=4795969289572314590787467990865205548430190921556722879891721107719262822789483863742356553249935437004378475661668768893462652103739250038700528111
'''

w已经给出,说明init已知

有$enc \equiv Init_1 \times m_1 + Init_2 \times m_2 + … + Init_n \times m_n \mod n$

构造格

最后记得逆序

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


w =
mod =
pubkey = [w*pow(3, i) % mod for i in range(512)]
c =


n = len(pubkey)

Ge = Matrix(ZZ,n+2,n+2)
for i in range(n):
Ge[i,i] = 1
Ge[i,-1] = pubkey[i]

Ge[-2,-2] = 1
Ge[-2,-1] = c
Ge[-1,-1] = mod


for i in Ge.LLL():
if i[-1] == 0:
tmp = i[:-2]
ans = ''
for j in tmp:
if abs(j) == 0:
ans += '0'
if abs(j) == 1:
ans += '1'

e = int(ans[::-1],2)
flag = long_to_bytes(e)
if b"0xGame" in flag:
print(flag)
#0xGame{Welc0me_2_Crypt0_G@me!#$&%}

密码,觅码,先有*再密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from secret import flag #从中导入秘密的flag,这是我们要破解的信息
from Crypto.Util.number import bytes_to_long #从函数库导入一些编码函数
from base64 import b64encode

flag = flag.encode()
lent = len(flag)
flag = [flag[i*(lent//4):(i+1)*(lent//4)] for i in range(4)]

c1 = bytes_to_long(flag[0])
c2 = ''.join([str(bin(i))[2:] for i in flag[1]])
c3 = b64encode(flag[2])
c4 = flag[3].hex()

print(f'c1?= {pow(c1,5)}\nc2 = {c2}\nc3 = {c3}\nc4 = {c4}')

'''
c1?= 2607076237872456265701394408859286660368327415582106508683648834772020887801353062171214554351749058553609022833985773083200356284531601339221590756213276590896143894954053902973407638214851164171968630602313844022016135428560081844499356672695981757804756591891049233334352061975924028218309004551
c2 = 10010000100001101110100010100111101000111110010010111010100001101110010010111111101000011110011010000001101011111110011010011000101011111110010110100110100000101110010010111101100101011110011110111100
c3 = b'lueggeeahO+8jOmCo+S5iOW8gOWni+aIkQ=='
c4 = e4bbace79a8443727970746fe68c91e68898e590a72121217d
'''
#全是乱码,那咋办嘛?

根据加密写解回去就行

最后会得到

0xGame{ \xe6\x81\xad\xe5\x96\x9c\xe4\xbd\xa0,\xe5\xb7\xb2\xe7\xbb\x8f\xe7\x90\x86\xe8\xa7\xa3\xe4\xba\x86\xe4\xbf\xa1\xe6\x81\xaf\xe6\x98\xaf\xe5\xa6\x82\xe4\xbd\x95\xe7\xbc\x96\xe7\xa0\x81\xe7\x9a\x84\xef\xbc\x8c\xe9\x82\xa3\xe4\xb9\x88\xe5\xbc\x80\xe5\xa7\x8b\xe6\x88\x91\xe4\xbb\xac\xe7\x9a\x84Crypto\xe6\x8c\x91\xe6\x88\x98\xe5\x90\xa7!!!}

加上一步decode()即可(一直以为flag是英文字母加数字,忘记了flag的内容可能是中文,中文进行encode()就会出现乱码),题目并不难,容易把他想难了。

exp:

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

c15 = 2607076237872456265701394408859286660368327415582106508683648834772020887801353062171214554351749058553609022833985773083200356284531601339221590756213276590896143894954053902973407638214851164171968630602313844022016135428560081844499356672695981757804756591891049233334352061975924028218309004551
m1 = gmpy2.iroot(c15,5)
c2 = "10010000100001101110100010100111101000111110010010111010100001101110010010111111101000011110011010000001101011111110011010011000101011111110010110100110100000101110010010111101100101011110011110111100"
m2 = int(c2,2)
c3 = b'lueggeeahO+8jOmCo+S5iOW8gOWni+aIkQ=='
m3 = b64decode(c3)
c4 = "e4bbace79a8443727970746fe68c91e68898e590a72121217d"
m4 = bytes.fromhex(c4)

flag = long_to_bytes(m1[0]) + long_to_bytes(m2) + m3 + m4
print(flag)
print(flag.decode())
#0xGame{ 恭喜你,已经理解了信息是如何编码的,那么开始我们的Crypto挑战吧!!!}

What’s CBC?

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 *
from secret import flag,key

def bytes_xor(a,b):
a,b=bytes_to_long(a),bytes_to_long(b)
return long_to_bytes(a^b)

def pad(text):
if len(text)%8:
return text
else:
pad = 8-(len(text)%8)
text += pad.to_bytes(1,'big')*pad
return text

def Encrypt_CBC(text,iv,key):
result = b''
text = pad(text)
block=[text[_*8:(_+1)*8] for _ in range(len(text)//8)]
for i in block:
tmp = bytes_xor(iv,i)
iv = encrypt(tmp,key)
result += iv
return result

def encrypt(text,key):
result = b''
for i in text:
result += ((i^key)).to_bytes(1,'big')
return result

iv = b'11111111'
enc = (Encrypt_CBC(flag,iv,key))
print(f'enc = {enc}')

#enc = b"\x8e\xc6\xf9\xdf\xd3\xdb\xc5\x8e8q\x10f>7.5\x81\xcc\xae\x8d\x82\x8f\x92\xd9o'D6h8.d\xd6\x9a\xfc\xdb\xd3\xd1\x97\x96Q\x1d{\\TV\x10\x11"

已知flag前7位是0xGame{,爆破1位求得tmp,再与密文前8位异或得到key = 143(可以加以检验)

得到key以后根据CBC的特点,用后一段密文和前一段密文异或即可得到明文

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

def bytes_xor(a,b):
a,b=bytes_to_long(a),bytes_to_long(b)
return long_to_bytes(a^b)

def encrypt(text,key):
result = b''
for i in text:
result += ((i^key)).to_bytes(1,'big')
return result

iv = b'11111111'
c = b"\x8e\xc6\xf9\xdf\xd3\xdb\xc5\x8e8q\x10f>7.5\x81\xcc\xae\x8d\x82\x8f\x92\xd9o'D6h8.d\xd6\x9a\xfc\xdb\xd3\xd1\x97\x96Q\x1d{\\TV\x10\x11"

# for i in range(256):
# m = b"0xGame{" + long_to_bytes(i)
# tmp = bytes_xor(iv,m)
# key = tmp[0] ^ c[0]
# cc = encrypt(tmp,key)
# if cc == c[:8]:
# print(m) #0xGame{0
# print(key) #143

key = 143

block=[c[_*8:(_+1)*8] for _ in range(len(c)//8)]
block = block[::-1]

m = []
for i in range(len(block)-1):
tmp = encrypt(block[i],key)
mm = bytes_xor(tmp,block[i+1])
m.append(mm)

m = m[::-1]
flag = b"0xGame{0" + b"".join(m)
print(flag)
#0xGame{098f6bcd4621d373cade4e832627b4f6}

猜谜

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
from secret import flag,key

def enc(text):
code = 'AP3IXYxn4DmwqOlT0Q/JbKFecN8isvE6gWrto+yf7M5d2pjBuk1Hh9aCRZGUVzLS'
text = ''.join([str(bin(i))[2:].zfill(8) for i in text])
length = len(text)
pad = b''
if length%3 == 1:
text += '00'
pad = b'=='
elif length%3 == 2:
text += '0'
pad = b'='
result = [code[int(text[3*i:3*(i+1)],2)] for i in range(0,len(text)//3)]
return ''.join(result).encode()+pad

def encrypt(flag):
result = b''
for i in range(len(flag)):
result += (key[i%7]^(flag[i]+i)).to_bytes(1,'big')
return result


c = enc(encrypt(flag))
print(f'c = {c}')

'''
c = b'IPxYIYPYXPAn3nXX3IXA3YIAPn3xAYnYnPIIPAYYIA3nxxInXAYnIPAIxnXYYYIXIIPAXn3XYXIYAA3AXnx='
'''

仔细阅读代码,注意一些细节

先通过c恢复出encrypt(flag),再通过部分encrypt(flag)和已知明文0xGame{求得key

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

c = 'IPxYIYPYXPAn3nXX3IXA3YIAPn3xAYnYnPIIPAYYIA3nxxInXAYnIPAIxnXYYYIXIIPAXn3XYXIYAA3AXnx'
code = 'AP3IXYxn4DmwqOlT0Q/JbKFecN8isvE6gWrto+yf7M5d2pjBuk1Hh9aCRZGUVzLS'

enc = []
for i in c:
enc.append(bin(code.index(i))[2:].zfill(3))

text = ''.join(enc)

block = [text[8*i:8*(i+1)] for i in range(len(text) // 8)]
print(block)

m = b"0xGame{"
key = []
for i in range(7):
kk = int(block[i],2) ^ (m[i] + i)
key.append(kk)

print(key)
flag = ""
for i in range(len(block)):
mm = (key[i%7] ^ (int(block[i],2))) - i
flag += chr(mm)

print(flag)
#0xGame{Kn0wn_pl@intext_Att@ck!}

Vigenere

1
密文:0dGmqk{79ap4i0522g0a67m6i196he52357q60f} 古老而神秘的加密方式?

根据0xGame对应0dGmqk,获得key=GAMEG,解密后发现不对,于是猜key=GAMEGAME

Reverse

数字筑基

丢到ida,shift+F12,得到flag:0xGame{5f4812eb-6dee-46ab-9910-92af643cd911}

代码金丹

同上,0xGame{620bbfcb-e56f-4e6d-8069-9587e066130a}

网络元婴

打开ida,发现很多数字,而且数值基本都在ASCII码表中,所以直接转ASCII拼接即可

解释一下v3 = 0i64;的作用:将变量 v3 设置为一个 64 位整数类型的复数,值为 0。

程序根本看不懂

虚拟化神

55行打个断点进行动调

发现v11里就是flag

赛博天尊

用z3解这个方程组,然后转16进制拼接

exp:

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

v7,v8,v9,v10,v11=BitVec('v7',64),BitVec('v8',64),BitVec('v9',64),BitVec('v10',64),BitVec('v11',64)
ans = Solver()
ans.add(7 * v9 + 5 * (v8 + v11) + 2 * (v10 + 4 * v7) == 0x12021DE669FC2)
v4 = v9 + v10 + 2 * v10 + 2 * (v11 + v7)
ans.add(v10 + v9 + v11 + 2 * v9 + 2 * (v9 + v11 + 2 * v9) + 2 * (v8 + 4 * v7) == 0xACE320D1250)
ans.add(v8 + 2 * (v7 + v11 + v9 + 2 * v10) == 0x733FFEB3A4FA)
ans.add(v8 + 7 * v11 + 8 * (v9 + v10) + 5 * v7 == 0x1935EBA54EB28)
ans.add(v8 + 2 * v4 + v4 == 0x159BFFC17D045)
if ans.check()==sat:
data=ans.model()
# print(data)

v8 = 14810
v11 = 63356652901730
v9 = 16488
v7 = 2693650760
v10 = 41791
print('0xGame{'+hex(v7)[2:]+'-'+hex(v8)[2:]+'-'+hex(v9)[2:]+'-'+hex(v10)[2:]+'-'+hex(v11)[2:]+'}')
#0xGame{a08dd948-39da-4068-a33f-399f5eca5562}

因为v7,v8,v9,v10,v11是64bit的,所以用BitVec('v7',64)

Week2

Crypto

What’s CRT?

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 secert import flag

m = bytes_to_long(flag)
e = 260792700
q,p,q_,p_ = [getPrime(512) for _ in range(4)]
gift = [q+p,q_+p_]
n,n_ = q*p,q_*p_
mq_ = pow(m,4,q_)
mp_ = pow(m,4,p_)
c = pow(m,e,n)

print(f'mygift={gift}\nmq_={mq_}\nmp_={mp_}\nn={n}\nn_={n_}\nc={c}')
'''
mygift=[15925416640901708561793293991573474917595642805739825596593339102414328214313430010166125066639132916608736569443045051644173933089503934675628814467277922, 18342424676996843423829480445042578097182127446865571536445030052846412665700132683433441858073625594933132038175200824257774638419166516796318527302903098]
mq_=6229615098788722664392369146712291169948485951371133086154028832805750551655072946170332335458186479565263371985534601035559229403357396564568667218817197
mp_=7514598449361191486799480225087938913945061715845128006069296876457814528347371315493644046029376830166983645570092100320566196227210502897068206073043718
n=63329068473206068067147844002844348796575899624395867391964805451897110448983910133293450006821779608031734813916287079551030950968978400757306879502402868643716591624454744334316879241573399993026873598478532467624301968439714860262264449471888606538913071413634346381428901358109273203087030763779091664797
n_=84078907800136966150486965612788894868587998005459927216462899940718213455112139441858657865215211843183780436155474431592540465189966648565764225210091190218976417210291521208716206733270743675534820816685370480170120230334766919110311980614082807421812749491464201740954627794429460268010183163151688591417
c=12623780002384219022772693100787925315981488689172490837413686188416255911213044332780064192900824150269364486747430892667624289724721692959334462348218416297309304391635919115701692314532111050955120844126517392040880404049818026059951326039894605004852370344012563287210613795011783419126458214779488303552
'''

通过两组$p+q = gift$和$p \times q = n$,解方程把p,q求出

这样有4组等式

$m_p \equiv m^e \mod p$

$m_p \equiv m^e \mod p$

$m_{p’} \equiv m^e \mod p’$

$m_{q’} \equiv m^e \mod q’$

解中国剩余定理就行

在求解过程会发现e = 260792700p-1以及q-1分别存在公因数4

处理一下$\because c \equiv m^e \mod n$,$ed \equiv 1 \mod \phi(n)$

因为$e$和$\phi(n)$存在公因数,设为$t$,把$e$除去$t$,即$e’ = \frac{t}{e}$,所以上式可化为$c \equiv (m^t)^{e’} \mod n$,这样$e’$和$\phi(n)$就可以求逆元了

对于上式,我们就可以得到$c \equiv (m^4)^{e’} \mod p$,模$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
37
from Crypto.Util.number import *
import gmpy2
from sympy.ntheory.modular import crt

p = 8237763448327424871950828228273863325587732991938648753016149761004918521337676972763871570006722552014080958105888713975090350689060892327170546305946879
q = 7687653192574283689842465763299611592007909813801176843577189341409409692975753037402253496632410364594655611337156337669083582400443042348458268161331043
c = 12623780002384219022772693100787925315981488689172490837413686188416255911213044332780064192900824150269364486747430892667624289724721692959334462348218416297309304391635919115701692314532111050955120844126517392040880404049818026059951326039894605004852370344012563287210613795011783419126458214779488303552
e = 260792700

def decrypt(c,e,phi,n):
t = gmpy2.gcd(e,phi)
if t != 1:
print(t)
e1 = e // t
d = gmpy2.invert(e1,phi)
m = pow(c,d,n)
return m
else:
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
return m


mp = decrypt(c,e//4,p-1,p)
mq = decrypt(c,e//4,q-1,q)

p_ = 8991690869897246321907509983425307437365288417861457732721314572165773880898701105065818281248373676758405021157703190132511219384704650086565345885727777
q_ = 9350733807099597101921970461617270659816839029004113803723715480680638784801431578367623576825251918174727017017497634125263419034461866709753181417175321
mq_ = 6229615098788722664392369146712291169948485951371133086154028832805750551655072946170332335458186479565263371985534601035559229403357396564568667218817197
mp_ = 7514598449361191486799480225087938913945061715845128006069296876457814528347371315493644046029376830166983645570092100320566196227210502897068206073043718

N = [p,q,p_,q_]
C = [mp,mq,mp_,mq_]
M4 = crt(N,C)[0]
flag = long_to_bytes(gmpy2.iroot(M4,4)[0])
print(flag)
#0xGame{7881ed67088e9f72b860f8c376599785}

中间的那个人

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
from secret import flag
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import sha256
from random import *

p = getPrime(128)
g = 2
A = getrandbits(32)
B = getrandbits(32)

Alice = pow(g,A,p)
Bob = pow(g,B,p)
key = pow(Alice,B,p)
key = sha256(long_to_bytes(key)).digest()

iv = b"0xGame0xGameGAME"
aes = AES.new(key, AES.MODE_CBC, iv)
enc = aes.encrypt(flag)
print(f'g={g}\np={p}') #we tell
print(f'Bob={Bob}') #Bob tell
print(f'Alice={Alice}') #Alice tell

print(f'enc={enc}')#Here is they secret

'''
g=2
p=250858685680234165065801734515633434653
Bob=33067794433420687511728239091450927373
Alice=235866450680721760403251513646370485539
enc=b's\x04\xbc\x8bT6\x846\xd9\xd6\x83 y\xaah\xde@\xc9\x17\xdc\x04v\x18\xef\xcf\xef\xc5\xfd|\x0e\xca\n\xbd#\x94{\x8e[.\xe8\xe1GU\xfa?\xda\x11w'
'''

因为

1
2
3
Alice = pow(g,A,p)
Bob = pow(g,B,p)
key = pow(Alice,B,p)

发现$p-1$光滑,而且不大,直接解离散对数$Bob \equiv g^B \mod p$

然后通过key和iv解AES

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
from Crypto.Cipher import AES
from Crypto.Util.number import *
from hashlib import sha256

def Hellman(h, g, N, p, qi):
h = pow(h, N//qi, p)
g = pow(g, N//qi, p)
ai = discrete_log(mod(h,p), mod(g,p))
return int(ai)

g = 2
p = 250858685680234165065801734515633434653
B = 33067794433420687511728239091450927373
A = 235866450680721760403251513646370485539
enc=b's\x04\xbc\x8bT6\x846\xd9\xd6\x83 y\xaah\xde@\xc9\x17\xdc\x04v\x18\xef\xcf\xef\xc5\xfd|\x0e\xca\n\xbd#\x94{\x8e[.\xe8\xe1GU\xfa?\xda\x11w'
iv = b"0xGame0xGameGAME"

x = discrete_log(mod(B,p),mod(g,p))
print(x)
print(B == pow(g,x,p))
# x = 1620639479
# True
key = pow(A,x,p)
key = sha256(long_to_bytes(int(key))).digest()
aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(enc)
print(flag)
#0xGame{51393fe1fd5fc2df1bf018d06f0fa11d}\x08\x08\x08\x08\x08\x08\x08\x08

Fault!Fault!

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
113
114
115
116
117
118
119
120
121
122
123
from Crypto.Util.number import *
import socketserver
import signal
from secret import flag
import random
import os
import string
from hashlib import sha256
from string import ascii_uppercase
from random import shuffle,choice,randint
import os


q = getPrime(512)
p = getPrime(512)
e = 65537
n = q*p
phi = (q-1)*(p-1)
d = inverse(e,phi)

def decrypt(c,d,n,index):
"""something go wrong"""
d_ = d^(1<<(index))
m_ = pow(c,d_,n)
return str(m_)

MEMU = """
Welc0me_2_0xGame2023!
/----------------------------\\
| options |
| [S]ign |
| [F]ault injection |
| [C]heck answer |
\\---------------------------/
"""


class Task(socketserver.BaseRequestHandler):
def proof_of_work(self):
'''验证函数'''
random.seed(os.urandom(8))
proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
_hexdigest = sha256(proof.encode()).hexdigest()
self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
return False
return True

def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass

def recv(self, prompt=b'> '):
self.send(prompt, newline=False)
return self._recvall()

def timeout_handler(self, signum, frame):
raise TimeoutError

'''以上是交互部分'''
def handle(self):
'''题干'''
signal.signal(signal.SIGALRM, self.timeout_handler)
signal.alarm(300)
self.send(MEMU)
if not self.proof_of_work():
self.send(b'[!] Wrong!')
return

self.send(MEMU.encode())
while True:
code = self.recv()
if code == b'S':
self.send(b'What you want to sign?:')
m = bytes_to_long(self.recv())
c = pow(m,e,n)
self.send(f'{n}\n{e}\n{c}'.encode())

elif code == b'F':
self.send(b'Give me the Signatrue:')
Signatrue = int(self.recv())
self.send(b'Where you want to interfere?')
index = int(self.recv())
self.send(b'The decrypt text:')
self.send(decrypt(Signatrue,d,n,index).encode())

elif code == b'C':
self.send(b'Give me the private key:')
ans = int(self.recv())
if ans == d:
self.send(b'Here is your flag:')
self.send(flag)

else:
self.send(b'invaild input')

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass

if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 10005
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()

Fault Injection

因为decrypt()返回$m{’} = c^{d’} \mod n$,d_ = d^(1<<(index)),说明$d$只有第$index$位受到影响,$0 \le index \le 1024$

如果$d$的第$index$位本来是1,那么,异或之后,$d’ = d - 2^{index}$

如果$d$的第$index$位本来是0,那么,异或之后,$d’ = d + 2^{index}$

因为,$m \equiv c^d \mod n$,如果用$d’$解密的话

$m’ \equiv c^{d’} = c^{d + 2^{index}} = c^{d} \times c^{2^{index}} \equiv m \times c^{2^{index}}\mod n$

或者$m’ \equiv c^{d’} = c^{d - 2^{index}} = c^{d} \times c^{-2^{index}} \equiv m \times c^{-2^{index}}\mod n$

对于上面式子,左右同乘$m$模$n$的逆元得到

$m’\times m^{-1} \equiv c^{2^{index}} \mod n$,或者$m’\times m^{-1} \equiv c^{-2^{index}} \mod n$

所以,我们可以通过$m’ \times m^{-1}$的值与$c^{2^{index}}$对比,来判断d的每一位是1还是0

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
72
73
74
75
76
from Crypto.Util.number import *
from itertools import product
from tqdm import *
from pwn import *
import string
import hashlib
import gmpy2

table = string.ascii_letters + string.digits

host = '43.139.107.237'
port = 10005

GeShi = b'[+] Plz tell me XXXX: '
sh = remote(host,port)

data = sh.recvuntil(GeShi).decode()

proof = data.split('sha256')[1]


Xnum = proof.split('+')[0].upper().count("X")
tail = proof.split('+')[1].split(')')[0].strip()
hash = proof.split('+')[1].split(')')[1].split('==')[-1].split('[')[0].strip()

print("未知数:",Xnum)
print(tail)
print(hash)
print("开始爆破")
for i in product(table,repeat=Xnum):
head = ''.join(i)
t = hashlib.sha256((head + tail).encode()).hexdigest()
if t == hash:
print('爆破成功!结果是:', end='')
print(head)
sh.send(head.encode())
break

print("以下是提交完XXXX之后的流程\n")
data = sh.recvuntil(b">")
sh.sendline(b"S")
message = b"flag{ABCDEFGHIJKLMNOPQRSTUVWXYZ}"
m = bytes_to_long(message)
sh.sendline(message)
sh.recvline()
n = int(sh.recvline().decode().split(' ')[1].split('\n')[0])
print("n =",n)
e = sh.recvline().decode().split('\n')[0]
print("e =",e)
c = int(sh.recvline().decode().split('\n')[0])
print("c =",c)
d = ''
for i in trange(1024):
sh.sendline(b"F")
sh.recvline()
# print(sh.recvline().decode().split('\n')[0])
sh.sendline(str(c).encode())
sh.recvline()
# print(sh.recvline().decode().split('\n')[0])
sh.sendline(str(i).encode())
sh.recvline()
m_ = int(sh.recvline().decode().split('\n')[0])
# print(m_)
C = m_ * gmpy2.invert(m,n) % n
if C == pow(c,2**i,n):
d += "0"
else:
d += '1'
print("d = ",d)
if (pow(c,int(d[::-1],2),n) == m):
break

sh.sendline('C')
sh.sendline(str(int(d[::-1],2)).encode())
sh.interactive()
#0xGame{F@ult_Milest0ne!!}

EzLFSR

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

assert flag == b'0xGame{'+secret+b'}'

def make_mask(m):
tmp = str(bin(bytes_to_long(m)))[2:].zfill(128)
return tmp

def string2bits(s):
return [int(b) for b in s]

def bits2string(bs):
s = [str(b) for b in bs]
return ''.join(s)

def lfsr(state, mask):
assert(len(state) == 128)
assert(len(mask) == 128)

output = 0
for i in range(128):
output = output ^ (state[i] & mask[i])

return output

if __name__ == '__main__':
initState = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
secret = make_mask(secret)
mask = string2bits(secret)

for b in secret: assert(b == '0' or b == '1')
assert(len(secret) == 128)

for i in range(256):
state = initState[i:]
output = lfsr(state, mask)
initState += [output]

outputState = bits2string(initState[128:])
print('outputState =', outputState)

'''
outputState = 1101111111011101100001000011111101001000111000110100010011110111010011100110100100111001101010110110101110000011110101000110010010000011111111001111000110111001100111101110010100100001101001111110001010000100111101011011100010000000100000100000100111010110
'''

^可以当作是模2下的加法运算,&当作乘法运算

假设每次输出作为$R_i$,$S_0$表示state[i],$m_i$表示二进制secret的每一位

则$R_1 = S_0 \times m_0 + … +S_{127}\times m_{127} \mod 2$,$R_2 = S_1 \times m_0 +… +R_{1} \times m_{127} \mod 2$

$R_{128} = S_{127}\times m_0 + … + R_{127}\times m_{127} \mod 2$

写成矩阵形式:

左边矩阵已知,右边向量已知,用sagemath解矩阵方程即可

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#sage
R = "1101111111011101100001000011111101001000111000110100010011110111010011100110100100111001101010110110101110000011110101000110010010000011111111001111000110111001100111101110010100100001101001111110001010000100111101011011100010000000100000100000100111010110"
S = [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0]
R = [i for i in R]
S = S + R

A = []

for i in range(128):
s = S[i:i+128]
A.append(s)

A = Matrix(Zmod(2),A)
B = vector(Zmod(2),R[:128])
M = A.solve_right(B)
print(M)
m = ''
for i in M:
m += str(i)

flag = b"0xGame{" + bytes.fromhex(hex(int(m,2))[2:]) + b"}"
print(flag)
#0xGame{Rec0ver_the_M@sk}

EzRSA

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from challenges.challenge1 import RSAServe as challenge1
from challenges.challenge2 import RSAServe as challenge2
from challenges.challenge3 import RSAServe as challenge3
from secret import flag
import random
import os
import string
from hashlib import sha256
from string import ascii_uppercase
from random import shuffle,choice,randint
import os
import socketserver
import signal


SCORE = [0, 0, 0]
BANNER = """
____ ____ _
| _ \/ ___| / \
| |_) \___ \ / _ \
| _ < ___) / ___ \
|_| \_\____/_/ \_\

Here are four challenges(1, 2, 3), solve them all then you can get flag.
"""
MEMU = """
/----------------------------\\
| options |
| 1. get public key |
| 2. get cipher text |
| 3. check |
\\---------------------------/
"""

class Task(socketserver.BaseRequestHandler):
def proof_of_work(self):
'''验证函数'''
random.seed(os.urandom(8))
proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
_hexdigest = sha256(proof.encode()).hexdigest()
self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
return False
return True

def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass

def recv(self, prompt=b'> '):
self.send(prompt, newline=False)
return self._recvall()

def timeout_handler(self, signum, frame):
raise TimeoutError

def Serve(self, S):
self.send(MEMU.encode())
while True:
option = self.recv()
if option == b'1':
pubkey = S.pubkey()
for s in pubkey:
self.send(str(s).encode())
elif option == b'2':
c = S.encrypt()
self.send(c.encode())
elif option == b'3':
usr_answer = self.recv(b"input your answer: ")
return S.check(usr_answer)
else:
self.send(b"invaild option")

def handle(self):
signal.signal(signal.SIGALRM, self.timeout_handler)
signal.alarm(300)
if not self.proof_of_work():
self.send(b'[!] Wrong!')
return
self.send(BANNER.encode())
while True:
self.send(f'your score {sum(SCORE)}'.encode())
if sum(SCORE) == 3:
self.send(f"here are flag:{flag}".encode())
break
self.send(b'select challange{1,2,3}')#
code = self.recv()
if code == b'1':
S = challenge1()
res = self.Serve(S)
if res == True:
SCORE[0] = 1
self.send(b'Conguration!You are right!')
elif code == b'2':
S = challenge2()
res = self.Serve(S)
if res == True:
SCORE[1] = 1
self.send(b'Conguration!You are right!')
elif code == b'3':
S = challenge3()
res = self.Serve(S)
if res == True:
SCORE[2] = 1
self.send(b'Conguration!You are right!')
else:
self.send(b'invaild input')


class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass


class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass


if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 10006
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()

challenge1

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

class RSAServe:
def __init__(self) -> None:
self.e = 65537
self.p = getPrime(1024)
self.q = getPrime(1024)
self.n = self.q*self.p
self.g, self.r1 = [random.randint(1, self.q*self.p) for _ in range(2)]
self.gift = pow(self.g, self.r1 * (self.p - 1), self.n)
self.m = b"Fermat's little theorem"

def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_, self.e, self.p*self.q)
return hex(c)

def check(self, msg):
return msg == self.m

def pubkey(self):
return self.p*self.q, self.e

费马定理

$\because gift \equiv g^{r_1(p-1)} \mod n \longrightarrow gift \equiv 1 \mod p$

$\therefore gift - 1 = kp$

gift - 1n的公因数得到p

challenge2

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

class RSAServe:
def __init__(self) -> None:
self.e = 65537
self.m = b'EzFactor'
self.p = self.GetMyPrime(1024)
self.q = self.GetMyPrime(1024)

def GetMyPrime(self,bits):
while True:
n = 2
while n.bit_length() < bits:
a = choice(sieve_base)
n *= a
if isPrime(n + 1):
return n + 1

def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_, self.e, self.p*self.q)
return hex(c)

def check(self, msg):
return msg == self.m

def pubkey(self):
return self.p*self.q, self.e

GetMyPrime函数知道,$p-1$和$q-1$都很光滑

challenge3

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
from Crypto.Util.number import *
from random import choice
from sympy import *
class RSAServe:
def __init__(self) -> None:
self.e = 65537
self.m = b'Continued fraction'
self.p = getPrime(896)
self.n1 = self.getN()
self.n2 = self.getN()

def getN(self):
q = getPrime(128)
self.p = nextprime(self.p)
return q*self.p

def encrypt(self):
m_ = bytes_to_long(self.m)
c = pow(m_, self.e, self.n2)
return hex(c)

def check(self, msg):
return msg == self.m

def pubkey(self):
return self.n1, self.n2 , self.e

$\because p_1 < p_2$且$p_1 \approx p_2$,$\therefore \frac{n_1}{n_2} \approx \frac{q_1}{q_2}$

连分数展开就有可能得到$q_2$

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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from Crypto.Util.number import *
from itertools import product
from pwn import *
import string
import hashlib
import gmpy2

def smooth(N):
a = 2
n = 2
while True:
a = pow(a, n, N)
res = gmpy2.gcd(a - 1, N)
if res != 1 and res != N:
return res
n += 1

#展开为连分数列表
def continuedFra(x, y):
cF = []
while y:
cF += [x // y]
x, y = y, x % y
return cF
#将当前连分数列表计算成有理分数
def Simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)
#将连分数列表变成不同的有理数逼近列表
def getit(c):
cf=[]
for i in range(1,len(c)):
cf.append(Simplify(c[:i]))
return cf

def decrypt3(n1, n2,c):
cf = continuedFra(n1, n2)
for (q2,q1) in getit(cf): #前面一个参数是分母
try:
if n2 % q2 == 0 and q2 != 1:
p2 = n2 // q2
d = gmpy2.invert(65537,(p2-1)*(q2-1))
m = pow(c,d,n2)
message = long_to_bytes(m)
return message
except:
continue

def getflag1():
sh.send(b"1")
sh.recvuntil(b">").decode()
sh.send(b"1")
n = int(sh.recvline().decode())
e = int(sh.recvline().decode())
gift = int(sh.recvline().decode())
sh.recvuntil(b">")
sh.sendline(b"2")
c = int(sh.recvline().decode().split(' ')[1],16)
p = gmpy2.gcd(n,gift - 1)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
message = long_to_bytes(m)
print("m1 =",message)
sh.recvuntil(b">")
sh.send(b"3")
sh.send(message)
#Fermat's little theorem?

def getflag2():
sh.send(b"2")
sh.recvuntil(b">").decode()
sh.send(b"1")
n = int(sh.recvline().decode())
e = int(sh.recvline().decode())
sh.recvuntil(b">")
sh.sendline(b"2")
c = int(sh.recvline().decode().split(' ')[1],16)
p = smooth(n)
q = n // p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
message = long_to_bytes(m)
print("m2 =",message)
sh.recvuntil(b">")
sh.send(b"3")
sh.send(message)
#EzFactor!

def getflag3():
sh.send(b"3")
sh.recvuntil(b">").decode()
sh.send(b"1")
n1 = int(sh.recvline().decode())
n2 = int(sh.recvline().decode())
e = int(sh.recvline().decode())
sh.recvuntil(b">")
sh.sendline(b"2")
c = int(sh.recvline().decode().split(' ')[1],16)
message = decrypt3(n1,n2,c)
print("m3 =",message)
sh.recvuntil(b">")
sh.send(b"3")
sh.send(message)
#Continued fractionnnn

table = string.ascii_letters + string.digits

host = '43.139.107.237' #ip地址
port = 10006 #端口

GeShi = b'[+] Plz tell me XXXX: ' # 改格式!
sh = remote(host,port) #建立连接

data = sh.recvuntil(GeShi).decode()

proof = data.split('sha256')[1]

Xnum = proof.split('+')[0].upper().count("X") #要爆破的数量
tail = proof.split('+')[1].split(')')[0].strip()
hash = proof.split('+')[1].split(')')[1].split('==')[-1].split('[')[0].strip()

print("未知数:",Xnum)
print(tail)
print(hash)
print("开始爆破")
for i in product(table,repeat=Xnum):
head = ''.join(i)
t = hashlib.sha256((head + tail).encode()).hexdigest()
if t == hash:
print('爆破成功!结果是:', end='')
print(head)
sh.send(head.encode())
break

print("以下是提交完XXXX之后的流程\n")

sh.recvuntil(b">")
getflag1()
print("challenge1完成!")
sh.recvuntil(b">")
getflag2()
print("challenge2完成!")
sh.recvuntil(b">")
getflag3()
print("challenge3完成!")

sh.interactive()
#0xGame{a1425c9ce44989ffd64968130ee2f9fd}

Re

符文解密师

shift + F12秒了

编码逆旅者

网站反编译得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11

import binascii

def main():
flag = binascii.unhexlify(hex(0x307847616D657B63646539646331372D356133312D356330612D646633342D3663373562373634366334627D)[2:].encode())
user_input = input('请输入一个秘密的数字:')
if not len(user_input) != 13 or user_input.isdigit():
print('无效输入。必须是13位数字。')
return None
if None == '1145141919810':
print(f'''真理的旗帜:{flag}''')
return None
None('秘密的数字错误!')

if __name__ == '__main__':
main()
return None

运行得到0xGame{cde9dc17-5a31-5c0a-df34-6c75b7646c4b}

码海舵师

密文MHhHYW1le2ZjYmVlZWM3LTc3NTgtYmEyZi1jMDU5LTJmNWNhOWEzODc5YX0=

base64解码0xGame{fcbeeec7-7758-ba2f-c059-2f5ca9a3879a}

注册侦探——复现

win + R 进入regedit,创建注册表

然后运行程序即可获得flag

有个问题想问大佬们,为什么我的ida无法把中文反编译出来

pwn

cal

exp:

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

host = "8.130.35.16"
port = 55001

sh = remote(host,port)

sh.recvline()

for i in range(100):
sh.recvline()
data = sh.recvuntil(b"=").decode().strip('=').split("+")
a = int(data[0])
b = int(data[1])
message = a+b
sh.sendline(str(message).encode())
sh.recvline()

print(sh.recvline().decode())
sh.sendline(b"cat flag")
print(sh.recvline().decode())
#0xGame{edf1f8de-66cc-43d5-9a30-9067371ca77a}

Week3

Crypto

EzECC

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

flag = b'0xGame{' + msg + b'}'

q = getPrime(80)
a,b= [random.randrange(1,q-1) for i in range(2)]

def add(P,Q):
if P[0] != Q[0] and P[1] != Q[1]:
t = ((Q[1]-P[1]) * inverse(Q[0]-P[0],q)) %q
else:
t = ((3*P[0]*P[0]+a) * inverse(2*P[1],q))%q

x3 = t*t - P[0] - Q[0]
y3 = t*(P[0] - x3) - P[1]
return (x3%q, y3%q)

def mul(t, A, B=0):
if not t: return B
return mul(t//2, add(A,A), B if not t&1 else add(B,A) if B else A)

assert len(msg)%2==0
m1=bytes_to_long(msg[:len(msg)//2])
m2=bytes_to_long(msg[len(msg)//2:])

k = random.getrandbits(64)
G = (641322496020493855620384 , 437819621961768591577606)
K = mul(k,G)

M = (m1,m2)
r = random.getrandbits(16)

C_1 = add(M,mul(r,K))
C_2 = mul(r,G)

print(f'q={q}\na={a}\nb={b}\n')
print(f'G = {G}\nK = {K}\nC_1={C_1}\nC_2={C_2}')

'''
q=1139075593950729137191297
a=930515656721155210883162
b=631258792856205568553568

G = (641322496020493855620384, 437819621961768591577606)
K = (781988559490437792081406, 76709224526706154630278)
C_1=(55568609433135042994738, 626496338010773913984218)
C_2=(508425841918584868754821, 816040882076938893064041)
'''

出题人用python实现了椭圆曲线的加法和乘法

$\because C_2 = r\times G$,$C_1 = M + rK$

$\therefore M = C_1 - rK$

所以我们先求出$r$,然后用减法求$M$,这里需要注意的是利用题目给的add(P,Q)函数,传入add(C_1,-rK)即可实现减法

而$-rK$和$rK$的关系是$x_{-rK} = x_{rK}$,$y_{-rK} = -y_{rK} \mod q$

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

q = 1139075593950729137191297
a = 930515656721155210883162
b = 631258792856205568553568
E = EllipticCurve(GF(q),[a,b])

G = E(641322496020493855620384, 437819621961768591577606)
K = E(781988559490437792081406, 76709224526706154630278)
C_2 = E(508425841918584868754821, 816040882076938893064041)

def add(P,Q):
if P[0] != Q[0] and P[1] != Q[1]:
t = ((Q[1]-P[1]) * inverse(Q[0]-P[0],q)) %q
else:
t = ((3*P[0]*P[0]+a) * inverse(2*P[1],q))%q

x3 = t*t - P[0] - Q[0]
y3 = t*(P[0] - x3) - P[1]
return (x3%q, y3%q)

for i in trange(2^16):
if C_2 == i*G:
r = i
print(r)
break

r = 10077
_rK = -r * K
print(_rK)

_rK = (550786064209051189742959,986834966171230458412423)
C_1=(55568609433135042994738, 626496338010773913984218)

M = add(C_1,_rK)
mx = M[0]
my = M[1]

flag = b"0xGame{" + long_to_bytes(int(mx)) + long_to_bytes(int(my)) + b"}"
print(flag)
# 0xGame{Al1ce_L0ve_B0b}

这里求解r选择用爆破的方式,因为通过sagemath求得的$r = 900793232925355612586660$不符合题意(不明白)

LLL-FirstBlood

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
from random import randrange
from Crypto.Util.number import getPrime,bytes_to_long
from secret import flag
assert len(flag) % 4 == 0

length = len(flag)//4
m = [bytes_to_long(flag[i*length:(i+1)*length]) for i in range(4)]
p = getPrime(int(128))

def MakeMask(n,p):
upper = identity_matrix(n)
low = identity_matrix(n)
for i in range(n-1):
for j in range(i+1, n):
upper[i, j] = randrange(1, p)
low[j, i] = randrange(1, p)
result = upper * low
assert det(result) == 1
return result

def Matrix2List(x):return [list(i) for i in x]

noise = [[randrange(1, p) for i in range(4)] for _ in range(4)]
noise[0] = m
M = matrix(noise)
A = MakeMask(4,p)
C = A*M

print(f'p={p}')
print(f'C={Matrix2List(C)}')
'''
p=198880159035681668071031460916089145469
C=[[1528140902799730745476264672501768332416990282355490479242339131918301176698899635154781328839496210200676497333428, 2081687444435007467807250373278513114045272585243815458840083487459795021302180077490134099644993120009567147202772, 3080873409460299046339495750746632185307246572817534784703936044874106809413620470006445984962733721029566440253675, 3491734341995174183626991907292607070252197520631412767989879432598743851171175369180080355977574296558734415823458], [2359409535809048127331244699867147546817134802610067329431135227991488324148374065940238308147500809599395748756798, 3191196199160821446351036460385791985682645040446022512790815348810555748825420237291839170774872264097466183208742, 4665346530155386457242345394284286198347336281451530670818113876767736288089400119492317775648206643242839430899283, 5369350746042850276067380638571565496087948799720968959426256192923852197959381101839484196445995828389461004495917], [1641407111066265429602929560264443103285908072677065498760570514577412905392260182334706635555256537745902283191251, 2190536173399177167068153351271988931232272884028569669242062395087922275021628334797729266560930040116807133977244, 3127556759140845426132305699421707182108351516931881411928719802847628408656887897596425133523782526561471050447359, 3707239956529200159380870618471703921011276020439315706352183576289925263316580408968092016782483770373121972835410], [9883814543195849013523934427451407019514807606993414569626142656857168165339, 13190422499129347541373922929251088892868361241120937213742340947017395215646, 18832738552342488056498211782604832513006649329982003661701684946590064734701, 22323329751908690611034666068697427811613727429398087082295754189068333861152]]
'''

假设

$\because C = AM$

直接对C用LLL算法就能得到$m_1,m_2,m_3,m_4$

exp:

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

p =
C =
C = Matrix(ZZ,C)

M = C.LLL()[0]
flag = b""
for i in M:
m = long_to_bytes(int(abs(i)))
flag += m
print(flag)
#0xGame{8e4d5924dc4cd78f11c1eeb99e991ab3}

LLL-SecondBlood

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

m = bytes_to_long(flag)
q = getPrime(512)
assert m.bit_length() == 318

def encrypt(m):
mask,noise = getPrime(511),getPrime(50)
mask_.append(mask)
noise_.append(noise)
c = (mask*m + noise)%q
return c

noise_,mask_ =[[] for _ in range(2)]
c_ = [encrypt(m) for i in range(4)]

print(f'q = {q}\nmask = {mask_}\nc_ = {c_}')

'''
q = 9342426601783650861020119568565656404715236059903009041977149778244153930435908024696666887269890479558473622355346816236972767736577737332173213722012253
mask = [6237128445236992920577225644858662677575951126467888858782461334057970069468925833844231116647406833999142659751374620280213290736114576089069396331226747, 6368031389213953889417545256750169233725975229197446803885029159767701479445576860704561593200907482372690851152126782391126462547524526631934408981070841, 5106473460982791188578285397420642137630347289252852045044021197988607082777231839839730169682158507822078412449827976663385282021916120837408192506341443, 6318090842950331228033349517542810123596316850353637421587264886413877142612686177796023049304908696413386218992511112752788640732410845589679820003047667]
c_ = [3823539664720029027586933152478492780438595004453489251844133830947165342839393878831914879334660250621422877333022321117120398528430519794109624186204492, 1721659645750224819953244995460589691120672649732560768435214608167861246790136217219349234604724148039910656573436663379375048145045443527267790379816425, 668633520079344839648950502380059311916108468801009386138810324259146523323704014491547148973835774917331333581475920804677395949854411894556705238578896, 497860586379981076499130281851986010889356253371192266267220334713415782402939318483926418213877341511996918189750595755372560345085899109305344338944066]
'''

$\because C_i \equiv a_im + b_i \mod p$

$\therefore \therefore b_i = C_i - a_im +kp$

构造格

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
q = 
mask =
c_ =

Ge = Matrix(ZZ,[
[q,0,0,0,0,0],
[0,q,0,0,0,0],
[0,0,q,0,0,0],
[0,0,0,q,0,0],
[-mask[0],-mask[1],-mask[2],-mask[3],1,0],
[c_[0],c_[1],c_[2],c_[3],0,2^318]
])

for i in Ge.LLL():
if abs(i[-1]) == 2^318:
m = abs(i[-2])
flag = bytes.fromhex(hex(m)[2:])
print(flag)
#0xGame{19255b5c7b19c790e28d87c8a8bb1d33}

EzMartix

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
from Crypto.Util.number import getPrime
from random import randint
from secert import secert,flag
from hashlib import md5
def n2b(n):return md5(str(n).encode()).hexdigest()

assert secert < pow(2,64)
assert flag == '0xGame{'+n2b(secert)+'}'

def Martix2list(Martix):
result = []
Martix = list(Martix)
for i in Martix:
result.append(list(i))
return result

A =
# 12 * 12的矩阵
p =
A = Matrix(GF(p),A)
enc = A**secert

def Martix2list(Martix):
result = []
Martix = list(Martix)
for i in Martix:
result.append(list(i))
return result

with open('enc.txt','w') as f:
f.write(str(Martix2list(enc)))

由$A^m = C$,结合线代知识知道

存在矩阵$P$,使得$P^{-1}AP = B$(B是对角矩阵)

$\therefore B^m = P^{-1}A^mP$

即$B^m = P^{-1}CP$

根据对角矩阵相乘的性质(主对角线上的元素自乘),这样就把矩阵的乘法转为求解$b^m \equiv c \mod p$这样的离散对数问题,其中$b$是矩阵$B$主对角线上任意一个元素,$c$是右边矩阵$P^{-1}CP$主对角线上任意一个元素

关于求解,利用了sagemath自带的函数diagonalization()

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import hashlib

A=
p =
C =

A = Matrix(GF(p),A)
C = Matrix(GF(p),C)
A,P = A.diagonalization()
# print(A)

P_ = P.inverse()
C = P_ * C * P

a = A[0][0]
c = C[0][0]
m = discrete_log(mod(c,p),mod(a,p))
print(m)
#6208835615336459559
flag = "0xGame{" + hashlib.md5(str(m).encode()).hexdigest() + "}"
print(flag)
#0xGame{06450201eb6171d40151563d967e59ea}

EzOverflow

ElGamal.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
from Crypto.Util.number import getPrime,GCD,inverse,bytes_to_long
import random

def getKey(bits):
p = getPrime(bits)
g = getPrime(bits//2)
d = random.randint(1,p-2)
y = pow(g,d,p)
public,private = (p,g,y),d
return public,private

def sign(m,public,private):
m = bytes_to_long(m)
p,g,y = public
d = private
while True:
k = random.randint(1,p-1)
if GCD(k,p-1)==1:break
r = pow(g,k,p)
s = ((m-d*r)*inverse(k,p-1)) % (p-1)
return (r,s)

def verity(m,sign,public):
m = bytes_to_long(m)
p,g,y = public
r,s = sign
if pow(g,m,p) == (pow(y,r,p)*pow(r,s,p)) % p:
return True
else:
return False

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from ElGamal import *
import socketserver
import signal
from secert import flag
pub,pri = getKey(512)

class Task(socketserver.BaseRequestHandler):
def proof_of_work(self):
random.seed(os.urandom(8))
proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
_hexdigest = sha256(proof.encode()).hexdigest()
self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
return False
return True

def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass

def recv(self, prompt=b'> '):
self.send(prompt, newline=False)
return self._recvall()

def timeout_handler(self, signum, frame):
raise TimeoutError

def handle(self):
signal.signal(signal.SIGALRM, self.timeout_handler)
signal.alarm(300)
if not self.proof_of_work():
self.send(b'[!] Wrong!')
return

self.send(b'Here are your public key:')
self.send(str(pub).encode())
while True:
#sign
self.send(b'Pz tell me what you want to sign?')
message = self.recv()
if message == b'0xGame':
self.send(b"Permission denied!")
quit()
self.send(b'Here are your sign:')
r,s = sign(message,pub,pri)
self.send(f'r={r}\ns={s}'.encode())
#ver
self.send(b'Tell me your signature,if you want to get the flag.')
r = int(self.recv())
s = int(self.recv())

if verity(b'0xGame',(r,s),pub):
self.send(b'Here you are:'+flag)
self.send(b'bye~')
quit()

else:
self.send(b"sorry~you can't get it.")

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass

if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 10007
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()

验证过程:

$g^m \equiv y^rr^s \mod p$,根据题目意思,我们能够控制$m,r,s$

如果$m’ = m +k(p-1)$,也能满足$g^{m’} = g^{m + k(p-1)} \equiv g^m \times (g^{p-1})^k \equiv g^m \equiv y^rr^s \mod p$

或者$m’ = m\times p$,则$g^{m’} = g^{mp} \equiv (g^m)^p \equiv g^m \mod p$

所以传入一个$m’$ = long_to_bytes(bytes_to_long(b"0xGame") + (p-1)),或者$m’$ = long_to_bytes(bytes_to_long(b"0xGame")*p) 得到签名$r,s$

随后可用$m$ = 0xGame完成验证

可用下面代码进行验证:

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
import gmpy2
from Crypto.Util.number import *
import random
from Crypto.Util.number import getPrime,GCD,inverse,bytes_to_long
import random

def getKey(bits):
p = getPrime(bits)
g = getPrime(bits//2)
d = random.randint(1,p-2)
y = pow(g,d,p)
public,private = (p,g,y),d
return public,private

def sign(m,public,private):
m = bytes_to_long(m)
p,g,y = public
d = private
while True:
k = random.randint(1,p-1)
if GCD(k,p-1)==1:break
r = pow(g,k,p)
s = ((m-d*r)*inverse(k,p-1)) % (p-1)
return (r,s)

def verity(m,sign,public):
m = bytes_to_long(m)
p,g,y = public
r,s = sign
if pow(g,m,p) == (pow(y,r,p)*pow(r,s,p)) % p:
return True
else:
return False

pub,pri = getKey(512)
p,g,y = pub
flag = b"0xGame"
m = long_to_bytes(bytes_to_long(flag)*p)
(r,s) = sign(m,pub,pri)

tt = verity(flag,(r,s),pub)
print(tt)

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
from pwn import *
import string
from itertools import product
import hashlib
from Crypto.Util.number import *

table = string.ascii_letters + string.digits

host = '43.139.107.237' #ip地址
port = 10007 #端口

GeShi = b'[+] Plz tell me XXXX: ' # 改格式!
sh = remote(host,port) #建立连接

data = sh.recvuntil(GeShi).decode()

proof = data.split('sha256')[1]


Xnum = proof.split('+')[0].upper().count("X") #要爆破的数量
tail = proof.split('+')[1].split(')')[0].strip()
hash = proof.split('+')[1].split(')')[1].split('==')[-1].split('[')[0].strip()

print("未知数:",Xnum)
print(tail)
print(hash)
print("开始爆破")
for i in product(table,repeat=Xnum):
head = ''.join(i)
t = hashlib.sha256((head + tail).encode()).hexdigest()
if t == hash:
print('爆破成功!结果是:', end='')
print(head)
sh.send(head.encode())
break

print("以下是提交完XXXX之后的流程\n")

sh.recvuntil(b"Here are your public key:\n")
sign = eval(sh.recvline().decode())
p,g,y = sign
m = b"0xGame"
message = long_to_bytes(bytes_to_long(m) + (p-1))
sh.recvuntil(b">")
sh.sendline(message)
sh.recvuntil(b"Here are your sign:\n")
r = int(sh.recvline().decode().split('=')[-1])
s = int(sh.recvline().decode().split('=')[-1])
sh.recvuntil(b">")
sh.sendline(str(r).encode())
sh.recvuntil(b">")
sh.sendline(str(s).encode())
sh.interactive()

#0xGame{24b6edfdc07d71311774ed15248f434e}

Re

代码启示录

0xGame{038e8685-0a59-a868-ed44-979261e99faf}

旋转密码城

把上面脚本跑一下即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Scanner;

class exp{
public static void main(String args[]){
String cipher = "_Iv2>6L424c_4c2\\f__5\\7fec\\da32\\3ef2`cgd4b46N";
StringBuilder flag = new StringBuilder();
for (char c : cipher.toCharArray()) {
if (c >= '!' && c <= '~') {
flag.append((char)((c - 33 + 47) % 94 + 33));
} else {
flag.append(c);
}
}
System.out.println(flag);
}
}
# 0xGame{cac40c4a-700d-f764-52ba-b67a1485c3ce}

数字幽灵城

反编译找到base58的密文RmC442S4tDMzc3CvzoCx8toKodL8SE8GRQSmz8M84k6g9jG1vVrf3c5TECZR

反编译base58的加密函数,找到码表ABCDEFGHJKLMNPQRSTUVWXYZ123456789abcdefghijkmnopqrstuvwxyz

解密得到0xGame{5f7dc2d9-5243-f706-cdbf-12e34dd3970c}

变量迷城

首先反编译

发现密文和等式

$x^2 + 2y^2 + 3x + 4y - 7384462351178 = 0$,$5x^2 + 6y^2 + 7x + 8y - 22179606057658$

解得x = 114514,y = 1919810

1
2
3
4
5
6
7
8
9
10
public class Main {
private static BiPredicate<BigInteger, BigInteger> equationCheck;

static {
equationCheck = ((x, y) -> {
BigInteger eq1 = x.pow(2).add(y.pow(2).multiply(BigInteger.valueOf(2L))).add(x.multiply(BigInteger.valueOf(3L))).add(y.multiply(BigInteger.valueOf(4L))).subtract(new BigInteger("7384462351178"));
BigInteger eq2 = x.pow(2).multiply(BigInteger.valueOf(5L)).add(y.pow(2).multiply(BigInteger.valueOf(6L))).add(x.multiply(BigInteger.valueOf(7L))).add(y.multiply(BigInteger.valueOf(8L))).subtract(new BigInteger("22179606057658"));
return (eq1.equals(BigInteger.ZERO) && eq2.equals(BigInteger.ZERO));
});
}

找到关键,发现key = "1145140xGame"

再进行异或即flag[i] = c[i] ^ key(i % len(key))

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
encrypted_flag = [
1, 73, 115, 84, 92, 81, 75, 65, 116, 84,
90, 93, 7, 2, 87, 24, 83, 87, 84, 64,
106, 4, 9, 86, 84, 28, 4, 5, 9, 82,
29, 74, 119, 85, 93, 1, 3, 84, 0, 0,
1, 0, 3, 5,
]

key = "1145140xGame"

decrypted_flag = ""
for i, byte in enumerate(encrypted_flag):
decrypted_byte = byte ^ ord(key[i % len(key)])
decrypted_flag += chr(decrypted_byte)

print(decrypted_flag)
#0xGame{9357863c-bcd8-ed3e-008f-2040d2e45043}

虚构核心

解密过程和key已经给出,差了密文

把密文文件导出

放cipherchef解密

1
2
3
4
0xGame{. 69b4fa3be19bdf400df34e41b93636a4. 76b662c5c3d6d98035190115d89ef42f. 87fff610a9c97ebbe5a16a6d4865c0e4..<init>..B..FlagChecker.java..I..L..LI..LII..LL..LLL..Lcom/ctf/a0xgame_5/FlagChecker;..Ljava/lang/Integer;..Ljava/lang/Object;..Ljava/lang/RuntimeException;..Ljava/lang/String;..Ljava/lang/StringBuilder;..Ljava/security/MessageDigest;.(Ljava/security/NoSuchAlgorithmException;..MD5.	MD5å. å¯.å.ºç.°é..误..V..VL..Z..ZL..[B..[Ljava/lang/Object;..[Ljava/lang/String;..append..b.	checkFlag..content..digest..e..endsWith..equals..f3eddaccb39f..f5bf50a3..format..getBytes..getInstance..i..input..length..md..md5.
md5Strings.
messageDigest..parts..sb..split.
startsWith. substring..toString..valueOf..}

根据提示,把前面三串密文放网站破解md5,分别得到9988,61ee,8c00

再拼接成uuid的形式:8-4-4-4-12

flag:0xGame{f5bf50a3-9988-61ee-8c00-f3eddaccb39f}

Week4

Crypto

LLL-Third Blood

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
113
114
115
116
117
118
119
120
121
import os
import string
import random
from hashlib import sha256
from string import ascii_uppercase
from random import shuffle,choice,randint
import socketserver
import signal
from DSA import *
from secret import flag
GAME = DSA()

MENU = """
Welcome_to_Final_Chanllange!
/----------------------------\\
| options |
| [S]ign |
| [V]erify |
| [C]heck answer |
\\---------------------------/
"""

class Task(socketserver.BaseRequestHandler):
def proof_of_work(self):
random.seed(os.urandom(8))
proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in range(20)])
_hexdigest = sha256(proof.encode()).hexdigest()
self.send(f"[+] sha256(XXXX+{proof[4:]}) == {_hexdigest}".encode())
x = self.recv(prompt=b'[+] Plz tell me XXXX: ')
if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest:
return False
return True

def _recvall(self):
BUFF_SIZE = 2048
data = b''
while True:
part = self.request.recv(BUFF_SIZE)
data += part
if len(part) < BUFF_SIZE:
break
return data.strip()

def send(self, msg, newline=True):
try:
if newline:
msg += b'\n'
self.request.sendall(msg)
except:
pass

def recv(self, prompt=b'> '):
self.send(prompt, newline=False)
return self._recvall()

def timeout_handler(self, signum, frame):
raise TimeoutError

def handle(self):
signal.signal(signal.SIGALRM, self.timeout_handler)
signal.alarm(300)
if not self.proof_of_work():
self.send(b'[!] Wrong!')
return
self.send(MENU.encode())
self.send(b'Here are your public key:')
self.send(f'q={GAME.q}\np={GAME.p}\ng={GAME.g}\ny={GAME.y}'.encode())
while True:
self.send(b'What you want to choice?')
code = self.recv()

if code == b'S':
self.send(b'What you want to sign?')
msg = self.recv()
if msg == b'admin':
self.send(b'Permission denied!')
self.send(b'Are you trying hack me?No way!')
quit()
self.send(b'Here are your signature:')
s,r = GAME.sign(msg)
self.send(f's = {s}'.encode())
self.send(f'r = {r}'.encode())

elif code == b'V':
self.send(b"Let's check your signature.")
self.send(b'Tell me your message:')
msg = self.recv()
self.send(b'Tell me the signature (s,r):')
s = int(self.recv())
r = int(self.recv())
if GAME.verify(msg,s,r):
self.send(b'OK,it work')
else:
self.send(b'Something wrong?')

elif code == b'C':
self.send(b"Tell me the signature of 'admin'")
s = int(self.recv())
r = int(self.recv())
if GAME.verify(b'admin',s,r):
self.send(b'Congratulations!You are Master of Cryptography!')
self.send(b'Here are your flag:')
self.send(flag)
quit()
else:
self.send(b'It seems Something wrong?')
else:
self.send(b'invaild input')

class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass

if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 10004
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
print(HOST, PORT)
server.serve_forever()

考察DSA签名,本题思路是求得私钥d,再用admin构造签名完成验证

DSA签名中

$s \equiv k^{-1}(h + dr) \mod q$

$\therefore k \equiv s^{-1}h + s^{-1}dr \mod q$

令$A = s^{-1}r$,$B = s^{-1}h$

$k_i \equiv A_id + B_i \mod q$,即$k_i = A_id + B_i +t_iq$

转化成了HNP问题

构造格

i可以取多组数据,我取了20组

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from Pwn4Sage.pwn import *
from hashlib import sha1
import hashlib
import gmpy2
from itertools import product
from Crypto.Util.number import *
import string

table = string.ascii_letters + string.digits

host = '43.139.107.237' #ip地址
port = 10004 #端口

GeShi = b'[+] Plz tell me XXXX: ' # 改格式!
sh = remote(host,port) #建立连接

data = sh.recvuntil(GeShi).decode()

proof = data.split('sha256')[1]


Xnum = proof.split('+')[0].upper().count("X") #要爆破的数量
tail = proof.split('+')[1].split(')')[0].strip()
hash = proof.split('+')[1].split(')')[1].split('==')[-1].split('[')[0].strip()

print("未知数:",Xnum)
print(tail)
print(hash)
print("开始爆破")
for i in product(table,repeat=Xnum):
head = ''.join(i)
t = hashlib.sha256((head + tail).encode()).hexdigest()
if t == hash:
print('爆破成功!结果是:', end='')
print(head)
sh.send(head.encode())
break

print("以下是提交完XXXX之后的流程\n")

sh.recvuntil(b"Here are your public key:\n")
q = eval(sh.recvline().decode().split("=")[1])
p = eval(sh.recvline().decode().split("=")[1])
g = eval(sh.recvline().decode().split("=")[1])
y = eval(sh.recvline().decode().split("=")[1])

R = []
S = []
H = []
for i in range(20):
sh.recvuntil(b"What you want to choice?")
sh.sendline(b"S")
sh.recvuntil(b"What you want to sign?")
m = getPrime(128)
msg = long_to_bytes(m)
h = bytes_to_long(sha1(msg).digest())
sh.sendline(msg)
sh.recvuntil(b"Here are your signature:\n")
s = eval(sh.recvline().decode().split("=")[1])
r = eval(sh.recvline().decode().split("=")[1])
S.append(s)
R.append(r)
H.append(h)

n = len(S)
Ge = Matrix(ZZ,n+2,n+2)
for i in range(n):
Ge[i,i] = q
Ge[-2,i] = gmpy2.invert(S[i],q) * R[i]
Ge[-1,i] = gmpy2.invert(S[i],q) * H[i]
K = 2^128
Ge[-1,-1] = K
Ge[-2,-2] = 1

def sign(m,k,x):
H = bytes_to_long(sha1(m).digest())
r = pow(g,k,p)%q
s = (inverse(k,q)*(H+r*x))%q
return r,s

for line in Ge.LLL():
if abs(line[-1]) == K:
k1 = abs(line[0])
d = abs(line[-2])
print("d =",d)
r,s = sign(b"admin",int(k1),int(d))
sh.recvuntil(b"What you want to choice?")
sh.sendline(b"C")
sh.recvuntil(b"> Tell me the signature of 'admin'")
sh.sendline(str(s).encode())
sh.sendline(str(r).encode())
sh.interactive()
# 0xGame{31260c7522632a69031d07133aedebfe}

Danger Leak

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

m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
phi = (p - 1) * (q - 1)
while True:
M = getrandbits(954)
d0 = getrandbits(70)
d1 = getrandbits(60)
d = M * d1 + d0
e = inverse(d, (p - 1) * (q - 1))
if GCD(d,phi) == 1:
break


c = pow(m,e,n)
print(f'n = {n}')
print(f'e = {e}', )
print(f'c = {c}')
print(f'leak={M}')

'''
n = 20890649807098098590988367504589884104169882461137822700915421138825243082401073285651688396365119177048314378342335630003758801918471770067256781032441408755600222443136442802834673033726750262792591713729454359321085776245901507024843351032181392621160709321235730377105858928038429561563451212831555362084799868396816620900530821649927143675042508754145300235707164480595867159183020730488244523890377494200551982732673420463610420046405496222143863293721127847196315699011480407859245602878759192763358027712666490436877309958694930300881154144262012786388678170041827603485103596258722151867033618346180314221757
e = 18495624691004329345494739768139119654869294781001439503228375675656780205533832088551925603457913375965236666248560110824522816405784593622489392063569693980307711273262046178522155150057918004670062638133229511441378857067441808814663979656329118576174389773223672078570346056569568769586136333878585184495900769610485682523713035338815180355226296627023856218662677851691200400870086661825318662718172322697239597148304400050201201957491047654347222946693457784950694119128957010938708457194638164370689969395914866589468077447411160531995194740413950928085824985317114393591961698215667749937880023984967171867149
c = 7268748311489430996649583334296342239120976535969890151640528281264037345919563247744198340847622671332165540273927079037288463501586895675652397791211130033797562320858177249657627485568147343368981852295435358970875375601525013288259717232106253656041724174637307915021524904526849025976062174351360431089505898256673035060020871892556020429754849084448428394307414301376699983203262072041951835713075509402291301281337658567437075609144913905526625759374465018684092236818174282777215336979886495053619105951835282087487201593981164477120073864259644978940192351781270609702595767362731320959397657161384681459323
leak=136607909840146555806361156873618892240715868885574369629522914036807393164542930308166609104735002945881388216362007941213298888307579692272865700211608126496105057113506756857793463197250909161173116422723246662094695586716106972298428164926993995948528941241037242367190042120886133717
'''

参考论文:035.pdf (iacr.org)

在模$Me$的域中构造多项式$f(x,y,z) = ex - Ny + yz - 1$,然后用多元copper解出小根

$x_0,y_0,z_0$分别对应,$d_0,k,p+q-1$

所以用多元copper的时候,以$d_0,k,p+q-1$作为$x,y,z$的上限

求得$p+q-1$后,联立$n = pq$解得$p,q$

$p = \frac{(p+q) + \sqrt{(p+q)^2 - 4n}}{2}$

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
#sage
import hashlib
import itertools
import gmpy2
from Crypto.Util.number import *

N =
e =
c =
M =

def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()

R = f.base_ring()
N = R.cardinality()

f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)

G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)

B, monomials = G.coefficient_matrix()
monomials = vector(monomials)

factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)

B = B.dense_matrix().LLL()

B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)

H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots

return []

R.<x,y,z>=PolynomialRing(Zmod(M*e))

f = e*x - N*y + y*z - 1
solves = small_roots(f,bounds=(2^71,2^1013,2^1026),m=3, d=3)
print(solves)

add = int(solves[0][2]) + 1 # p+q
sub = gmpy2.iroot(add^2 - 4*N,2)[0] # p-q
p = (add + sub)//2
q = N//p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,N)
print(long_to_bytes(int(m)))
# 0xGame{a9e1f260f845be84f56ff06b165deb80}

本地测试几组数据发现,$k$大概在1013bit以下,$p+q-1$的大小在1025bit左右,所以bound设置为(2^71,2^1013,2^1026)

$d=3$表示变量个数或者说是最高次幂?m从1试到了3

Normal ECC

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
from Crypto.Util.number import getPrime
from Crypto.Cipher import AES
from random import getrandbits
from secret import flag,M
from hashlib import md5

def MD5(m):return md5(str(m).encode()).hexdigest()

p = 11093300438765357787693823122068501933326829181518693650897090781749379503427651954028543076247583697669597230934286751428880673539155279232304301123931419
a = getPrime(int(512))
b = getPrime(int(512))
assert p>a
assert p>b
E = EllipticCurve(GF(p),[a,b])
G = E.random_point()
k = getPrime(int(512))
K = k*G
r = getrandbits(64)
M = E(M)

C1 = M + r*K
C2 = r*G

assert '0xGame{'+MD5( M.xy()[0] )+'}' == flag

print(f'p={p}\na={a}\nb={b}')
print(f'G={G.xy()}')
print(f'K={K.xy()}')
print(f'C1={C1.xy()}')
print(f'C2={C2.xy()}')
'''
p=11093300438765357787693823122068501933326829181518693650897090781749379503427651954028543076247583697669597230934286751428880673539155279232304301123931419
a=7150069360142473220874778371025253986400531606173784255855621272842352949822722345927984117158003009207785424116052251585892319431674211713978446093533949
b=8963713118505064052475299691180792684131316295319527298757291586802733177771327455119311985236802185776962863601191772056992397979199759282886953573897623
G=(4070512847946293053993474472718195445326650730220767223671483350865356914474371813956296088808339388116138119830978356761203350661975684819340687599188773, 7919267117945460629179349735575165185291048599591225961407006624231142667171694867758723087028969163792156367031144131919207578182780960301059191834343484)
K=(3429071535068496391288385908059514112858019444898682888326563488381066866765760330150826456161675891783443971423132174003430225228636705672269386133448242, 10156980123178962109303543933598555000559941757051056925651640103802811004794287116521872896690665760105638977618361662092227807698111279640177447796532347)
C1=(4139336890213227868613795086096336512836348527349045673681270821212710038308856344020383776363498787598928112315425033118240925101586130966715819924212989, 8496671787567254905958613320810855596994019625894595967770545586397682431545287861458500877647243710691962626334781301359445519608668358210417703062746989)
C2=(2151204832133866138854176239337864259798539350706680161553247616590123485482950549170787112029461554837485268534053338274459614702685163614673775491725035, 612484077350471488714018386040340578068868389564012902083181785403536097453280569723896780143638704225018931513080350876551883282131207177391746460216488)
'''

发现曲线的阶和p一样,用SmartAttack求出$r$

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
from hashlib import md5

p =
a =
b =

G=(, )
K=(, )
C1=(, )
C2=(, )

E = EllipticCurve(GF(p),[a,b])
G = E(G)
K = E(K)
C1 = E(C1)
C2 = E(C2)

order = E.order()
print(order)
print(order == p)
def MD5(m):return md5(str(m).encode()).hexdigest()

def SmartAttack(P,Q,p):
E = P.curve()
Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + randint(0,p)*p for t in E.a_invariants() ])

P_Qps = Eqp.lift_x(ZZ(P.xy()[0]), all=True)
for P_Qp in P_Qps:
if GF(p)(P_Qp.xy()[1]) == P.xy()[1]:
break

Q_Qps = Eqp.lift_x(ZZ(Q.xy()[0]), all=True)
for Q_Qp in Q_Qps:
if GF(p)(Q_Qp.xy()[1]) == Q.xy()[1]:
break

p_times_P = p*P_Qp
p_times_Q = p*Q_Qp

x_P,y_P = p_times_P.xy()
x_Q,y_Q = p_times_Q.xy()

phi_P = -(x_P/y_P)
phi_Q = -(x_Q/y_Q)
k = phi_Q/phi_P
return ZZ(k)

r = SmartAttack(G,C2,p)
print(r)

M = C1 - r*K
flag = '0xGame{'+MD5(M[0])+'}'
print(flag)
# 0xGame{6f2b3accf11a8cb7a9d3c7b159bc6c6c}

Re

序列9-二进制学徒

反编译python得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11

'''
0xGame{15cf69f6-69f9-6b18-1464-7785f106b0d3}
'''

def main():
print('我的flag去哪儿了?')

if __name__ == '__main__':
main()
return None

序列8-代码悟道者

拿到base64的密文和码表,解就行

exp:

1
2
3
4
5
6
7
8
9
import base64

cipher = "MH7HYWrb4p2oYpYtMcEvLTb8Np2jOD2mMoqqYTauLTatYTarMWYvMp7bMdq="
table1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

table2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz-_"
flag = base64.b64decode(cipher.translate(str.maketrans(table2,table1)))
print(flag)
# 0xGame{72c672a9-9b77-8703-4a98-97a951f938e2}
-------------已经到底啦!-------------