2021天翼杯 密码官方wp

2021天翼杯

crypto

TryHash

审计题目代码,题目给出了一个feistel结构的加密算法,密钥长度为8字节。用随机生成的密钥对flag进行了加密。攻击者可以提供一段明文让服务器用同样的密钥进行加密。

密钥长度为8字节,直接爆破的复杂度为2^64,是不太现实的。

本题密码算法的设计漏洞其实在于其轮函数f的设计。具体来说其轮函数具有较差的差分性质。


def g(self,v1,v2,x):  
    value = (v1+v2+x)%256  
    value = ((value<<3) | (value>>5)) &0xff  
    return value  
  
def f(self,value):  
    v1,v2 = unpack('>2B',pack('>H',value))  
    v2 = self.g(v1,v2,1)  
    v1 = self.g(v1,v2,0)  
    value = unpack('>H',pack('>2B',v1,v2))  
    return value[0]  

具体来说,通过数学推导,我们可以发现,对于f来说,当其两个输入的差分为0x8080时,其输出差分100%是0x400。根据这一差分性质,我们可以对该加密算法进行差分分析攻击。差分分析的具体原理可以参考这个blog http://www.theamazingking.com/crypto-feal.php

我们以对最后一轮加密(即第3轮)进行攻击为例,介绍攻击的流程。

我们构造两个特殊的输入 (L0,R0)和 (L0’,R0’)其中 L0 = L0‘, R0 = R0’^0x8080,让服务器加密,得到加密结果 (L3,R3),(L3’,R3’).通过对该加密算法的推导,我们可以得到关于第3轮轮函数f的运算关系。


