首页
社区
课程
招聘
[原创]2022MT-CTF Re
2022-9-18 22:45 5976

[原创]2022MT-CTF Re

2022-9-18 22:45
5976

2022MT-CTF逆向部分题解,这次题目比较有意思,一大一小,small and static。

small

很精致的のlf文件,IDA加载失败,但是代码足够小,用cutter进行识别。

 

关键代码逻辑如下,可见是个tea加密,魔改了delta和加密轮数。

 

image-20220917182706615

 

翻译后的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
void Tea_Encrypt(ut32* src) {
    ut32 sum = 0;
    ut32 v0 = src[0];
    ut32 v1 = src[1];
    for (int i = 0; i < 0x23; i++) {
        sum += 0x67452301;
        v0 += ((v1 << 4) +1) ^ (v1 + sum) ^ ((v1 >> 5) + 0x23);
        v1 += ((v0 << 4) + 0x45) ^ (v0 + sum) ^ ((v0 >> 5) + 0x67);
    }
    src[0] = v0;
    src[1] = v1;
}

接着是密文比对,是倒叙进行比对。

 

image-20220917183048589

 

因为rsi在上面代码中每次会+8,所以实际的密文顺序不变,并且在偏移0x100f7处。

 

image-20220917183254493

 

解密代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""
enc=list(bytes.fromhex('437108ded21bf9c4dcdaf6da4cd59e6de74eeb7504dc1d5dd90f1b51fb88dc51'))
for i in range(0,len(enc),4):
    num=0
    for j in range(4):
        num|=(enc[i+j]<<(8*j))
    print(hex(num),end=',')
