Hgame25
Hgame 2025 Writeup
0. Introduction
之前那两周学同源相关内容 + 练车,导致Hgame没怎么看,然后开学后Hgame刚好结束,2月18日用一天半做了一下题,只能说跟21年22年相比,貌似确实难了很多。。。。
因为题目是18日做的,所以就不区分第一周第二周了,直接按题目分数排序了。
1.Ancient Recall(4pts,144sol)
先看看题目代码:
1 |
|
其实这个题虽然写了一大堆,但其核心部分就是要根据最终拿到Value,求出原始的Value,最终可以直接得到flag。
注意到这样的递推式:
1 |
|
该递推式执行了250次得到了最终的结果。可以发现这就是一个线性递推,尝试构建:
那么求原始值就是求左边矩阵的负250次幂乘上最终的Value向量,然后根据题目组flag的方式组成flag就OK了。
1 |
|
2.SuprimeRSA(6pts,61sol)
好家伙,这竟然是个没见过的玩意,先看看题目代码。
1 |
|
题目的素数生成方式有点特殊,但你可以看出明显的小量 $k,a$,以及 $n=(k_1M+e^{a_1})(k_2M+e^{a_2})$,并且根据 $n$ 的规模,可以很快地确定三个选项中取的是 $39$ 。
当时先把 $e^{a_1}e^{a_2}$ 看作一个整体,然后把上面都式子展开 $n$ 写成 $M$ 进制的形式进行多项式处理。但发现 $e^{a_1}e^{a_2}$ 会超过 $M$,因此多项式的方式不管用。(虽然但是 n%M
的值还真能分解成两个素数的乘积)。。。
然后瞄了一眼week 1的WP,结果发现竟然是ROCA Attack。。。好家伙,上来就来论文题是吧?
那就点击 这个链接 下载github攻击代码,改改攻击参数,$n$ 就被分解了。。
1 |
|
运行结果:
flag:hgame{ROCA_ROCK_and_ROll!}
看完第二个开始预感情况不妙了
3.Intergalactic Bound(7pts,45sol)
好家伙,这又是个啥题?THCurve又是啥?
1 |
|
然后自己去查了一下,原来这种Curve的形式是:
$$
ax^3+y^3+1=dxy
$$
呃,奇怪的知识又增加了。
然后搜THCurve,搜到了羊城杯有过类似的题目,就是把这个曲线转成椭圆曲线的形式,然后做离散对数就OK了。
所以这个题最难的还是搞懂这是个啥曲线,然后怎么转成椭圆曲线。
代码就直接偷网上羊城杯那个题的wp了。
1 |
|
4.ezBag(7pts,75sol)
终于见到一个还算熟悉的题了,背包问题:
1 |
|
题目给了 $4$ 组数据,构成了一个 $64$ 位的背包问题,要求出密钥解得flag。
背包问题的格构造方法在 2021 年的 LatticeNotes5 中已经提到过了,回顾一下:
上面的矩阵中:$E$ 为单位矩阵,$\vec a$ 为每个物品重量的列向量,$\vec 1$ 为全 $1$ 向量,$b$ 为物品重量之和。对 $M$ 进行LLL,可以得到一个最后一个分量为 $0$,其他分量只有 $-1$ 和 $1$ 的向量,分别对应着 $1$ 和 $0$。
这边插播一句:其实也可以将 $2E$ 换成 $E$,$\vec 1$ 换成 $\vec 0$,$b$ 换为 $-b$,这样解出来的就恰好是向量 $0,1$。但事实上,这种构造方法并不常用,因为这样构造会将行列式的值缩小为原来的一半,降低解出目标向量的概率(这个思想后面一个题也会用到)。
然而,题目给了 $4$ 组数据,那么构造的矩阵就是
然而,即使是这样,仍然解不出正确向量。考虑到最后 4 列在目标向量中的分量为 $0$。因此可以给最后 4 列乘上 $2^{2000}$,强行增加最后四列权重,解得最短向量即为目标向量。
1 |
|
这个mask虽然没用到,但其实有的时候也是会用到的:因为目标向量有时会多个 $-1$ 的系数,导致解出的比特全是反的,第一遍得不到结果。如果出现这种情形,直接异或一下mask,就给比特全翻转回来了!
5.sieve (7pts,140sol)
一看就是个oi✌出的题,可以看出,我们要求出 $65537^2/6$ 内的素数个数和所有数字的素数个数和欧拉函数之和。
1 |
|
因此正解是素数筛和杜教筛,但后者我不会写,考虑到这个值为 $715849728$,并不是很大,可以用 $O(n\log n)$ 的复杂度逐个求解。
不过据说sage中可以直接枚举 euler_phi
并求和,在服务器上单核跑的时间为 40 分钟左右,反正也能出。
1 |
|
求出需要的两个值之后,直接解就OK了
1 |
|
6.SPiCa(8pts,21sol)
看到题目中 $0.035$,$A$ 为随机 $0,1$ 矩阵,大概率能够猜到是正交格。
1 |
|
正交格主要是用于解决 $A\vec x\equiv \vec b \pmod p$ 的问题,其中 $A$ 为 $0,1$ 的未知置矩阵,$\vec x$ 为秘密向量,我们只知道最终向量 $\vec b$ 和模数 $p$,其余内容我们均不知道。
题目中,我们得到向量 $\vec h=\vec xA$ ,$A$ 符合上述的特点。由于 $\vec x$ 为行向量,$A$ 可以看作 $\vec a_0,\vec a_1,…,\vec a_{m-1}$ 这 $m$ 个行向量组成的矩阵。
我们先回顾一下线性代数的知识(真巧,18号写这个,19号就要学矩阵论)
对于一个 $m$ 行 $n$ 列的矩阵(如果 $m\not=n$),那么这个矩阵的秩一定不超过 $\min(m,n)$。根据链接中的内容,我们可以得到行空间、列空间、左0空间、右0空间的概念:
行空间:$\vec xA=\vec b$ 中,所有 $\vec b$ 构成的空间,此时 $A$ 的每一行构成空间的基底向量。
列空间:$A\vec x=\vec b$ 中,所有 $\vec b$ 构成的空间,此时 $A$ 的每一列构成空间的基底向量。
左0空间:满足 $\vec xA=\vec 0$ 的所有 $\vec x$ 构成的集合,在sagemath中为
A.left_kernel().matrix()
。其个数为 $m-r+1$,$r$ 为 $A$ 中互相线性无关的行向量个数。右0空间:满足 $A\vec x=\vec 0$ 的所有 $\vec x$ 构成的集合,在sagemath中为
A.right_kernel().matrix()
。其个数为 $n-r+1$,$r$ 为 $A$ 中互相线性无关的列向量个数。
性质:行空间和右0空间正交,列空间与左0空间正交。
由于题目中 $\vec xA=\vec h$,因此,我们可以先设法构造 $\vec u$,使得 $\vec u\cdot\vec h=0$,也就是 $\sum_{i=0}^{m-1}u_ih_i\equiv 0\pmod p$。
写成矩阵的形式就是(为方便展示,以三个分量为例):
很明显,为了求出 $\vec u$ ,我们需要对上面的矩阵LLL处理,设上面的矩阵为 $M$,那么就可以得到 $M_{3L}$。
1 |
|
这样,我们就得到了向量 $\vec u$,满足 $\vec u\cdot \vec h\equiv 0\pmod p$
1 |
|
然后,我们可以用 $M_{3L}$ 的前 $m-n$ 列,构造格 $L_x$,然后求 $L_x$ 的右 0 空间(因为题目中是 $\vec xA$ 得到的是行空间,因此要求右 0 空间),构造 $L_c$,然后对 $L_c$ 做BKZ就能够得到原始矩阵 $A$(对于 $0/1$ 决策,使用BKZ算法比LLL算法有更高概率得到正确结果),这一部分可以参考给出的链接的内容,这一部分代码如下:
1 |
|
我们期待找出一个仅包含 $0,1$ 的向量,但发现得到的向量基本都会包含 $-1,0,1$ 三个数字。这和之前做背包密码时产生的问题相同。因此,可以借鉴其方法,构造矩阵 $\left[\dfrac{\vec 1}{2L_c}\right]$,这样原矩阵 $A$ 就变成了 $2A-1$ ,使得所有向量的分量均为 $±1$,某种意义上来说,也算一种系数平衡方法吧。
那么最后的exp如下(当然,如果解不出来,可以对 $V_{3L}$ 取反再尝试一下):
1 |
|
9.总结
今年Hgame比21年和22年的难太多了,0xGame2024也是,感觉难度和20,21年不是一个档次的(当时21年我还怕出难了,Predict1和Predict2借鉴了21年Hgame的夺宝大冒险,其实就是直接抄的,但最终看来题目还是比0xGame2020难)。
Hgame2022的题我附件还在(因为那个时候我CTF已经处于一个半退役的状态了),并且我手中还保存了当年SACC寒假打卡的材料,看了看学弟Schen交给我的打卡记录,感觉题目和21年的相仿,并且22年的题目我那个寒假也做了一些,貌似四周的题目也都是一天AK的(但当时好像就没打理博客了,所以找不到22年的做题记录,后面有空补一篇)。。。
不过话说回来,这几年CTF咋出了这么多东西,我CTF两年的空窗期究竟发生了什么?