一个良心的比赛,赛完后给出wp,都是挺好的题,有必要都试一下
签到题,直接给了加密算法和密文,逐位的进行异或移位操作,这个东西都可以爆破
- class baby_arx():
- def __init__(self, key):
- assert len(key) == 64
- self.state = list(key)
-
- def b(self):
- b1 = self.state[0]
- b2 = self.state[1]
- b1 = (b1 ^ ((b1 << 1) | (b1 & 1))) & 0xff
- b2 = (b2 ^ ((b2 >> 5) | (b2 << 3))) & 0xff
- b = (b1 + b2) % 256
- self.state = self.state[1:] + [b]
- return b
-
- def stream(self, n):
- return bytes([self.b() for _ in range(n)])
-
-
- FLAG = open('./flag.txt', 'rb').read().strip()
- cipher = baby_arx(FLAG)
- out = cipher.stream(64).hex()
- print(out)
-
- # cb57ba706aae5f275d6d8941b7c7706fe261b7c74d3384390b691c3d982941ac4931c6a4394a1a7b7a336bc3662fd0edab3ff8b31b96d112a026f93fff07e61b
爆破
- #!/usr/bin/env python3
- def b_cust(b1, b2):
- c1 = (b1 ^ ((b1 << 1) | (b1 & 1))) & 0xff
- c2 = (b2 ^ ((b2 >> 5) | (b2 << 3))) & 0xff
- b = (c1 + c2) % 256
- return b
-
- out = 'cb57ba706aae5f275d6d8941b7c7706fe261b7c74d3384390b691c3d982941ac4931c6a4394a1a7b7a336bc3662fd0edab3ff8b31b96d112a026f93fff07e61b'
- enc = bytes.fromhex(out)
-
- flag = 'D'
- for i in range(len(enc) - 1):
- for code in range(32, 127):
- b = b_cust(ord(flag[-1]), code)
- if b == enc[i]:
- flag += chr(code)
- break
-
- print(flag)
- #DUCTF{i_d0nt_th1nk_th4ts_h0w_1t_w0rks_actu4lly_92f45fb961ecf420}
'运行
当然也可以不爆破,用z3可以直接出.
AES的OFB模式加密,可以交互两次,用户提供IV给出加密结果
- #!/usr/bin/env python3
-
- from os import urandom, path
- from Crypto.Cipher import AES
-
-
- FLAG = open(path.join(path.dirname(__file__), 'flag.txt'), 'r').read().strip()
- MESSAGE = f'Decrypt this... {urandom(300).hex()} {FLAG}'
-
-
- def main():
- key = urandom(16)
- for _ in range(2):
- iv = bytes.fromhex(input('iv: '))
- aes = AES.new(key, iv=iv, mode=AES.MODE_OFB)
- ct = aes.encrypt(MESSAGE.encode())
- print(ct.hex())
-
-
- if __name__ == '__main__':
- main()
-
- #nc 2022.ductf.dev 30009
OFB的加密方式为先用iv=z0加密得到z1然后用m0⊕z1得到c0,也就是用iv得到的加密流z1,z2,...与明文异或得到密文。所以如果把z1作为iv得到的加密的就是z2,z3,z4...这些z与上边的z相同。
由于第1段明文已知,那么第一次随意输入一个iv得到密文c0,然后用已知的第1断明文和c0的第1段得到z1,第2次输入iv为z1得到c1,同样通过c1与已知明文异或得到z2,然后用z2和c0的第2段异或得到第2段明文,最后得到flag
- #!/usr/bin/env python3
- from pwn import *
- from os import urandom, path
- from Crypto.Cipher import AES
-
-
- #FLAG = open(path.join(path.dirname(__file__), 'flag.txt'), 'r').read().strip()
- #MESSAGE = f'Decrypt this... {urandom(300).hex()} {FLAG}'
-
-
- def main():
- key = urandom(16)
- for _ in range(2):
- iv = bytes.fromhex(input('iv: '))
- aes = AES.new(key, iv=iv, mode=AES.MODE_OFB)
- ct = aes.encrypt(MESSAGE.encode())
- print(ct.hex())
-
- #nc 2022.ductf.dev 30009
- '''
- m0 m1 m2 m3
- iv z1 z2 z3 z4 ...
- c0 c1 c2 c3
- m0 m1 m2 m3
- z1 z2 z3 z4 z5 ...
- x0 x1 x2 x3
- OFB模式每轮只对iv加密,然后由c=m^z
- 第1次随意输入
- 第2次输入由第1次得到的z1
- 这样循环 m0^x0 => z2得到下一轮的z, c1^z2 => m1 得到下一块明文
- '''
- m = [b'Decrypt this... ']
- iv = b'\x00'*16
-
- context.log_level = 'debug'
-
- p = remote('2022.ductf.dev', 30009)
-
- #由已知明文得到z(i)
- p.sendlineafter(b'iv: ', iv.hex().encode())
- c0 = unhex(p.recvline()[:-1])
- z0 = xor(c0[:16],m[0])
- z = [z0]
-
- #以z(i)为iv,由已知明文0得到z(i+1)
- p.sendlineafter(b'iv: ', z0.hex().encode())
- c1 = unhex(p.recvline()[:-1])
-
- for i in range(0, len(c0), 16):
- #c(i+1) xor z(i+1) => m(i)
- z.append(xor(m[-1], c1[i: i+16]))
- m.append(xor(z[-1], c0[i+16: i+16+16]))
-
- print(b''.join(m))
- #DUCTF{0fb_mu5t_4ctu4lly_st4nd_f0r_0bvi0usly_f4ul7y_bl0ck_c1ph3r_m0d3_0f_0p3ra710n_7b9cb403e8332c980456b17a00abd51049cb8207581c274fcb233f3a43df4a}
-
- '''
- C:\2022_DownUnderCTF\crypto_2_oracle-for-block-cipher-enthusiasts>py a.py
- [x] Opening connection to 2022.ductf.dev on port 30009
- [x] Opening connection to 2022.ductf.dev on port 30009: Trying 34.87.217.252
- [+] Opening connection to 2022.ductf.dev on port 30009: Done
- [DEBUG] Received 0x4 bytes:
- b'iv: '
- [DEBUG] Sent 0x21 bytes:
- b'00000000000000000000000000000000\n'
- [DEBUG] Received 0x5f9 bytes:
- b'c5d2cc11722803d1c34f2b0d59938a06f58c4f0e2b7acbd08f30115bb58e08f8726c4226c125282faa8a50687573f8aac72d58f83b531cff4a
- 8264bb7dbdfce9839165ec3b943ceaf7a8da0234e100f720407004441b28bb82cbe48cc4f017b4385783468e239391ffe8aad14fdfb37e5685d31a6a
- 234830b7d032bfa8f82543616bc6be663b7d098a46e3c147b51f1bbded127a303dc6d762a3429aa2f05d6526dff55799179f33e4e2062850be1b26dd
- dc471b010b15bca6aa5b7ba802cd16d69cd34ac959f7042919d6ed88804c4253f298328b5cd0f6f4ba9aff14eea8d7b0dc728780fa895dc52c9cd083
- 08f4c1c75e8d529f8cee054df4e1e615c50798b06b95439152d8a90778afa5c17944cdf3dd753147245f1331fc84c18111ca4a13013150acee86bbb5
- 8cd16fa9371f570b23f80269443e1bf7d58bd2dde86217ddd6ce40f9c67308ac9c870c9901e14874bdd608ba6cde6ef662e7b0683458fae41cee5d8c
- e565f7add226c7379359c0b0853dc56199971ad924b04033e3969905acf68ba3bdb21331df811edbb3dda90b4bff4413ccd0164f72e83e1e4312ff12
- bcd5fc3ea4af22955c229d90113813cba196afe84492331c880761a6d0dd3fcaa881dda419826f8bc42bbd834d1f5247621547f1d325c5716b086ba6
- b841092ad451decdfd50590e2b767af754c4ae271cea75e4ffbd6a1a255a2f2f93dac2291b1c814a34395c0ee6cb9b45dd1ad925ff4db46a2a61c06f
- dbe256c62dc26cff7907757eddb5855fd1e8dd4f2ae6df0a08f48799b5e0ffcc62fcaee4f9a73598190677d7e6235598cc383c2f9b01e1cb47523f3e
- f733700ee7ab7ff5fadce14000ca46b671346796573781232069743733e6be7a16838b837d8ea9371d6b4174ff29362f8061168f71cbf7b7cce5d83c
- f5e1cd3f47450d8ccf521a44cea4ef83f8a2c8cb25a30a31c6987c1b6f5dcee3579c44a8907bfec9fa20a55aa1cfedf7dd0a3242da1481eeff93fc8b
- 7d1ff848314ca0df57756a28ae2d6bfa1d09adced1340b85ea3fa6a3330daec73a9226e5030f31dbfae51a2c43\n'
- b'iv: '
- [DEBUG] Sent 0x21 bytes:
- b'81b7af630b5877f1b727427e77bda426\n'
- [DEBUG] Received 0x5f5 bytes:
- b'd7df494e346bdbc7c26c1e49a29211ed706e45759377747da78c0e6a7b70fdfac22f0dff3b5046a218826fbc7deaafbdda9364b93fc166e0a5
- a8880566bf57f529127255154626bfd59db7df95f114b13c53d5418e29979effeffdd21dd5bf2906d6804e3e204b3eb28562bea8ae7844603fc2b66b
- 692d06d949e3c045b51d48bcea45213b6d96dd34a81490f6ad0c6322dff5049c1d9d60beb4062654b61473dd8e411a000544e4aaf80c78ab53c51181
- 9fd34a980ca7592b16d4ef8dd04c1100a5cb37db5cd4f1f3b39ba845edaf80ed8d7587d4ac8f5f977ecad3d259fac19b538e54ccdebd024df3e2b112
- 940b99ed36934398528faa532eacf195731090f2d922374d245e4f62aed693d01c9b424e066706aebb82b1e6d8813afa341955597daa026d443810f9
- d18ed5dde632468fdace14afc57603f5ccd954990ee51a74ead15abe6fd839f560e9b9683159f2e046ea5ad9b234aafdd326c665c4589cb3dd3c9430
- 99c21adc27b24067e3c69b57a8ab8cf6eeb24b628a8c1ed8e3dcf90c1ef64846cad5451376e73b4f4715fb14bbd2a068a2fe279c092298c4126f409b
- a793fced1797601cdc5564f4d788389faf818cf41cda328f9478e8d41e4b5712361414a3d42a9d753d0b6fa5ba470b2dd050df9ca8540c5d7d772ff6
- 00c3a97818be23e5f4bd3f4a26562b2dc1d891214c49d7183c3a5e59b294cb428a4cd876ab1be338236097688eb4549e20966bad2f51707ed1b28959
- d7ee8f4627b4dd5e5aa183ceb9eea59034faacedfea061c94b067186bb2c0195ce3b3d22cb52bdc8110c6d3fa663200bb4f97cf0ae8bea45059416e3
- 226165867103f6465020766235dfb53e45c4b0975aaf9f57377c084dee026f34d14a2f8b60e0b2e1d6e09116f5f9800e452e1ed08a747544d4fdbc9d
- d4ad80e42ba40d029cd1474a5c5dcbd7388f46aa997fbda6f94ff60bc79ce99cdd496408881082bda8f4fbdd714af84d361ef5d705243c7ea6256ff7
- 4b5df7cdd6620e8dba3ef0a1365bf99c6bc32db1005930d0afe01c7a0ac01e9aa4b18a27f9f3315197ec12b680\n'
- b'Decrypt this... f6e2fad794fa9275d4ba438e428c712ea67f40b8f23d7fa184630e8242ace8631f4ba866cd2049565bbea229cce3f39ae11151
- 17f652fedfde598ca85953def5ebbb3312c2c90873abb1693a9dc7408fa0d077b956447a0a63d0fb2d79662102ed756b6c007ac27e8505b40abbab2c
- 9ed8331fcfbeb5525d9e538f4e63aaa8a98ab52f59ea330501ef4c031365cfc66378fc437881fac8fbe4f7b023aa89c7b0ecaef34dbc60c2c8a9eb3d
- e92b611ebdbad3bd097a41ee2f0e94770ad491f5367008b15280647142177d47d71e61c2caa1271dad11d4156f462faa995a7affbcab353f6a174eed
- daff24b324ba50d0cf9bfbc82a2b94fba51534101ce6fda574baecc904bc0f98c3073fc578de640511defb499b8306926e57fded6651374be96a86d5
- ff0ba416223dff1f3d DUCTF{0fb_mu5t_4ctu4lly_st4nd_f0r_0bvi0usly_f4ul7y_bl0ck_c1ph3r_m0d3_0f_0p3ra710n_7b9cb403e8332c98045
- 6b17a00abd51049cb8207581c274fcb233f3a43df4a}C~\xf7\xa7YCA\xca\x92\x05b\xf3\x8a&\xd7\xfdd\x87\x04\x96\x08\xd4'
- '''
这是个脑筋急转弯的题。题目是一个很难计算的算式C = A^n * B^m 给出3组解,然后让输入3组解使式子成立
- p = 55899879511190230528616866117179357211
- V = GF(p)^3
- R.
= PolynomialRing(GF(p)) - f = x^3 + 36174005300402816514311230770140802253*x^2 + 35632245244482815363927956306821829684*x + 10704085182912790916669912997954900147
- Q = R.quotient(f)
-
- def V_pow(A, n):
- return V([a^n for a in list(A)])
-
- n, m = randint(1, p), randint(1, p)
- A = Q.random_element()
- B = Q.random_element()
- C = A^n * B^m
-
- print(' '.join(map(str, list(A))))
- print(' '.join(map(str, list(B))))
- print(' '.join(map(str, list(C))))
-
- phi_A = V(list(map(int, input().split())))
- phi_B = V(list(map(int, input().split())))
- phi_C = V(list(map(int, input().split())))
-
- check_phi_C = V_pow(phi_A, n).pairwise_product(V_pow(phi_B, m))
-
- if phi_C == check_phi_C:
- print(open('./flag.txt', 'r').read().strip())
但是这个算式有两个特殊解0,1当ABC都是0或者都是1时算式恒成立,所以直接输入1组即可
- $ nc 2022.ductf.dev 30012
- 47778318564842784566021875964043407448 14225130399845907372219257728746212147 8574612587622189283548244260000651099
- 54562657673431046093572570377554257218 13201212589661363040860414827784708283 6559649814714882162760393923770035994
- 42068356418631381456403302803023702216 2953351887187401071583384926766279486 28509402046235153374884180763878587638
- 0 0 0
- 0 0 0
- 0 0 0
- DUCTF{CRT_e4sy_as_0ne_tw0_thr3e}
-
-
- $ nc 2022.ductf.dev 30012
- 14202332705912194922737102630420425225 25456741823861199641984966822367393116 49401604133125475446972443244172984778
- 35742550950811340910151890855042975986 30127926032118592751540416970212811542 37792889060452965734274017750212553062
- 4755274484612010897449319953362032907 33809699771879943330968717144050513513 20099247008524376332197577971971190549
- 1 1 1
- 1 1 1
- 1 1 1
- DUCTF{CRT_e4sy_as_0ne_tw0_thr3e}
以下4道都是RSA oracle的题,以前见到的都是LSB,这个第一回见,学习了。
第1题比较简单,给一N,e,c 然后可以输入密文,反回明文是否在区间内,区间自己输入。
- #!/usr/bin/env python3
-
- import signal, time
- from os import urandom, path
- from Crypto.Util.number import getPrime, bytes_to_long
-
-
- FLAG = open(path.join(path.dirname(__file__), 'flag.txt'), 'r').read().strip()
-
- N_BITS = 384
- TIMEOUT = 20 * 60
- MAX_INTERVALS = 384
- MAX_QUERIES = 384
-
-
- def main():
- p, q = getPrime(N_BITS//2), getPrime(N_BITS//2)
- N = p * q
- e = 0x10001
- d = pow(e, -1, (p - 1) * (q - 1))
-
- secret = bytes_to_long(urandom(N_BITS//9))
- c = pow(secret, e, N)
-
- print(N)
- print(c)
-
- intervals = []
- queries_used = 0
-
- while True:
- print('1. Add interval\n2. Request oracle\n3. Get flag')
- choice = int(input('> '))
-
- if choice == 1:
- if len(intervals) >= MAX_INTERVALS:
- print('No more intervals allowed!')
- continue
-
- lower = int(input(f'Lower bound: '))
- upper = int(input(f'Upper bound: '))
- intervals.insert(0, (lower, upper)) #从头部插入,如果判断时成功则返回0,不成功会返回上一次成功的位置>1,全部不成功才返回-1
-
- elif choice == 2:
- queries = input('queries: ')
- queries = [int(c.strip()) for c in queries.split(',')]
- queries_used += len(queries)
- if queries_used > MAX_QUERIES:
- print('No more queries allowed!')
- continue
-
- results = []
- for c in queries:
- m = pow(c, d, N)
- for i, (lower, upper) in enumerate(intervals):
- in_interval = lower < m < upper
- if in_interval:
- results.append(i)
- break
- else:
- results.append(-1)
-
- print(','.join(map(str, results)), flush=True)
-
- time.sleep(MAX_INTERVALS * (MAX_QUERIES // N_BITS - 1))
- elif choice == 3:
- secret_guess = int(input('Enter secret: '))
- if secret == secret_guess:
- print(FLAG)
- else:
- print('Incorrect secret :(')
- exit()
-
- else:
- print('Invalid choice')
-
-
- if __name__ == '__main__':
- signal.alarm(TIMEOUT)
- main()
解决办法:对于同样的c,划定m的区间这样就能通过区间确定m的大小,利用二分法每次确定1位。
- from pwn import *
-
- p = remote('2022.ductf.dev', 30008)
-
- #context.log_level = 'debug'
-
- N = int(p.recvline())
- c = int(p.recvline())
-
- N_BITS = 384
- border = [-1, 2<<(N_BITS//9*8)]
-
- def sendborder(low,high):
- p.sendlineafter(b'> ', b'1')
- print(low)
- print(high)
- p.sendlineafter(b'Lower bound: ', str(low).encode())
- p.sendlineafter(b'Upper bound: ', str(high).encode())
-
- def get_v():
- p.sendlineafter(b'> ', b'2')
- p.sendlineafter(b'queries: ', str(c).encode())
- res = int(p.recvline())
- return res
-
- def get_flag(sec):
- p.sendlineafter(b'> ', b'3')
- p.sendlineafter(b'Enter secret: ', str(sec).encode())
- flag = p.recvline()
- return flag
-
- for i in range(N_BITS//9*8):
- tb = (border[0]+border[1])//2 #检测下半区是否命中
- sendborder(border[0], tb)
- res = get_v()
- print(i,'RES:' , res)
- if res != 0: #命中时返回i==0,其它-1,2,3,4都是未命中
- border[0] = tb-1 #未命中的情况, 值在上半区,更新下边界
- else:
- border[1] = tb #命中,在本区更新上边界
-
- context.log_level = 'debug'
-
- print(get_flag(border[0]+1))
第2题在第1题的程序上改动了输入区间的次数为1,也就是只允许输入1次区间。那么这个区间就输入是固定的,难度就象羊了个羊第2关。
我理解是输入一个分数比如4/3m就会落在大于1的范围上,但在有限域上不能输入分数。就得用比较复杂的办法来模拟,但由于精度不够,在最后还需要爆破24位
- from pwn import *
- from gmpy2 import invert, c_div
-
- p = remote('2022.ductf.dev', 30011)
-
- context.log_level = 'debug'
-
- N = int(p.recvline())
- c = int(p.recvline())
- e = 0x10001
- N_BITS = 384
- border = [-1, 2<<(N_BITS//9*8)]
-
- def sendborder(low,high):
- p.sendlineafter(b'> ', b'1')
- #print(low)
- #print(high)
- p.sendlineafter(b'Lower bound: ', str(low).encode())
- p.sendlineafter(b'Upper bound: ', str(high).encode())
-
- def get_v(fc):
- p.sendlineafter(b'> ', b'2')
- p.sendlineafter(b'queries: ', str(fc).encode())
- res = int(p.recvline())
- return res
-
- def get_flag(sec):
- p.sendlineafter(b'> ', b'3')
- p.sendlineafter(b'Enter secret: ', str(sec).encode())
- flag = p.recvline()
- return flag
-
-
- '''
- #local
- from os import urandom
- from Crypto.Util.number import getPrime, bytes_to_long
- N_BITS = 384
- p = 0xbe103afbae6d9ef1bf866a9fe44da3a9c3b2818e315de13b
- q = 0xf206c05bd9f2cb28822f84874b94b2dbbf0e3e625426c2f5
- N = p*q
- e = 0x10001
- d = pow(e, -1, (p - 1) * (q - 1))
- print('d = ', hex(d))
- secret = 0x1ad7dbd636f2eb28c75bd0e70a08e6a16a75ae540f3bced8c33e091bd588bf5c406e152431973476f930
- c = pow(secret, e, N)
- print('N =', hex(N))
- print('secret =',hex(secret))
- #发送tc 返回是否命中 0命中,-1未命中(本地模拟)
- def get_v(tc):
- tm = pow(tc, d, N)
- print(hex(tm).rjust(100, ' '))
- print(hex(border[1]).rjust(100, ' '))
- if border[0] < tm < border[1]:
- return 0
- else:
- return -1
- def get_flag(s):
- if s == secret:
- return "flag{test OK}"
- else:
- return "Fail "+hex(secret)
- '''
-
- def oracle(f):
- return get_v(c * pow(f,e,N) % N )
-
- #1,secret长度384//9*8=336 边界设置为 B = 336+40
- B = 1<<336+40
- border = [-1, B]
- sendborder(border[0], border[1])
-
- #2,查询secret到B前0的个数
- f1 = 1<<40
- while oracle(f1) == 0:
- f1 <<=1
- f1>>=1
-
- #3, ((N+B)/B + delta)*f1*m 是否在边界内
- f2 = (N + B)//B * f1
- while oracle(f2) == -1:
- f2 += f1
-
- #4,
- low = c_div(N, f2)
- high= (N + B)//f2
- while high > low:
- tmp = (2*B)//(high - low)
- i = c_div(tmp * low, N)
- f3 = c_div(i*N, low)
- if oracle(f3) == -1:
- low = c_div(i*N+B, f3)
- else:
- high = (i*N+B)//f3
-
- #5 test
- assert high - low < (1<<24)
- for f4 in range(low, high+1):
- if pow(f4,e,N) == c:
- print(get_flag(f4))
- break
-
- '''
- [DEBUG] Received 0x30 bytes:
- b'1. Add interval\n'
- b'2. Request oracle\n'
- b'3. Get flag\n'
- b'> '
- [DEBUG] Sent 0x2 bytes:
- b'3\n'
- [DEBUG] Received 0xe bytes:
- b'Enter secret: '
- [DEBUG] Sent 0x67 bytes:
- b'131648374553052306210268283842344617331957330884679611956409650994486668851589013872428584385213442659\n'
- [DEBUG] Received 0x24 bytes:
- b'DUCTF{Manger_w0uld_b3_pr0ud_0f_y0u}\n'
- '''
这个又变了,sleep的时间更长,总timeout变小了,这个有一个工具集lbc_toolkit这里边有个hidden_number_problem 这里输入4个区间,每个差1位,然后输入4700个随机数,当某个数字落在这个区间内就会返回0,1,2,3不在区间内返回-1,当这个题至少50个的时候就可以很快算出m
- from pwn import *
- #from collections import Counter
-
- # https://github.com/josephsurin/lattice-based-cryptanalysis
- from lbc_toolkit import ehnp
-
-
- def add_interval(lower, upper):
- conn.sendlineafter(b'> ', b'1')
- conn.sendlineafter(b'Lower bound: ', str(lower).encode())
- conn.sendlineafter(b'Upper bound: ', str(upper).encode())
-
- def query_oracle(cts):
- conn.sendlineafter(b'> ', b'2')
- conn.sendlineafter(b'queries: ', ','.join(map(str, cts)).encode())
- r = list(map(int, conn.recvline().decode().split(',')))
- return r
-
- N_BITS = 384
- MAX_INTERVALS = 4
- MAX_QUERIES = 4700
- e = 0x10001
-
- #context.log_level = 'debug'
- # conn = process('./rsa-interval-oracle-iii.py')
- def go():
- global conn
-
- conn = remote('2022.ductf.dev', 30010)
-
- N = int(conn.recvline().decode())
- secret_ct = int(conn.recvline().decode())
- print("N = ", N)
- print("secret_ct = ", secret_ct)
-
- for i in range(8, 8 + MAX_INTERVALS):
- add_interval(0, 1<<(N_BITS - i))
-
-
- rs = [randint(1, N) for _ in range(MAX_QUERIES)]
- cts = [pow(r, e, N) * secret_ct for r in rs]
- query_res = query_oracle(cts) #测试4700个随机数
- #print(Counter(query_res))
-
- rs_and_Us = [(r, N_BITS - (MAX_INTERVALS - i + 7)) for r, i in zip(rs, query_res) if i != -1]
-
- ell = len(rs_and_Us)
- print('ell:', ell)
- if ell < 50:
- conn.close()
- print("Fail")
- return False
-
- print('rs_and_Us = ', rs_and_Us)
-
- open('data.py', 'w').write(f'ell = {ell}\nsecret_ct = {secret_ct}\nN = {N}\nrs_and_Us = {rs_and_Us}')
- print(f'e = {e}\nell = {ell}\nsecret_ct = {secret_ct}\nN = {N}\nrs_and_Us = {rs_and_Us}')
- conn.sendlineafter(b'> ', b'3')
- conn.interactive()
- '''
- xbar = 0
- Pi = [0]
- Nu = [336]
- Alpha = [r for r, _ in rs_and_Us]
- Rho = [[1]] * ell
- Mu = [[U] for _, U in rs_and_Us]
- Beta = [0] * ell
- print(xbar, N, Pi, Nu, Alpha, Rho, Mu, Beta)
-
- sol = ehnp(xbar, N, Pi, Nu, Alpha, Rho, Mu, Beta, delta=1/10**22, verbose=True)
- secret = -sol % N
- print('secret = ', secret)
- print('c = ', pow(secret,e,N))
-
- context.log_level = 'debug'
- conn.sendlineafter(b'> ', b'3')
- conn.sendlineafter(b'Enter secret: ', str(secret).encode())
- flag = conn.recvline().decode()
- print(flag)
- if 'DUCTF' in flag:
- conn.close()
- return True
- '''
-
- while not go():
- pass
-
- #DUCTF{rsa_1nt3rv4l_0r4cl3_1s_n0_m4tch_f0r_y0u!}
由于网站运行很慢,程序到最后提交的时候总是报错,我把运算的部分单出来,到生成超过50时,由另外一个程序运行,最后再把结果粘回来。
- from lbc_toolkit import ehnp
- from data import *
-
- e = 0x10001
- xbar = 0
- Pi = [0]
- Nu = [336]
- Alpha = [r for r, _ in rs_and_Us]
- Rho = [[1]] * ell
- Mu = [[U] for _, U in rs_and_Us]
- Beta = [0] * ell
- print(xbar, N, Pi, Nu, Alpha, Rho, Mu, Beta)
-
- sol = ehnp(xbar, N, Pi, Nu, Alpha, Rho, Mu, Beta, delta=1/10**22, verbose=True)
-
- secret = -sol % N
- print('secret = ', secret)
- print('c = ', pow(secret,e,N))
这个题在上题基础上给了固定的区间,因为都是预期用同一个程序解,所以区间跟上一题一样。只不过不用输入而已,不过这题用那个官方程序和上边验证过的都试过,结果不正确。不知道原因。
这个到最后也没看懂,先保留一下吧。应该是关于矩阵快速幂的,基本上纯数学问题。给的是一个可以出flag的程序,但由于n非常大,每次减1 不可能实现。这就需要一个简化的方法。
- from hashlib import sha256
- from Crypto.Util.Padding import unpad
- from Crypto.Cipher import AES
-
-
- ct = bytes.fromhex('85534f055c72f11369903af5a8ac64e2f4cbf27759803041083d0417b5f0aaeac0490f018b117dd4376edd6b1c15ba02')
-
-
- p = 275344354044844896633734474527970577743
- a = [2367876727, 2244612523, 2917227559, 2575298459, 3408491237, 3106829771, 3453352037]
- α = [843080574448125383364376261369231843, 1039408776321575817285200998271834893, 712968634774716283037350592580404447, 1166166982652236924913773279075312777, 718531329791776442172712265596025287, 766989326986683912901762053647270531, 985639176179141999067719753673114239]
-
-
- def f(n):
- if n < len(α):
- return α[n]
-
- n -= len(α) - 1
- t = α[::-1]
- while n > 0:
- x = sum([a_ * f_ for a_, f_ in zip(a, t)]) % p
- t = [x] + t[:-1]
- n -= 1
-
- return t[0]
-
-
- n = 2**(2**1337)
- key = sha256(str(f(n)).encode()).digest()
- aes = AES.new(key, AES.MODE_ECB)
- flag = unpad(aes.decrypt(ct), 16)
- print(flag.decode())
官方结果
- from Crypto.Util.number import long_to_bytes
- from hashlib import sha256
- from Crypto.Util.Padding import unpad
- from Crypto.Cipher import AES
-
- ct = bytes.fromhex('85534f055c72f11369903af5a8ac64e2f4cbf27759803041083d0417b5f0aaeac0490f018b117dd4376edd6b1c15ba02')
-
- p = 275344354044844896633734474527970577743
- a = [2367876727, 2244612523, 2917227559, 2575298459, 3408491237, 3106829771, 3453352037]
- α = [843080574448125383364376261369231843, 1039408776321575817285200998271834893, 712968634774716283037350592580404447, 1166166982652236924913773279075312777, 718531329791776442172712265596025287, 766989326986683912901762053647270531, 985639176179141999067719753673114239]
-
- M = Matrix(GF(p), [a])
- M = M.stack(Matrix.identity(len(a) - 1).augment(Matrix.column([0] * (len(a) - 1))))
- order = prod([p^len(a) - p^k for k in range(0, len(a))])
- n = int(pow(2, 2^1337, order)) - 6
- fn = (M^n * vector(α[::-1]))[0]
-
- key = sha256(str(fn).encode()).digest()
- aes = AES.new(key, AES.MODE_ECB)
- flag = unpad(aes.decrypt(ct), 16)
- print(flag.decode())
虽然题都不会,不过把sage安上了,可以直接在sage里from pwn import *了,还算是有收获的。
马上放假了,可以有时间把pwn都过一遍了。