
文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载本篇技术指南围绕 ctf-wiki 密码学板块的 FNVFowler–Noll–Vo哈希主题以 2018 网鼎杯hashcoll题目为完整案例系统讲解一类自定义迭代哈希的碰撞攻击方法先把哈希展开为关于消息字节的整式再把寻找两个同哈希消息转化为在格中寻找满足模线性约束的短向量最后用 LLL 格基规约算法求解。读完本文你将掌握从哈希函数代数结构到格矩阵构造、再到 Sage 脚本落地的完整攻击链路可直接复现于同类 CTF 哈希碰撞题目。题目背景从 FNV 到自定义哈希fnv.md即本文对应的仓库文档 docs/zh/docs/crypto/hash/fnv.md首先引出 Fowler–Noll–Vo hash function 这一概念随后立刻转入实战案例——2018 网鼎杯的hashcoll题目。该题实际上改编自 NSU Crypto 2017 的同类问题此前已有公开 writeup题目名hashcoll即 hash collision 的缩写其目标非常直白给定一个自定义哈希函数构造两个不同的消息使它们的哈希值完全相同。在进入题目之前先回顾哈希攻击的整体视角在 Hash 攻击 一节中常见哈希攻击被分为暴力攻击如生日攻击与密码分析两类而hashcoll属于后者——它不依赖生日界而是利用自定义哈希函数代数结构上的弱点将碰撞问题精确地归结为格上的短向量求解这比穷举 256 位哈希值的生日攻击约需 2^128 次计算高效得多。题目源码解读一个多项式型迭代哈希题目给出了如下完整源码Python 2 风格h0 45740974929179720441799381904411404011270459520712533273451053262137196814399 # 2**168 355 g 374144419156711147060143317175368453031918731002211L def shitty_hash(msg): h h0 msg map(ord, msg) for i in msg: h (h i) * g # This line is just to screw you up :)) h h 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff return h - 0xe6168647f636逐点拆解这个函数的构成h0是 256 位量级的初始向量IV长度为 77 个十进制数字约 2^256。g是一个很大的乘数代码注释明确给出g 2**168 355它是一个 168 位量级的奇数。对消息的每个字节i通过map(ord, msg)得到执行h (h i) * g。h h 0xffff...ffff64 个f即 256 位全 1 的掩码等价于h mod 2**256代码注释戏称这行只是为了搞你——事实上它只起到取模的作用是攻击中必须显式处理的约束并非额外障碍。最终返回h - 0xe6168647f636减去一个固定常数偏移。可以推断由于两个消息在计算中都减去同一个常数该偏移对碰撞条件没有任何影响攻击时可以完全忽略它。观察这个迭代形式它其实是一种多项式型哈希每一轮先加一个字节再乘g整体上哈希值是消息字节的某种加权多项式。这正是攻击的切入点。碰撞条件的数学推导设消息m (x_1, x_2, ..., x_n)其中x_i为第 i 个字节的 ASCII 码。按上述迭代展开h1 (h0 x1) * g h2 ((h0 x1) * g x2) * g (h0 x1) * g^2 x2 * g h3 (h0 x1) * g^3 x2 * g^2 x3 * g ...归纳可得全程模 2^256$$hash(m)h_0g^nx_1g^nx_2g^{n-1}\cdotsx_ng \bmod 2^{256}$$现在设两个消息m (x_1, ..., x_n)与m (y_1, ..., y_n)哈希值相同则$$h_0g^nx_1g^nx_2g^{n-1}\cdotsx_ng \equiv h_0g^ny_1g^ny_2g^{n-1}\cdotsy_ng \pmod{2^{256}}$$两侧的h0 * g^n相互抵消令z_i x_i - y_ii 1, ..., n得到碰撞的充要条件$$(x_1-y_1)g^{n-1}(x_2-y_2)g^{n-2}\cdots(x_n-y_n)g^0 \equiv 0 \pmod{2^{256}}$$即$$z_1g^{n-1}z_2g^{n-2}\cdotsz_ng^0-k\cdot 2^{256}0$$其中k是某个整数模意义下的商。关键结论我们不再需要猜哈希值而只需要找到一个 n 维整数向量z使上述带模数的等式成立。只要找到这样一个z把z_i加到基准消息的对应字节上x_i base_i z_i就能得到一个与基准消息同哈希的新消息。由于z_i是有正有负的小整数通常是几十量级新消息的每个字节只需满足0 x_i 255即可保持为合法 ASCII 字节。构造格并交给 LLL问题归约上述等式z_1g^{n-1} z_2g^{n-2} ... z_ng^0 - k*2^{256} 0可以理解为在 n1 维整数向量空间中找一组整数系数(z_1, ..., z_n, k)使得它们与权重向量(g^{n-1}, g^{n-2}, ..., g^0, -2^{256})的内积为 0。这正是 ctf-wiki 格的基本介绍 与 格概述 中反复出现的格问题形态在格中寻找短向量。文档明确指出本题可以认为是 LLL Paper 中第二个例子的简单情况——即在 LLL 格基规约算法 一节所讲解的给定 n 个实数寻找它们的有理线性组合逼近 0问题。LLL 论文的第二个例子正是构造如下形式的矩阵通过 LLL 找出近似为零的线性组合。按同样的思路为本题构造如下格矩阵行数 n1列数 n2用K放大末列以便引导规约方向$$ A \left[ \begin{matrix} 1 0 0 \cdots 0 Kg^{n-1} \ 0 1 0 \cdots 0 Kg^{n-2} \ 0 0 1 \cdots 0 Kg^{n-3} \ \vdots \vdots \vdots \ddots \vdots \ 0 0 0 \cdots 1 K\cdot mod \end{matrix} \right]$$直觉如下单位阵部分保证格中向量的前 n 个坐标就是系数z_i本身末列K*g^{n-i}与K*mod的组合使得任何一个格向量的末列坐标等于K * (z_1g^{n-1} ... z_ng^0 k*mod)。若该格向量是短的而K又足够大则末列坐标只能被迫为 0从而精确满足碰撞方程。这与 LLL 格基规约算法 中c 足够大时求和必须足够小的分析完全一致。Sage 攻击脚本逐步解析仓库文档给出了完整的 Sage 脚本逐段说明如下from sage.all import * mod 2**256 h0 45740974929179720441799381904411404011270459520712533273451053262137196814399 g 2**168 355 def shitty_hash(msg): h h0 msg map(ord, msg) for i in msg: h (h i) * g # This line is just to screw you up :)) h h 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff return h - 0xe6168647f636这部分只是把题目给出的哈希函数原样抄回来用于最终验证两个消息哈希值相等。K 2**200 N 50 base_str a * N base map(ord, base_str) m Matrix(ZZ, N 1, N 2) for i in xrange(N 1): ge ZZ(pow(g, N - i, mod)) m[i, i] 1 m[i, N 1] ZZ(ge * K) m[i, N 1] ZZ(K * mod)参数说明N 50消息长度为 50 字节。base_str a * 50作为基准消息所有字节均为 97ASCIIa。K 2**200末列放大系数。K越大LLL 越倾向于把末列压到 0从而命中碰撞方程。若规约结果末列不为 0脚本会提示Zero not reached, increase K增大 K。Matrix(ZZ, N 1, N 2)构造 (51 × 52) 的整数环矩阵ZZ表示整数环。循环内第 i 行主对角线置 1末列置K * g^(N-i)N-i从N递减到0循环结束后最后一行末列被覆盖为K * mod即矩阵公式中K*mod那一行。这里有一个文档特别强调的大坑不能直接仅仅使用pow(g, N - i, mod)作为矩阵元素而不做处理否则生成的数值会落在mod对应的模数域中而不是整数环ZZ上导致 LLL 无法在正确的代数结构上规约。正确做法是用ZZ(...)把模幂结果显式包装为整数如脚本中ge ZZ(pow(g, N - i, mod))确保矩阵元素全部是整数。ml m.LLL() ttt ml.rows()[0] print result:, ttt if ttt[-1] ! 0: print Zero not reached, increase K exit() else: msg [] for i in xrange(N): msg.append(base[i] ttt[i]) if not (0 msg[i] 255): print Need more bytes! quit() print msg other .join(map(chr, msg)) print shitty_hash(base_str) print shitty_hash(other)规约与验证流程m.LLL()对构造的矩阵执行 LLL 格基规约ml.rows()[0]取出规约后的第一个最短的行向量ttt。ttt[-1] ! 0检查末列是否被规约为 0。若不为 0说明K不够大需要增大K重新构造。若末列为 0则ttt[0..N-1]正是所需的差分向量z元素有正有负如 15、-14、17 等。msg[i] base[i] ttt[i]把差分叠加到基准消息的每个字节上并检查每个字节是否落在0 ~ 255的合法范围内若超出提示Need more bytes!需要更长的消息来消化更大范围的差分。最后分别打印base_str与other的shitty_hash值若两行数字相同即攻击成功。运行结果与验证在 SageMath 中执行sage exp.sage输出如下➜ hashcoll sage exp.sage result: (15, -14, 17, 14, 6, 0, 12, 21, 8, 29, 6, -4, -9, 10, -2, -12, -6, 0, -12, 13, -28, -28, -24, -3, 6, -5, -16, 15, 17, -14, 3, -2, -16, -25, 3, -21, -27, -9, 16, 5, -1, 0, -3, -4, -4, -19, 6, 8, 0, 0, 0, 0) [112, 83, 114, 111, 103, 97, 109, 118, 105, 126, 103, 93, 88, 107, 95, 85, 91, 97, 85, 110, 69, 69, 73, 94, 103, 92, 81, 112, 114, 83, 100, 95, 81, 72, 100, 76, 70, 88, 113, 102, 96, 97, 94, 93, 93, 78, 103, 105, 97, 97] 106025341237231370726407656306665079105509255639964756437758376184556498283725 106025341237231370726407656306665079105509255639964756437758376184556498283725解读运行结果第一行是 LLL 找到的差分向量ttt前 50 个元素即z_i末列 0 表示碰撞方程精确命中无需增大K。注意差分元素基本都在 ±30 以内说明 LLL 找到了一个足够短的向量。第二行是把差分叠加到a*50后得到的消息字节序列例如第一个字节112即p、第二个字节83即S……所有字节均在合法 ASCII 范围65 左右的字母区无需Need more bytes!提示。第三、四行是两个不同消息的shitty_hash输出均为同一个 256 位十进制数1060253...282725两个消息哈希完全相同碰撞构造成功。可以看到整个攻击的核心开销就是一次 51 维整数矩阵的 LLL 规约在普通机器上秒级即可完成——这正是格攻击相对生日攻击的压倒性优势。攻击要点小结从hashcoll案例中可以提炼出针对多项式型迭代哈希的通用攻击模板展开定式把迭代哈希展开为关于消息字节的整式明确各项系数这里是g的幂。碰撞归约令两个消息逐字节做差把哈希相等化为差分向量与权重向量的内积 ≡ 0 (mod 2^256)的模线性方程。格构造以单位阵编码系数、以放大系数K加权权重向量g的幂与模数mod构造 (n1)×(n2) 的整数矩阵。LLL 求解规约后取最短向量末列若为 0 即得到合法的字节差分必要时增大K或增加消息长度N。落地验证把差分叠加到基准消息上检查字节合法性并实际调用原哈希函数双重确认碰撞。格理论部分格的 基本介绍、概述 与 LLL 格基规约算法为本题提供了完整的理论支撑SVP最短向量问题是格中的核心困难问题而 LLL 是求解其近似解的经典多项式时间算法。hashcoll正是利用自定义哈希的代数弱点 格基规约这一思路的典型示范理解了它就掌握了处理一类弱哈希碰撞题目的标准姿势。赞分享文档网络安全教程【免费下载链接】ctf-wikiCome and join us, we need you!项目地址https://gitcode.com/gh_mirrors/ct/ctf-wiki点击查看免费下载相关推荐CTF-Wiki 格攻击实战用 LLL 构造 FNV 式哈希碰撞2018 网鼎杯 hashcoll 全解析CTF Wiki 格攻击实战用 LLL 构造 FNV 式哈希碰撞2018 网鼎杯 hashcoll 全解析 哈希函数把任意长度的消息压缩成固定长度的摘要文档网络安全教程margin-analyzer 利润率分析避坑指南小型企业定价决策中七大数据陷阱的识别与规避margin analyzer 利润率分析避坑指南小型企业定价决策中七大数据陷阱的识别与规避 本文是知识工作插件仓库knowledge work plugi文档网络安全教程ctf-wiki 内核利用实战ret2usr 攻击手法解析——以 2018 强网杯 core 为例ctf wiki 内核利用实战ret2usr 攻击手法解析——以 2018 强网杯 core 为例 导读 ret2usrreturn to user spa文档网络安全教程上一篇如何3步完成微信聊天记录导出Mac用户的终极数据自由指南下一篇如何快速导出微信聊天记录Mac用户的完整数据自由指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考