TetCTF——Crypto
Shares
Description: Yet another secret sharing scheme.
Service: nc 139.162.61.222 13371
Binary: https://drive.google.com/file/d/1sP0zKSKoF6TJZ-gtaUf7rv4dQ-bGr-cp/view?usp=sharing
用nc并没能拿到题目代码,不知道问题出哪了🐷一直显示链接超时
所以比完赛才拿到题目
"""
This is an (incomplete) implement for a new (and experimental) secret/password
sharing scheme.
The idea is simple. Basically, a secret or password is turned into a set of
finite field elements and each share is just a linear combination of these
elements. On the other hand, when enough shares are collected, the finite field
elements are determined, allowing the original secret or password to be
recovered.
"""
from typing import List
from secrets import randbelow
import string
ALLOWED_CHARS = string.ascii_lowercase + string.digits + "_"
P = len(ALLOWED_CHARS)
INT_TO_CHAR = {}
CHAR_TO_INT = {}
for _i, _c in enumerate(ALLOWED_CHARS):
INT_TO_CHAR[_i] = _c
CHAR_TO_INT[_c] = _i
def get_shares(password: str, n: int, t: int) -> List[str]:
"""
Get password shares.
Args:
password: the password to be shared.
n: the number of shares returned.
t: the minimum number of shares needed to recover the password.
Returns:
the shares.
"""
assert len(password) <= t
assert n > 0
ffes = [CHAR_TO_INT[c] for c in password]
ffes += [randbelow(P) for _ in range(t - len(password))]
result = []
for _ in range(n):
coeffs = [randbelow(P) for _ in range(len(ffes))]
s = sum([x * y for x, y in zip(coeffs, ffes)]) % P
coeffs.append(s)
result.append("".join(INT_TO_CHAR[i] for i in coeffs))
return result
def combine_shares(shares: List[str]) -> str:
raise Exception("unimplemented")
def main():
pw_len = 16
password = "".join(INT_TO_CHAR[randbelow(P)] for _ in range(pw_len))
# how about n < t :D
n = 16
t = 32
for _ in range(2022):
line = input()
if line == password:
from secret import FLAG
print(FLAG)
return
else:
print(get_shares(password, n, t))
if __name__ == '__main__':
main()
考点依旧在格
对整个程序的描述是:
这是一个新的(实验性的)秘密/密码共享方案的(不完整的)实现。
这个想法很简单。基本上,一个秘密或密码被转换成一组有限域元素,每个共享只是这些元素的线性组合。另一方面,当收集到足够多的共享时,确定有限字段元素,允许恢复原始的秘密或密码
对get_shares的描述是:
得到密码的shares.
参数:
password:共享用户的密码。
N:返回的shares数量。
T:找回密码所需的最小shares数量。
返回:shares。
读程序
从这里开始,char表示允许的
37
37
37个字符中的一个,而int表示
0
0
0到
36
36
36之间的整数。
正如我们在源代码中看到的,一个1616个字符的密码
c
1
c
2
…
c
16
c_1c_2\ldots c_{16}
c1c2…c16
一开始就确定了,我们的目标是猜测它。还可以获得20212021股get_shares(pwd),其中:
向密码追加
16
16
16个随机字符
P
=
c
1
c
2
…
c
16
r
1
r
2
…
r
16
P= c_1c_2\ldots c_{16}r_1r_2\ldots r_{16}
P=c1c2…c16r1r2…r16
生成
(
Z
/
37
Z
)
32
v
(\mathbb{Z} / 37\mathbb{Z})^{32}v
(Z/37Z)32v中
16
16
16个32位的随机向量
v
1
,
v
2
,
l
d
o
t
s
,
v
16
v_1, v_2, ldots, v_{16}
v1,v2,ldots,v16
…
…
…
from pwn import *
from tqdm import tqdm
# local runs in 30 seconds, remote takes 20 minutes
r = remote('139.162.61.222', 13371)
# r = process('pypy3 shares.py', shell=True)
P = 37
CHARS = "abcdefghijklmnopqrstuvwxyz0123456789_1"
def INT_TO_CHAR(i): return CHARS[i]
def CHAR_TO_INT(c): return CHARS.index(c)
lhs, rhs = [], []
tq = tqdm(range(2000))
cnt = 0
for _ in tq:
r.sendline(b'a')
rv = eval(r.recvline())
# Notice I keep the c1, c2, ..., c16 coefficients as vectors
rv = [[CHAR_TO_INT(c) for c in r] for r in rv]
cs = Matrix(GF(P), [r[16:32] for r in rv])
# Singular?
if cs.rank() < 16:
rs = Matrix(GF(P), [r[:16] + [r[-1]] for r in rv])
res = cs.augment(rs).rref()[-1]
# first 16 columns are the v_{i, j}
lhs.append(res[16:32])
rhs.append(res[32])
if len(lhs) == 16:
break
cnt += 1
tq.set_description(f"{len(lhs)} / {cnt}")
# solve for password
ref = Matrix(GF(P), lhs).solve_right(vector(GF(P), rhs))
pwd = ''.join((INT_TO_CHAR(r) for r in ref))
r.sendline(pwd.encode())
print("Flag:", r.recvline().decode())
看人家的代码看好几天,虽然没都懂,而且时间过了差不多也不能访问了,但是还是有点收获的,比如: 我太菜了😥