这个比赛是一个网友让我看看的,这个比赛很有意思,crypto题全是百度网盘,pwn题全是谷歌网盘,这样我这pwn题就基本over了。还好这些crypto都不怎么难,都答出来了。最后成绩到10名了。
第1个50分的题,还真不会,看来看去,由于flag头是SYC{所以可以找到一些线索We后是间隔3字符,前边(右边)是间隔4字符,看上去就是栅栏,根据字符猜就是welcome,然后猜第2行,与第1行方向相反。经网友提示是Rail Fence就是一种特殊的栅栏,前边被题目的说明zigzag误导了。这个好像真没啥关系。
- 0_cmdo1elfe_2_}WtoC!{0mr!C__7!YtepoS34
- ^ ^ ^ ^ ^ ^ ^ ^ <---从右向左
- c 1 e W { C Y S
- 0 m e _ t 0 _ t 3 <---从左向右
- d l 2 o m _ e <---右向左
- _ o f _ C r 7 p 4
- } ! ! ! o
正确的应该解法是
- (1)倒序
- '0_cmdo1elfe_2_}WtoC!{0mr!C__7!YtepoS34'[::-1]
- '43SopetY!7__C!rm0{!CotW}_2_efle1odmc_0'
-
- (2)cyberchef->Rail Fence Cipher Decode
- Key:9
- Offset:27
- }!!!o4p7rC_fo_dl2om_e3t_0t_em0c1eW{CYS
-
- (3)倒序
- '}!!!o4p7rC_fo_dl2om_e3t_0t_em0c1eW{CYS'[::-1]
- 'SYC{We1c0me_t0_t3e_mo2ld_of_Cr7p4o!!!}'
题目给了个摩尔斯电码
-../.-../.-./---/.--/---/-/.--./-.--/.-./-.-./---/.-../.-.././....
解码后再反过来
- dlrowotpyrcolleh
- SYC{hellocryptoworld}
一个标准的小指数攻击题e=6,m很小n很大
- from Crypto.Util.number import *
- import libnum
-
- flag = b'****hidden_message****'
- p = getPrime(512)
- q = getPrime(512)
- n = p * q
- e = 6
- m = libnum.s2n(flag)
- c = pow(m,e,n)
- print(c)
- print(n)
-
- '''
- *****************************************************
- c = 50072006338339389555118552154159240037219794211505206943873038914830972293138548550568229783754227896661905769853250134014183574039535969574789925550365619292404703617997980492432173682029840923107651199593049684918577536870537471401209938966780904496397505606866028917883152417396458811357069626629334483341
- n = 147194403642833538539720995718314310463580322118979932658805936518215523735242613107271741138837389303135352865058107054820876285524238471152015504027014461168105771913435200522726300893493981125032256531337768716089003105857799620333243431585087621669813946444872568719527503184655024233193716871553607529747
- *****************************************************
- '''
解法就是直接开根号,不够开就加个n,因为6次一般情况不会溢出多少。
- from gmpy2 import iroot
-
- c = ...
- n = ...
-
- while True:
- v,k = iroot(c,6)
- if k:
- print(bytes.fromhex(hex(int(v))[2:]))
- break
- c +=n
- #SYC{0ops_y0u_f1Nd_m3!}
- '''
- R.
= PolynomialRing(Zmod(n)) - f = x^6 - c
- f.monic()
- f.roots()
- '''
给了一个密文:3tl2nv2zl2zl2zl4pg6gh5tr2z76kf2nt5zc56a6w0
一共42字节,也要放到网盘上。有提示:hint: My twin brother send me a message.Can you decrypt it? 1、 Alice and Bob are twins of Hex
一个twin-hex加密,直接找网站解
又一个rsa的题,仅给了n,c,e但明显n非常小,可以直接分解
- n= 69984814757288857831977509185208500866724771756561629279687819301222483218728663
- e= 65537
- c= 67672845063517415442486175096448664617581579564885311842326107871805595697454701
经过分解发现p是一个小因子,直接解rsa
- from gmpy2 import *
- from Crypto.Util.number import long_to_bytes
-
- n= 69984814757288857831977509185208500866724771756561629279687819301222483218728663
- e= 65537
- c= 67672845063517415442486175096448664617581579564885311842326107871805595697454701
-
- p = 733
- q = 95477237049507309456995237633299455479842799122185033123721445158557275878211
- phi = (p-1)*(q-1)
- d = invert(e, phi)
- m = pow(c,d,n)
- print(long_to_bytes(m))
-
- #SYC{5t4rt_R5A_ls_1t_3a5y?}
还是个rsa题,题目有点长,先是加密m得到c但n没有给出,后边两个paper提示是对p,q分别进行的rsa加密
- flag = b'xxxxxx'
- p = getPrime(1024)
- q = getPrime(1024)
- m = bytes_to_long(flag)
- n = p*q
- e = 65537
- c = pow(m,e,n)
- print('c={}'.format(c))
-
- p1 = getPrime(1024)
- q1 = getPrime(1024)
- n1 = p1*q1
- e1 = 65537
- assert gcd(e1,(p1-1)*(q1-1)) == 1
- c1 = pow(p,e1,n1)
- print('n1={}'.format(n1))
- print('c1={}'.format(c1))
- hint1 = pow(2022 * p1 + q1, 222222, n1)
- hint2 = pow(2023 * p1 + 232323, q1, n1)
- print('hint1={}'.format(hint1))
- print('hint2={}'.format(hint2))
-
- p2 = getPrime(1024)
- q2 = getPrime(1024)
- n2 = p2*q2
- e2 = 65537
- assert gcd(e1,(p2-1)*(q2-1)) == 1
- c2 = pow(q,e2,n2)
- hint3 = pow(2022 * p2 + 2023 * q2, 222222, n2)
- hint4 = pow(2023 * p2 + 2022 * q2, 232323, n2)
- print('n2={}'.format(n2))
- print('c2={}'.format(c2))
- print('hint3={}'.format(hint3))
- print('hint4={}'.format(hint4))
这种曾经作过类似的也就没有难度了。第一步先对q1取模得到仅含p1的两个算式,将p1约掉后得到q1,再与n1取公约数得到q1,然后解Rsa得到p
- #p
- t1 = hint1 * pow(2022, -222222, n1) % n1
- t2 = (hint2 - 232323) * pow(2023,-1, n1) % n1
- q1 = gcd(t1 - pow(t2, 222222, n1) , n1)
- p1 = n1//q1
- phi1 = (p1 - 1)* (q1 - 1)
- d1 = invert(e, phi1)
- p = pow(c1, d1, n1)
- print(f'p = {p}')
第2步同理得到q
- #q
- t3 = pow(hint3 * pow(2023, -222222, n2),232323,n2)
- t4 = pow(hint4 * pow(2022, -232323, n2),222222,n2)
- p2 = gcd(t3-t4, n2)
- q2 = n2//p2
- phi2 = (p2-1)*(q2-1)
- d2 = invert(e, phi2)
- q = pow(c2, d2, n2)
- print(f'q = {q}')
最后由p,q得到m
- n = p*q
- phi = (p-1)*(q-1)
- d = invert(e, phi)
- flag = pow(c,d,n)
- print(long_to_bytes(flag))
-
- #The_key_I_am_white_Please_continue_decryting
这时候还没完,flag.txt是维吉尼亚加密的,得到的是key:iamwhite,到网站上在线解得到
- #Key:iamwhite
- #密文(flag.txt文件): ayo{2ek_g0n_v3i11y_4ujk_bai_zisda_ig5amr}
- #SYC{2dz_y0a_s3a11y_4iiz_tnf_rigcp_at5xer}
又是一个rsa,两个m分别是m加上两个padding得到的,而padding已知,所以这个用关联信息
- from Crypto.Util.number import *
- flag = b'xxxxxxxxxx'
- m = bytes_to_long(flag)
- e = 3
- p = getPrime(256)
- q = getPrime(256)
- n = p * q
- pad1 = 105932791230388043786415766547423404991945041940365436758701967602353965252168
- pad2 = 927899423531845853332048235055407925992275378422616390929
- m1 = m + pad1
- m2 = m + pad2
- c1 = pow(m1,e,n)
- c2 = pow(m2,e,n)
- print("c1 =",c1)
- print("c2 =",c2)
- print("n =",n)
-
-
- '''
- c1 = 3720637940274958886432460233359341402765303073408436397771852426914390218432084755791424796944302399361378059153348441733368574505589165431342734218087692
- c2 = 1857483070190148986251195374434228339562792548542508665250465210130431058280559201968992393617573644598954953409645690993451979549050973992242158354491780
- n = 5106069782765072129956779902712742815006764735937158686628819801242945179548793829832666946413859309545558089370129318039174135569850663668730057188261837
- '''
这个关联信息攻击有模板,只当个搬运工。
- def related_message_attack(c1,c2, di, e,n):
- from Crypto.Util.number import GCD
- #展开(x+a)^e的系数,杨辉三角
- def poly_coef(a, e):
- assert e >= 0
- if e == 0:
- return 1
- elif e == 1:
- return [1,1]
- else:
- res = [1]
- coe_prev = poly_coef(a, e-1)
- for i in range(len(coe_prev)-1):
- res.append(sum(coe_prev[i:i+2]))
- res.append(1)
- return res
-
- def poly_extend(a, e, n,c):
- coef = poly_coef(a, e)
- res = [a**i * coef[i] for i in range(len(coef))]
-
- res[-1] = res[-1] + c
- res = [x%n for x in res]
-
- return res
-
- #化首1
- def poly_monic(pl,n):
- from gmpy2 import invert
- for p in pl:
- if p!=0:
- inv = invert(p,n)
- break
- return [int((x*inv)%n) for x in pl]
-
- #模运算,这部分写的不是很好,待优化
- def poly_mod(pl1,pl2,n):
- from functools import reduce
- assert len(pl1) == len(pl2)
- pl1 = poly_monic(pl1,n)
- pl2 = poly_monic(pl2,n)
- for i in range(len(pl1)):
- if pl1[i] > pl2[i]:
- break
- elif pl1[i] < pl2[i]:
- return poly_mod(pl2,pl1,n)
- else:
- return 0
- idx = -1
- for i in range(len(pl1)):
- if pl1[i] == 1:
- idx = i
- break
- for i in range(idx,len(pl2)):
- if pl2[i] == 1:
- pl2 = pl2[:idx] + pl2[i:]
- pl2 += [0]*(len(pl1)-len(pl2))
- break
-
- res = []
- for i in range(len(pl1)):
- if pl2[i] == 0:
- res.append(pl1[i])
- else:
- res.append(pl1[i]-pl2[i])
-
- res = [int(x%n) for x in res]
- g = int(reduce(GCD,res))
- if g > 1:
- res = [x//g for x in res]
- return res
- #最大公因式
- def poly_gcd(pl1,pl2,n):
- while pl2 != 0:
- pl1,pl2 = pl2, poly_mod(pl1,pl2,n)
- pl1 = poly_monic(pl1,n)
-
- return pl1
-
- #x^e-c1
- #(x+di)^e-c2
- pl1 = poly_extend(0,e,n,-c1)
- pl2 = poly_extend(di,e,n,-c2)
-
- pl_d = poly_gcd(pl1,pl2,n)
-
- #求得(x-m),所以取负数即为m
- m = n - pl_d[-1]
- return m
-
- x = related_message_attack(c1, c2, pad2-pad1, e, n)
- bytes.fromhex(hex(x-pad2)[2:])
- #SYC{1_c4n_d0_th15_a1l_d@y}
终于走出rsa了,这里给出了q=p+1然后c = (m+p)**q %p
- from Crypto.Util.number import *
- from secret import flag
- flag = bytes_to_long(flag)
-
- p = getPrime(1024)
- q = p+1
- assert flag**2 < p
- a = pow(flag+p, q, p)
-
- print('p=',p)
- print('a=',a)
-
- '''
- p= 132485702522161146757217734716447479208806639208543182360084149642567339473293168036770464973129405874692085101982109256055320486303869520189058357502693388509190430447787056423080714947904812339604787610679547711291646116182650401371922642011766279740399192613052280061981102203595808184804858315094410004923
- a= 1718205151527213531940354061216609955728503626623437131525315244599535856595391286686273033612529023037466615611832668265075325829196053041494716601943531710744433426780718569225
- '''
根据费马小定理,先把这个q分成p-1+2,将p-1去掉,后边就剩个开平方了,模p的话flag+p=flag
- long_to_bytes(iroot(a,2)[0])
- #SYC{7ca905c9dbba1ffe7ff0ee3ee93f1ac1}
这题目很长很长,但一看也没内容,已经一个很普通的式子运算
- import signal
- import socketserver
- import os
- import string, random
- from hashlib import sha256
- from secret import flag
-
- num = 1000
-
- class Task(socketserver.BaseRequestHandler):
- 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 close(self):
- self.send(b"Remember to solve me later~")
- self.request.close()
-
- def cal(self):
- from Crypto.Util.number import getRandomNBitInteger
- k = 2753645094
- n = 17968909282851700307
- c = getRandomNBitInteger(56)
- a = getRandomNBitInteger(36)
- b = (a * k + c) % n
- self.send(b'[+] k = ' + str(k).encode())
- self.send(b'[+] n = ' + str(n).encode())
- self.send(b'[+] a = ' + str(a).encode())
- self.send(b'[+] b = ' + str(b).encode())
- self.send(b'[+] b = (a * k + c) % n')
- self.send(b'Please give me c:')
- return self.recv(prompt=b'[+] c = ').decode() == str(c)
-
- def handle(self):
- for turn in range(num):
- if not self.cal():
- self.send(b"It's wrong. Please try again!")
- return
- else:
- self.send(b'Good job!')
- self.send(b'the encflag is = ' + str(flag).encode())
-
-
-
- class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
- pass
-
-
- class ForkedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
- pass
-
-
- if __name__ == "__main__":
- HOST, PORT = '0.0.0.0', 80
- server = ForkedServer((HOST, PORT), Task)
- server.allow_reuse_address = True
- server.serve_forever()
因为不知道它什么时候结束,只能读到爆为止
- from pwn import *
-
- p = remote('124.71.215.231', 2223)
- context.log_level = 'debug'
- def aaa():
- k = eval(p.recvline().split(b' = ')[1])
- n = eval(p.recvline().split(b' = ')[1])
- a = eval(p.recvline().split(b' = ')[1])
- b = eval(p.recvline().split(b' = ')[1])
- print(k,n,a,b)
- c = (b - a*k)%n
- p.sendlineafter(b'[+] c = ', str(c).encode())
- res = p.recvline()
- return b'Good' in res
-
- while True:
- aaa()
-
- '''
- [DEBUG] Received 0x92 bytes:
- b'[+] k = 2753645094\n'
- b'[+] n = 17968909282851700307\n'
- b'[+] a = 67398904367\n'
- b'[+] b = 5963091574066878625\n'
- b'[+] b = (a * k + c) % n\n'
- b'Please give me c:\n'
- b'[+] c = '
- 2753645094 17968909282851700307 67398904367 5963091574066878625
- [DEBUG] Sent 0x12 bytes:
- b'59522051419156197\n'
- [DEBUG] Received 0x4f bytes:
- b'Good job!\n'
- b"the encflag is = b'U1lDezEwMDBfTENHX0BuZF95MHVfa24wd18zaGVfZjFAZ30='\n"
- '''
一个非常长的程序
- from PIL import Image
- from Crypto.Util.number import *
- from numpy import array, zeros, uint8
- from random import randint
- from secret import x,y
- import cv2
- import hashlib
- import gmpy2
-
- def gen_key(a,b):
- key = ''
- for i in range(len(a)):
- if a[i] >= '1' and a[i] <= '9':
- key += '0'
- else:
- key += '1'
- for j in range(len(b)):
- if b[j] >= '1' and b[j] <= '9':
- key += '1'
- else:
- key += '0'
- return key
-
- def add(n):
- s = 0
- for i in range(0,len(n),2):
- s += int(n[i])
- return s
-
- image = cv2.imread("flag.jpg")
- img_array = array(image)
- dim1 = len(img_array)
- dim2 = len(img_array[0])
- dim3 = 3
- count = 0
- a = randint(1,2**64)
- b = randint(1,2**64)
-
- assert a * x + b * y == gmpy2.gcd(a, b)
- tmp_1 = hashlib.md5(str(x).encode('utf-8')).hexdigest()
- tmp_2 = hashlib.md5(str(y).encode('utf-8')).hexdigest()
- key = gen_key(tmp_1,tmp_2)
-
- for i in range(len(key)):
- if key[i] == '1':
- count += 1
- else:
- continue
-
- s = add(key)
- enc_img = zeros(shape=[dim1, dim2, dim3], dtype=uint8)
- for t in range(0,count):
- for i in range(0, dim1):
- for j in range(0, dim2):
- for k in range(0, dim3):
- enc_img[i][j][k] = (img_array[i][j][k] ^ (s + int(key)%3))
- s += 3
-
- enc_array = Image.fromarray(enc_img)
- enc_array.show()
- enc_array.save("encflag.jpg")
- print("a = ",a)
- print("b = ",b)
-
-
- '''
- a = 12071216147395236101
- b = 12613118707743158458
- '''
题目长到不想看,就是把一个东西加密成写成图片,其实这跟图也没啥关系就是个数据。因为前边有md5然后再把数据变成01也基本不可逆。唯一办法就是爆破,不过对于jpg图来说,差点也没关系,大概能看出来就行,眼的容错率很高
- from PIL import Image
- from Crypto.Util.number import *
- from numpy import array, zeros, uint8
- import cv2
- import hashlib
- import gmpy2
-
- '''
- tmp_1 = hashlib.md5(str(x).encode('utf-8')).hexdigest()
- tmp_2 = hashlib.md5(str(y).encode('utf-8')).hexdigest()
- key = gen_key(tmp_1,tmp_2)
- for i in range(len(key)): #根据key计算count MD5 64位16进制 count<128
- if key[i] == '1':
- count += 1
- else:
- continue
- s = add(key)
- enc_img = zeros(shape=[dim1, dim2, dim3], dtype=uint8)
- for t in range(0,count):
- for i in range(0, dim1):
- for j in range(0, dim2):
- for k in range(0, dim3):
- enc_img[i][j][k] = (img_array[i][j][k] ^ (s + int(key)%3))
- s += 3
- '''
-
- image = cv2.imread("encflag.jpg")
- img_array = array(image)
- dim1 = len(img_array)
- dim2 = len(img_array[0])
- dim3 = 3
-
- #s<64
- ps = 0
- for key_3 in range(1):
- for count in range(128):
- for s in range(64):
- ps = s
- enc_img = zeros(shape=[dim1, dim2, dim3], dtype=uint8)
- for t in range(0,count):
- for i in range(0, dim1):
- for j in range(0, dim2):
- for k in range(0, dim3):
- enc_img[i][j][k] = (img_array[i][j][k] ^ (s + key_3))
- s += 3
- enc_array = Image.fromarray(enc_img)
- enc_array.save(f"./img/f{key_3}_{count}_{ps}.jpg")
-
- #SYC{not_n1c0_Nico_n1_1t_i5_l0velive}
这个程序会生成很多图片,每过一段就会越来越清楚,比较清楚的就能看到flag
最后几个题干脆名字都没有了。这个把flag与密文异或
- from Crypto.Util.number import *
- from flag import flag
-
- key = bytes_to_long(flag)
- f = open('message.txt','r').read().split('\n')
- cipher = open('cipher.txt','w')
- for i in f:
- i = bytes_to_long(i.encode())
- c = i ^ key
- cipher.write(hex(c)[2:]+'\n')
- cipher.close()
好像也没有好办法,前一段作一题叫snake就是一个个字母猜,开头有4个已知SYC{拿这个异或后得到一堆数据
- 0 b'The '
- 1 b'd by'
- 2 b'cord'
- 3 b' by '
- 4 b'sinc'
- 5 b' if '
- 6 b'5 de'
- 7 b'rota'
- 8 b'e el'
- 9 b'put '
- 10 b'ol s'
- 11 b'le f'
- 12 b' its'
- 13 b' is '
- 14 b'd as'
- 15 b'"lea'
- 16 b'ying'
- 17 b' in '
- 18 b'et w'
- 19 b'f th'
- 20 b'four'
- 21 b' tar'
- 22 b'n an'
- 23 b' fro'
- 24 b' mis'
- 25 b'ngle'
- 26 b'ptio'
- 27 b' ang'
这里可以猜的字符很多,比如19行猜是the,14行后边可能是空格,这样用程序辅助一个个猜。单词猜中的面还是比较大的,而且越往后越容易。
- c = open('cipher.txt','r').read().split()
- a = [bytes.fromhex(i) for i in c[:-1]]
- #print(a)
- flag = b'SYC{' #b'SYC{A1m9_1nfr4r3d_guid4nc3}'
- flag+= bytes([a[19][len(flag)]^ord('e')])
- print(flag)
- for i,v in enumerate(a):
- print(i, bytes([v[j]^flag[j] for j in range(len(flag))]))
给了c和一个缺两位的公钥
- -----BEGIN PUBLIC KEY-----
- MC??DQYJKoZIhvcNAQEBBQADGwAwGAIRAIO444FSJFXBf/yDN67IcCMCAwZpnQ==
- -----END PUBLIC KEY-----
-
- c = 85806005072257465677925369913039323947
因为就差两位,基本上就等于直接给了,爆破出来就行,而且公钥非常小,很容易分解
- from Crypto.PublicKey import RSA
- from Crypto.Cipher import PKCS1_OAEP
- from Crypto.Util.number import long_to_bytes
- from gmpy2 import invert
-
- a = 'MC??DQYJKoZIhvcNAQEBBQADGwAwGAIRAIO444FSJFXBf/yDN67IcCMCAwZpnQ=='
-
- b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-
- for i in b64s:
- for j in b64s:
- c = a[:2]+i+j+a[4:]
- kstr = "-----BEGIN PUBLIC KEY-----\n"+c+"\n-----END PUBLIC KEY-----\n"
- try:
- f = kstr.encode()
- pub = RSA.importKey(f)
- print('n,e=',pub.n,',',pub.e)
- except:
- pass
-
- c = 85806005072257465677925369913039323947
- n,e= 175088864422629078008785584658147995683 , 420253
- p = 12865536769562115787
- q = 13609137928614252809
- phi = (p-1)*(q-1)
- d = invert(e,phi)
- m = pow(c,d,n)
- print(long_to_bytes(m))
- #Panzer_Vor!
- #SYC{Panzer_Vor!}
这个题给了个远程,就是算 e=(r*h+p)%q 的p,其中e,h,q已知
- import signal
- from Crypto.Util.number import *
- import gmpy2 as gp
- import random
- import hashlib
- from secret import flag
-
-
- def gen(self,bound):
- q=getPrime(bound)
- bound1=int(gp.iroot(q//2,2)[0])
- bound2=int(gp.iroot(q//4,2)[0])
- while True:
- f,g=random.randint(1,bound1),random.randint(bound2,bound1)
- if gp.gcd(f,q*g) == 1 :
- break
- h=(gp.invert(f,q)*g)%q
- return q,h,f,g
-
- def gen_m(self,bound):
- p=getPrime(gp.iroot(bound//4,2)[0])
- p_=long_to_bytes(p)
- hash=hashlib.md5()
- hash.update(p_)
- return p,hash.hexdigest()
-
- def dec(self,e,f,g,q):
- a=f*e%q
- b=gp.invert(f,g)*a%g
- return b
-
- def check(self,rec,hash):
- hash_=hashlib.md5()
- hash_.update(rec)
- if hash == hash_.hexdigest():
- return 1
- else:
- return 0
-
-
-
-
- signal.alarm(60)
- bound=1024
- f=1
- for i in range(50):
- q,h,f,g=gen(bound)
-
- p,hash=gen_m(bound)
- r=getPrime(bound//2)
- e=(r*h+p)%q
- print(b'q= '+f'{q}'.encode()+b'\n'+b'h= '+f'{h}'.encode()+b'\n'+b'e= '+f'{e}'.encode()+b'\n')
-
- rec = input(b'Input md5 p: ')
- if rec.decode() == hash:
- print(b'YES!')
- continue
- else:
- print(b'NO!')
- f=0
- break
- if f :
- print(flag)
这个题是一个很标准的NRTU,也就是求最短向量问题(SVP),先前存了个模板,直接套就行了。
- from pwn import *
- import hashlib
- from Crypto.Util.number import long_to_bytes
-
- io = remote('124.71.215.231', 1145)
- context.log_level = 'debug'
-
- def get_v():
- #c = rh + m mod p
- p = eval(io.recvline().split(b'= ')[1])
- h = eval(io.recvline().split(b'= ')[1])
- c = eval(io.recvline().split(b'= ')[1])
- print(p,h,c)
- M = matrix(ZZ, [[1,h],[0,p]])
- f,g = shortest_vector = M.LLL()[0]
- if f<0:
- f = -f
- if g<0:
- g = -g
-
- a = f*c % p % g
- m = a * inverse_mod(f, g) % g
- print('m = ', m)
- hs = hashlib.md5()
- hs.update(long_to_bytes(m))
- v = hs.hexdigest()
- print('v = ', v)
- io.sendlineafter(b'Input md5 p: ', v.encode())
- io.recvline()
-
- for i in range(50):
- get_v()
-
- print(p.recvline())
这题以前没遇到过LWE问题有提示,网友给了搜到的贴子
- from Crypto.Util.number import *
- import gmpy2 as gp
- from secret import flag
- m = 132
- n = 400
- p = 3
- q = 2^20
-
- def gen_mat():
- return matrix(ZZ, [[q//2 - randrange(q) for _ in range(n)] for _ in range(m)])
-
-
- rp,rq = getPrime(m*3),getPrime(400)
- sp,sq = bin(rp)[2:] ,bin(rq)[2:]
- A, B, C = gen_mat(), gen_mat(), gen_mat()
-
- x = vector(ZZ, [int(sp[i]) for i in range(0,m)])
- y = vector(ZZ, [int(sp[i]) for i in range(m,2*m)])
- z = vector(ZZ, [int(sp[i]) for i in range(2*m,3*m)])
- e = vector(ZZ, [int(i) for i in sq])
- c = x*A+y*B+z*C+e
-
-
- flag = bytes_to_long(flag)
- n = rp * rq
- re=65537
- h = gp.powmod(flag,re,n)
-
-
- print('A = \n',A)
- print('B = \n',B)
- print('C = \n',C)
- print('c = ',c)
- print('h = ',h)
- print('n = ',n)
-
- #
把p(396位)分成3段,分别乘上个随机矩阵,然后加一起再加上q,这里q分成位0和1,对于LWE就是那个误差,解法直接套。p这396位先合到一起,组成矩阵,ABC合到一起,求出误差e来取前400位就是q
- from text import *
-
- #A,B,C,c
- M = matrix(ZZ, 0, 400)
-
- for t in [A,B,C]:
- for r in t:
- M = M.stack(vector(r))
-
- c = matrix(ZZ, c)
-
- # c = X*M + e
- z = matrix(ZZ, [0 for _ in range(396)]).transpose()
- beta = matrix(ZZ, [1])
- T = block_matrix([[M, z], [matrix(c), beta]])
-
- L = T.LLL()
- print(L[0])
-
- #e = (1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1)
- q = int(''.join([str(i) for i in L[0][:400]]), 2)
- p = n//q
- m = pow(h,inverse_mod(65537,(p-1)*(q-1)),n)
- print(bytes.fromhex(hex(m)[2:]))
- #{afb65e240bf2b8c5d67756967e2ec2d6}
- #SYC{afb65e240bf2b8c5d67756967e2ec2d6}