[华东交大第二届信息安全竞赛]Crypto-top_secret

0x01 题目:Top_secret

  • 附件📎:

task.py

#python3
from random import *
from gmpy2 import *
from secret import flag
from Crypto.Util.number import *

e = 0x10001

common_p = next_prime(getrandbits(64))
common_q = next_prime(getrandbits(64))
common_n = common_p*common_q
common = '(%d,%d)' % (common_n, e)

f = open('test', 'w')
f.write(common+'\n')

test = [getrandbits(64) for i in range(512)]
for i in test:
    f.write(str(pow(i, e, common_n))+'\n')

top_p = next_prime(getrandbits(1024))
top_q = next_prime(getrandbits(1024))
top_n = top_p*top_q
top = '(%d,%d)' % (top_n, e)

m=bytes_to_long(flag)

f = open('top_secret', 'w')
f.write(top+'\n')
f.write(str(pow(m, e, top_n)))

test

(76436798540605363536477649122583467659,65537)
55186050945367642475707075553224810751
25230392976483617195172228672398327555
13402586421932983833466929662539579831
73577334713803339185143437689323273802
38551782957548094407447800753751168665
······(此处省略...)
66417142292403444690306408437925436539
16917869489156458807988614612206952611
62433740855979549009477295935969264632
54703498276817055998735161171803303420

top_secret

(6778341886512983471750645456950728290523536616361299371741958671360393083882319627518672438545115814129137657182781214208816455570796241668174521203607532582846713044946980024783900646043967377749611378975743784775184880644929838298609658208272073728954171415761808451070649956713090699363828704967425598555240857728605492559334918924364181243615109772911597831275788990921847678043264311757080086808770372237384343263695430482298224638114383481163242159396421912093570982271665015871698548239583006809079195143432434252317382780354946136908751753704879594650848364606279745816610061533345112504778579863240146035803,65537)
418919112322035719080296282188262556318147208740019952103384898777739260429989830467043589948286391778496053290993573572770668930715827948954387013380968757428438279330384918638646330090780491358345953558632784799412654785756895941844475592045474255714700612603241873989982425698945208444003573618381342067450033353217477323111093274062491515883275867746619738296397569905705052009378569807157998159800021519653031832333686380591812114745289471610313845110578057278593565079742329184877876988624852591803357662165422951088131736792374156848783221486055402017298046164798460834330495680663944310194208485613787684535

0x02 解题思路

分析源码,第一部分代码:

e = 0x10001

common_p = next_prime(getrandbits(64))
common_q = next_prime(getrandbits(64))
common_n = common_p*common_q
common = '(%d,%d)' % (common_n, e)

f = open('test', 'w')
f.write(common+'\n')

test = [getrandbits(64) for i in range(512)]
for i in test:
    f.write(str(pow(i, e, common_n))+'\n')

通过两个64位的common_pcommon_q生成公钥 ( N , e ) (N,e) (N,e)存放到test文件中。

这对公钥common_n,e用来加密51264位的随机数,也将其存放到test文件中。

ecommon_n题目给出,且common_n位数较低,直接通过大数分解即可得到common_pcommon_q

然后就可以逆向出512个随机数了。

再看看第二部分代码:

top_p = next_prime(getrandbits(1024))
top_q = next_prime(getrandbits(1024))
top_n = top_p*top_q
top = '(%d,%d)' % (top_n, e)

m=bytes_to_long(flag)

f = open('top_secret', 'w')
f.write(top+'\n')
f.write(str(pow(m, e, top_n)))

第二部分比较简单,

通过getrandbits(1024)生成一个1024位的随机数,再通过next_prime()取这个数的下一个素数

从而生成 p p p q q q,再用 p p p q q q计算得到的公钥对flag进行加密,将公钥 ( n , e ) (n,e) (n,e)和密文 c c c存储到top_secret文件中。


本题的漏洞点是getrandbits()函数,

最终可以利用第一部分代码给出的大量随机数,预测出top_ptop_q

我使用的是python3的randcrack进行预测

安装方法:

pip3 install randcrack

首先需要解出第一部分所给出的512个随机数,

大数分解common_n得到common_pcommon_q:

image-20221126105615237

具体代码如下:

