2020网鼎杯青龙组

badmonkey 2020年05月10日 938次浏览

2020网鼎杯青龙组

you_raise_me_up

离散对数问题,直接用sage求解,脚本如下:

m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
n = 2**512
m = Mod(m,n)
c = Mod(c,n)
flag=discrete_log(c,m)
# flag = 56006392793405651552924479293096841126763872290794186417054288110043102953612574215902230811593957757
print(long_to_bytes(flag))
# flag{5f95ca93-1594-762d-ed0b-a9139692cb4a}

Boom

非常简单得初中计算题,算出方程得解,再加上原始字符串,得到flag

#en5oy,x=74,y=68,z=31,x=89127561
#flag{en5oy_746831_89127561}

easy_ya

通过common prime attack 可以还原key。encode流程非常类似md5得流程不过简化了很多,可以注意到最后一步

hex((y << 52) ^ (pads << 20) ^ z)

其实泄露了很多信息,比如完整的y,25bits的z,20bits的pads,而且pads的低7bits和z的高7bits,异或结果已知。于是可以爆破pads的高位和低位。得到最后一轮的y,z。再看一下每一轮的操作

y = limit( y + ((z*16 + a) ^ (z + pads) ^ ((z>>5) + b)))
z = limit( z + ((y*16 + c) ^ (y + pads) ^ ((y>>5) + d)))

我们可以发现计算完y之后再计算z,而我们已经得到了最后一轮的y完整信息,于是可以逆向上一轮的z,通过上一轮的z逆向上一轮的y,最后循环32轮的初始的y,z信息。每一轮的逆向如下

def recoverRound(Z,Y,a,b,c,d,pads):
    Z = limit(Z-((Y * 16 + c) ^ (Y + pads) ^ ((Y >> 5) + d)))
    Y = limit(Y-((Z * 16 + a) ^ (Z + pads) ^ ((Z >> 5) + b)))
    return Y,Z

通过交互脚本,收集flag的hash信息

'''
@Author: badmonkey
@Date: 2020-05-10 10:16:21
@LastEditTime: 2020-05-10 15:42:28
@LastEditors: Please set LastEditors
@Description: In User Settings Edit
@FilePath: /easy_ya.py
'''
import os
# os.environ['TERM'] = 'screen'
from random import randint
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from pwn import *
from tqdm import tqdm
from hashlib import sha384,sha256,sha1,sha224,sha512,md5
from string import printable
from itertools import product
# 32bits
limit = lambda n: n & 0xffffffff
padding="\xe6\xe6\xe7\xe6\xe5\xe6\xe5\xe9\xe5"
ek='\xe6\x84\xbf'


def encode(key,data):
    pad  = randint(0x10000000,0xffffffff)
    Key  = [ord(i) for i in key]
    Data = [ord(i) for i in data]
    a = limit((Key[0] << 24) | (Key[1] << 16) | (Key[2] << 8) | Key[3])
    b = limit((Key[4] << 24) | (Key[5] << 16) | (Key[6] << 8) | Key[7])
    c = limit((Key[8] << 24) | (Key[9] << 16) | (Key[10] << 8) | Key[11])
    d = limit((Key[12] << 24) | (Key[13] << 16) | (Key[14] << 8) | Key[15])
    y = limit((Data[0] << 24) | (Data[1] << 16) | (Data[2] << 8) | Data[3])
    z = limit((Data[4] << 24) | (Data[5] << 16) | (Data[6] << 8) | Data[7])
    pads = 0
    for j in range(32):
        pads = limit(pads + pad)
        y = limit( y + ((z*16 + a) ^ (z + pads) ^ ((z>>5) + b)))
        z = limit( z + ((y*16 + c) ^ (y + pads) ^ ((y>>5) + d)))
    print (hex((y << 52) ^ (pads << 20) ^ z))


add = "39.96.90.217"
port = 17497
context.log_level = 'debug'




def collect():
    code = []
    for i in range(100):
        sh = remote("39.96.90.217","17497")
        sh.recvuntil("x[:20] = ")
        sh.recv(len('f91a551dfa31e47458df'))
        sh.recvuntil('openssl_')
        method = sh.recvuntil('\n')
        if method not in code:
            code.append(method)
        sh.close()
    return code






