import os
flag = os.getenv("FLAG", "fake{fakeflag_blahblah}") ##319bit
x = int.from_bytes(flag.encode(), "big")
p = random_prime(1 << int(x.bit_length() * 2.5)) #796
Fp = GF(p)
params = []
while len(params) != 6:
try:
y = randint(2, x)
a = randint(2, p-1)
b = (y^2 - (x^3 + a*x)) % p
EC = EllipticCurve(Fp, [a, b])
EC(x, y)
params.append([a, b])
except ValueError:
pass
print(p)
print(params)
문제를 보면 고정 값 x, p가 있을 때,
p와 $x^3+ax+b=y^2 (mod\;p)$를 만족하는 $(a,b)$쌍 6개를 제공해준다.
이때, p의 bit를 알기 때문에, 다른 변수들의 bit도 예상 가능하다.
** 각 변수 크기
x, y : 319bit
a, b, p : 796bit
x가 고정 값이기 때문에 식 2개를 빼보면 아래와 같은 식을 얻을 수 있다.
$$(a_0-a_1)*x+(b_0-b_1)=y_0^2-y_1^2\;(mod\;p)$$
주어진 값이 총 6개이기 때문에 위와 동일한 형태의 식 5개를 얻을 수 있는 것이다.
$$ -2^{319}<(a_i-a_{i+1})*x+(b_i-b_{i+1})\;(mod\;p)<2^{319} $$
여기서 x를 구하기 위해 여러 부등식들을 세우고, rkm님의 CVP repository를 이용하면 풀 수 있어 보인다.
해당 문제의 경우 부등식이 $Zmod(p)$위에서 존재하기 때문에 어떻게 CVP repo에 적용할 수 있을지 몰랐는데, rkm님의 도움을 얻어 변수를 하나 더 추가해주면 modulo 연산을 무시할 수 있다는 사실을 깨달았다.
$$ -2^{319}<(a_i-a_{i+1})*x+(b_i-b_{i+1})+p*c_i <2^{319}$$
여기서{b_i}는 주어진 값이므로 lower/upper bound 쪽으로 넘기면 된다.
$$ -2^{319}-(b_i-b_{i+1})<(a_i-a_{i+1})*x+p*c_i <2^{319}-(b_0-b_i) $$
추가적으로 우리가 아는 식이 1개 더 있다.
$$ 0<x<2^{319} $$
이제 변수는$x$, $c_1$, ... $c_5$로 총 6개이고 식이 6개이므로 아래와 같은 6x6 Matrix를 만들어서 rkm’s CVP repo를 적용하면 각 변수의 값을 구할 수 있다.
$$ \begin{bmatrix} a_0-a_1 &a_1-a_2 & a_2-a_3 & a_3-a_4 & a_4-a_5 & 1 \\p & 0 & 0 & 0 & 0 & 0 \\0 & p & 0 & 0 & 0 & 0 \\0 & 0 & p & 0 & 0 & 0 \\0 & 0 & 0 & p & 0 & 0 \\0 & 0 & 0 & 0 & p & 0 \end{bmatrix}$$
첨언 하자면 각 열이 하나의 부등식이고 각 행이 변수의 계수라고 보면 된다.
1번 행은 $x$, 2번행은 $c0$ , 6번행은 $c5$인 것이다.
ans.sage
from sage.modules.free_module_integer import IntegerLattice
from Crypto.Util.number import *
# Directly taken from rbtree's LLL repository
# From https://oddcoder.com/LOL-34c3/, https://hackmd.io/@hakatashi/B1OM7HFVI
def Babai_CVP(mat, target):
M = IntegerLattice(mat, lll_reduce=True).reduced_basis
G = M.gram_schmidt()[0]
diff = target
for i in reversed(range(G.nrows())):
diff -= M[i] * ((diff * G[i]) / (G[i] * G[i])).round()
return target - diff
def solve(mat, lb, ub, weight = None):
num_var = mat.nrows()
num_ineq = mat.ncols()
max_element = 0
for i in range(num_var):
for j in range(num_ineq):
max_element = max(max_element, abs(mat[i, j]))
if weight == None:
weight = num_ineq * max_element
# sanity checker
if len(lb) != num_ineq:
print("Fail: len(lb) != num_ineq")
return
if len(ub) != num_ineq:
print("Fail: len(ub) != num_ineq")
return
for i in range(num_ineq):
if lb[i] > ub[i]:
print("Fail: lb[i] > ub[i] at index", i)
return
# heuristic for number of solutions
DET = 0
if num_var == num_ineq:
DET = abs(mat.det())
num_sol = 1
for i in range(num_ineq):
num_sol *= (ub[i] - lb[i])
if DET == 0:
print("Zero Determinant")
else:
num_sol //= DET
# + 1 added in for the sake of not making it zero...
print("Expected Number of Solutions : ", num_sol + 1)
# scaling process begins
max_diff = max([ub[i] - lb[i] for i in range(num_ineq)])
applied_weights = []
for i in range(num_ineq):
ineq_weight = weight if lb[i] == ub[i] else max_diff // (ub[i] - lb[i])
applied_weights.append(ineq_weight)
for j in range(num_var):
mat[j, i] *= ineq_weight
lb[i] *= ineq_weight
ub[i] *= ineq_weight
# Solve CVP
target = vector([(lb[i] + ub[i]) // 2 for i in range(num_ineq)])
result = Babai_CVP(mat, target)
for i in range(num_ineq):
if (lb[i] <= result[i] <= ub[i]) == False:
print("Fail : inequality does not hold after solving")
break
# recover x
fin = None
if DET != 0:
mat = mat.transpose()
fin = mat.solve_right(result)
## recover your result
return result, applied_weights, fin
f = open("output.txt",'rb')
a = f.read().split(b'\n')
p = int(a[0])
params = eval(a[1])
M = Matrix(ZZ,6)
lb = [0] * 6
ub = [0] * 6
for i in range(5):
M[0,i] = (params[i][0] - params[i+1][0]) % p
M[i+1,i] = p
dy = (params[i][1] - params[i+1][1]) % p
lb[i] = -1 * (2 ^ 638) - dy
ub[i] = (2^638) - dy
M[0,5] = 1
lb[-1] = 0
ub[-1] = 2 ^ 319
result, applied_weights, fin = solve(M, lb, ub)
print(long_to_bytes(int(fin[0])))
#SECCON{9dd4e461268c8034f5c8564e155c67a6}
진짜 갓갓 repo인데 아직 문제에 쉽게 적용하지 못하고 있다.. 여러 문제에 적용해보면서 빨리 익혀야지
'CTF > CTF_writeup' 카테고리의 다른 글
[SECCON CTF 2021] CCC (4) | 2022.01.03 |
---|---|
[SECCON CTF 2021] oOoOoO (0) | 2022.01.03 |
[SECCON CTF 2021] pppp (0) | 2021.12.28 |
[SCTF 2020] Eat the pie (0) | 2020.08.19 |
[SCTF 2020] T express (0) | 2020.08.19 |