from Crypto.Util.number import *
from gmpy2 import *
e = 65537
common_n = 76436798540605363536477649122583467659
common_p = 5105923512372711233
common_q = 14970220050375442123
common_phi = (common_p-1)*(common_q-1)
common_d = gmpy2.invert(e, common_phi)
test = open('test', 'r').readlines()
with open('deTest', 'w') as deTest:
    for i in test:
        if i == "(76436798540605363536477649122583467659,65537)\n":
            continue
        # print(pow(int(i),common_d,common_n))
        deTest.write(str(pow(int(i),common_d,common_n))+'\n')

得到原512个随机数:

6664610210323177003
17661097700361369885
303206696427486439
16389245002373137587
5670728676319485833
12056818099668268163
······(此处省略...)
1106083047604041265
17146900470736302356

由于RandCrack()所需的随机数为32位,而题目中getrandbits(64)是64位,

了解一下getrandbits对于高位随机数的生成方式,即可将64位的随机数分解为32位的随机数。

具体原理如下:

import random
 
random.seed(0)
a=random.getrandbits(32)
b=random.getrandbits(32)
print(a)
print(b)
print((b<<32)+a)
random.seed(0)
 
print(random.getrandbits(64))

输出:

3626764237
1654615998
7106521602475165645
7106521602475165645

即先得到32位随机数作为低位,然后再用下一个32位随机数作为高位,组成一个64位随机数。

得知原理后,编写python脚本进行预测最后的top_ptop_q

这里面还有一个小坑,randcrack中最多提供624个32bits的随机数进行预测,否则会报错:ValueError: Already got enough bits

所以只需要取最后624/2=312个随机数就行,前面200个舍弃,具体在下面给的代码中会有体现

最终exp如下:

from Crypto.Util.number import *
from gmpy2 import *
e = 65537
common_n = 76436798540605363536477649122583467659
common_p = 5105923512372711233
common_q = 14970220050375442123
common_phi = (common_p-1)*(common_q-1)
common_d = gmpy2.invert(e, common_phi)
test = open('test', 'r').readlines()
with open('deTest', 'w') as deTest:
    for i in test:
        if i == "(76436798540605363536477649122583467659,65537)\n":
            continue
        # print(pow(int(i),common_d,common_n))
        deTest.write(str(pow(int(i),common_d,common_n))+'\n')
from randcrack import RandCrack
rc = RandCrack()
bitsum = 0
with open('deTest') as f:
    s = f.readlines()
    for l in s:
        a = int(l) % (2 ** 32)
        b = int(l) // (2 ** 32)
        # print(f"{bitsum} : {(b<<32)+a}")
        bitsum += 1
        if bitsum <= 200:
            continue
        rc.submit(a)
        rc.submit(b)
p = next_prime(rc.predict_getrandbits(1024))
q = next_prime(rc.predict_getrandbits(1024))
# print(p)
# print(q)
n = p * q
print(f"n = {n}")
top_n = 6778341886512983471750645456950728290523536616361299371741958671360393083882319627518672438545115814129137657182781214208816455570796241668174521203607532582846713044946980024783900646043967377749611378975743784775184880644929838298609658208272073728954171415761808451070649956713090699363828704967425598555240857728605492559334918924364181243615109772911597831275788990921847678043264311757080086808770372237384343263695430482298224638114383481163242159396421912093570982271665015871698548239583006809079195143432434252317382780354946136908751753704879594650848364606279745816610061533345112504778579863240146035803
c = 418919112322035719080296282188262556318147208740019952103384898777739260429989830467043589948286391778496053290993573572770668930715827948954387013380968757428438279330384918638646330090780491358345953558632784799412654785756895941844475592045474255714700612603241873989982425698945208444003573618381342067450033353217477323111093274062491515883275867746619738296397569905705052009378569807157998159800021519653031832333686380591812114745289471610313845110578057278593565079742329184877876988624852591803357662165422951088131736792374156848783221486055402017298046164798460834330495680663944310194208485613787684535
phi = (p-1)*(q-1)
assert gmpy2.gcd(e, phi) == 1 and n == top_n
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))

运行后即可得到flag:

image-20221126110646659

flag{4f43bb3f-12bc-4c85-a19a-833185d1deae}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值