中午才起床,舍友喊我起床恰烂钱。ak了密码。逆向只做了了一题。没时间了。不到五小时做了500分我个人感jio还行吧。

crypto

rsa

('c=', '0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9eL')
('e=', '0x872a335')
#q + q*p^3 =1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
#qp + q *p^2 = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594

入门难度,通过给出表达式轻松求出p和q

from Crypto.Util.number import *
from gmpy2 import *

a = 1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
b = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
e = 0x872a335
c = 0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9e


gcd_ = gcd(a, b)        # q*(1+p)

p = b // gcd_
q = b // (p*(p+1))

n = p * q
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(long2str(m))

Yusa_cbc

from Crypto.Cipher import AES
import os
flag='flag{********************************}'
BLOCKSIZE = 16
 
 
 
def pad(data):
        pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if  len(data) % BLOCKSIZE != 0 else 0
        return data + "=" * pad_len
 
def unpad(data):
        return data.replace("=","")
 
 
def enc(data,key,iv):
    cipher = AES.new(key,AES.MODE_CBC,iv)
    encrypt = cipher.encrypt(pad(data))
    return encrypt
 
 
def dec(data,key,iv):
    try:
        cipher = AES.new(key,AES.MODE_CBC,iv)
        encrypt = cipher.decrypt(data)
        return unpad(encrypt)
    except:
        exit()
 
 
def task():
        try:
                key = os.urandom(16)
                iv = os.urandom(16)
                pre = "yusa"*4
                for _ in range(3):
                        choice = raw_input(menu)
                        if choice == '1':
                                name = raw_input("What's your name?")
                                if name == 'admin':
                                        exit()
                                token = enc(pre+name,key,iv)
                                print "Here is your token(in hex): "+iv.encode('hex')+token.encode('hex')
                                continue
                        elif choice == '2':
                                token = raw_input("Your token(in hex): ").decode('hex')
                                iv = token[:16]
                                name = dec(token[16:],key,iv)
                                print iv.encode('hex')+name.encode('hex')
                                if name[:16] == "yusa"*4:
                                        print "Hello, "+name[16:]
                                        if name[16:] == 'admin':
                                                print flag
                                                exit()
                        else:
                                continue
        except:
                exit()
menu='''
1. register
2. login
3. exit
'''
if __name__ == "__main__":
        task()

cbc bit flipping攻击

两个密文块,通过改第一个密文块,可以使得第二个密文块解密出admin.

但是这会使得第一个密文块解密出乱码。而题目也需要第一个密文块的值为yusayusayusayusa.

好在题目给出了三次交互的机会,第一次用于登陆,第二次用于改第一个密文块,从而使第二个密文块解密出admin。

第三次交互,需要从第二次交互的输出中提取第一个密文块的明文,与yusayusayusayusa异或后,再与iv进行异或,作为新的iv。这样aes cbc解密出乱码也没关系,因为会被iv抵消掉乱码。

from binascii import *
import struct

def bstr_xor(s1, s2):
    l = min(len(s1), len(s2))
    res = b''
    for i in range(l):
        tmp = s1[i] ^ s2[i]
        res += struct.pack('B', tmp)
    return res


token = unhexlify('9b41cb6addcea48f7f2b682afd6b5e75a2c94d578c9a7050fd5c51883d6a238e0df403bcb027bab1c36accccac29cd0e')
iv, enc1, enc2 = token[:16], token[16:32], token[32:]

n_enc1 = bstr_xor(enc1, bstr_xor(b'iyzyi', b'admin')) + enc1[5:]
print(enc1)
print(n_enc1)

result = iv + n_enc1 + enc2
print(result)
print('第一次登陆:', hexlify(result))
print('\n\n\n\n')


token2 = unhexlify('9b41cb6addcea48f7f2b682afd6b5e759b55c130fc13ab03f31c142883099e3161646d696e')
enc1_2 = token2[16:32]
print(enc1_2)
n_iv = bstr_xor(iv, bstr_xor(enc1_2, b'yusayusayusayusa'))
print(n_iv)
result2 = n_iv + n_enc1 + enc2
print('第二次登陆:', hexlify(result2))

Snipaste_2020-12-06_13-28-02

Yusa_ecb

from Crypto.Cipher import AES
import os
BLOCKSIZE = 16
flag='flag{********************************}'


def pad(data):
        pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if  len(data) % BLOCKSIZE != 0 else 0
        return data + chr(pad_len) * pad_len

def unpad(data):
        num = ord(data[-1])
        return data[:-num]


def enc(data,key):
    cipher = AES.new(key,AES.MODE_ECB)
    encrypt = cipher.encrypt(pad(data))
    return encrypt


def dec(data,key):
    try:
        cipher = AES.new(key,AES.MODE_ECB)
        encrypt = cipher.decrypt(data)
        return unpad(encrypt)
    except:
        exit()


def task():
        try:
                key = os.urandom(16)
                while True:
                        plaintext = raw_input("Amazing function: ").decode('hex')
                        yusa = plaintext+flag
                        print enc(yusa,key).encode('hex')
        except Exception as e:
                print str(e)
                exit()
if __name__ == "__main__":
        task()

byte at a time 攻击。

