题目源码
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
= 'flag{d3b07b0d416ebb}'
flag
assert len(flag) <= 45
assert flag.startswith('flag{')
assert flag.endswith('}')
= bytes_to_long(pad(flag.encode(), 128))
m
= 0xf6e82946a9e7657cebcd14018a314a33c48b80552169f3069923d49c301f8dbfc6a1ca82902fc99a9e8aff92cef927e8695baeba694ad79b309af3b6a190514cb6bfa98bbda651f9dc8f80d8490a47e8b7b22ba32dd5f24fd7ee058b4f6659726b9ac50c8a7f97c3c4a48f830bc2767a15c16fe28a9b9f4ca3949ab6eb2e53c3
p = 5
g
assert m < (p - 1)
= pow(g, m, p)
c
with open('out.txt', 'w') as f:
print(f"{p = }", file=f)
print(f"{g = }", file=f)
print(f"{c = }", file=f)
= 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299
p = 5
g = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854 c
分析
离散对数问题,flag填充到128长度,但是flag长度未知
比赛的时候以为给的假flag是flag的高位,赛后得知flag里面的长度是12,可能是根据爆破难度来推测长度的,因为用到了bsgs法,相当于爆6位的[0-9a-f],再长一点就很难爆破了
得知flag长度后,我们把同余式转化成 \(c \equiv g^{flag} \mod{p}\) 的形式,方便最后进行bsgs
同余式转化
第一步
将flag头尾和padding先移到c那边,得到c1,因为padding+'}'
的长度是111,此时有
\(c_1 \equiv (g^{flag})^{2^{111 \times 8}}
\mod{p}\)(这里以及后面说的flag都是指flag花括号里的内容)
= bytes_to_long(pad(b"flag{" + b"\x00" * 12 + b"}", 128))
flag_pattern = c * pow(g, -flag_pattern, p) % p c1
第二步
令 \(g_1 = g^{2^{111 \times 8}}\),有 \(c_1 \equiv g_1^{flag} \mod{p}\)
= pow(g, 2**(111*8), p) g1
这里还有一种做法,就是把 \(2^{111 \times 8}\) 也移到c那边,因为这个 \(p\ \%\ 4 = 3\),可以用到Rabin里的思想
assert p % 4 == 3
for _ in range(111*8):
= pow(c1, (p+1)//4, p) c1
这样,就有 \(c_1 \equiv g^{flag}
\mod{p}\),也就是说后面的步骤直接用g = 5
但是经过尝试,发现用g和用g1的爆破速度基本一样,所以不如直接用g1
BSGS
根据大步小步法,因为flag长度是12,令 \(flag = im + j\),其中 \(m = 2^{6 \times 8}\),\(0 < i < m\),\(0 < j < m\)
因为 \(c_1 \equiv g_1^{flag} \equiv g_1^{im + j} \mod{p}\),有 \(c_1 (g_1^{-m})^i \equiv g_1^j \mod{p}\)
大步
左边先乘c1,然后每次乘上n次的\(g_1^{-m}\)(这里写n次是因为flag的字符只有[0-9a-f],遍历的时候存在“跳跃”,所以n不一定为1)
遍历完所有结果存进字典dic中
= pow(g1, -2**(6*8), p)
g1m_inv = c1
left for i in tqdm(range(len(flag))):
= left * pow(g1m_inv, bflag[i+1] - bflag[i], p) % p
left = i dic[left]
小步
右边每次乘上n次的\(g_1\)
每次乘完得到的值判断是否在dic中,如果存在,即left = right
,说明找到了正确的i、j
= 1
right for j in tqdm(range(len(flag))):
= right * pow(g1, bflag[j+1] - bflag[j], p) % p
right if right in dic.keys():
= dic[right]
i print(i, j)
解题
from Crypto.Util.number import *
import itertools
from Crypto.Util.Padding import pad
from tqdm import tqdm
= 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299
p = 5
g = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854
c
= bytes_to_long(pad(b"flag{" + b"\x00" * 12 + b"}", 128))
flag_pattern = c * pow(g, -flag_pattern, p) % p
c1 = pow(g, 2**(111*8), p)
g1
= {}
dic
= list(itertools.product("0123456789abcdef", repeat=6))
flag = [0] + [bytes_to_long("".join(_).encode()) for _ in flag]
bflag
= pow(g1, -2**(6*8), p)
g1m_inv = c1
left for i in tqdm(range(len(flag))):
= left * pow(g1m_inv, bflag[i+1] - bflag[i], p) % p
left = i
dic[left]
= 1
right for j in tqdm(range(len(flag))):
= right * pow(g1, bflag[j+1] - bflag[j], p) % p
right if right in dic.keys():
= dic[right]
i print(i, j) # 6416384 8246879
print("".join(flag[i] + flag[j])) # 61e8007dd65f
"""
100%|██████████| 16777216/16777216 [01:48<00:00, 154175.60it/s]
49%|████▉ | 8244395/16777216 [00:52<00:54, 155872.85it/s]6416384 8246879
61e8007dd65f
100%|██████████| 16777216/16777216 [01:47<00:00, 156349.35it/s]
"""
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 skatexu@qq.com