easyxor
核心加密算法convert就是四个shift,写个逆就行,flag被分为两部分,前半部分用OFB模式加密,后半部分用CBC模式加密,由于CBC模式的缺陷,当我们只考虑最后一块时,将倒数第二块作为iv,凭借flag的格式做判断即可爆破出key,再利用OFB模式的漏洞,结合key与已知的flag格式即可逆推出iv,此时iv和key尽知,直接解密即可
from Crypto.Util.number import bytes_to_long, long_to_bytes
from random import randint, getrandbits
def shift(m, k, c):
if k < 0:
return m ^ m >> (-k) & c
return m ^ m << k & c
def unshift(value, k, mask, bits=64):
if(k == 0):
return value ^ value & mask
tmp = value
if k < 0:
for _ in range(bits // (-k)):
tmp = value ^ tmp >> (-k) & mask
else:
for _ in range(bits // k):
tmp = value ^ tmp << k & mask
assert shift(tmp, k, mask) == value
return tmp
def convert(m, key):
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c]
for t in range(4):
m = shift(m, key[t], c_list[t])
return m
def unconvert(m, key):
tmp = m
c_list = [0x37386180af9ae39e, 0xaf754e29895ee11a, 0x85e1a429a2b7030c, 0x964c5a89f6d3ae8c]
for t in range(3,-1,-1):
m = unshift(m, key[t], c_list[t])
assert convert(m, key) == tmp
return m
def decrypt(c, k, iv, mode='CBC'):
cipher = []
for i in range(0,len(c),16):
cipher.append(int(c[i:i+16],16))
groups = []
if mode == 'CBC':
cipher = cipher[::-1]
last = cipher[0]
for eve in (cipher[1:] + [iv]):
cur_c = last
cur = unconvert(cur_c, k)
groups.append(cur ^ eve)
last = eve
groups = groups[::-1]
elif mode == 'OFB':
last = iv
for eve in cipher:
cur_c = convert(last, k)
groups.append(cur_c ^ eve)
last = cur_c
else:
print('Not supported now!')
m = b''
for i in groups:
m += long_to_bytes(i)
assert len(m) % 8 == 0
return m
flag = b'ByteCTF{'
padding = bytes_to_long(flag)
cipher = '89b8aca257ee2748f030e7f6599cbe0cbb5db25db6d3990d3b752eda9689e30fa2b03ee748e0da3c989da2bba657b912'
cipher1, cipher2 = cipher[:len(cipher) // 2], cipher[len(cipher) // 2:]
c_list = []
for i in range(0,len(cipher2),16):
c_list.append(int(cipher2[i:i+16],16))
def get_key():
for a in range(-32,33):
for b in range(-32,33):
for c in range(-32,33):
for d in range(-32,33):
try:
plain = decrypt(cipher2[-16:],[a,b,c,d],c_list[-2])
if(plain.endswith(b'$$$') and plain.strip(b'$').endswith(b'}')):
print(a,b,c,d,plain)
return [a,b,c,d]
except:
continue
key = get_key()
# key = [-12, 26, -3, -31]
# print(cipher1)
c_list = []
for i in range(0,len(cipher1),16):
c_list.append(int(cipher1[i:i+16],16))
E = (padding ^ c_list[0])
iv = unconvert(E, key)
# print(iv)
flag = b''
flag += (decrypt(cipher1, key, iv, mode='OFB'))
flag += (decrypt(cipher2, key, iv))
print(flag.strip(b'$'))
# ByteCTF{5831a241s-f30980q535af-2156547475u2t}
JustDecrypt
AES_CFB模式,只提供解密,并且使用了不安全的unpad函数,虽然iv不知道,但是iv并不会影响后续的解密,所以我们可以通过提交一个固定块来保证iv不变,但是由于有unpad的存在,我们需要知道我们解密后的结果,就需要一个至少大于256长度的尾来保证我们想要的东西不会被删掉,这里我们称为padding,所以我们先给服务器打两个过去,一来检测一下是否可用,二来调整一下服务器的iv值
接下来我们需要伪造目标字符串,根据每次的返回值算出该位密位应该是多少,逐位修改一下即可,最后计算一下padding最后一位的数值,将后面多余的部分利用unpad删掉即可
from Crypto.Util.number import bytes_to_long, long_to_bytes
from pwn import *
import hashlib
POST = '39.105.181.182'
HOST = 30001
r = remote(POST,HOST)
# context.log_level = 'debug'
table = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
def passpow():
rev = r.recvuntil("sha256(XXXX+")
suffix = r.recv(28).decode()
r.recvuntil(" == ")
res = r.recv(64).decode()
def f(x):
hashresult = hashlib.sha256((x+suffix).encode()).hexdigest()
if hashresult == res:
return 1
else:
return 0
prefix = util.iters.mbruteforce(f,table,4,'upto')
r.recvuntil("XXXX > ")
r.sendline(str(prefix))
def talk(msg):
r.recvuntil("hex > ")
r.sendline(msg)
r.recvuntil("hex: \n")
plain = r.recvline(False)
# print(plain)
plain = long_to_bytes(int(plain.decode(),16))
return plain
def xor(a,b):
assert len(a) == len(b)
return bytes([i ^ j for (i,j) in zip(a,b)])
aim = b"Hello, I'm a Bytedancer. Please give me the flag!"
passpow()
padding = b''
for i in range(256):
padding += hex(i)[2:].zfill(2).encode()
# print(padding)
# print(cipher)
plain = talk(padding*2)
# print(plain)
# plain = talk(padding)
# print(plain)
if len(plain) <= 32:
r.close()
exit()
# plain = talk(b'\x00'*32 + padding)[:32]
payload = bytearray(b'\x00' * 16 * 4)
plain = plain[256:256+32]
# print(plain)
for i in range(len(aim)):
payload[i] = aim[i] ^ plain[i]
# print(payload.hex().encode())
plain = talk(payload.hex().encode() + padding)
# print(plain)
padnum = len(payload.hex().encode()) + len(payload) - len(plain)
padnum //= 2
# print(padnum)
length = len(plain) - len(aim)
length = length // 16
length *= 16
padding = long_to_bytes(int((padding[length*2:]).decode(),16))
payload = payload + padding
plain = talk(payload.hex())
# print(plain)
length = len(payload) - len(plain)
payload[-1] = payload[-1] ^ length ^ (len(payload) - len(aim))
plain = talk(payload.hex())
print(plain)
r.recvlines(2)
flag = r.recvline(False).strip()
print(flag)
r.close()
# r.interactive()
abusedkey
阅读理解题,先从协议二构造 Q c = h c ⋅ Q s Q_c = h_c \cdot Q_s Qc=hc⋅Qs ,此时返回的两个点满足 Y s ⋅ h s = = Y c Y_s \cdot h_s == Y_c Ys⋅hs==Yc ,所以直接爆破 π s \pi_s πs 即可
再打协议一,令 T c = − P c T_c=-P_c Tc=−Pc ,此时 K c s = d s ⋅ T c K_cs = d_s \cdot T_c Kcs=ds⋅Tc ,直接解密即可
from Crypto.Util.number import long_to_bytes
from random import getrandbits, randint
from Crypto.Cipher import AES
from hashlib import sha256
from tqdm import tqdm
from curve import *
import requests
def talk(mode, msg):
host = 'http://39.105.181.182:30000'
if mode == 11:
url = host + '/abusedkey/server/msg11'
elif mode == 13:
url = host + '/abusedkey/server/msg13'
elif mode == 21:
url = host + '/abusedkey/server/msg21'
elif mode == 23:
url = host + '/abusedkey/ttp/msg23'
elif mode == 25:
url = host + '/abusedkey/server/msg25'
return requests.get(url,data=msg).text
def H(msg):
return int(sha256(msg).hexdigest(), 16)
pi_C = b'\xFF\xFF'
Curve = curve()
def get_hint():
r_c = randint(0,Curve.p)
R_c = Curve.G * r_c
h_c = H(pi_C)
Q_c = h_c * R_c
sid2 = getrandbits(256)
sid2 = hex(sid2)[2:].zfill(64)
msg21 = sid2
msg22 = talk(21,msg21)
Q_s = msg22
msg23 = str(Q_c) + Q_s
msg24 = (talk(23,msg23))
# print(msg24)
# print(len(msg24))
# print(len(msg23))
Y_c, Y_s = msg24[:128], msg24[128:]
# print(Y_c, Y_s)
Y_c, Y_s = Point(int(Y_c[:64],16), int(Y_c[64:],16)), Point(int(Y_s[:64],16), int(Y_s[64:],16))
msg25 = sid2 + str(Y_c)
msg26 = talk(25,msg25)
print(msg26)
msg26 = long_to_bytes(int(msg26,16))
# print(msg26)
iv, cipher, tag = msg26[:12], msg26[12:-16], msg26[-16:]
Z_cs = r_c * Y_s
sk2 = long_to_bytes(H(long_to_bytes(Z_cs.x)))
aes = AES.new(sk2, AES.MODE_GCM, iv)
hint = aes.decrypt_and_verify(cipher, tag)
print(hint)
return
def get_pis():
sid2 = getrandbits(256)
sid2 = hex(sid2)[2:].zfill(64)
msg21 = sid2
msg22 = talk(21,msg21)
Q_s = Point(int(msg22[:64],16), int(msg22[64:],16))
h_c = H(pi_C)
Q_c = h_c * Q_s
msg23 = str(Q_c) + str(Q_s)
msg24 = talk(23,msg23)
# print(msg24)
Y_c, Y_s = msg24[:128], msg24[128:]
Y_c, Y_s = Point(int(Y_c[:64],16), int(Y_c[64:],16)), Point(int(Y_s[:64],16), int(Y_s[64:],16))
# print(Y_c)
# print(Y_s)
for i in tqdm(range(0xffff + 1)):
h_s = H(b'\x00' * (2 - len(long_to_bytes(i))) + long_to_bytes(i))
if(Y_s * h_s == Y_c):
# print(i)
return long_to_bytes(i)
pi_s = get_pis()
# pi_s = long_to_bytes(36727)
h_s = H(pi_s)
# check pi_s
sid2 = getrandbits(256)
sid2 = hex(sid2)[2:].zfill(64)
msg21 = sid2
msg22 = talk(21,msg21)
Q_s = Point(int(msg22[:64],16), int(msg22[64:],16))
h_c = H(pi_C)
Q_c = h_c * Curve.G
Q_s = h_s * Curve.G
msg23 = str(Q_c) + str(Q_s)
msg24 = talk(23,msg23)
# print(msg24)
Y_c, Y_s = msg24[:128], msg24[128:]
Y_c, Y_s = Point(int(Y_c[:64],16), int(Y_c[64:],16)), Point(int(Y_s[:64],16), int(Y_s[64:],16))
assert(Y_c == Y_s)
# solve
d_s = H(pi_s)
P_cx = int('b5b1b07d251b299844d968be56284ef32dffd0baa6a0353baf10c90298dfd117', 16)
P_cy = int('ea62978d102a76c3d6747e283091ac5f2b4c3ba5fc7a906fe023ee3bc61b50fe', 16)
P_c = Point(P_cx, P_cy)
T_c = Point(P_cx, -P_cy % Curve.p)
sid1 = getrandbits(256)
sid1 = hex(sid1)[2:].zfill(64)
msg11 = sid1
msg12 = talk(11,msg11)
msg13 = sid1 + str(T_c)
msg14 = talk(13,msg13)
# print(msg14)
msg14 = long_to_bytes(int(msg14,16))
iv, cipher, tag = msg14[:12], msg14[12:-16], msg14[-16:]
K_cs = d_s * T_c
sk1 = long_to_bytes(H(long_to_bytes(K_cs.x)))
# print(sk1, iv, cipher, tag)
cip = AES.new(sk1, AES.MODE_GCM, iv)
plaintext = cip.decrypt_and_verify(cipher, tag)
print(plaintext)
Overheard
HNP问题
依次提交 g a , g a + 1 , g a + 2 . . . g^{a},g^{a+1},g^{a+2}... ga,ga+1,ga+2... 可得 g a b , g ( a + 1 ) b , g ( a + 2 ) b . . . g^{ab},g^{(a+1)b},g^{(a+2)b}... gab,g(a+1)b,g(a+2)b...
构造如下格子即可得出
from pwn import *
from random import*
p = 62606792596600834911820789765744078048692259104005438531455193685836606544743
g = 5
sh=remote("39.105.38.192","30000")
print(sh.recv().decode())
sh.sendline(b"1")
a=int(sh.recvuntil(b"\n",drop=True).decode())
print(sh.recv())
sh.sendline(b"2")
sh.recvuntil(b"$ ",drop=True)
b=int(sh.recvuntil(b"\n",drop=True).decode())
sh.sendline(b"3")
sh.sendline(str(a).encode())
sh.recvuntil(b"Bob: ")
r=(int(sh.recvuntil(b"\n").decode()))
sh.recvuntil(b"exit\n")
cnt=0
B=[]
A=[]
for i in range(1,15):
sh.sendline(b"3")
sh.sendline(str(a*pow(g,i,p)%p).encode())
sh.recvuntil(b"Bob: ")
B.append(int(sh.recvuntil(b"\n").decode()))
A.append(pow(b,i,p))
sh.recvuntil(b"exit\n")
M=[]
s=16
k=1
for i in range(s):
l=[0]*s
l[i]=p*k
if(i==s-2):
for j in range(s-2):
l[j]=A[j]*k
if(i==s-1):
for j in range(s-2):
l[j]=B[j]*k
M.append(l)
M[-2][-2]=1
M[-1][-1]=2**60
m=M.copy()
m[-2][-2]=1/2^189
m=matrix(QQ,m)
print(m.LLL()[0][-1]//m[-1][-1]==1)
print(m.LLL()[0][-2]*2^189)
print(r)
sh.sendline(b'4')
sh.sendline(str(abs(m.LLL()[0][-2]*2^189)%p).encode())
print(sh.recvall())