f(round3_key^L0)  = out1   
   f(round3_key^L0') = out2  
   out1^out2 = R0^L0^R0'^L0'^0x400  

其中,只有round3_key是未知的,其他参数都是已知的。round3_key的大小为2个字节,完全可以通过爆破来得到正确的解。这样我们就把对于整个key的求解,拆分到对于轮密钥的求解,爆破复杂度从 2^64降低到了 2^16

需要注意的是对于一组明密文对,可能有多个符合关系的解,我们可以同时对多组明密文对进行求解,来过滤掉错误的解。

依次类推,可以用相似的方法得到第1,2,3轮的轮密钥。有了这三轮的轮密钥后,可以通过逆运算很块的求解出第0轮的密钥,最终恢复出整个密钥。

完整解题脚本


from hashlib import sha256  
import random  
from pwn import *  
from pwnlib.util.iters import bruteforce  
from struct import pack, unpack  
  
def g(v1,v2,x):  
    value = (v1+v2+x)%256  
    value = ((value<<3) | (value>>5)) &0xff  
    return value  
  
def f(value):  
    v1,v2 = unpack('>2B',pack('>H',value))  
    v2 = g(v1,v2,1)  
    v1 = g(v1,v2,0)  
    value = unpack('>H',pack('>2B',v1,v2))  
    return value[0]  
  
def decrypt_ecb(cipher,key):  
    msg = ''  
    for i in range(0,len(cipher),4):  
        msg += decrypt(cipher[i:i+4],key)  
    return msg.strip('\x00')   
  
def decrypt(msg,key):  
    subkeys = unpack('>4H',key)  
    left,right = unpack('>2H',msg)  
    left = right^left  
    for i in range(3):  
        left,right = right,left  
        left = left^f(subkeys[2-i]^right)  
    right = right^subkeys[3]  
    return pack('>2H', left, right)  
  
def encrypt_ecb(msg,key):  
    l = len(msg)  
    if l%4 !=0:  
        msg = msg+'\x00'*(4-(l%4))  
    cipher = ''  
    for i in range(0,len(msg),4):  
        cipher += encrypt(msg[i:i+4],key)  
    return cipher  
  
def encrypt(msg,key):  
    subkeys = unpack('>4H',key)  
    left,right = unpack('>2H',msg)  
    right = right^subkeys[3]  
    for i in range(3):  
        tmp = left^f(subkeys[i]^right)   
        left = right  
        right = tmp  
    left = right^left  
    return pack('>2H', left, right)  
  
def dfa_f():  
    for i in range(1000):  
        input1 = random.randint(0,0xffff)  
        output1 = f(input1)  
        input2 = input1^0x8080  
        output2 = f(input2)  
  
        assert(output1^output2 == 0x400)  
  
def genpayload1(num):  
    payload = ''  
    for i in range(num):  
        data1 = random.randint(0,0xffff)  
        data2 = random.randint(0,0xffff)  
        data2diff = data2^0x8080  
        payload += pack('>2H',data1,data2)   
        payload += pack('>2H',data1,data2diff)   
    return payload  
    
def genpayload2(num):  
    payload = ''  
    for i in range(num):  
        data1 = random.randint(0,0xffff)  
        data2 = random.randint(0,0xffff)  
        data2diff = data2^0x400  
        payload += pack('>2H',data1,data2)   
        payload += pack('>2H',data1,data2diff)   
    return payload  
  
def testkey_round3(pairs,key):  
    for pair in pairs:  
        output1 = pair[0]  
        output2 = pair[1]  
        output1_0,output1_1 = unpack('>2H',output1)  
        output2_0,output2_1 = unpack('>2H',output2)  
        f_out_diff = output1_1 ^ output2_1 ^0x400  
        f_in1 = key^output1_0^output1_1  
        f_in2  = key^output2_0^output2_1  
        if(f(f_in1)^f(f_in2)==f_out_diff):  
            continue  
        else:  
            return False  
    return True  
  
def testkey_round2(pairs,key,r3key):  
    for pair in pairs:  
        output1 = pair[0]  
        output2 = pair[1]  
        output1_0,output1_1 = unpack('>2H',output1)  
        output2_0,output2_1 = unpack('>2H',output2)  
        output1_r3_1 = output1_0^output1_1   
        output2_r3_1 = output2_0^output2_1  
        f_out_diff  = output1_r3_1^output2_r3_1^0x400  
        f_in1 = key^output1_1^f(r3key^output1_r3_1)    
        f_in2  = key^output2_1^ f(r3key^output2_r3_1)  
        if(f(f_in1)^f(f_in2)==f_out_diff):  
            continue  
        else:  
            return False  
    return True  
  
def attack_round1(msg,cipher,keys):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    msgs = [msg[i:i+4] for i in range(0,len(msg),4)]  
    c = ciphers[0]  
    m = msgs[0]  
    output0,output1 = unpack('>2H',c)  
    output0 = output0^output1  
    input0,input1 = unpack('>2H',m)  
    candkeys = []  
    for key in keys:  
        r2k,r3k = key  
        output_r2_1 = output0  
        output_r2_0 = output1^f(r3k^output0)  
        output_r1_1 = output_r2_0   
        output_r1_0 = output_r2_1^f(r2k^output_r2_0)  
        k0 = output_r1_0^input1  
        for k in range(0x10000):  
            f_in = k^output_r1_0  
            f_out = output_r1_1^input0   
            if f(f_in) == f_out:  
                candkeys.append([k,r2k,r3k,k0])  
    return candkeys  
  
def attack_round2(msg,cipher,keys):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)]  
    candkeys = []  
    for r3k in keys:  
        for key in range(0x10000):  
            if testkey_round2(cipher_pairs,key,r3k):  
                candkeys.append([key,r3k])  
    return candkeys  
  
def attack_round3(msg,cipher):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)]  
    candkeys = []  
    for key in range(0x10000):  
        if testkey_round3(cipher_pairs,key):  
            candkeys.append(key)  
    return candkeys      
  
def exploit():  
    con = remote('127.0.0.1',10005)  
  
    context.log_level = 'debug'  
    con.recvuntil("XXXX+")  
    d = con.recvuntil(")")[:-1]  
    con.recvuntil(" == ")  
    target = con.recvline().strip()  
    ans = bruteforce(lambda x: sha256(x+d).hexdigest() == target,string.letters+string.digits,4)  
    con.sendlineafter("Give me XXXX",ans)  
    con.recvuntil('is:')  
    flag = con.recvline().strip()  
    payload = genpayload1(6)+genpayload2(6)  
    con.sendlineafter(':',payload)  
    cipher = con.recv(len(payload))  
    cipher_round3 = cipher[:48]  
    msg_round3 = payload[:48]  
    possible_keys = attack_round3(msg_round3,cipher_round3)  
    print 'round3 keys maybe:', possible_keys  
    cipher_round2 = cipher[48:96]  
    msg_round2 = payload[48:96]  
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys)  
    print 'round2 keys maybe:', possible_keys  
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys)  
    print 'round1&0 keys maybe:',possible_keys  
    for key in possible_keys:  
        real_key = pack('>4H',*key)  
        print 'decrypt with key ',repr(real_key)  
        print repr(decrypt_ecb(flag,real_key))  
    con.close()  
  
