美文网首页
MeepwnCTF18-BITBITBIT

MeepwnCTF18-BITBITBIT

作者: Robin_Tan | 来源:发表于2018-07-18 14:55 被阅读0次

    这题主要考察的是RSA
    题目代码如下:

    #!/usr/bin/env python2
    from gmpy2 import next_prime, powmod
    from random import randint, getrandbits
    from hashlib import sha512, sha256
    from os import urandom
    
    introduction = """
     .--.     .-------------------------------.
     | _|     |                               |
     | O O   <  Hey man, wanna mid some bit ? |
     |  |  |  |                               |
     || | /   `-------------------------------'
     |`-'|
     `---'
    Whoever says live is simple, is the one never actually live. :)) 
    """
    
    
    def pad(num, length):
        result = bin(num).lstrip('0b').strip('L')
        result = result + '0' * (length - len(result))
        return int(result, 2)
    
    
    def xor(a, b):
        return ''.join(chr(ord(i) ^ ord(j)) for i, j in zip(a, b))
    
    
    def gen_key():
        t1 = randint(768, 928)
        t2 = 1024 - t1
    
        if t1 > t2:
            t1, t2 = t2, t1
        assert t1 < t2
    
        p2 = pad(getrandbits(1024 - t2) << t2, 1024)
        p0 = pad(getrandbits(t1), t1)
    
        q2 = pad(getrandbits(1024 - t2) << t2, 1024)
        q0 = pad(getrandbits(t1), t1)
    
        r = pad(getrandbits(t2 - t1) << t1, t2)
    
        p = next_prime((p2 ^ r ^ p0))
        q = next_prime((q2 ^ r ^ q0))
    
        N = p * q
    
        return N, t2 - t1, p0 - q0,p,q,
    
    
    def proof_of_shit():
        """
        This function has very special purpose 
        :)) Simply to screw you up
        """
        raw = urandom(6)
        print 'prefix = {}'.format(raw.encode('hex'))
        challenge = raw_input('Challenge: ')
        temp = sha256(raw + challenge).hexdigest()
        if temp.startswith('25455'):
            return True
        else:
            return False
    
    
    if __name__ == "__main__":
        try:
            assert proof_of_shit() == True
            N, delta, gamma = gen_key()
    
            m = FLAG
            c = powmod(m, 0x10001, N)
    
            print introduction
            print 'N = {}'.format(N)
            print 'delta = {}'.format(delta)
            print 'gamma = {}'.format(gamma)
            print 'ciphertext = {}'.format(c)
    
        except AssertionError:
            print "Take your time and think of the inputs."
    

    可以看到服务端会除了返回N和密文之外,还会返回delta和gamma两个非常奇怪的值
    所以具体看他的p、q的生成算法

    p = next_prime((p2 ^ r ^ p0))
    q = next_prime((q2 ^ r ^ q0))

    根据next_prime的性质,一般而言得到的p和next_prime的输入p2 ^ r ^ p0之间相差不超过10000,
    由此可知结论1

    | (p0-q0)-(p-q)&(2t1-1) | <10000

    此外根据p2、q2和r的生成算法,有结论2

    p和q的中间 1024-2×t1 位是相同的,较高的t1位不同,较低的t1位也不同

    根据coppersmit 攻击,有结论3

    如果我们能得到质因数p的足够数量的低比特位,可以对n=p×q进行分解

    而由代码知t2=1024-t1 属于区间[768, 928],满足结论3的攻击条件
    因此我们只要能够根据结论1,结论2和给出的n,gamma,推导出p的低t2比特位,即可进行coppersmith攻击。
    假设p的低t2比特位为x,gamma 和真实p,q低t1位的差为i,根据n,gamma计算x的方程如下:

    g=gamma+i
    r1=solve_mod([x * (x+g)==n0],2t1)
    r2=solve_mod([x * (x+g)==n&(2t2-1)],2t2)

    因此我们可以在一个合理的范围爆破i来求出x
    需要说明的是,通过这种方法会求出多个满足等式的x
    还需要把x代入coppersmith中,看是不是真的存在满足条件的p
    具体sage脚本如下:

    def partial_p(p0, kbits,pbits, n,offset=0):
        #print "lower %d bits (of %d bits) is given" % (kbits, pbits)
        PR.<x> = PolynomialRing(Zmod(n))
        nbits = n.nbits()
    
        f = 2^kbits*x + p0
        f = f.monic()
        roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3)  # find root < 2^(nbits//2-kbits) with factor >= n^0.3
        if roots:
            x0 = roots[0]
            p = gcd(2^kbits*x0 + p0, n)
            return ZZ(p)
    
    
    
    def compute(i):
        g=gamma+i
        var('xx')
        n0=n&(2^t1-1)
        r1=solve_mod([xx*(xx+g)==n0],2^t1)
        r2=solve_mod([xx*(xx+g)==n&(2^t2-1)],2^t2)
        
        if(len(r2)>0):
            print i
            for yy in r2:
                
                result=partial_p(yy[0].lift(),t2,t2+t1,n,2)
                if(result):
                    print result
                
    n = 19787744055007771920075491868994595093008774777733094463267657045445491006226236122756176027670521293033971930544901550426019602751914449163021323306625597709926868006449807069771718137975569399401849816498362414538410746758435242648534889529758318238899434433000229062428208609293124251445336557626496221144799221046211625817903374716018476165360438767645671019540717239635125639502429065579038145981461938320723654297611786334692045444446931985658100226649855775288924797607205159552266184766109424149643788888036522548799788510471386824605128594324123755605356061187596278801235136397504966233996876612550128991993
    delta = 608
    gamma = 10356174804751816155721586247435033090295658846311470412894333
    
    t2=(1024+delta)/2
    t1=1024-t2
    for i in range(-100,100):
        compute(i)
    for i in range(-500,-100):
        compute(i)
    for i in range(100,500):
        compute(i)
    for i in range(-1000,-500):
        compute(i)
    for i in range(500,1000):
        compute(i)
    for i in range(-1500,-1000):
        compute(i)
    for i in range(1000,1500):
        compute(i)
    for i in range(-2000,-1500):
        compute(i)
    for i in range(1500,2000):
        compute(i)
    
    
    
    

    最后根据分解出的p求出flag

    >>> p=120636006277871411275371530087790065770134552887607039956902910661113789275639922696690508302593627744373797262608926169377237610359496446738472601322383943513077466708305240126154227404187298195677026542923410015128149399197711734201505801640198120678665925046049173946467463512174621999415403951225544839099
    >>> q=164028507454307953998030584561374532729364541052939989108986085613755695456310053587570797100201540198211442715120682600140701077905210171298161735285877275283595109376452234736485541588980439459655220129066692701413940064735892881327113198833726660675511352354042700510883423696866994972583876907812196351707
    >>> n=19787744055007771920075491868994595093008774777733094463267657045445491006226236122756176027670521293033971930544901550426019602751914449163021323306625597709926868006449807069771718137975569399401849816498362414538410746758435242648534889529758318238899434433000229062428208609293124251445336557626496221144799221046211625817903374716018476165360438767645671019540717239635125639502429065579038145981461938320723654297611786334692045444446931985658100226649855775288924797607205159552266184766109424149643788888036522548799788510471386824605128594324123755605356061187596278801235136397504966233996876612550128991993
    >>> n==p*q
    True
    >>> f=(p-1)*(q-1)
    >>> from libnum import *
    >>> d=invmod(0x10001,f)
    >>> cipher=10063064794864843312128550042856940325978411568147543113920034231240570289963573829350421824150738515370421890157251474391322062002314450945021754117310424572492269370708571470899634910437973313992828194830717962139782475599768731817262528197135385396676490833516836507954960687728249257889382361566995432480474003042400686070268597001143235114910699463880385869328802742259244425195913477126022427275517767473528864476008925769721936711219464549635822368655994152344558111678892454800804705969648049428383321047344672503044122691602273760755850221193346698969570690169363339213010957323861023611410002000863099686168
    >>> n2s(pow(cipher,d,n))
    'MeePwnCTF{It_is_the_time_to_move_to_Post_Quantum_Cryptography_DAGS}'
    
    
    

    相关文章

      网友评论

          本文标题:MeepwnCTF18-BITBITBIT

          本文链接:https://www.haomeiwen.com/subject/iomopftx.html