zoukankan      html  css  js  c++  java
  • 西湖论剑2020中国杭州网络安全技能大赛部分题目WriteUp

    作为一个刚接触CTF不到3个月的小白,抱着来学习的想法,参加了西湖论剑·2020中国杭州网络安全技能大赛,只做出来2道题目,发一下WriteUp。

    一、[CRYPTO]BrokenSystems

    介绍大意是,有人黑进了加密系统并进行了篡改,剩下的就交给你了。

    提供了3个文件

    1.加密算法脚本

    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_OAEP
    from secret import flag
    import os
    rsa = RSA.generate(2048)
    public_key = rsa.publickey().exportKey()
    f=open("public.key","w")
    f.write(public_key.decode())
    f.close()
    
    rsakey=RSA.importKey(open("public.key","r").read())
    rsa = PKCS1_OAEP.new(rsakey)
    msg=rsa.encrypt(flag.encode())
    f=open("message","wb")
    f.write(msg)
    f.close()

    2.公钥public.key

    -----BEGIN PUBLIC KEY-----
    MIICITANBgkqhkiG9w0BAQEFAAOCAg4AMIICCQKCAQEAwgdFIj/1uUss2EEhZvco
    iiHyGH4aQhRTkYyrA8gCU0USM+sb3CNjdEIoqoaUqMLLyDP4Dd9AgxpokBsjC4Pz
    8P7Uty0LlCteld7ayNzABHoq+5DIHtctOtSbcvyL0NMWfd2qarUWfAWN82rxkLIW
    CFu9nWIfm9I6CT5OPZzDh7YnTywznIjhstkIrLM/TiDmR6vuBxSjzORkbolilLeB
    A9zJpNt+1oEWTG5sx/0zR24XSmxwcDeyUEkTZfnw63auq6B9svZi2IBIr5jIjHbG
    cQ25ZY1J/KDK8fXNmdwH8YhDK0j4VXEWitEPyCS3toK61sql0S/28EySeGtzirGb
    twKCAQAdLS8fFz+BzzaP7AbUDUf9kvhhXBLuwUFo8ohCeVK4z1pTj3C6M0G2oXOu
    gDdalrDThNlyKxkUn3iUc3Xgoz315pPtq9Xk1Ez/qeUl6gFPP6SZtfeymyGdkLiN
    pVquOghjczjXvtBW467Fdb5Wu95TSzVaLndX23rsqW541n8hUwt8PsJKxh+bR0qy
    gyIN2VRRNdBlpyTOL49E4y5GDu9fmVgAnFivWVGT135ywl8MsBUFuZPBNTKLEbUA
    3KvJVckXf4Od0ENYbiWjEzXn1UN9yebNbU6+yyk34WAmwnkuF0X0Tu1UEb6qtV7Q
    kF25GYy9QxERvodGL0Y2njHRpGE/
    -----END PUBLIC KEY-----

    3.密文message

    由于是二进制,这里转为BASE64贴出来,需要的自己转回去即可。

    J6a4HIY3ilKlD3lwR7GRG5WCPANVLC4NV9UKv/jHw23jj6I6LhgFhuY3P3PAtMtoEA7Wu1r7vNH/xSaQGidEryCJ8SXdqH29AqfMfmEszf2KtZib2sl2fatU1gHsLCNhZIE5pSck7N+cjOBnDDDfVTsOI8nJhF8yEPkO7pyK02srFdDooySSzkhEumWWkblciuwDwb4A6uD0K7X45rsJQ0TN3/cZFTOnIGgf9RNWoDlwrFp8C/xkVVWbask14UzaqrfWYp3fGrORgH3DLn5RHUq7O+exk7AJgqr3qIlTDcQeEEnm860nt9FKQl+TFE8wJgIP0AH3wg1TeE7hr3kY4g==

    解题思路:

     首先从加密脚本确定是一个正常的RSA公钥加密,需要破解得到私钥才能解密。由于提供了公钥,我们能获得e和n的值,从而判断属于什么漏洞。

    第一步,获取e和n:

    from Crypto.PublicKey import RSA
    from rsa import PublicKey,transform, core
    from Crypto.Cipher import PKCS1_OAEP
    
    pubkey=open("public.key","r").read()
    rsakey = PublicKey.load_pkcs1_openssl_pem(pubkey)
    
    n=rsakey.n
    e=rsakey.e
    
    print(n)
    print(e)

    观察打印出来的n和e:

    24493816160588971749455534346389861269947121809901305744877671102517333076424951483888863597563544011725032585417200878377314372325231470164799594965293350352923195632229495874587039720317200655351788887974047948082357232348155828924230567816817425104960545706688263839042183224681231800805037117758927837949941052360649778743187012198508745207332696876463490071925421229447425456903529626946628855874075846839745388326224970202749994059533831664092151570836853681204646481502222112116971464211748086292930029540995987019610460396057955900244074999111267618452967579699626655472948383601391620012180211885979095636919
    3683191938452247871641914583009119792552938079110383367782698429399084083048335018186915282465581498846777124014232879019914546010406868697694661244001972931366227108140590201194336470785929194895915077935083045957890179080332615291089360169761324533970721460473221959270664692795701362942487885620152952927112838769014944652059440137350285198702402612151501564899791870051001152984815689187374906618917967106000628810361686645504356294175173529719443860140795170776862320812544438211122891112138748710073230404456268507750721647637959502454394140328030018450883598342764577147457231373121223878829298942493059211583

    发现e很大,我们知道一般e取值为65537,当加密指数e取得过大时,会导致解密指数d较小,存在低解密指数攻击的可能性。我们套用破解脚本:

    def rational_to_contfrac (x, y):
        ''' 
        Converts a rational x/y fraction into
        a list of partial quotients [a0, ..., an] 
        '''
        a = x//y
        if a * y == x:
            return [a]
        else:
            pquotients = rational_to_contfrac(y, x - a * y)
            pquotients.insert(0, a)
            return pquotients
    def convergents_from_contfrac(frac):    
        '''
        computes the list of convergents
        using the list of partial quotients 
        '''
        convs = [];
        for i in range(len(frac)):
            convs.append(contfrac_to_rational(frac[0:i]))
        return convs
    
    def contfrac_to_rational (frac):
        '''Converts a finite continued fraction [a0, ..., an]
         to an x/y rational.
         '''
        if len(frac) == 0:
            return (0,1)
        elif len(frac) == 1:
            return (frac[0], 1)
        else:
            remainder = frac[1:len(frac)]
            (num, denom) = contfrac_to_rational(remainder)
            # fraction is now frac[0] + 1/(num/denom), which is 
            # frac[0] + denom/num.
            return (frac[0] * num + denom, num)
    
    def egcd(a,b):
        '''
        Extended Euclidean Algorithm
        returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
        '''
        u, u1 = 1, 0
        v, v1 = 0, 1
        while b:
            q = a // b
            u, u1 = u1, u - q * u1
            v, v1 = v1, v - q * v1
            a, b = b, a - q * b
        return u, v, a
    
    def gcd(a,b):
        '''
        2.8 times faster than egcd(a,b)[2]
        '''
        a,b=(b,a) if a<b else (a,b)
        while b:
            a,b=b,a%b
        return a
    
    def modInverse(e,n):
        '''
        d such that de = 1 (mod n)
        e must be coprime to n
        this is assumed to be true
        '''
        return egcd(e,n)[0]%n
    
    def totient(p,q):
        '''
        Calculates the totient of pq
        '''
        return (p-1)*(q-1)
    
    def bitlength(x):
        '''
        Calculates the bitlength of x
        '''
        assert x >= 0
        n = 0
        while x > 0:
            n = n+1
            x = x>>1
        return n
    
    
    def isqrt(n):
        '''
        Calculates the integer square root
        for arbitrary large nonnegative integers
        '''
        if n < 0:
            raise ValueError('square root not defined for negative numbers')
    
        if n == 0:
            return 0
        a, b = divmod(bitlength(n), 2)
        x = 2**(a+b)
        while True:
            y = (x + n//x)//2
            if y >= x:
                return x
            x = y
    
    
    def is_perfect_square(n):
        '''
        If n is a perfect square it returns sqrt(n),
    
        otherwise returns -1
        '''
        h = n & 0xF; #last hexadecimal "digit"
    
        if h > 9:
            return -1 # return immediately in 6 cases out of 16.
    
        # Take advantage of Boolean short-circuit evaluation
        if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
            # take square root if you must
            t = isqrt(n)
            if t*t == n:
                return t
            else:
                return -1
    
        return -1
    
    def hack_RSA(e,n):
        frac = rational_to_contfrac(e, n)
        convergents = convergents_from_contfrac(frac)
    
        for (k,d) in convergents:
            #check if d is actually the key
            if k!=0 and (e*d-1)%k == 0:
                phi = (e*d-1)//k
                s = n - phi + 1
                # check if the equation x^2 - s*x + n = 0
                # has integer roots
                discr = s*s - 4*n
                if(discr>=0):
                    t = is_perfect_square(discr)
                    if t!=-1 and (s+t)%2==0:
                        print("
    Hacked!")
                        return d
    
    def main():
        n = 24493816160588971749455534346389861269947121809901305744877671102517333076424951483888863597563544011725032585417200878377314372325231470164799594965293350352923195632229495874587039720317200655351788887974047948082357232348155828924230567816817425104960545706688263839042183224681231800805037117758927837949941052360649778743187012198508745207332696876463490071925421229447425456903529626946628855874075846839745388326224970202749994059533831664092151570836853681204646481502222112116971464211748086292930029540995987019610460396057955900244074999111267618452967579699626655472948383601391620012180211885979095636919
    e = 3683191938452247871641914583009119792552938079110383367782698429399084083048335018186915282465581498846777124014232879019914546010406868697694661244001972931366227108140590201194336470785929194895915077935083045957890179080332615291089360169761324533970721460473221959270664692795701362942487885620152952927112838769014944652059440137350285198702402612151501564899791870051001152984815689187374906618917967106000628810361686645504356294175173529719443860140795170776862320812544438211122891112138748710073230404456268507750721647637959502454394140328030018450883598342764577147457231373121223878829298942493059211583
        d=hack_RSA(e,n)
        print ("d=")
        print (d)
    
    if __name__ == '__main__':
        main()
    View Code

    输出结果为:

    Hacked!
    d=
    1779217788383673416690068487595062922771414230914791138743960472798057054853883175313487137767631446949382388070798609545617543049566741624609996040273727

    这样就得到了d。如果直接用pow(c,d,n)尝试计算原文,会发现输出是乱码,琢磨了半天发现,我们应当构造RSA私钥进行解密:

    from Crypto.PublicKey import RSA
    from rsa import PublicKey,transform, core
    from Crypto.Cipher import PKCS1_OAEP
    
    private_key = RSA.construct((n, e, d))
    rsa = PKCS1_OAEP.new(private_key)
    m=rsa.decrypt(long_to_bytes(c))
    print(m)

    这样就解出了原文:

    DASCTF{ce02347b86167f2d3519251b9a8a5ba8}

    二、[Misc]指鹿为马

      题目给了一个地址和端口,没有附件。用nc连上去一看,长这样:

    --------------------------------------------------------------------------------------------------------------------------------------
          ____       __            _          _   _                _                              _   _            _
         |  __      / _|          | |        | | | |              | |                            | | | |          | |
         | |__) |___| |_ ___ _ __  | |_ ___   | |_| |__   ___    __| | ___  ___ _ __    __ _ ___  | |_| |__   ___  | |__   ___  _ __ ___  ___
         |  _  // _   _/ _  '__| | __/ _   | __| '_  / _   / _` |/ _ / _  '__|  / _` / __| | __| '_  / _  | '_  / _ | '__/ __|/ _ 
         | |    __/ ||  __/ |    | || (_) | | |_| | | |  __/ | (_| |  __/  __/ |    | (_| \__  | |_| | | |  __/ | | | | (_) | |  \__   __/
         |_|  \_\___|_| \___|_|     \__\___/   \__|_| |_|\___|  \__,_|\___|\___|_|     \__,_|___/  \__|_| |_|\___| |_| |_|\___/|_|  |___/\___|
    
    --------------------------------------------------------------------------------------------------------------------------------------
            1.show source code
            2.give me the source pictures
            3.upload picture
            4.exit

    Refer to the deer as the horse,好一个指鹿为马。

    输入1,获得源文件代码:

    import numpy as np
    from PIL import Image
    import math
    import operator
    import os
    import time
    import base64
    import random
    
    def load_horse():
        data = []
        p = Image.open('./horse.png').convert('L')
        p = np.array(p).reshape(-1)
        p = np.append(p,0)
        data.append(p)
        return np.array(data)
    
    def load_deer():
        data = []
        p = Image.open('./deer.png').convert('L')
        p = np.array(p).reshape(-1)
        p = np.append(p,1)
        data.append(p)
        return np.array(data)
    
    def load_test(pic):
        data = []
        p = Image.open(pic).convert('L')
        p = np.array(p).reshape(-1)
        p = np.append(p,1)
        data.append(p)
        return np.array(data)
    
    
    def euclideanDistance(instance1, instance2, length):
        distance = 0
        for x in range(length):
            distance += pow((instance1[x] - instance2[x]), 2)
        return math.sqrt(distance)
    
    
    def getNeighbors(trainingSet, testInstance, k):#k===1
        distances = []
        length = len(testInstance) - 1
        for x in range(len(trainingSet)):
            dist = euclideanDistance(testInstance, trainingSet[x], length)
            distances.append((trainingSet[x], dist))
        distances.sort(key=operator.itemgetter(1))
        print('Eud: ', distances)
        neighbors = []
        for x in range(k):#(0,1)
            neighbors.append(distances[x][0])
            return neighbors
    
    
    def getResponse(neighbors):
        classVotes = {}
        for x in range(len(neighbors)):
            response = neighbors[x][-1]
            if response in classVotes:
                classVotes[response] += 1
            else:
                classVotes[response] = 1
        sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
        return sortedVotes[0][0]
    
    
    def getAccuracy(testSet, predictions):
        correct = 0
        for x in range(len(testSet)):
            if testSet[x][-1] == predictions[x]:
                correct += 1
        return (correct / float(len(testSet))) * 100.0
    
    def check(pic):
        source_p = Image.open('deer.png')
        try:
            c_p = Image.open(pic)
        except:
            print("Please upload right picture.")
            exit()
        diff_pixel = 0
        a, b = source_p.size
        if c_p.size[0] != a and c_p.size[1] != b:
            print("Please upload right picture size("+str(a)+','+str(b)+')')
            exit()
        for y in range(b):
            for x in range(a):
                diff_pixel += abs(source_p.getpixel((x, y)) - c_p.getpixel((x, y)))
        print(diff_pixel)
        return diff_pixel
    
    def main():
        while 1:
            print('-' * 134)
            print('''      ____       __            _          _   _                _                              _   _            _                         
         |  __      / _|          | |        | | | |              | |                            | | | |          | |                        
         | |__) |___| |_ ___ _ __  | |_ ___   | |_| |__   ___    __| | ___  ___ _ __    __ _ ___  | |_| |__   ___  | |__   ___  _ __ ___  ___ 
         |  _  // _   _/ _  '__| | __/ _   | __| '_  / _   / _` |/ _ / _  '__|  / _` / __| | __| '_  / _  | '_  / _ | '__/ __|/ _ \
         | |    __/ ||  __/ |    | || (_) | | |_| | | |  __/ | (_| |  __/  __/ |    | (_| \__  | |_| | | |  __/ | | | | (_) | |  \__   __/
         |_|  \_\___|_| \___|_|     \__\___/   \__|_| |_|\___|  \__,_|\___|\___|_|     \__,_|___/  \__|_| |_|\___| |_| |_|\___/|_|  |___/\___|
        ''')
            print('-'*134)
            print('	1.show source code')
            print('	2.give me the source pictures')
            print('	3.upload picture')
            print('	4.exit')
            choose = input('>')
            print(choose)
            if choose == '1':
                w = open('run.py','r')
                print(w.read())
                continue
            elif choose == '2':
                print('this is horse`s picture:')
                h = base64.b64encode(open('horse.png','rb').read())
                print(h.decode())
                print('-'*134)
                print('this is deer`s picture:')
                d = base64.b64encode(open('deer.png', 'rb').read())
                print(d.decode())
                continue
            elif choose == '4':
                break
            elif choose == '3':
                print('Please input your deer picture`s base64(Preferably in png format)')
                pic = input('>')
                try:
                    pic = base64.b64decode(pic)
                except:
                    exit()
                if b"<?php" in pic or b'eval' in pic:
                    print("Hacker!!This is not WEB,It`s Just a misc!!!")
                    exit()
                salt = str(random.getrandbits(15))
                pic_name = 'tmp_'+salt+'.png'
                tmp_pic = open(pic_name,'wb')
                tmp_pic.write(pic)
                tmp_pic.close()
                #跟deer要相似
                if check(pic_name)>=100000:
                    print('Don`t give me the horse source picture!!!')
                    os.remove(pic_name)
                    break
                ma = load_horse()
                print('ma:')
                print(ma)
                lu = load_deer()
                print('lu:')
                print(lu)
                k = 1
                trainingSet = np.append(ma, lu).reshape(2, 5185)
                print('train:', trainingSet)
                testSet = load_test(pic_name)
                print('test:', testSet, len(testSet[0]))
                neighbors = getNeighbors(trainingSet, testSet[0], k)
                print('neighbors:', neighbors)
                result = getResponse(neighbors)
                if repr(result) == '0':
                    os.system('clear')
                    print('Yes,I want this horse like deer,here is your flag encoded by base64')
                    flag = base64.b64encode(open('flag','rb').read())
                    print(flag.decode())
                    os.remove(pic_name)
                    break
                else:
                    print('I want horse but not deer!!!')
                    os.remove(pic_name)
                    break
            else:
                print('wrong choose!!!')
                break
        exit()
    
    if __name__=='__main__':
        main()
    View Code

    输入2,获得图片的BASE64值:

    this is horse`s picture:
    iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAAAAABwhuybAAAFeElEQVR4nO2Xy28TVxTGvzN2ZpLYIY5dkgImIU4I2DFqQqiaqGpL2gXqv8AC2lUX/BFl032lSpWqblqpGyQ2LQhERQhUDSqk4ZnEtHnxCATn4TjP8fOeLmZszzPEUpeclefeM7/z3e/OfRh4G/9n+Dtk907v7jnKh42vc6690u5BTe/u1FsFyEPVgGoaqkAbw+pR5+m5689dq+5QxApSWjuO/DhbGoRgU6dcv7E7UH1472EUw2fuFDVS8e+UKblmX3JXoHBfiEKAOJjSClPOOpTOp2k3kCG19aN3IADA08habGyZk7nxRN2bFTWc8AuEWiWADtG8AIAF1ZLNrZ77SwynqIAa19cpHpMZgLddmcsTCpmwBACFZLGcFQ69TKoaivPragVKxl/9Z/YI/WlxRiVtoKC1qyoAtJzyAgAx66+LrWdPNu2KGL2n/el6vaFZntogzUBS8wCALXUPA2CQXl0KBPbdXtFfN5gdPxt68M210lNTNFj6mSxooJdWX5ibB3w20JEv9vLMqyeFUlJDtEX7pb4kSZIInFi3rTZuOWIdWuTLfUJiVNxjpUuZFwA8xwVAUzNYvTvgs03ZoYRqAsW+CgnAh3rDWL3t8tMCULMfAD0H8CxzbH+NQQ4A9jeYQF3fHR1LE/fXdHkMNaWD8kyGwAAKaQBIpkJBWRsf1YeCEgOSvmtqrW3fnxTp+2kiYov21alNAkDL1zLWQdW2xQMMcX1eKwoA9edPFjnQG2AWVg+CsSAA8LSNg8w/N1cq7ksA8P7nAuBAT4CJyDwz3HC0BcCLaRsHwModtZztBYC4XwDgpt6RJY/gBo+JVNslL6/N+f12Tl59PRczgXQsN937SRY43StM+d5ION9nx5DILSeWyqvQCwDjmz4GQBt/LQIYOqqYX5FqXTaPgz3p5flSEgDcveohgDyXRwFgctK2NbNzCA50HJYNoO2vL2xJ0uYv51UAyA5btyH3YBz4WPtEdXt8J7p5fGxbe1DO9QmXFx0i98NdA8gcvecUp2bnkB59m4XLSTsxUcUpye0H4AbKVeES2Bd2BWGyGklSozuoKknat+hSuSpJtAMod8NdkvPtxq1w4pFbD684XtuMZ78n3Fx+u7hWdKxMuZnNQFuNvcMI6vqk8h1yIzuBqHB58XgKDiTDAChSKyrheMJT4cpvOULqWX4nRZKX4Walzslf/bVAABw0WW9sBX222OFKTdlLV3Sj7SQLSEoOaQtfdMet0yalLo6UzmE7yaZoQ99BVItJxE8uJgCQv0ySjSm7u/kTide3bq0DQEenftmZHTvVZCC5ghjQ55S5sD1//552UwsNKAwAtPBHMnk2UCG5gho8QPbWGoGLanpxKau1Kv26iumRNYzCQLKCvB5NudzvFdL4BctqoN4IA6Dio9EMYCJZpka0HNNaYt0C6rB1VUXeAwBSR25rJ/joz6ul784AKqYBeD/o8QCQB+sgjScsnOCAAkBKDz0snYujQ6U+o6KHrwio6WsuCbppEaQMBBmgV9dmy84o7WScFz3SQwuE4sMlQD5ZB2li0syhnggDmP7d8D8i1i2gzllBSA0tiNGxAhCNOzjU3gOQeHBjzaBxsA7SZAKwzlrqRsu/RUAerBM2QcEBhUkdfVw0tEVjAupw1g7CygrgLEjpDzHSf84Zl4U8WCekSa2g0wfpKKgzwsgMvzC1RbvLghz3bEeH/B5QbtVaECVBTiD507KDO0c0LpC5mXUFxQyCDWG7XmqCJvQnu0dGBw2RXWPaNO1R0bhAplzQDup2FpSYZYhtW8GSIDtIcRaErBUdMwmyexSLOQqyhdkhh//9n/kEOQiyRfwYpKyhoA00PgU8frMg5C8JWp94c97bqMR/qKdMxhtIpukAAAAASUVORK5CYII=
    --------------------------------------------------------------------------------------------------------------------------------------
    this is deer`s picture:
    iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAAAAABwhuybAAAEXUlEQVR4nO2XS2xbRRSG/5l7b/xSb2wnDqbBSdU0FcQUmsRZVCAkorZJumkrFWEkWLJgyZINC5bsQQKEVAkhNRKJRKWqjUiFEAgUkYRQtYQ+ZCc4jzbk4dgkaWzfOSwSP+7D9r3Jtmc198ycz/+ZmTMzBp6Zc2N959wAXGdjDEDTxY6DggJfXT8FoOv7L/wArox/xG2FmUcpHsUNwKO4FYB3QNABQaCKyGi39pc9kKzT8p/Yb3pdfkhNSvTtpvu/2eLoQBfPfjkNAGh7+bTqlYIfs8aGha9XHYOkUyd7pgFAes/L8iIHldIzo4/scSpB2mPRpWYAwLtwK1EAINZW8jY5utQmzr8Uv5YB+MKnf9uNtwTdGbt8uWtW8tG4c44OVPiWBqJRiELSOUcHQvbqw4FjDR4qHBbU/mane0MJy+e2Z7VDgFj3W01ZhZFGL4bGx2wvVzG63IzF/TMjZwYYh0Dh1k2HpHKtxeIqJZcfaqRpRPLgkGI3cM9KqcXiKjHCfoWSPIiamviQd3KuspyL4FhcJcALLyuRampiJ4Y+OFMxL0VFvXGVAOpTTkg2NQktcGm5YsNxAGCxd/wAQIH+SElu3XkSgV6jotbXsptySNKfafXnCWGpvN1kANB+JzraLxnH1SVJFZMkA0BWcvlebTAfqSQPSjef1tJkAG0pA17F6mgm+XxoLCUseqxB9AveCO5lxhViABVjifd13vlzYctUepVZASiVCGsMKQAg2j8JCrDtmaelgYzl0umcEcQiR4jf/ax8TuzvI0qn9xrJxCsaoC3Pl9MjOdRiToUI5A8vlL6NJbP73bYQgrfplpCE2Qig1vejVUH46Z4EUIvfzrVIR989WRW0el0AcEdscADRfEmtBsKNJQ6g1WvrphYdxTIxgx7c5gCpYVuSwHtc1UDaaIYBUti4UayNwoFqIExMcQCyTZBbrQrKjhYA8cRWYQCSUhWEHxKySM7ZU1SqDdmiK/XNlfUnebsgVAfRyPNHWJljyJFZ/4IVCKnp/nK0K6iP3NmwDxK3OyNFkgi+rp/H3amUVYz123dlZL3UwbjevLE2+yDcu5ood+lTI48lyTI1ALPLvd3HJQBM7EqGsuOntUVTQI1FDn8YIIAt/2xYNmrpyUvB4pf2+d2aigAUCADY6o/GA7vVxRtEs8Fp74+G3hjn+X/WioDQwUEAWG5+bW9W+IXYYUBguflFAgBqjEftgaosB9u6NskAgPzHgZqTvR9Q5VnKVh4tsT4C9t9m9RSxjV+tSSKhZYcny3LrKGLp4T+sO9YXgcwwSk+kOorYxJTZ6eMAJXcAbN7IFDXVS23H7JLaGNjW3p2+W8r7AMvf/BwBqU2D9wCgdheQSxrvT+cgXwRgj1eMbuegVpUgEqY94RgkHeNg60smv2NQcwuB5syL6RjU7gLbmjP7nYJ8EQCpjLmjVokwTtxY+y80guUTpBtTD7Q95iF23+icBnb+1Y95UEPMM6uw/wEb7IPCRqC/gwAAAABJRU5ErkJggg==
    --------------------------------------------------------------------------------------------------------------------------------------
    View Code

    输入3,提示输入图片:Please input your deer picture`s base64(Preferably in png format)

    解题思路:

    阅读代码,发现需要用户上传的图片符合一定要求,才会给出flag。这个要求就是,看起来是鹿,却又更像马-_-||

    具体来说,就是以check函数计算出的距离来看,与鹿的图片差距值小于一定阈值(100000),而用euclideanDistance(欧氏距离)作为依据又更接近马的图片。

    乍一看,这有可能吗?我们来分析一下。

    我们把问题简化,假如图片只有2个像素,IMG鹿=(x1, y1), IMG马=(x2, y2),用户上传图片IMG_USER=(xt, yt),则要求:

    abs(x1-xt) + abs(y1-yt) < T

    且:

    d1 = sqrt((x1 - xt)^2 + (y1 - yt)^2)

    d2 = sqrt((x2 - xt)^2 + (y2 - yt)^2)

    min(d1, d2) == d2

    在坐标系中表示出来,就是这样:

    我们需要找到一个点User(xt, yt),落在图示中的位置,这就是答案。

    而题目中的向量是图片的灰度矩阵拉平后的值,有5184维。我们无法求解出这个目标区域的解析解,只需要找到一个符合的向量就可以了。

    我是通过在鹿的图片中替换一部分像素为马的像素来求解,脚本如下:

    from PIL import Image
    import numpy as np
    from PIL import Image
    import math
    import os
    import time
    import base64
    import random
    
    
    def euclideanDistance(instance1, instance2, length):
        distance = 0
        for x in range(length):
            distance += pow((instance1[x] - instance2[x]), 2)
        return math.sqrt(distance)
    
    
    def check(p1, p2):
        diff_pixel=0
        for x in range(len(p1)):
            diff_pixel += abs(p1[x] - p2[x])
        #print(diff_pixel)
        return diff_pixel
        
    
    
    p1 = Image.open('./horse.png').convert('L')
    p1 = np.array(p1).reshape(-1)
    print('horse', p1)
    
    p2 = Image.open('./deer.png').convert('L')
    p2 = np.array(p2).reshape(-1)
    print('deer', p2)
    
    test = np.array(p2).reshape(-1)
    
    for i in range(3000):
        test[i] = p1[i]
    
    eud1 = euclideanDistance(p1, test, 5184)
    print('Eu1: ', eud1)
    
    eud2 = euclideanDistance(p2, test, 5184)
    print('Eu2: ', eud2)
    
    dif = check(test, p2)
    print('Diff:', dif)
    
    if(eud1 < eud2):
        print('Eud Good')
    if dif < 100000:
        print('Diff Good')
    
    img = test.reshape(72, 72)
    #Image.save(img, 'test.png')
    img = np.uint8(img)
    im = Image.fromarray(img)
    im.save("out.png", 'png')
    
    
     
    with open("out.png", 'rb') as f:
        base64_data = base64.b64encode(f.read())
        s = base64_data.decode()
        print(s)
    View Code

    得到的图片BASE64值输入到服务器后,返回了另一段BASE64,转为PNG图片后,得到flag:

    由于本人水平有限,只做出来这两道题目,与道友们共同学习多多交流,如有纰漏欢迎指正。

  • 相关阅读:
    jQuery使用手册
    数据结构排序算法总结(转)
    VS2008升级激活码
    用VS2005建立解决方案
    backgroundposition 用法详细介绍
    CSS布局口诀,学ccs不再难
    Web.Config文件中SQLServerExpress数据库连接配置解释(转)
    css
    2011,我来了!
    Ajax验证用户名是否存在
  • 原文地址:https://www.cnblogs.com/pleiades/p/13802550.html
Copyright © 2011-2022 走看看