"""
 
 
#include<iostream>
#define ut32 unsigned int
#define delta 0x67452301
 
void Tea_Decrypt(ut32* enc) {
    unsigned int sum = 0x67452301 * 0x23;//0x1e73c923;
    ut32 v0 = enc[0];
    ut32 v1 = enc[1];
    for (int i = 0; i < 0x23; i++) {
        v1 -= ((v0 << 4) + 0x45) ^ (v0 + sum) ^ ((v0 >> 5) + 0x67);
        v0 -= ((v1 << 4) + 1) ^ (v1 + sum) ^ ((v1 >> 5) + 0x23);
        sum -= 0x67452301;
    }
    enc[0] = v0;
    enc[1] = v1;
}
 
void Tea_Encrypt(ut32* src) {
    ut32 sum = 0;
    ut32 v0 = src[0];
    ut32 v1 = src[1];
    for (int i = 0; i < 0x23; i++) {
        sum += 0x67452301;
        v0 += ((v1 << 4) +1) ^ (v1 + sum) ^ ((v1 >> 5) + 0x23);
        v1 += ((v0 << 4) + 0x45) ^ (v0 + sum) ^ ((v0 >> 5) + 0x67);
    }
    printf("%08x\n", sum);
    src[0] = v0;
    src[1] = v1;
}
int main() {
    ut32 enc[8] = { 0xde087143,0xc4f91bd2,0xdaf6dadc,0x6d9ed54c,0x75eb4ee7,0x5d1ddc04,0x511b0fd9,0x51dc88fb };
    for (int i = 0; i < 8; i += 2) {
        Tea_Decrypt(enc+i);
    }
 
    for (int i = 0; i < 32; i++) {
        printf("%c",*((unsigned char*)enc+i));
    }
        //327a6c4304ad5938eaf0efb6cc3e53dc
    return 0;
}

static

采用静态编译,程序比较的臃肿,加载或者是恢复符号需要大量的时间,并且程序控制流走向不是很清晰。

 

因为符号恢复时间比较长,所以wp基于修复后的程序编写,符号恢复思路是全局使用Lumina,对于部分函数使用finger。

 

主函数处理如下,前部分是取出flag的内容,去掉"-"的符号

 

image-20220917184140810

 

可是调试发现,在循环右移2后,走到vector_unicorn的地方程序会退出,并且v10是重复的两组显然不是需要的flag。

 

借助find_crypt插件,发现程序中存在aes加密,所以猜测发生了重定位。用pintool打印trace,最好是code coverage,因为比较轻量且会高亮控制流。
https://github.com/gaasedelen/lighthouse

测试输入flag{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa},走过的代码会被高亮。

 

image-20220917184946792

 

结合对表的交叉引用,发现可疑处理函数。

 

image-20220917185116625

 

继续交叉引用,直到sub_4064F0

 

image-20220917185157993

 

发现该部分处理过32字节的字符串,分成两段处理,IDA调试发现该部分断下后rdi0中存储的是输入flag{}中的内容。

 

第一段处理

 

image-20220917185935985

 

结合常量表和10次异或,猜测是aes加密,并且轮秘钥已预先生成好写在了10个xmmword变量中,所以第一个便是初始秘钥。

 

对于第二部分的加密,因为之前出现的unicorn字符串,并且结构与unicorn比较类似,搜索一个c调用的模板进行比对。

 

image-20220917190417537

 

sub_406BBBuc_open确定架构和模式,2对应着ARM64。

1
2
3
4
5
6
7
8
9
10
typedef enum uc_arch {
    UC_ARCH_ARM = 1,    // ARM architecture (including Thumb, Thumb-2)
    UC_ARCH_ARM64,      // ARM-64, also called AArch64
    UC_ARCH_MIPS,       // Mips architecture
    UC_ARCH_X86,        // X86 architecture (including x86 & x86-64)
    UC_ARCH_PPC,        // PowerPC architecture (currently unsupported)
    UC_ARCH_SPARC,      // Sparc architecture
    UC_ARCH_M68K,       // M68K architecture
    UC_ARCH_MAX,
} uc_arch;

字节码存在byte_19762c0中,调试可知v2=0x5dc, dump出0x5dc个字节写入一个文件,ida用arm架构解析,结合代码可知该部分是对第二部分flag进行了处理。

1
2
3
4
5
6
7
8
code=[    0xFF, 0x43, 0x01, 0xD1, 0xE0, 0x27, 0x00, 0xF9, 0xE8, 0x27, 0x40, 0xF9, 0x08, 0x01, 0x40, 0x39,
    0xE9, 0x27, 0x40, 0xF9, 0x29, 0x15, 0x40, 0x39, 0x08, 0x01, 0x09, 0x4A, 0xE9, 0x27, 0x40, 0xF9,
    0x29, 0x09, 0x40, 0x39, 0x08, 0x15, 0x09, 0x4A, 0xE9, 0x27, 0x40, 0xF9, 0x29, 0x25, 0x40, 0x39,
    0x08, 0x05, 0x09, 0x4A, 0xE9, 0x27, 0x40, 0xF9, 0x29, 0x29, 0x40, 0x39, 0x09, 0x05, 0x09, 0x4A,
    ...
    0xE8, 0x03, 0x00, 0xB9, 0xF2, 0xFF, 0xFF, 0x17, 0xFF, 0x43, 0x01, 0x91]
f=open(r'bin','wb+')
f.write(bytes(code))

ida加载bin后第一部分如下,逻辑方程,可用z3约束求解。

 

image-20220917190959288

 

第二部分是个xxtea,delta为 -0x21524111(0xdeadbeef)

 

image-20220917191302637

 

综上第一部分加密为aes_ecb,第二部分为逻辑方程+xxtea,接下来找到比对密文即可,根据trace可知真正比对密文为下面32字节。

 

image-20220917191639777

 

解密如下

 

part1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Cipher.AES import *
def getb(a:list):
    res=b''
    for i in a:
        res+=int.to_bytes(i,8,'little')
    return res
enc=[0x1624B3C3E0E4FEAA, 0xA0CAE19E13F75B4E, 0x4D26D4BBFB732728, 0x26BAFC68DA122E3A]
c1=getb(enc[:2])
c2=getb(enc[2:])
 
#flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
k=[0x0B, 0x3A, 0xBA, 0x39, 0xA2, 0x64, 0x27, 0x1C, 0x36, 0x31, 0x98, 0x80, 0x9E, 0x77, 0x9E, 0xEB]
aes=new(bytes(k),MODE_ECB)
t=aes.decrypt(c1)
print(t)
##2e64949cd16c4449

part2

 

xxtea

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<iostream>
#define ut32 unsigned int
#define delta 0xdeadbeef
using namespace std;
void XXTea_Encrypt(ut32* src, ut32 n, ut32* key);
void XXTea_Decrypt(ut32* enc, ut32 n, ut32* key);
void output(ut32* m, ut32 len);                   
 
void XXTea_Encrypt(ut32* src, ut32 n, ut32* key) {
    ut32 y, z, sum = 0;
    ut32 e, rounds;
    int p; // 定义为无符号时 p-1>=0这个判断恒成立
    rounds = 6 + 52 / n;
    do {
        z = src[n - 1];
        sum += delta;
        e = (sum >> 2) & 3;
        for (p = 0; p < n - 1; p++) {
            y = src[p + 1];
            src[p] += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
            z = src[p];
        }
        y = src[0];
        src[n - 1] += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
    } while (--rounds);
 
}
 
void XXTea_Decrypt(ut32* enc, ut32 n, ut32* key) {
    ut32 y, z, sum;
    ut32 e, rounds;
    int p;
    rounds = 6 + 52 / n;
    sum = delta * rounds;
 
    do {
        e = (sum >> 2) & 3;
        for (p = n - 1; p > 0; p--) {
            y = enc[(p + 1) % n];
            z = enc[(p - 1)];
            enc[p] -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
        }
        y = enc[1];
        z = enc[n - 1];
        enc[0] -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(0 & 3) ^ e] ^ z)));
        sum -= delta;
    } while (--rounds);
 
}
 
void output(ut32* m, ut32 len) {
    for (int i = 0; i < len; i++)
        printf("0x%08x ", m[i]);
    printf("\n");
}
 
int main() {
    ut32 m[4] = { 0xFB732728, 0x4D26D4BB, 0xDA122E3A, 0x26BAFC68 };
    ut32 k[4] = { 12,34,56,78 };
    XXTea_Decrypt(m, 4, k);
    for (int i = 0; i < 16; i++) {
        printf("%d,", *((unsigned char*)m + i));
    }
    return 0;
}

z3约束求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from z3 import *
s=Solver()
enc=[53,0,27,154,177,235,146,141,130,127,222,7,180,208,151,164]
m=[BitVec('m%d'%i,8) for i in range(16)]
s.add(m[0] ^ m[5] ^ (32 * m[2]) ^ (2 * m[9]) ^ (2 * m[10])            ==enc[0]   )
s.add(m[1] ^ (m[13] >> 2) ^ (m[12] >> 2) ^ m[15] ^ (m[4] >> 6)        ==enc[1]   )
s.add(m[2] ^ (m[1] << 7) ^ (m[15] >> 6) ^ (8 * m[14]) ^ (m[4] >> 1)   ==enc[2]   )
s.add(m[3] ^ (2 * m[10]) ^ (m[14] >> 4) ^ (m[6] >> 4) ^ (32 * m[13])  ==enc[3]   )
s.add(m[4] ^ (4 * m[3]) ^ m[10] ^ (2 * m[0]) ^ (m[1] >> 2)             ==enc[4]   )
s.add(m[5] ^ (m[1] >> 3) ^ (m[13] << 7) ^ (m[2] >> 7) ^ (4 * m[8])    ==enc[5]   )
s.add(m[6] ^ (m[8] >> 7) ^ (4 * m[5]) ^ (16 * m[3]) ^ (m[14] >> 3)    ==enc[6]   )
s.add(m[7] ^ (m[11] >> 6) ^ (m[2] >> 5) ^ (m[3] << 6) ^ (2 * m[1])    ==enc[7]   )
s.add(m[8] ^ (m[11] << 7) ^ (m[5] >> 6) ^ (2 * m[4]) ^ (16 * m[6])    ==enc[8]   )
s.add(m[9] ^ (8 * m[15]) ^ (m[4] >> 3) ^ (32 * m[12]) ^ m[2]          ==enc[9]   )
s.add(m[10] ^ ( m[0] >> 2) ^ (2 * m[9]) ^ (m[5] << 7) ^ (m[11] >> 7==enc[10]    )
s.add(m[11] ^ m[5] ^ (m[10] >> 4) ^ (m[6] >> 6) ^ (m[3] >> 6)         ==enc[11]   )
s.add(m[12] ^ (m[4] << 6) ^ (m[2] >> 1) ^ (m[15] >> 1) ^ (m[11] << 7) ==enc[12]   )
s.add(m[13] ^ (m[6] >> 3) ^ (m[9] >> 7) ^ (32 * m[1]) ^ (m[11] >> 7==enc[13]   )
s.add(m[14] ^ (m[7] << 7) ^ (16 * m[9]) ^ (m[8] >> 1) ^ (16 * m[2])   ==enc[14]   )
s.add(m[15] ^ ( m[0] >> 1) ^ (m[13] >> 6) ^ (4 * m[7]) ^ (m[11] >> 5) ==enc[15]    )
 
print(s.check())
ans=s.model()
for i in range(16):
    print(chr(ans[m[i]].as_long()),end='')
#87320a0cc24e6667

最终提交uuid格式


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回