HITCON 2019 Lost Modular again writeup

HITCON 2019 Lost Modular again writeup

算是基础题,有很多之前题的影子,做不出来纯属菜。

题目

  • 加密脚本
from Crypto.Util.number import *

class Key:
    def __init__(self, bits):
        assert bits >= 512
        self.p = getPrime(bits)
        self.q = getPrime(bits)
        self.n = self.p * self.q
        self.e = 0x100007
        self.d = inverse(self.e, (self.p-1)*(self.q-1))
        self.dmp1 = self.d%(self.p-1)
        self.dmq1 = self.d%(self.q-1)
        self.iqmp = inverse(self.q, self.p)
        self.ipmq = inverse(self.p, self.q)

    def encrypt(self, data):
        num = bytes_to_long(data)
        result = pow(num, self.e, self.n)
        return long_to_bytes(result)

    def decrypt(self, data):
        num = bytes_to_long(data)
        v1 = pow(num, self.dmp1, self.p)
        v2 = pow(num, self.dmq1, self.q)
        result = (v2*self.p*self.ipmq+v1*self.q*self.iqmp) % self.n
        return long_to_bytes(result)

    def __str__(self):
        return "Key([e = {0}, n = {1}, x = {2}, y = {3}])".format(self.e, self.d, self.iqmp, self.ipmq)

def main():
    key = Key(1024)
    flag = open('flag').read()
    encrypt_flag = key.encrypt(flag)
    assert key.decrypt(encrypt_flag) == flag
    print key
    print encrypt_flag.encode('hex')

if __name__ == '__main__':
    main()
  • 输出
Key([e = 1048583, n = 20899585599499852848600179189763086698516108548228367107221738096450499101070075492197700491683249172909869748620431162381087017866603003080844372390109407618883775889949113518883655204495367156356586733638609604914325927159037673858380872827051492954190012228501796895529660404878822550757780926433386946425164501187561418082866346427628551763297010068329425460680225523270632454412376673863754258135691783420342075219153761633410012733450586771838248239221434791288928709490210661095249658730871114233033907339401132548352479119599592161475582267434069666373923164546185334225821332964035123667137917080001159691927, x = 22886390627173202444468626406642274959028635116543626995297684671305848436910064602418012808595951325519844918478912090039470530649857775854959462500919029371215000179065185673136642143061689849338228110909931445119687113803523924040922470616407096745128917352037282612768345609735657018628096338779732460743, y = 138356012157150927033117814862941924437637775040379746970778376921933744927520585574595823734209547857047013402623714044512594300691782086053475259157899010363944831564630625623351267412232071416191142966170634950729938561841853176635423819365023039470901382901261884795304947251115006930995163847675576699331])
32074de818f2feeb788e36d7d3ee09f0000381584a72b2fba0dcc9a2ebe5fd79cf2d6fd40c4dbfea27d3489704f2c1a30b17a783baa67229d02043c5bc9bdb995ae984d80a96bd79370ea2c356f39f85a12d16983598c1fb772f9183441fea5dfeb5b26455df75de18ce70a6a9e9dbc0a4ca434ba94cf4d1e5347395cf7aafa756c8a5bd6fd166bc30245a4bded28f5baac38d024042a166369f7515e8b0c479a1965b5988b350064648738f6585c0a0d1463bd536d11a105bb926b44236593b5c6c71ef5b132cd9c211e8ad9131aa53ffde88f5b0df18e7c45bcdb6244edcaa8d386196d25297c259fca3be37f0f2015f40cb5423a918c51383390dfd5a8703

初步分析

题目给定了e,d,x,y,\(x = q^{-1} \mod p,y = p^{-1} \mod q\)(代码命名混乱)。

根据rsa的原理,\(ed == 1 \mod \phi(n)\),故\(e*d-1\)一定是\(\phi(n)\)的倍数,即\(e*d-1==k*\phi(n)\),\(k\)是整数,由于\(d<n\)故\(k<e\)。\(e\)的值不是很大,通过枚举可以确定所有\(k\)的可能值,代入\(e*d-1==k*\phi(n)=k*(p-1)*(q-1)\),得到关于\(p,q\)的方程。凭借直觉,通过\(x,y\)肯定能确定另外一个方程,最后解出\(p,q\)。