首先通过更改plaintext的长度,测出flag长度是38(plaintext长为10的时候,密文长度48,长为11的时候,密文长度64)

参考了这篇文章:ECB Byte at Time - scriptkid - 博客园 (cnblogs.com)

每次爆破一个字符即可。

from pwn import *
from binascii import *

context.log_level = 'debug'
p = remote('das.wetolink.com', 42887)

#while (b'flag' not in p.recvline()):
'''
p.sendlineafter(b'Amazing function: ', b'88' * 11) 
r = p.recvline()
print((len(r)-1)//2)        # 10 => 48, 11 = > 64, so flag's length is 38
'''

def n2b(n):
    h = hex(n)[2:]
    return struct.pack('B', ord(h[0])) + struct.pack('B', ord(h[1]))

enc = []
for i in range(38):
    payload = b'88' * (47-i)
    p.sendlineafter(b'Amazing function: ', payload)
    enc.append(p.recvline()[64:96])
print(enc)


flag = b''
for i in range(38):
    f = False
    for c in range(32, 127):
        payload = b'88' * (47-len(flag)//2) + flag + n2b(c)
        p.sendlineafter(b'Amazing function: ', payload)
        e = p.recvline()[:-1]
        if e[64:96] in enc:
            flag += n2b(c)
            print(flag)
            f = True
            break
    if not f:
        exit()

print(unhexlify(flag))

逆向

RealEzRE

这题很有意思。

字符串都是加密过的了,走了一个类似base64的解码。

有两个反调试,一个是时间调试,另一个我没深入去看:

image-20201206184130092

看了看,跟进这个函数:

image-20201206184216905

里面是个smc,但我没找到具体的smc的解码代码。

索性直接解码后dump出来。虽然不能动调了,但是可以静态看。

dword_437FA0 = 825373492;
  for ( i = 0; i < sub_40F3D0(*(_DWORD **)(a1 + 4)); ++i )
    input[i] = *(_BYTE *)(*(_DWORD *)(a1 + 4) + i);
  sub_40B3A0((__m128i *)v13, 0, 0x408u);
  rc4_(v13, 8);
  if ( sub_401460() )
  {
    strcpy((char *)&v23, "RGVidWdnaW5nISEh");   // debuging
    prin1(&v23, &v19);
    v1 = (void *)prin2(&off_4380C0, &v19);
    prin3(v1, (int (__cdecl *)(void *))sub_402F00);
    result = -1;
  }
  else
  {
    v3 = sub_40F3D0(input);
    sub_401640(v13, (int)input, (int)v15, v3);
    for ( j = 0; j < 13; ++j )
    {
      if ( v15[j] != byte_4370C8[j] )
      {
        strcpy((char *)&v22, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
        prin1(&v22, &v19);
        v4 = (void *)prin2(&off_4380C0, &v19);
        prin3(v4, (int (__cdecl *)(void *))sub_402F00);
        return -1;
      }
    }
    for ( k = 0; k < 6; ++k )
    {
      if ( v17[k] != byte_4370E8[k] )
      {
        strcpy((char *)&v21, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
        prin1(&v21, &v19);
        v5 = (void *)prin2(&off_4380C0, &v19);
        prin3(v5, (int (__cdecl *)(void *))sub_402F00);
        return -1;
      }
    }
    for ( l = 0; l < 13; ++l )
    {
      if ( v16[l] != byte_4370D8[l] )
      {
        strcpy((char *)&v20, "SW5jb3JyZWN0IGZsYWch");// incorrect flag
        prin1(&v20, &v19);
        v6 = (void *)prin2(&off_4380C0, &v19);
        prin3(v6, (int (__cdecl *)(void *))sub_402F00);
        return -1;
      }
    }
    dword_437FA4 = 'abcd';
    strcpy(&v18, "ZmxhZyBpcyAiZmxhZ3t5b3VyIGlucHV0fSIg");
    prin1(&v18, &v19);
    v7 = prin3(&off_4380C0, (int (__cdecl *)(void *))sub_402F00);
    v8 = (void *)prin2(v7, &v19);
    prin3(v8, (int (__cdecl *)(void *))sub_402F00);
    sub_40F781(aPause);
    result = 0;
  }

稍微看了下,就一个rc4,没别的了。

解密脚本:

from Crypto.Cipher import ARC4
from binascii import unhexlify, hexlify
import struct

def l2b(l):
    t = b''
    for i in l:
        t += struct.pack('B', i)
    return t

def rc4_decrypt(cipher, key):
    rc4 = ARC4.new(key)
    return rc4.decrypt(cipher)


rc4_key = b'\x01\x23\x45\x67\x89\xab\xcd\xef'
cipher = [0x12, 0xA7, 0xF5, 0xDE, 0x75, 0x2A, 0x6E, 0x4A, 0x6E, 0x73, 0xE6, 0x62, 0x50] + [0xBF, 0x2A, 0x98, 0xFE, 0x2B, 0xDD, 0x7B, 0xBA, 0xB6, 0x05, 0x13, 0x63, 0x57] + [0x2D, 0xD4, 0x45, 0xB8, 0xFE, 0xBC]
cipher = l2b(cipher)
print(cipher)

result = rc4_decrypt(cipher, rc4_key)
print(result)
Last modification:December 8th, 2020 at 11:37 pm