1. 程式人生 > 其它 >[GWCTF 2019]re3 wp

[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}