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名。。。