ACTF2022 rsa leak

之前是不想写这个wp的,但是这两天突然想起来这道题发现没有留exp,怕下次遇到,浅记一下

from sage.all import *
from secret import flag
from Crypto.Util.number import bytes_to_long


def leak(a, b):
    p = random_prime(pow(2, 64))
    q = random_prime(pow(2, 64))
    n = p*q
    e = 65537
    print(n)
    print((pow(a, e) + pow(b, e) + 0xdeadbeef) % n)


def gen_key():
    a = randrange(0, pow(2,256))
    b = randrange(0, pow(2,256))
    p = pow(a, 4)
    q = pow(b, 4)
    rp = randrange(0, pow(2,24))
    rq = randrange(0, pow(2,24))
    pp = next_prime(p+rp)
    qq = next_prime(q+rq)
    if pp % pow(2, 4) == (pp-p) % pow(2, 4) and qq % pow(2, 4) == (qq-q) % pow(2, 4):
        n = pp*qq
        rp = pp-p
        rq = qq-q
        return n, rp, rq
    
n, rp, rq = gen_key()
e = 65537
c = pow(bytes_to_long(flag), e, n)
print("n =", n)
print("e =", e)
print("c =", c)
print("=======leak=======")
leak(rp, rq)

'''
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
=======leak=======
122146249659110799196678177080657779971
90846368443479079691227824315092288065
'''

首先对于leak(rp,rq),可以通过某种手段,来找到rp和rq
n很小可以直接分解
首先是打表爆破:

from tqdm import tqdm
def de_leak():
    n=122146249659110799196678177080657779971
    p=8949458376079230661
    q=13648451618657980711
    e=65537
    c=90846368443479079691227824315092288065
    c=c-(0xdeadbeef%n)
    dict={}
    for rp in tqdm(range(1,2**24)):
        tmp=(c-pow(rp,e,n))%n
        dict[tmp]=rp
    for rq in tqdm(range(1,2**24)):
        tmp=pow(rq,e,n)
        if tmp in dict.keys():
            print(rq,dict[tmp])
            break

de_leak()

得到
rp=405771
rq=11974933
网上学到了一种新方法 中间相遇攻击

假设有两个函数,加密函数E和解密函数D,k1,k2分别是两次加密使用的密钥.
那么,当用户知道一对明文和密文时
攻击者可以枚举所有的 k1,将 P 所有加密后的结果存储起来,并按照密文的大小进行排序。(设第一次加密后的密文为P1)
攻击者进一步枚举所有的 k2,将密文 C 进行解密得到 C1。比对P1和C1,如果搜索到,则我们在一定程度上可以认为我们找到了正确的 k1 和 k2
因为是两面逼近的方式获得密码所以称为中间相遇攻击。

哇塞这个不就是打表爆破吗,还以为能学到新东西!!?
知道rp和rq后,可以参考论文 A New Attack on Special-Structed RSA Primes
伪代码:

论文节选
复现:

from math import ceil, floor
import gmpy2
from tqdm import tqdm
from Crypto.Util.number import long_to_bytes

