随手记录一下~
Danger_RSA
题目描述:
1 | 看似简单的rsa |
题目:
1 | from Crypto.Util.number import * |
题目初看没有什么下手点,但其实get_key函数的这两行暴露了很多信息:
1 | X = getRandomInteger(nbit // a) |
也就是说,a可能的范围其实很小,粗略的范围都仅有[2,1024],这个时候再看生成的e,可以发现,e相对来说太小了,甚至可以得到他的全部素因子分解,即:
因此我们完全可以用下面这个方式来进一步确定a的取值范围:
1 | for a in range(2,1024): |
可以发现,a其实仅能取4;与此同时可以明白,对于刚才的e的因子分解,仅有两种可能的组合让两次生成的s均落在a规定的范围里:
此时再看n的生成过程:
s和t相较于X1、X2来说非常小,因此对n开4次方根就可以得到X1*X2,此时,就可以以以下方式分解n:
将所有量移动到同一侧:
左右同时乘$\; X1^4$,得:
此时,令$\;x = X1^4$,就得到下面的一元二次方程:
将可能的两组s、t,逐个代入解上述方程,就可以得到n的分解。
得到n的分解后,想要直接求解RSA解密却发现$\;gcd(e,phi_n)\;!=\;1$,发现是因为$\;3|(p-1)$且$\;7|(q-1)$,此时由于题目中并未说明对flag做过额外填充处理,而p、q两个因子均有接近1024比特,正常来说远大于明文比特位,因此可以转化到模p下求解,这是因为:
而
所以可以将$m^3$当作一个整体,进行RSA解密后在模p下开三次方根即可。
exp.ipynb:
1 | from Crypto.Util.number import * |
得到flag:
DASCTF{C0nsTruct!n9_Techn1qUe2_f0r_RSA_Pr1me_EnC2ypt10N}当然,这题还有一些值得思考的地方,如若明文的比特位超过了p,又该怎么办?
首先可以先将与p-1、q-1均不互素的素因子用普通RSA解密剔去,得到
然后就可以使用AMM算法,但是这时使用AMM算法又有一点特殊,这是因为虽然$7|q-1$,但是49却不整除于q-1,因此无法一次性在模q下开49次方根,而需要先开七次方根,再对7个开出的根再各开7次方根,最后再与模p下开出的3次方根作中国剩余定理求解:
exp.ipynb:
1 | import random |
而简便一点,直接解有限域下的方程也是可行的:
exp.ipynb:
1 | from Crypto.Util.number import bytes_to_long,long_to_bytes,inverse |
多种方法求解,也是为了能更灵活的思考问题,掌握更多求解方式,让自己一种方法卡住时,可以有路可走。
Easy_3L
题目描述:
1 | 无 |
题目:
1 | from gmpy2 import * |
题目的3L显然指的是LLL算法,加密过程分为两层:
- LCG加密种子flag
- NTRU加密LCG的S3
那么解题思路也很清晰,先解决NTRU解出S3,进而恢复LCG的种子即可。
本题你会发现要规约出的向量(f,g)数量级好像差的有点多,很难规约出1024比特的f,但是不重要,f是否为原始值对于解密影响并不大,只需要检查S3的数量级正常即可。(正常来说,为使规约后的向量比特相近,应在第二列乘上2^512,使 f 与 (2^512)*g具有相同数量级,但本题中这是解不出来的,因此可以采用爆破手段,会发现有很多短向量f、g均可以用于解密,这也符合NTRU的密钥特性)
解出S3后是个简单的LCG问题,不再赘述。
exp.ipynb:
1 | from Crypto.Util.number import * |
得到flag:
DASCTF{NTRU_L0G_a6e_S1mpLe}SigninCrypto
题目描述:
1 | 随机数真随机吗?如随! |
题目:
1 | from random import * |
可以发现,题目最终用3DES对flag进行了加密,因此目标就是还原3DES的key与iv即可。
其中,两个量分别分为了以下几部分:
- KEY = K1 + K2 + K3 ,每个部分大小8字节
- IV=iv,每个部分大小4字节
按照如下方式逐步还原每个部分:
K1
1 | K1= key |
hint1为16字节量,而K1为8字节量,因此xor的高位即为hint1的高位,又因为hint1由重复字节构成,hint1高位与低位相等。得到完整hint1后与xor异或即得K1
K2
1 | def Rand(): |
考察的是MT19937伪随机数生成,利用randcrack模块,提交624个32bit数,即可对之后的随机数进行精准预测。而注意到生成List1、List2之间重新调整了一次随机数种子,因此List1、List2是使用同一随机数种子生成的。
而注意到,List1仅有$62416$bit,List2却有$32464 = 624*32$bit,因此List2生成的位数是足够的,而最终task.txt文本中却只给了List2的部分字节,不需要深究原理也能明白:List1生成的字节恰好就是List2生成的随机数中缺失的字节。因此只需要每种补充方式均尝试一下即可得到K2。
K3
1 | K3 = flag[:8] |
很显然,因为flag一般以DASCTF{开头,因此只需要爆破一个可见字符即可得到正确K3。
IV1及IV2
1 | IV1=IV[:len(IV)//2] |
首先明确IV一共8个字节,因此hint2的高位即为IV1,此时题目的几个哈希值貌似给了一个暗示:爆破求解IV2.可是需要爆破的量有4个字节,虽然不能说很大,却也需要很长时间。此时就需要注意到,digest=digest1+digest2这一行,并不是数值的相加,而是字符串的连接,而当你将digest解码后,你会发现:
1 | digest1 = digest2 |
没错,太幽默了,所以IV2与IV1相同(基本无需考虑哈希碰撞)
此时所有量都得到了还原,解密3DES即可:
exp.py:
1 | import hashlib |
得到flag:
DASCTF{8e5ee461-f4e1-4af2-8632-c9d62f4dc073}esyRSA
题目描述:
1 | 好像这个RSA有点怪啊!私钥给你了!我的e呢? |
题目:
1 | from gmpy2 import invert |
无力吐槽。。。这题附件锅了,n是两个重复的大整数拼起来的,因此要先取一半当作正确的n。之后的做法就多了,d过大可以考虑wiener或构造格,但是题目给了e为五位数的暗示,因此也只需要爆破一下e,当作已知e、d分解n即可。
exp.py:
1 | from Crypto.Util.number import * |
得到flag:
DASCTF{4ae33bea90f030bfddb7ac4d9222ef8f}(为什么主办方没有发现附件需要更新?/(ㄒoㄒ)/~~)
MCeorpkpleer
题目描述:
1 | 这数据都不全要怎么计算呢 |
题目:
1 | from Crypto.Util.number import * |
观察题目,e_cry用于背包加密的就是e的二进制串本身,因此直接格基规约出e,再用coppersmith解已知p高位问题即可。
exp.ipynb:
1 | from Crypto.Util.number import * |
得到flag:
DASCTF{T81I_tPPS_6r7g_xlPi_OO3M_6vyV_Rkba}XOR贯穿始终
题目描述:
1 | 一切都是有意义的,拿下它吧。 |
题目:
message.txt:
1 | 自由和谐和谐富强公正友善爱国公正法治法治文明和谐自由法治自由法治平等公正友善公正公正民主法治自由公正敬业和谐富强公正友善爱国和谐平等平等友善敬业法治敬业和谐富强法治平等平等友善敬业公正公正公正友善敬业法治平等平等诚信自由公正自由平等友善敬业公正友善法治和谐和谐 |
task.py:
1 | from gmpy2 import gcd |
pri.pem:
1 | -----BEGIN PRIVATE KEY----- |
第一层,解开社会主义核心价值观编码得到:
1 | C0ngr4tulati0n5_y0u_fou^d_m3 |
第二层,恢复破损RSA私钥文件,base64解码后得到:
1 | b'30820277020100300d06092a864886f70d0101010500048202613082025d02010002818100b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913020301000102818100974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361024100ea59434f560de2eaf4f21c22fb10691b79485e6290007dc28242bc63739fb95fa03e5ed807000d491f0ca43e50a91d43a6940f390c91757a3ba8226ce58112c9024100cad4c29d017e30ddabd606805044d9ca3e6a3184fb4e1f332845555498c36b02e7b97e2eb09d85c919e30a493ce94ef9412261c3998c7344271b6e6e1b3dfefb' |
按照RSA私钥格式还原,可以得到以下信息:
1 | n 028181 00b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913 |
可以看到,私钥中的dp、dq以及inv(q,p)损坏了,但是剩下的值已经足够用于RSA解密,因此正常解密即可得到:
1 | DASCTF{0e287wQ\x08R\x17\x00FGXYFZ\x07V\x03kIUCn\x02VDg\x01f\x0cN |
发现题目描述XOR还没用上,将第一步社会主义核心价值观解密得到的串用于异或即可。
得到flag:
DASCTF{0e2874af5e422482378640e61d919e9a}总结
总体难度确实不大,但是怎么说呢,题目有点坑,自己能力也还存在不足,下次加油吧。