西湖论剑网络安全技能大赛 2023
虽然没机会参赛,但也还是要复现学习的。
LockByLock
求n可以利用选择明文攻击,两次输入的明文分别为2和4(两倍关系),通过平方再做差求gcd即可;因为e1和e2都大概是50比特长,可以考虑用bsgs来求解,最后还需要共模攻击计算flag。
MyErrorLearn
这是一个MIHNP,但可以用二元copper的模板来解。两个式子都是\((s+r_i)(d_i+e_i)\equiv 1\;mod\;p\),把s的系数乘为一样然后消去即可建立模p下的二元<e1,e2>方程,板子求解就行。
# MIHNP
from pwn import *
from Crypto.Util.number import *
import itertools
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 []
sh = remote('1.14.71.254',28817)
exec(sh.recvline().strip()[2:])
p = mod
sh.sendline(b'1')
print(sh.recvline())
exec(sh.recvline()[2:].strip())
exec(sh.recvline()[2:].strip())
r1 = r
d1 = d
sh.sendline(b'1')
print(sh.recvline())
exec(sh.recvline()[2:].strip())
exec(sh.recvline()[2:].strip())
r2 = r
d2 = d
print(r1)
print(d1)
print(r2)
print(d2)
P.<e1,e2> = PolynomialRing(Zmod(p))
f = (r1-r2) * (d1+e1)* (d2+e2) - (d2+e2-d1-e1)
print(f)
e1_,e2_ = small_roots(f,[2^246,2^246],m=3)[0]
s = (inverse_mod(int(d1+e1_),p) - r1) % p
sh.sendline(b'2')
print(sh.recvline())
sh.sendline(str(s).encode())
print(sh.recvline())
print(sh.recvline())
# NSSCTF{4ed49415-bdf9-48a2-841f-079c2a3bb8ca}
MyErrorLearnTwice
参考hnp论文的Chapter 7照着造格子就行,NSSCTF上的远程不容易打通,写了个本地的进行验证。
from Crypto.Util.number import *
import random, os
from gmpy2 import *
p = random.getrandbits(1024)
print('> mod =', p)
secret = random.randint(1, p-1)
def XennyOracle():
while True:
try:
r = getPrime(512)
e = getPrime(328)
d = invert(secret+r, p) - e
break
except:
continue
return ZZ(r),ZZ(d),ZZ(e)
samples = [ XennyOracle() for _ in range(15) ]
rs,ds,es = zip(*samples)
A = []
B = []
C = []
D = []
n = 15
r0 = rs[0]
d0 = ds[0]
for j in range(1,n):
A.append(r0 - rs[j])
B.append(ds[j]*(r0 - rs[j]) + 1)
C.append(d0*(r0 - rs[j]) - 1)
D.append(d0*ds[j]*(r0-rs[j])+d0 - ds[j])
n = 14
m = int(p).bit_length()
k = m - 328
mat = [[0 for _ in range(2*n+2)] for _ in range(3*n+2)]
mat[0][0] = 1
for i in range(1,n+2):
mat[i][i] = 2 ^ (k - m)
for i in range(n+2,2*n+2):
mat[i][i] = 4 ^ (k - m)
mat1 = [[0 for _ in range(n)] for _ in range(3*n+2)]
for j in range(n):
mat1[0][j] = D[j]
for i in range(1,n+1):
mat1[i][i-1] = C[i-1]
for j in range(n):
mat1[n+1][j] = B[j]
for i in range(n+2,2*n+2):
mat1[i][i-n-2] = A[i-n-2]
for i in range(2*n+2,3*n+2):
mat1[i][i-2*n-2] = p
M = matrix(QQ, mat).augment(matrix(QQ,mat1))
print('LLL...')
solve = M.LLL()
for i in solve:
if i[0] == 1 or i[0] == -1:
t1 = i[1]
if t1 < 0 :
t1 = t1 * (-1)
e1 = t1 * 2 ^ 328
print(f'e1={e1}')
s = (inverse_mod((ds[1] + e1),p) - rs[1]) % p
if s == secret:
print('success!')
break
print('done...')
MyCurveErrorLearn
同样参考hnp论文,造的格和上题十分类似。大致思路就是向server先后发t和-t,然后根据椭圆曲线表达式和点加法构造多项式,主要过程: