Loading

[GWCTF 2019]re3 wp

[GWCTF 2019]re3

关键点:AES MD5 动态调试 smc自解密 gdb使用
跟进main函数 发现一个典型smc异或自解密

可以用idc脚本 或者python patch 或者动态调试查看逻辑

a = [0xCC,0xD1,0x10,0x7C,0xD1,0x18,0x75,0x69,0x99,0x99,0x99,0xD1,0x10,0x24,0x81,0x66,0x66,0x66,0xFD,0xD1,0x12,0x9D,0xBC,0xB1,0x99,0x99,0x99,0xD1,0x10,0xDC,0x61,0xA8,0x59,0xD1,0x14,0x1C,0xA9,0x66,0x66,0x66,0x27,0xE9,0xA8,0xF9,0x99,0xD1,0x10,0x5E,0x71,0xBA,0x71,0x66,0x66,0xD1,0x12,0x0C,0x81,0x66,0x66,0x66,0xD1,0x14,0x1C,0xA9,0x66,0x66,0x66,0xD1,0x10,0x4F,0xD1,0x10,0x5E,0x71,0x9E,0x6E,0x66,0x66,0xD1,0x12,0x1C,0x81,0x66,0x66,0x66,0xD1,0x14,0xC9,0x89,0xD1,0x14,0x1C,0xA9,0x66,0x66,0x66,0xD1,0x10,0x4F,0xD1,0x10,0x5E,0x71,0x73,0x6F,0x66,0x66,0x5E,0x1C,0xB1,0x66,0x66,0x66,0x98,0x99,0x99,0x99,0x5E,0x1C,0xB5,0x66,0x66,0x66,0x99,0x99,0x99,0x99,0x72,0xA3,0x12,0x1C,0xB5,0x66,0x66,0x66,0xD1,0xFA,0x49,0xD1,0x12,0x1C,0x81,0x66,0x66,0x66,0xD1,0x98,0x49,0x96,0x2F,0x89,0x12,0x1C,0xB5,0x66,0x66,0x66,0xD1,0x01,0x96,0x2F,0x19,0x39,0xA9,0xF9,0x99,0xA1,0x5B,0xED,0x93,0x5E,0x1C,0xB1,0x66,0x66,0x66,0x99,0x99,0x99,0x99,0x1A,0x1C,0xB5,0x66,0x66,0x66,0x98,0x1A,0x24,0xB5,0x66,0x66,0x66,0x86,0xE7,0x24,0x12,0x1C,0xB1,0x66,0x66,0x66,0xD1,0x12,0xD4,0x61,0xFD,0xD1,0xAA,0x95,0xBC,0xB1,0x99,0x99,0x99,0xED,0x9C,0x71,0xC0,0x7A,0x66,0x66,0x50,0x5A]
for i in range(len(a)):
	a[i] ^= 0x99
with open(r'D:\sundry\attachment (1)','rb+') as f:
    for i in range(0x2219):
        x = f.read(1)
    for i in range(224):
        y = []
        y.append(a[i])
        f.write(bytes(y))

idc脚本


#include <idc.idc>

static main()
{
    auto addr = 0x402219;
    auto i = 0;
    for(i=0;i<224;i++)
    {
        PatchByte(addr+i,Byte(addr+i)^0x99);
    }
}

都是网上抄的(

手动patch一下 得到如图主逻辑
findcrypto插件查一下 跟进到sub_40207B 函数

sub_401CF9明显的md5函数

几个经典MD5常数

经过多次动态调试 发现sub_40207B返回值相同 拿到该返回值 可以ida远程联动linux调试
在这里我使用gdb来调试
断在该函数结束后一行 0x4021e9
然后查看unk_603170的值 来拿到第一步加密结果

gdb查看地址内容 x指令

接着分析sub_402219函数

很明显 后半部分for循环是判断flag是否正确 我们把byte_6030A0拿走 这就是加密后结果
根据findcrypto与对称加密特征
能看出是ECB方式的AES加密 密钥就是我们刚才动态拿到的unk_603170的值

AES加密数据块分组长度必须为128比特(16字节),密钥长度可以是128比特(16字节)、192比特(24字节)、256比特(32字节)中的任意一个(如果数据块及密钥长度不足时,会补齐)
所以我们直接使用脚本解密

import re
from Cryptodome.Cipher import AES
from binascii import b2a_hex
print("a" * 32)
enc = [0xBC, 0x0A, 0xAD, 0xC0, 0x14, 0x7C, 0x5E, 0xCC, 0xE0, 0xB1,
       0x40, 0xBC, 0x9C, 0x51, 0xD5, 0x2B, 0x46, 0xB2, 0xB9, 0x43,
       0x4D, 0xE5, 0x32, 0x4B, 0xAD, 0x7F, 0xB4, 0xB3, 0x9C, 0xDB,
       0x4B, 0x5B]
print(len(enc))
md5_ = [0xcb, 0x8d, 0x49, 0x35, 0x21, 0xb4, 0x7a, 0x4c,
        0xc1, 0xae, 0x7e, 0x62, 0x22, 0x92, 0x66, 0xce, ]
print(len(md5_))
mode = AES.MODE_ECB
key = b'\xcb\x8d\x49\x35\x21\xb4\x7a\x4c\xc1\xae\x7e\x62\x22\x92\x66\xce'
text = b'\xBC\x0A\xAD\xC0\x14\x7C\x5E\xCC\xE0\xB1\x40\xBC\x9C\x51\xD5\x2B\x46\xB2\xB9\x43\x4D\xE5\x32\x4B\xAD\x7F\xB4\xB3\x9C\xDB\x4B\x5B'
cryptos = AES.new(key, mode)
cipher_text = cryptos.decrypt(text)
t = b2a_hex(cipher_text).decode()
t = re.findall(".{2}", t)
for x in t:
    print(chr(int(x, 16)), end="")

flag{924a9ab2163d390410d0a1f670}

posted @ 2021-12-21 16:39  FW_ltlly  阅读(247)  评论(0编辑  收藏  举报