0%

2023-0xGame-week1-wp-crypto

比赛记录

[Week 1] What’s CBC?

题目描述:

1
经典的加密预处理?

题目:

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"

题目比较简单,就不梳理流程了,主要漏洞在于encrypt函数中:

1
result += ((i^key)).to_bytes(1,'big')

可以看到,key只用了最低的一个字节来进行加密,因此有两种思路:

  • 爆破256种可能的key,均进行解密,在解密出来的文本中,有0xGame的flag头即为正确解密
  • 用已知的0xGame这个flag头直接确定key,再进行解密

不管用哪个思路,最终发现key的最低字节是 b’\x8f’

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

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"
iv = b'11111111'
key = 8*b'\x8f'

for i in range(6):
print(str(bytes_xor(bytes_xor(enc[8*i:8*i+8],iv),key))[2:-1],end = "")
iv = enc[8*i:8*i+8]

#0xGame{098f6bcd4621d373cade4e832627b4f6}



[Week 1] 密码,觅码,先有*再密

题目描述:

1
在开始挑战BOSS前,先来通关新手村吧

hint:

1
Hint 1: Test your python

题目:

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
'''
#全是乱码,那咋办嘛?

可以看到flag被分为四份,进行不同的编码,那么首先要对应解码:

1
2
3
4
b'0xGame{ \xe6\x81\xad\xe5\x96\x9c\xe4\xbd\xa0,\xe5\xb7\xb2\xe7\xbb\x8f\xe7'
b'\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'
b'\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'
b'\xe4\xbb\xac\xe7\x9a\x84Crypto\xe6\x8c\x91\xe6\x88\x98\xe5\x90\xa7!!!}'

解出来后,发现解密内容除了flag头尾,剩下的仍然是字节流,猜测可能是汉字编码,解码即可

exp:

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

c1 = 2607076237872456265701394408859286660368327415582106508683648834772020887801353062171214554351749058553609022833985773083200356284531601339221590756213276590896143894954053902973407638214851164171968630602313844022016135428560081844499356672695981757804756591891049233334352061975924028218309004551
c1 = iroot(c1,5)[0]
c2 = "10010000100001101110100010100111101000111110010010111010100001101110010010111111101000011110011010000001101011111110011010011000101011111110010110100110100000101110010010111101100101011110011110111100"
c3 = b'lueggeeahO+8jOmCo+S5iOW8gOWni+aIkQ=='
c4 = "e4bbace79a8443727970746fe68c91e68898e590a72121217d"

t1 = long_to_bytes(c1)
t2 = long_to_bytes(int(c2,2))
t3 = b64decode(c3)
t4 = long_to_bytes(int(c4,16))

t = t1+t2+t3+t4
print(t.decode())

#0xGame{ 恭喜你,已经理解了信息是如何编码的,那么开始我们的Crypto挑战吧!!!}



[Week 1] Take my bag!

题目描述:

1
我包呢?

题目:

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

一个背包加密,需要注意到的是这里的 pow(3, i) 是一个超递增序列,因此有两种方法:

  • 直接当作普通背包加密,用格基规约做
  • 如果flag长度较短,那么很可能前面的背包加密根本没有取模,可以直接当作超递增序列解密

无论哪个方法都不麻烦,当然因为是新生赛所以推荐先学会第二种方法

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

w=16221818045491479713
n=9702074289348763131102174377899883904548584105641045150269763589431293826913348632496775173099776917930517270317586740686008539085898910110442820776001061
c=4795969289572314590787467990865205548430190921556722879891721107719262822789483863742356553249935437004378475661668768893462652103739250038700528111

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

n = len(init)
L = Matrix(ZZ, n+1, n+1)

for i in range(n):
L[i,i] = 1
L[i,-1] = init[i]
L[-1,-1] = -c

res = L.LLL()

for i in range(n + 1):
M = res.row(i).list()
flag = True
for m in M:
if m != 0 and m != 1:
flag = False
break
if flag:
print(i, M)

m = [1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in range(len(m)):
m[i] = str(m[i])
m = "".join(m)[::-1]
print(long_to_bytes(int(m,2)))

#0xGame{Welc0me_2_Crypt0_G@me!#$&%}



[Week 1] BabyRSA

题目描述:

1
经典的数学,经典的算法

题目:

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

多素数的RSA,factordb分解后直接解密即可,最后还需乘上mask的逆元

exp:

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

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

plist = [2329990801, 2436711469, 2732757047, 2770441151, 2821163021, 2864469667, 2995527113, 3111632101, 3162958289, 3267547559, 3281340371, 3479527847, 3561068417, 3978177241, 4134768233, 4160088337]
phi = 1
for i in plist:
phi *= (i-1)

d = inverse(e,phi)
mmask = pow(c,d,n)
m = mmask // mask
print(long_to_bytes(m))

#0xGame{Magic_M@th_Make_Crypt0}



[Week 1] 猜谜

题目描述:

1
什么情况,密钥不见了?(flag格式: 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
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='
'''

加密流程如下:

  • flag 是一个字节流,记其长度为 l
  • 将 flag[i] + i 与 key[i%7] 异或,并转为一个字节后,得到 encrypt(flag)
  • 将 encrypt(flag) 进行 enc 加密

其中,enc加密过程为:

  • 将 encrypt(flag) 的每个字节转化为二进制,并补齐 8 位
  • 把每个字节的二进制再拼接在一起,得到一个01串
  • 将01串每三位转化为十进制数,作为当前需添加的密文字符在 code 中的下标
  • 添加完所有密文后,填充上对应补充字节,作为密文给出

那么解密流程就是:先恢复 enc,再恢复 encrypt

enc的恢复是容易的,简单逆向回去就行,当然需要注意一下解填充:

1
2
3
4
5
6
7
8
9
10
11
12
code = 'AP3IXYxn4DmwqOlT0Q/JbKFecN8isvE6gWrto+yf7M5d2pjBuk1Hh9aCRZGUVzLS'
c = 'IPxYIYPYXPAn3nXX3IXA3YIAPn3xAYnYnPIIPAYYIA3nxxInXAYnIPAIxnXYYYIXIIPAXn3XYXIYAA3AXnx'

temp = ""
for i in c:
t = code.index(i)
temp += str(bin(t)[2:].zfill(3))
temp = temp[:-1]

enc = []
for i in range(len(temp)//8):
enc.append(int(temp[8*i:8*i+8],2))

然后就是恢复encrypt,注意到我们拥有flag头0xGame{,刚好七个,因此可以直接恢复密钥,然后对应解密

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

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

temp = ""
for i in c:
t = code.index(i)
temp += str(bin(t)[2:].zfill(3))
temp = temp[:-1]

enc = []
for i in range(len(temp)//8):
enc.append(int(temp[8*i:8*i+8],2))

prefix = "0xGame{"
key = []
for i in range(7):
key.append((enc[i])^(ord(prefix[i])+i))

result = b''
for i in range(len(enc)):
result += ((key[i%7]^((enc[i])))-i).to_bytes(1,'big')
print(result)

#0xGame{Kn0wn_pl@intext_Att@ck!}



[Week 1] Vigenere

题目描述:

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

没有附件,那么结合题目内容就知道用的是Vigenere加密,上cyberchef,直接用flag头就能看出密钥是game:

image-20231001192856742

那么用game解密就好:

image-20231001192949166

flag:

0xGame{79ad4e0522a0a67a6e196be52357e60b}