def exploit_local():  
    key = os.urandom(8)  
    print repr(key)  
    payload = genpayload1(6)+genpayload2(6)  
    cipher = encrypt_ecb(payload,key)  
    cipher_round3 = cipher[:48]  
    msg_round3 = payload[:48]  
    possible_keys = attack_round3(msg_round3,cipher_round3)  
    print 'round3 keys maybe:', possible_keys  
    cipher_round2 = cipher[48:96]  
    msg_round2 = payload[48:96]  
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys)  
    print 'round2 keys maybe:', possible_keys  
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys)  
    print 'round1&0 keys maybe:',possible_keys  
    flag = 'flag{test}'  
    flag = encrypt_ecb(flag,key)  
    print decrypt_ecb(flag,key)  
    for key in possible_keys:  
        real_key = pack('>4H',*key)  
        print 'decrypt with key ',repr(real_key)  
        print repr(decrypt_ecb(flag,real_key))  
  
exploit()  

在这里插入图片描述

babypack

由于题目中方案设计的缺陷,导致在公钥中

$$

2*A[i+1]-A[i]\approx n

$$

这其中插值于pq的乘积在高位比特上大多数是相等的,因此需要通过check功能拿到部分的低位比特。但仍然无法拿到完整的n,且就算拿到完整的n也无法通过分解来解出p,q。

这是注意发现,公钥A是通过UV和中国剩余定理来生成的,因此可以通过解二元一次方程得到uv值。再用公钥与uv的差值与n的最大公因数来确定n和得到p,q。

具体详见exp


from netcat import *  
from copy import deepcopy  
from gmpy2 import iroot, gcd  
import time  
  
start = time.time()  
r = remote("47.100.138.126", 10002)  
r.recv_until(b"your pubkey:\n")  
s = r.recv_until(b"\n").strip().decode()  
pub = eval(s)  
add = int(r.recv_until(b"\n").strip().decode())  
mult = int(r.recv_until(b"\n").strip().decode())  
#print(add)  
#print(mult)  
M = max(2 * pub[2] - pub[1], 2 * pub[3] - pub[2])  
Mbin = bin(M)[2:532]  
n = ["0"] * M.bit_length()  
for i in range(530):  
    n[i] = Mbin[i]  
  
r.recv_until(b">")  
r.sendline(b"1")  
r.recv_until(b">")  
tmp = int("".join(n), 2)  
r.sendline(str(tmp).encode())  
count = int(r.recv_until(b"\n").strip())  
#print(count)  
  
for i in range(498):  
    r.recv_until(b">")  
    r.sendline(b"1")  
    r.recv_until(b">")  
    n2 = deepcopy(n)  
    n2[530 + i] = str(int(n2[530 + i]) ^ 1)  
    tmp = int("".join(n2), 2)  
    r.sendline(str(tmp).encode())  
    count2 = int(r.recv_until(b"\n").strip())  
    if count2 > count:  
        n[530 + i] = str(int(n[530 + i]) ^ 1)  
        count = count2  
    #print(count)  
  
M = int("".join(n), 2)  
u = (add + iroot(add**2-4*mult, 2)[0]) // 2  
v = (add - iroot(add**2-4*mult, 2)[0]) // 2  
count = 0  
while True:  
    tmp1 = gcd(pub[0] - u, M)  
    tmp2 = gcd(pub[0] - v, M)  
    if tmp1.bit_length() > 100 or tmp2.bit_length() > 100:  
        p = max(tmp1, tmp2)  
        break  
    else:  
        M += 1  
        count += 1  
    #print(count)  
  
q = M // p  
if p < q:  
    p, q = q, p  
  
r.recv_until(b">")  
r.sendline(b"2")  
r.recv_until(b"\n")  
s = r.recv_until(b"\n").strip().decode()  
ct = int(s)  
c1 = ct % p  
c2 = ct % q  
pt = abs(c1 - c2)  
r.recv_until(b">")  
r.sendline(str(pt).encode())  
#print(pt)  
print(r.recv(1024))  
r.close()  
end = time.time()  
#print(end - start)  

在这里插入图片描述

Crypto_mycipher


from hashlib import sha256  
import random  
from pwn import *  
from pwnlib.util.iters import bruteforce  
from struct import pack, unpack  
  
def g(v1,v2,x):  
    value = (v1+v2+x)%256  
    value = ((value<<3) | (value>>5)) &0xff  
    return value  
  