另一个方程的推导

\[xq = 1 + w_1*p,yp = 1 + w_2*q\]

\[xq-1 = w_1*p,yp-1 = w_2*q\]

我们的目的是得到\(p,q\)的数量关系,势必要去掉\(w_1,w_2\)。所以两边相乘\(xypq-xq-yp+1=w_1w_2pq\),\(xq+yp-1= (xy-w_1w_2)*pq\)。这里我们知道\(x<p,y<q\)。所以\(0<(xy-w_1w_2)*pq<2*pq\)。这样我们就知道了其实\(xy-w_1w_2=1\)。这样我们又得到了一个关于\(p,q\)的等式。通过两个方程联立,最终可以解出\(p,q\)的值。

解决脚本

依赖

  • pycryptodome
  • tqdm
  • gmpy2
from Crypto.Util.number import long_to_bytes
from tqdm import trange
import gmpy2,binascii

d = 20899585599499852848600179189763086698516108548228367107221738096450499101070075492197700491683249172909869748620431162381087017866603003080844372390109407618883775889949113518883655204495367156356586733638609604914325927159037673858380872827051492954190012228501796895529660404878822550757780926433386946425164501187561418082866346427628551763297010068329425460680225523270632454412376673863754258135691783420342075219153761633410012733450586771838248239221434791288928709490210661095249658730871114233033907339401132548352479119599592161475582267434069666373923164546185334225821332964035123667137917080001159691927
x = 22886390627173202444468626406642274959028635116543626995297684671305848436910064602418012808595951325519844918478912090039470530649857775854959462500919029371215000179065185673136642143061689849338228110909931445119687113803523924040922470616407096745128917352037282612768345609735657018628096338779732460743
y = 138356012157150927033117814862941924437637775040379746970778376921933744927520585574595823734209547857047013402623714044512594300691782086053475259157899010363944831564630625623351267412232071416191142966170634950729938561841853176635423819365023039470901382901261884795304947251115006930995163847675576699331
e = 1048583

klist = []
for i in trange(1,e):
    if (e*d-1)%i==0:
        klist.append(i)
print(len(klist))
nlist = []
for k in klist:
    w = (e*d-1)//k
    a = y-1
    b = x-y-w
    c = 1-x+w*x
    delt = b*b-4*a*c
    if delt<0 :
        continue
    s,t = gmpy2.isqrt_rem(delt)
    if t!=0:
        continue
    if (s-b)%(2*a)!=0:
        continue
    q = (s-b)//(2*a)
    if (w+q-1)%(q-1)!=0:
        continue
    p = (w+q-1)//(q-1)
    n = p*q
    nlist.append(n)
print(nlist)
n = 22509077260984027608263845908083202879597081619164800783060781115945741547031252889863077300004310236160814653393991988068104999928735140821504649764471313283345921984799288521496479399032837319974588038186917872597078510975400908137738190304700710900604891709265153418588830065918981914371070605822998222527238465925300150253661563857557769597206945843298561291788401379974127990007737364134474570192828364417568030703631487414510799126846577679080152555651843717973023204220528124089432708534457966658829476472791371567790491496967424845002161008643478300481541860754837427906812836584810660110698219790829058527133
c = 0x32074de818f2feeb788e36d7d3ee09f0000381584a72b2fba0dcc9a2ebe5fd79cf2d6fd40c4dbfea27d3489704f2c1a30b17a783baa67229d02043c5bc9bdb995ae984d80a96bd79370ea2c356f39f85a12d16983598c1fb772f9183441fea5dfeb5b26455df75de18ce70a6a9e9dbc0a4ca434ba94cf4d1e5347395cf7aafa756c8a5bd6fd166bc30245a4bded28f5baac38d024042a166369f7515e8b0c479a1965b5988b350064648738f6585c0a0d1463bd536d11a105bb926b44236593b5c6c71ef5b132cd9c211e8ad9131aa53ffde88f5b0df18e7c45bcdb6244edcaa8d386196d25297c259fca3be37f0f2015f40cb5423a918c51383390dfd5a8703
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))
上一篇:i春秋网络内生安全试验场CTF夺旗赛(第二季)部分Web题WriteUp


下一篇:南邮CTF - Writeup