def brute(method,target):
    for i in product(printable,repeat=4):
        t = ''.join(i)
        if method == 'md5':
            res = md5(t.encode()).hexdigest()
            if res[:20] == target:
                return t
        elif method == 'sha384':
            res = sha384(t.encode()).hexdigest()
            if res[:20] == target:
                return t
        elif method == 'sha256':
            res = sha256(t.encode()).hexdigest()
            if res[:20] == target:
                return t
        elif method == 'sha512':
            res = sha512(t.encode()).hexdigest()
            if res[:20] == target:
                return t
        elif method == 'sha224':
            res = sha224(t.encode()).hexdigest()
            if res[:20] == target:
                return t
        elif method == 'sha1':
            res = sha1(t.encode()).hexdigest()
            if res[:20] == target:
                return t
                
def byte2str(byte):
    res = ''
    for i in byte:
        res += chr(i)
    return res


def login(sh):
    token = 'icq72ad23582b5b753974d6c586010e7'
    sh.recvuntil("x[:20] = ")
    hs = byte2str(sh.recv(20))
    print("hs is {}".format(hs))
    sh.recvuntil('openssl_')
    method = sh.recvuntil('\n')
    # print(method)
    method = byte2str(method[:-2])
    print("method is {}\n".format(method))
    payload = brute(method,hs)
    print("payload is {}\n".format(payload))
    # sh.recvline()
    sh.sendline(payload)
    sh.recvuntil('Please input your token:')
    sh.sendline(token)
    sh.interactive()


sh = remote(add,port)
login(sh)

最后通过得到的flag的hash信息,逆向得到flag,脚本如下:

from itertools import product
limit = lambda n: n & 0xffffffff
def toMessage(Y,Z):
    mess = [0]*8
    binZ = bin(Z)[2:].zfill(32)
    binY = bin(Y)[2:].zfill(32)

    mess[0] = int(binY[0:8],2)
    mess[1] = int(binY[8:16],2)
    mess[2] = int(binY[16:24],2)
    mess[3] = int(binY[24:32],2)
    mess[4] = int(binZ[0:8],2)
    mess[5] = int(binZ[8:16],2)
    mess[6] = int(binZ[16:24],2)
    mess[7] = int(binZ[24:32],2)
    # print(mess)
    res = ''
    for i in mess:
        res += chr(i)
    return res

def recoverRound(Z,Y,a,b,c,d,pads):
    Z = limit(Z-((Y * 16 + c) ^ (Y + pads) ^ ((Y >> 5) + d)))
    Y = limit(Y-((Z * 16 + a) ^ (Z + pads) ^ ((Z >> 5) + b)))
    return Y,Z

def recover(res):
    a = 2291239296
    b = 2293340064
    c = 3215425945
    d = 2994836927
    all = 'flag{}0123456789abcdef\x00'
    binRes = bin(res)[2:]
    y = int(binRes[:32],2)
    # z = binRes[-25:]
    # pad = binRes[32:32+20]
    cnt = 0
    for pre in product(['0','1'],repeat=5):
        for suf in product(['0','1'],repeat=7):
            i = ''.join(pre)
            j = ''.join(suf)
            pad = int(i+binRes[32:32+20]+j,2)
            preZ = bin(int(j,2)^int(binRes[-32:-25],2))[2:].zfill(7)
            z = int(preZ+binRes[-25:],2)
            Y, Z = y, z
            for k in range(31,-1,-1):
                pads = limit((k+1)*pad)
                Y,Z = recoverRound(Z,Y,a,b,c,d,pads)
            message = toMessage(Y,Z)
            if pad == 2889388799:
                print (Y,Z)
            tag = True
            for k in message:
                if k not in all:
                    tag = False
            if tag:
                return(message)


enc = [0x9ae29517aa3fa43221411L,0xb92b75e9434453bb6894cL,0xb87560cf60c07cdce0651L,0xf62b41fcaadc3284a938dL,0xb03195a6d867ce8f01dfaL]
flag  = ''
cnt = 0
for i in enc:
     flag += recover(i)
print flag
# flag = "flag{8591558350855d725d7d237b29c46ff7}"

闲谈

太难了,没打进了线下最后166名。。。

result