def f(value):  
    v1,v2 = unpack('>2B',pack('>H',value))  
    v2 = g(v1,v2,1)  
    v1 = g(v1,v2,0)  
    value = unpack('>H',pack('>2B',v1,v2))  
    return value[0]  
  
def decrypt_ecb(cipher,key):  
    msg = ''  
    for i in range(0,len(cipher),4):  
        msg += decrypt(cipher[i:i+4],key)  
    return msg.strip('\x00')    
  
def decrypt(msg,key):  
    subkeys = unpack('>4H',key)  
    left,right = unpack('>2H',msg)  
    left = right^left  
    for i in range(3):  
        left,right = right,left  
        left = left^f(subkeys[2-i]^right)  
    right = right^subkeys[3]  
    return pack('>2H', left, right)  
  
def encrypt_ecb(msg,key):  
    l = len(msg)  
    if l%4 !=0:  
        msg = msg+'\x00'*(4-(l%4))  
    cipher = ''  
    for i in range(0,len(msg),4):  
        cipher += encrypt(msg[i:i+4],key)  
    return cipher  
  
def encrypt(msg,key):  
    subkeys = unpack('>4H',key)  
    left,right = unpack('>2H',msg)  
    right = right^subkeys[3]  
    for i in range(3):  
        tmp = left^f(subkeys[i]^right)   
        left = right  
        right = tmp  
    left = right^left  
    return pack('>2H', left, right)  
  
def dfa_f():  
    for i in range(1000):  
        input1 = random.randint(0,0xffff)  
        output1 = f(input1)  
        input2 = input1^0x8080  
        output2 = f(input2)  
  
        assert(output1^output2 == 0x400)  
  
def genpayload1(num):  
    payload = ''  
    for i in range(num):  
        data1 = random.randint(0,0xffff)  
        data2 = random.randint(0,0xffff)  
        data2diff = data2^0x8080  
        payload += pack('>2H',data1,data2)   
        payload += pack('>2H',data1,data2diff)   
    return payload  
    
def genpayload2(num):  
    payload = ''  
    for i in range(num):  
        data1 = random.randint(0,0xffff)  
        data2 = random.randint(0,0xffff)  
        data2diff = data2^0x400  
        payload += pack('>2H',data1,data2)   
        payload += pack('>2H',data1,data2diff)   
    return payload   
  
def testkey_round3(pairs,key):  
    for pair in pairs:  
        output1 = pair[0]  
        output2 = pair[1]  
        output1_0,output1_1 = unpack('>2H',output1)  
        output2_0,output2_1 = unpack('>2H',output2)  
        f_out_diff = output1_1 ^ output2_1 ^0x400  
        f_in1 = key^output1_0^output1_1  
        f_in2  = key^output2_0^output2_1  
        if(f(f_in1)^f(f_in2)==f_out_diff):  
            continue  
        else:  
            return False  
    return True  
  
def testkey_round2(pairs,key,r3key):  
    for pair in pairs:  
        output1 = pair[0]  
        output2 = pair[1]  
        output1_0,output1_1 = unpack('>2H',output1)  
        output2_0,output2_1 = unpack('>2H',output2)  
        output1_r3_1 = output1_0^output1_1   
        output2_r3_1 = output2_0^output2_1  
        f_out_diff  = output1_r3_1^output2_r3_1^0x400  
        f_in1 = key^output1_1^f(r3key^output1_r3_1)    
        f_in2  = key^output2_1^ f(r3key^output2_r3_1)  
        if(f(f_in1)^f(f_in2)==f_out_diff):  
            continue  
        else:  
            return False  
    return True  
  
def attack_round1(msg,cipher,keys):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    msgs = [msg[i:i+4] for i in range(0,len(msg),4)]  
    c = ciphers[0]  
    m = msgs[0]  
    output0,output1 = unpack('>2H',c)  
    output0 = output0^output1  
    input0,input1 = unpack('>2H',m)  
    candkeys = []  
    for key in keys:  
        r2k,r3k = key  
        output_r2_1 = output0  
        output_r2_0 = output1^f(r3k^output0)  
        output_r1_1 = output_r2_0   
        output_r1_0 = output_r2_1^f(r2k^output_r2_0)  
        k0 = output_r1_0^input1  
        for k in range(0x10000):  
            f_in = k^output_r1_0  
            f_out = output_r1_1^input0   
            if f(f_in) == f_out:  
                candkeys.append([k,r2k,r3k,k0])  
    return candkeys  
 