rp=405771
rq=11974933
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
#rp,rq=rq,rp
begin=ceil((rp*rq)^0.5)
end=floor(rq/2+2*rp+1)
for i in tqdm(range(begin,end)):
    sigma=(isqrt(n)-i)^2
    z=(n-rp*rq)%sigma
    delta=z^2-4*sigma*rp*rq
    if delta<0:
        continue
    if isqrt(delta)**2==delta:
        x1=(z+int(isqrt(delta)))/2
        p=int(n//((x1//rq+rp)))
        if n%p==0:
            q=n//p
            break
        x2=(z-int(isqrt(delta)))/2
        p=int(n//((x2//rp)+rq))
        if n%p==0:
            q=n//p
            break

phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(int(m)))

下面给出不用论文的wp:
每次复现论文都不知道如何确定一个数的精度,相比之下我感觉这个方法要常规许多,也许更加符合ctf的解题思路
显然p和q要比rp和rq大许多,我们直接对n开四次方就得到了a*b
已知:
p p = p + r p pp=p+rp pp=p+rp q q = q + r q qq=q+rq qq=q+rq n = p p ∗ q q = p q + p ∗ r q + q ∗ r p + r p ∗ r q = ( a b ) 4 + a 4 ∗ r q + b 4 ∗ r p + r p ∗ r q n=pp*qq=pq+p*rq+q*rp+rp*rq=(ab)^4+a^4*rq+b^4*rp+rp*rq n=ppqq=pq+prq+qrp+rprq=(ab)4+a4rq+b4rp+rprq
所以:
n − ( n 4 ) 4 − r p ∗ r q = a 4 ∗ r p + b 4 ∗ r q = p ∗ r q + q ∗ r p n-(\sqrt[4]{n})^4-rp*rq=a^4*rp+b^4*rq=p*rq+q*rp n(4n )4rprq=a4rp+b4rq=prq+qrp
两边同时乘p
( n − ( n 4 ) 4 − r p ∗ r q ) ∗ p = p 2 ∗ r q + n ∗ r p (n-(\sqrt[4]{n})^4-rp*rq)*p=p^2*rq+n*rp (n(4n )4rprq)p=p2rq+nrp
左边的值已知,整理得到
r p ∗ p 2 − t ∗ p + n ∗ r p = 0 rp*p^2-t*p+n*rp=0 rpp2tp+nrp=0
求解二次方程即可得到p

import gmpy2
rp,rq=405771,11974933
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
ab=int(gmpy2.iroot(n,4)[0])
a_4,b_4=var('a_4 b_4')
r=solve([a_4*b_4-ab^4,(a_4+rp)*(b_4+rq)-n],[a_4,b_4])[1]
print(r)
# [a_4 == 70102828721558534948345339875672972694466981761923685698221464095350842567073878119031031001553580576396374042398681177813432211192009435021654721839600881033401700453496031215200878726773965083072958368869100670943702515680428810181896567941226764174676649752402094845184768854288495448882912408034163036416, b_4 == 45412915496099851216618901310768894310584095399914513550903694354875119254073464201324397609041971419465018896956786021330038801780511592201795793118669826074313642092350150811064582048553811833181582093091649655549475320526152216592300774144665572210409104781712067015180667377938234003697976545066894141456]
from Crypto.Util.number import *
n = 3183573836769699313763043722513486503160533089470716348487649113450828830224151824106050562868640291712433283679799855890306945562430572137128269318944453041825476154913676849658599642113896525291798525533722805116041675462675732995881671359593602584751304602244415149859346875340361740775463623467503186824385780851920136368593725535779854726168687179051303851797111239451264183276544616736820298054063232641359775128753071340474714720534858295660426278356630743758247422916519687362426114443660989774519751234591819547129288719863041972824405872212208118093577184659446552017086531002340663509215501866212294702743
e = 65537
c = 48433948078708266558408900822131846839473472350405274958254566291017137879542806238459456400958349315245447486509633749276746053786868315163583443030289607980449076267295483248068122553237802668045588106193692102901936355277693449867608379899254200590252441986645643511838233803828204450622023993363140246583650322952060860867801081687288233255776380790653361695125971596448862744165007007840033270102756536056501059098523990991260352123691349393725158028931174218091973919457078350257978338294099849690514328273829474324145569140386584429042884336459789499705672633475010234403132893629856284982320249119974872840
a_4=70102828721558534948345339875672972694466981761923685698221464095350842567073878119031031001553580576396374042398681177813432211192009435021654721839600881033401700453496031215200878726773965083072958368869100670943702515680428810181896567941226764174676649752402094845184768854288495448882912408034163036416
p=a_4+rp
q=n//p
print(long_to_bytes(int(pow(c,gmpy2.invert(e,(p-1)*(q-1)),n))))
 
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Paintrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值