要给自己学校的招新赛出题了,于是混进CNSS招新赛前的夏令营找找出题灵感,不得不说,很多题目都出的很不错,难度与知识点控制的很好,于是在此记录一下。
Rank:3
Crypto Guideline
签到题,标志着crypto方向题目的开始,直接提交flag即可。
flag:
cnss{Welcome to the world of cryptography!}cyclic group
题目描述:
1 | 可以找到我藏在循环群中的flag吗? |
题目内容:
1 | from Crypto.Util.number import * |
可以看到,实际上就是:
因此直接幂乘e关于p-1的逆元即可。而本题的题目名字cyclic group指代的是循环群,在这里即是在说,由于模数p为素数,那么群Z*(p)的阶就为p-1,因此其中任意一个元素满足:
因此可以直接求指数关于p-1的逆元求解题目。
exp.py:
1 | from Crypto.Util.number import * |
flag:
cnss{Unbelievable! You know the key of cyclic group!}cnss娘的代码Ⅰ
题目描述:
1 | cnss娘写了一段感觉意义不明的代码,你能帮她找到flag吗? |
题目:
1 | from Crypto.Util.number import * |
简洁明了地考察中国剩余定理。
exp.py:
1 | from Crypto.Util.number import * |
flag:
cnss{Wow!Chinese remainder theorem is so interseting!}RSA Ⅰ
题目描述:
1 | Can you factorize n ? |
题目:
1 | from Crypto.Util.number import * |
题目给了n的一个素因子p与mask的&及|位运算结果,那么对于每一位,可以简单枚举一下所有可能性:
- &运算为1,则p该位为1
- &运算为0,|运算为1,则当mask该位为1时,p该位为0;当mask该位为0时,p该位为1
- &运算为0,|运算为0,则p该位为0
因此可以还原p的所有比特位,进而解密RSA。
exp.py:
1 | from Crypto.Util.number import * |
flag:
cnss{1t_s33ms_bit_is_useful}cnss娘的代码 Ⅱ
题目描述:
1 | cnss娘最近在研究一类数论中的难题,你可以帮助她吗? |
题目:
1 | from Crypto.Util.number import * |
直接用sage求解离散对数即可。
exp.ipynb:
1 | from Crypto.Util.number import * |
flag:
cnss{Congratulation! You crack the DLP problem!}cnss娘的代码 Ⅲ
题目描述:
1 | cnss娘最近在学习线性代数,你可以帮她解出这道题吗? |
题目:
1 | from Crypto.Util.number import * |
直接在sage中求解逆矩阵即可
exp.ipynb:
1 | from Crypto.Util.number import * |
flag:
cnss{Line8ar alg3ebra 1s 50 i0mportant!}HomoBlock
题目描述:
1 | 你是一个,一个一个一个Homo啊啊啊啊啊啊啊 |
题目:
1 | from secret import flag |
观察加密方式,发现具有以下特点:
- 明文按长度为8分组,分别加密
- 每一轮交换上一轮得到结果的高低32位,然后异或 MASK2 ,异或key。
可以发现,这样交换4次后就会恢复初值,所以实际交换5次后,就能得到初始值异或 MASK2 并异或key的结果。又因为明文的第一部分已经给出,所以可以根据这个明文恢复key,后续逐步恢复即可。
exp.py:
1 | from Crypto.Util.number import * |
flag:
cnss{I_am_n0t_HHHHHHoooommmmmmmoooo0000}ezLFSR
题目描述:
1 | do you know LFSR? |
题目:
task.py:
1 | from secret import mask,seed |
cipher.enc:
1 | E3306EA1B67E13D02B59A0DEA270AD8C3AF0110FBF60C07740A699A5918E7DC5 |
注意到mask也仅取了低16位,那么爆破的范围也仅有65536,因此直接爆破出符合要求的明文串即可。
exp.py:
1 | from Crypto.Util.number import long_to_bytes |
运行时间大概需要不到1分钟。
flag:
cnss{Y0u_can_brust_0r_F1nd_seed}从flag串以及hint可以看出,本题应该是可以通过LFSR的方式恢复明文的,但是数量级太小,没必要。
RSA Ⅱ
题目描述:
1 | It's more difficult than RSA Ⅰ,right? Can you factorize n ? |
并提供了一篇论文链接:1506.pdf (iacr.org)
题目:
1 | from Crypto.Util.number import * |
相较于RSA1,这一次不能根据位运算结果完全确定出p、q的比特位了,不过仍然可以利用以下线索还原:
- &运算为1,则p该位必为1
- &运算为0,mask该位为1,则p该位必为0
而当&运算为0,mask也为0时,p的该比特位就存在两种结果,无法完全确定。可是这题不仅给了p,还给了q的位运算结果,因此我们可以利用下面这一点信息,从高位向低位进行深度优先搜索,显著降低复杂度:
1 | 1、将p、q当前确定的二进制位后方全部填充0,直至填满512位,此时p、q乘积应小于n。 |
如此就能在极短时间内还原出p、q。
exp.py:
1 | from Crypto.Util.number import * |
flag:
cnss{A1g0r1thm_1s_5o_hard_for_Me!}BabyLattice
题目描述:
1 | Do you know SVP and LLL? |
题目:
1 | from Crypto.Util.number import * |
招新赛前的夏令营就出Lattice的题目了。。确实狠
不过确实是最基础的Lattice题目了,大致思路就是列出线性关系式,转化为矩阵形式,并保证较短向量都在等式右侧,即可对构造出来的格进行规约得到短向量。
exp.ipynb:
1 | from Crypto.Util.number import * |
flag:
cnss{W0w!Y0u_know_WhatisL4ttice}(有关格的问题本篇不会展开讲,因为它需要对一些基本原理的了解,想要明白此类问题需要先自行查阅一些格相关的基本概念)
ezSignature
题目描述:
1 | 这样使用数字签名是否安全呢? |
题目:
1 | from Crypto.Util.number import * |
一道靶机交互题,代码较长,但是其实大部分是交互相关的函数,细读发现是很正常的DSA,需要用给定明文通过他的验签操作。(如果不熟悉DSA签名流程,一定要自行查阅了解一下)
检查代码发现漏洞出在sign,由于交互开始时,随机密钥k就不会再变动,因此两个明文共用了k用作签名,因此直接使用共享k攻击即可,具体原理也很简单,自行搜索共享k攻击即可。进阶的还有对线性k、指数k等相关攻击方式。
exp.py:
1 | from Crypto.Util.number import * |
(这题没有完整脚本,拿着这个r,s去交互就可以了;因为比较懒,当时直接用xshell连接上后手动过的sha256爆破,手动提交的r,s。。所以就没有完整pwntools交互脚本)
flag:
cnss{1ts_Dr4nger0us_t0_u5eThe_Same_K}StrangeCurve
题目描述:
1 | The Cruve is SOO0000 Strange! |
题目:
1 | rom Crypto.Util.number import * |
椭圆曲线加密,下面这行是重要信息:
1 | assert E.order() == p |
因此可以确定是Smart’s attack。
exp.ipynb:
1 | from Crypto.Util.number import * |
flag:
cnss{DLPise45y_if5pecia1}一🔪一个牛头人
题目描述:
1 | 学了NTRU,就要NTR u(❌) |
题目:
1 | from random import shuffle, getrandbits |
一个普通的NTRU多项式密码,也是与格有关的,其具体原理可以参考:(甚至详细阐述了每个函数的作用)
Translation of LatticeHacks · K1rit0’s Blog
exp.ipynb:
1 | from Crypto.Util.number import * |
(可能需要跑几分钟)
flag:
cnss{NTRU_w1th_un5afe_par4}MidLattice
题目描述:
1 | 看上去像gcd,但是有区别 |
题目:
1 | import hashlib |
以及一个output.txt
题目描述的很明确了,agcd问题(近似公约数问题),也与格相关,不进行展开。
exp.ipynb:
1 | from itertools import permutations |
也需要跑几分钟才出结果,能更精确地调整参数的话可能可以减少耗时。
flag:
cnss{dde0cc3ac3539c66a74ed445a81c3f5b12938c286fa569a3b143b72369c708c9}铜匠的世界
题目描述:
1 | 怎样在2^512个可能中找到唯一的答案呢? |
题目:
1 | from Crypto.Util.number import * |
如果给的是p^q,题目是容易的,只需要按照RSA Ⅱ类似的思路进行深搜即可。而给的是isqrt(p) ^ isqrt(q),很容易会有思路如下:
- 对n开根,得到isqrt(p*q)
- 将isqrt(p*q) 看作n,将isqrt(p) ^ isqrt(q)看作p^q,转化成上面给定p^q的问题求解
看上去没什么问题,可是实际操作就会发现存在两点问题:
- 由于一些低位误差,有一些可能正确的根号p、q高位被舍弃。
- 即使得到了正确的isqrt(p)与isqrt(q),各自平方后与真正的p、q还有至少256比特的差距,即使是用coppersmith也完全满足不了使用条件。
因此不能再使用RSA Ⅱ中的返回条件进行按位查找了。此时搜索题目,发现了佬的类似的题目思路:
https://blog.maple3142.net/2023/06/12/seetf-2023-writeups/#shard
这样子查找成功后,还需要对低位进行一定程度的爆破后才能使用coppersmith,并且参数要卡的比较死,比如epsilon取0.03虽然快一些,但是跑不出结果,因此只能取0.01甚至更小,但这个就会耗费很长时间。遗憾的是我也没有想出更好的办法。
exp_step1.ipynb:(求出可能的p高位):
1 | from Crypto.Util.number import getPrime |
将运行结果填充至下面脚本中的sqrtplist中
exp_step2.ipynb:
1 | from Crypto.Util.number import * |
跑出结果可能需要6个小时到10个小时不等。如果你有更好的方式欢迎在评论区留言!
flag:
cnss{We hav3 n0 0ther ch0ice but c0ppersm1th.}总结
题目质量确实很不错,每道题目考察的知识点很有针对性,准备好好借鉴参考(开偷)。