def attack_round2(msg,cipher,keys):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)]  
    candkeys = []  
    for r3k in keys:  
        for key in range(0x10000):  
            if testkey_round2(cipher_pairs,key,r3k):  
                candkeys.append([key,r3k])  
    return candkeys  
  
def attack_round3(msg,cipher):  
    ciphers = [cipher[i:i+4] for i in range(0,len(cipher),4)]  
    cipher_pairs = [(ciphers[i],ciphers[i+1]) for i in range(0,len(ciphers),2)]  
    candkeys = []  
    for key in range(0x10000):  
        if testkey_round3(cipher_pairs,key):  
            candkeys.append(key)  
    return candkeys      
  
def exploit():  
    con = remote('127.0.0.1',10005)  
  
    context.log_level = 'debug'  
    con.recvuntil("XXXX+")  
    d = con.recvuntil(")")[:-1]  
    con.recvuntil(" == ")  
    target = con.recvline().strip()  
    ans = bruteforce(lambda x: sha256(x+d).hexdigest() == target,string.letters+string.digits,4)  
    con.sendlineafter("Give me XXXX",ans)  
    con.recvuntil('is:')  
    flag = con.recvline().strip()  
    payload = genpayload1(6)+genpayload2(6)  
    con.sendlineafter(':',payload)  
    cipher = con.recv(len(payload))  
    cipher_round3 = cipher[:48]  
    msg_round3 = payload[:48]  
    possible_keys = attack_round3(msg_round3,cipher_round3)  
    print 'round3 keys maybe:', possible_keys  
    cipher_round2 = cipher[48:96]  
    msg_round2 = payload[48:96]  
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys)  
    print 'round2 keys maybe:', possible_keys  
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys)  
    print 'round1&0 keys maybe:',possible_keys  
    for key in possible_keys:  
        real_key = pack('>4H',*key)  
        print 'decrypt with key ',repr(real_key)  
        print repr(decrypt_ecb(flag,real_key))  
    con.close()  
  
def exploit_local():  
    key = os.urandom(8)  
    print repr(key)  
    payload = genpayload1(6)+genpayload2(6)  
    cipher = encrypt_ecb(payload,key)  
    cipher_round3 = cipher[:48]  
    msg_round3 = payload[:48]  
    possible_keys = attack_round3(msg_round3,cipher_round3)  
    print 'round3 keys maybe:', possible_keys  
    cipher_round2 = cipher[48:96]  
    msg_round2 = payload[48:96]  
    possible_keys = attack_round2(msg_round2,cipher_round2,possible_keys)  
    print 'round2 keys maybe:', possible_keys  
    possible_keys = attack_round1(msg_round2,cipher_round2,possible_keys)  
    print 'round1&0 keys maybe:',possible_keys  
    flag = 'flag{test}'  
    flag = encrypt_ecb(flag,key)  
    print decrypt_ecb(flag,key)  
    for key in possible_keys:  
        real_key = pack('>4H',*key)  
        print 'decrypt with key ',repr(real_key)  
        print repr(decrypt_ecb(flag,real_key))  
  
exploit()    

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2021陇剑线下赛wp指的是该比赛的胜利方案(Winning Proposal)。这个问题的答案取决于具体的比赛和题目,因此我无法提供具体的场景和情况。不过,我可以向你介绍一些常见的比赛wp示例,帮助你理解wp的含义。 通常,比赛wp是指参赛者提出的在比赛中胜出的最佳方案。这种方案可能涉及各种因素,包括创新性、技术实施、解决问题的方法和效率等。具体来说,一个好的wp可能包括以下几个要素: 1. 题目分析:清晰理解比赛的题目和要求,明确问题的关键点和目标。 2. 解决方案:提出独特、创新和可行的解决方案,展示自己的技术和专业知识。 3. 实施计划:描述实施该方案的详细步骤和时间表,包括资源的分配和团队协作。 4. 风险分析:识别潜在的风险和挑战,并提供解决方法和备选方案。 5. 评估指标:明确关键的评估指标和成功的标准,展示方案的效果和可衡量的结果。 在许多比赛中,评委会或专家小组会对参赛者提交的wp进行评审,选出最佳的方案。一个优秀的wp将会体现出创新性、可行性和适应性。并且,一个优秀的方案通常能够提供有说服力的理由来解释为什么这个方案是最好的,以及为什么它比其他方案更优秀。 总的来说,2021陇剑线下赛wp是指在比赛中成功的方案,这个方案提供了创新、可行和有效的解决问题的方法,并且能够清晰地展示其技术和团队的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值