The flare-on challenge 6th writeup

这是第三次参加flare on了 这次也是第二次做完全部的题。

1 - Memecat Battlestation

C# 题目,一共两关

stage1Form.WeaponCode 为明文:

Stage2Form.WeaponCode 为异或结果:

1
2
3
4
5
array = [0x3,ord(' '),ord('&'),ord('$'),ord('-'),0x1e,0x2,ord(' '),ord('/'),ord('/'),ord('.'),ord('/')]

s2 = ''
for i in xrange(len(array)):
s2 += chr(array[i]^ord('A'))

2 - overlong

一个patch 题目,题目默认输出个

“I never stop the encoding”

在栈上将长度改大,然后就get flag

3 - flarebear

apk 题 使用jeb逆向发现

当满足 ishappy() 和 isEcstatic() 两个函数的时候,会打印flag。

ishappy() 逻辑如下:

isEcstatic() 逻辑如下:

游戏有三个功能分别为 feed play clean:

三个功能分别如下:

feed

play

clean:

1
2
3
4
5
6
7
8
from z3 import *


feed = Int('feed')
play = Int('play')
clean = Int('clean')

solve(feed/play >= 2, feed/play<=2.5,feed*10-play*2 == 72,feed*2 + play*4 - clean == 30,-feed -play + clean*6==0)

结果为:

1
2
swing@ubuntu:/media/psf/Home/Desktop/flare-on/3 - Flarebear $ python solve.py 
[Clean = 2, feed = 8, play = 4]

最后可打印出flag:

4 - Dnschess

题目了三个附件,一个pcap流量包 一个ChessUI 和ChessAI.so 文件。

通过DNS协议下棋

首先将满足条件的ip提取出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
iplist = []
cap = FileCapture(input_file='capture.pcap')
for i,p in enumerate(cap):
# if p.dns.flags == '0x00000120':
if p.dns.flags == '0x00008580':
name = p.dns.qry_name
ip = p.dns.a.split('.')
# print(ip)
if ip[0] != 127 or ip[3]&1 and (i/2)&(ip[2])&0xf:
# print (map(chr,t2))
ip = ".".join(ip)
iplist.append(str(ip))
continue
else:
continue
print(iplist)
print(len(iplist))

iplist:

1
['127.150.96.223', '127.252.212.90', '127.215.177.38', '127.118.118.207', '127.89.38.84', '127.109.155.97', '127.217.37.102', '127.49.59.14', '127.182.147.24', '127.0.143.11', '127.227.42.139', '127.101.64.243', '127.201.85.103', '127.200.76.108', '127.50.67.23', '127.157.96.119', '127.99.253.122', '127.25.74.92', '127.168.171.31', '127.148.37.223', '127.108.24.10', '127.37.251.13', '127.34.217.88', '127.57.238.51', '127.196.103.147', '127.141.14.174', '127.238.7.163', '127.230.231.104', '127.55.220.79', '127.184.171.45', '127.196.146.199', '127.191.78.251', '127.159.162.42', '127.184.48.79', '127.127.29.123', '127.191.34.35', '127.5.22.189', '127.233.141.55', '127.55.250.81', '127.53.176.56']

最后:

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
t3 = ['127.150.96.223', '127.252.212.90', '127.215.177.38', '127.118.118.207',
'127.89.38.84', '127.109.155.97', '127.217.37.102', '127.49.59.14',
'127.182.147.24', '127.0.143.11', '127.227.42.139', '127.101.64.243',
'127.201.85.103', '127.200.76.108', '127.50.67.23', '127.157.96.119',
'127.99.253.122', '127.25.74.92', '127.168.171.31', '127.148.37.223',
'127.108.24.10', '127.37.251.13', '127.34.217.88', '127.57.238.51',
'127.196.103.147', '127.141.14.174', '127.238.7.163', '127.230.231.104',
'127.55.220.79', '127.184.171.45', '127.196.146.199', '127.191.78.251',
'127.159.162.42', '127.184.48.79', '127.127.29.123', '127.191.34.35',
'127.5.22.189', '127.233.141.55', '127.55.250.81', '127.53.176.56']
# i = 0

t2 = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x66,
0x6c,0x61,0x72,0x65,0x2d,0x6f,0x6e,0x2e,
0x63,0x6f,0x6d,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]

for j,p in enumerate(t3):
ip = map(int,p.split('.'))
if ip[0] == 127 and not ip[3]&1:
i = ip[2]&0xf
t2[i*2] = ip[1]^t1[i*2]
t2[i*2+1] = ip[1]^t1[i*2+1]
# print (''.join(map(chr,t2)))
print (''.join(map(chr,t2)))

5 - demo

这个函数将修改视角

6 - bmphide

参数的0 1 2 位分别是 原图、 待隐写数据 和保存的图片。

函数i 可知是一个类似于LSB 隐写的代码,将加密后的数据隐写到

R G B 对应为 低0 1 2 ; 0 1 2 ; 0 1处

j 函数大致逻辑录下:

1
2
3
4
5
6
7
8
9
10
11
j(z)  (ww*yy+zz+4+f(6))^b(z,1) 
ww = 0x1F7D1482
yy = 20*136+18
zz = MzQxOTk= 34199
j(103) = 0
j(231) = 1
j(230) = 3
j(27) = 0xf8
j(228) = 7
j(25) = 0xfc
j(100) = 6

利用如下代码提取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image
img = Image.open('flag.bmp')
# img2 = Image.open('new1.jpg')
pixel = img.load()
d = []
for x in range(img.size[0]):
for y in range(img.size[1]):
p = pixel[x, y]
# print(p)
data = (p[0]&7) | ((p[1]&7)<<3) | ((p[2]&3)<<6)
d.append(data)

extract_file = "".join(map(chr,d))

with open("extract_file","wb") as f:
f.write(extract_file)

通过分析代码逻辑发现其中h的逻辑大致如下:

1
2
# c((a((data[i] ^ f(num++)) , 7))) ^ f(num++),3)
# f => g a => b c => d

但其中几个函数被替换,f 替换为 g, a替换为b, c替换为d

最后代码:

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
#coding:utf-8
def extractFile():
from PIL import Image
img = Image.open('flag.bmp')
# img2 = Image.open('new1.jpg')
pixel = img.load()
d = []
for x in range(img.size[0]):
for y in range(img.size[1]):
p = pixel[x, y]
# print(p)
data = (p[0]&7) | ((p[1]&7)<<3) | ((p[2]&3)<<6)
d.append(data)

extract_file = "".join(map(chr,d))

with open("extract_file","wb") as f:
f.write(extract_file)

def g(idx):
b = ((0xc5*(idx+1))^ (0x7d*(idx+2)))&0xff

return b

def b(byte,len): #
for i in xrange(len):
b2 = ((byte & 128) / 128) &0xff
b = ((byte * 2 & 0xff) + b2) & 0xff
return b

def d(byte,len):
for i in xrange(len):
b2 = ((byte & 1) * 128) & 0xff
b = ((byte / 2 & 0xff) + b2) & 0xff
return b

def e(a, b):
return a^b
for i in range(8):
if (a>>i&1) == (b>>i&1):
a = a & ~(1<<i)&255
else:
a = a | (1<<i)&255
return

# def f(idx):
# n = 1
# while True:
# yield ((n*309030853)^((n+1)*209897853))&0xff
# n += 1
# b = ((idx+1)*309030853)&0xff
# k = ((idx+2)*209897853)&0xff
# return b ^ k

def circular_shift_left (int_value,k,bit = 8):
bit_string = '{:0%db}' % bit
bin_value = bit_string.format(int_value) # 8 bit binary
bin_value = bin_value[k:] + bin_value[:k]
int_value = int(bin_value,2)
return int_value


# right circular shift

def circular_shift_right (int_value,k,bit = 8):
bit_string = '{:0%db}' % bit
bin_value = bit_string.format(int_value) # 8 bit binary
bin_value = bin_value[-k:] + bin_value[:-k]
int_value = int(bin_value,2)
return int_value

# c((a((data[i] ^ f(num++)) , 7))) ^ f(num++),3)
# f => g a => b c => d
def decode():
data = open("extract_file","rb").read()
# data = data[::-1]

data2 = ""
data3 = ""
data4 = ""
data5 = ""
for i in xrange(len(data)):
data2 += chr(circular_shift_left(ord(data[i]),3))
data3 += chr(ord(data2[i]) ^ g(2*i+1) )
data4 += chr(circular_shift_right(ord(data3[i]),7))
data5 += chr(ord(data4[i]) ^ g(2*i))

save = open("flag.bmp","wb")

save.write(data5)

decode()

7 - wopr

一个 PE 文件,IDA打开分析发现是 pyintaller 打包的,使用 pyinstxtractor 进行解包

1
python pyinstxtractor.py wopr.exe

得到一堆解包后的文件:

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
# swing @ localhost in ~/Desktop/flare-on/7 - wopr/wopr.exe_extracted [14:15:19]
$ ls
PYZ-00.pyz api-ms-win-crt-convert-l1-1-0.dll
PYZ-00.pyz_extracted api-ms-win-crt-environment-l1-1-0.dll
VCRUNTIME140.dll api-ms-win-crt-filesystem-l1-1-0.dll
_bz2.pyd api-ms-win-crt-heap-l1-1-0.dll
_ctypes.pyd api-ms-win-crt-locale-l1-1-0.dll
_hashlib.pyd api-ms-win-crt-math-l1-1-0.dll
_lzma.pyd api-ms-win-crt-process-l1-1-0.dll
_socket.pyd api-ms-win-crt-runtime-l1-1-0.dll
_ssl.pyd api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-core-console-l1-1-0.dll api-ms-win-crt-string-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll api-ms-win-crt-time-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll api-ms-win-crt-utility-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll base_library
api-ms-win-core-file-l1-1-0.dll base_library.zip
api-ms-win-core-file-l1-2-0.dll libcrypto-1_1.dll
api-ms-win-core-file-l2-1-0.dll libssl-1_1.dll
api-ms-win-core-handle-l1-1-0.dll pyexpat.pyd
api-ms-win-core-heap-l1-1-0.dll pyi-windows-manifest-filename wopr.exe.manifest
api-ms-win-core-interlocked-l1-1-0.dll pyiboot01_bootstrap
api-ms-win-core-libraryloader-l1-1-0.dll pyiboot01_bootstrap_dis
api-ms-win-core-localization-l1-2-0.dll pyiboot02_cleanup.py
api-ms-win-core-memory-l1-1-0.dll pyiboot02_cleanup.pyc
api-ms-win-core-namedpipe-l1-1-0.dll pyiboot02_cleanup_dis
api-ms-win-core-processenvironment-l1-1-0.dll pyimod01_os_path
api-ms-win-core-processthreads-l1-1-0.dll pyimod02_archive
api-ms-win-core-processthreads-l1-1-1.dll pyimod03_importers
api-ms-win-core-profile-l1-1-0.dll python37.dll
api-ms-win-core-rtlsupport-l1-1-0.dll select.pyd
api-ms-win-core-string-l1-1-0.dll struct
api-ms-win-core-synch-l1-1-0.dll this key
api-ms-win-core-synch-l1-2-0.dll this\__init__.py
api-ms-win-core-sysinfo-l1-1-0.dll this\key
api-ms-win-core-timezone-l1-1-0.dll ucrtbase.dll
api-ms-win-core-util-l1-1-0.dll unicodedata.pyd
api-ms-win-crt-conio-l1-1-0.dll wopr.exe.manifest

由于题目提示是要找启动代码,所以找到了pyi 开头的几个文件 由于几个文件缺少了pyc头,我们将pyc头给补上(python3.7版本)然后使用 python-uncompyle6** 进行反编译,其中 pyiboot-2_cleanup代码如下:

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
import hashlib, io, lzma, pkgutil, random, struct, sys, time
from ctypes import *
print('LOADING...')
BOUNCE = pkgutil.get_data('this', 'key')

def ho(h, g={}):
k = bytes.fromhex(format(h, 'x')).decode()
return g.get(k, k)


a = 1702389091
b = 482955849332
g = ho(29516388843672123817340395359, globals())
aa = getattr(g, ho(a))
bb = getattr(g, ho(b))
a ^= b
b ^= a
a ^= b
setattr(g, ho(a), aa)
setattr(g, ho(b), bb)

def eye(face):
leg = io.BytesIO()
for arm in face.splitlines():
print(arm)
arm = arm[len(arm.rstrip(' \t')):]
leg.write(arm)

face = leg.getvalue()
bell = io.BytesIO()
x, y = (0, 0)
for chuck in face:
taxi = {9:0,
32:1}.get(chuck)
if taxi is None:
continue
x, y = x | taxi << y, y + 1
if y > 7:
bell.write(bytes([x]))
x, y = (0, 0)
return bell.getvalue()


def fire(wood, bounce):
meaning = bytearray(wood)
bounce = bytearray(bounce)
regard = len(bounce)
manage = list(range(256))

def prospect(*financial):
return sum(financial) % 256

def blade(feel, cassette):
cassette = prospect(cassette, manage[feel])
manage[feel], manage[cassette] = manage[cassette], manage[feel]
return cassette

cassette = 0
for feel in range(256):
cassette = prospect(cassette, bounce[(feel % regard)])
cassette = blade(feel, cassette)

cassette = 0
for pigeon, _ in enumerate(meaning):
feel = prospect(pigeon, 1)
cassette = blade(feel, cassette)
meaning[pigeon] ^= manage[prospect(manage[feel], manage[cassette])]

return bytes(meaning)

for i in range(256):
try:
print(lzma.decompress(fire(eye(__doc__.encode()), bytes([i]) + BOUNCE)))
except Exception:
pass

他会取__doc__ 里的制表符和空格进行编码,然后rc4解密,然后解压缩,但是 python-uncompyle6 这个反编译后的代码没有了 制表符,后面我又搜了个工具叫 pycdc 重新反编译,得到了一部分新代码。

但是后面发现没有输出,最后发现前面有一段代码将print 替换成了exec

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
GREETINGS = ["HI", "HELLO", "'SUP", "AHOY", "ALOHA", "HOWDY", "GREETINGS", "ZDRAVSTVUYTE"]
STRATEGIES = ['U.S. FIRST STRIKE', 'USSR FIRST STRIKE', 'NATO / WARSAW PACT', 'FAR EAST STRATEGY', 'US USSR ESCALATION', 'MIDDLE EAST WAR', 'USSR CHINA ATTACK', 'INDIA PAKISTAN WAR', 'MEDITERRANEAN WAR', 'HONGKONG VARIANT', 'SEATO DECAPITATING', 'CUBAN PROVOCATION', 'ATLANTIC HEAVY', 'CUBAN PARAMILITARY', 'NICARAGUAN PREEMPTIVE', 'PACIFIC TERRITORIAL', 'BURMESE THEATERWIDE', 'TURKISH DECOY', 'ARGENTINA ESCALATION', 'ICELAND MAXIMUM', 'ARABIAN THEATERWIDE', 'U.S. SUBVERSION', 'AUSTRALIAN MANEUVER', 'SUDAN SURPRISE', 'NATO TERRITORIAL', 'ZAIRE ALLIANCE', 'ICELAND INCIDENT', 'ENGLISH ESCALATION', 'MIDDLE EAST HEAVY', 'MEXICAN TAKEOVER', 'CHAD ALERT', 'SAUDI MANEUVER', 'AFRICAN TERRITORIAL', 'ETHIOPIAN ESCALATION', 'TURKISH HEAVY', 'NATO INCURSION', 'U.S. DEFENSE', 'CAMBODIAN HEAVY', 'PACT MEDIUM', 'ARCTIC MINIMAL', 'MEXICAN DOMESTIC', 'TAIWAN THEATERWIDE', 'PACIFIC MANEUVER', 'PORTUGAL REVOLUTION', 'ALBANIAN DECOY', 'PALESTINIAN LOCAL', 'MOROCCAN MINIMAL', 'BAVARIAN DIVERSITY', 'CZECH OPTION', 'FRENCH ALLIANCE', 'ARABIAN CLANDESTINE', 'GABON REBELLION', 'NORTHERN MAXIMUM', 'DANISH PARAMILITARY', 'SEATO TAKEOVER', 'HAWAIIAN ESCALATION', 'IRANIAN MANEUVER', 'NATO CONTAINMENT', 'SWISS INCIDENT', 'CUBAN MINIMAL', 'CHAD ALERT', 'ICELAND ESCALATION', 'VIETNAMESE RETALIATION', 'SYRIAN PROVOCATION', 'LIBYAN LOCAL', 'GABON TAKEOVER', 'ROMANIAN WAR', 'MIDDLE EAST OFFENSIVE', 'DENMARK MASSIVE', 'CHILE CONFRONTATION', 'S.AFRICAN SUBVERSION', 'USSR ALERT', 'NICARAGUAN THRUST', 'GREENLAND DOMESTIC', 'ICELAND HEAVY', 'KENYA OPTION', 'PACIFIC DEFENSE', 'UGANDA MAXIMUM', 'THAI SUBVERSION', 'ROMANIAN STRIKE', 'PAKISTAN SOVEREIGNTY', 'AFGHAN MISDIRECTION', 'ETHIOPIAN LOCAL', 'ITALIAN TAKEOVER', 'VIETNAMESE INCIDENT', 'ENGLISH PREEMPTIVE', 'DENMARK ALTERNATE', 'THAI CONFRONTATION', 'TAIWAN SURPRISE', 'BRAZILIAN STRIKE', 'VENEZUELA SUDDEN', 'MALAYSIAN ALERT', 'ISREAL DISCRETIONARY', 'LIBYAN ACTION', 'PALESTINIAN TACTICAL', 'NATO ALTERNATE', 'CYPRESS MANEUVER', 'EGYPT MISDIRECTION', 'BANGLADESH THRUST', 'KENYA DEFENSE', 'BANGLADESH CONTAINMENT', 'VIETNAMESE STRIKE', 'ALBANIAN CONTAINMENT', 'GABON SURPRISE', 'IRAQ SOVEREIGNTY', 'VIETNAMESE SUDDEN', 'LEBANON INTERDICTION', 'TAIWAN DOMESTIC', 'ALGERIAN SOVEREIGNTY', 'ARABIAN STRIKE', 'ATLANTIC SUDDEN', 'MONGOLIAN THRUST', 'POLISH DECOY', 'ALASKAN DISCRETIONARY', 'CANADIAN THRUST', 'ARABIAN LIGHT', 'S.AFRICAN DOMESTIC', 'TUNISIAN INCIDENT', 'MALAYSIAN MANEUVER', 'JAMAICA DECOY', 'MALAYSIAN MINIMAL', 'RUSSIAN SOVEREIGNTY', 'CHAD OPTION', 'BANGLADESH WAR', 'BURMESE CONTAINMENT', 'ASIAN THEATERWIDE', 'BULGARIAN CLANDESTINE', 'GREENLAND INCURSION', 'EGYPT SURGICAL', 'CZECH HEAVY', 'TAIWAN CONFRONTATION', 'GREENLAND MAXIMUM', 'UGANDA OFFENSIVE', 'CASPIAN DEFENSE', 'CRIMEAN GAMBIT', 'BRITISH ANTICS', 'HUNGARIAN EXPULSION', 'VENEZUELAN COLLAPSE']

def wrong():
trust = windll.kernel32.GetModuleHandleW(None)

computer = string_at(trust, 1024)
dirty, = struct.unpack_from('=I', computer, 60)

_, _, organize, _, _, _, variety, _ = struct.unpack_from('=IHHIIIHH', computer, dirty)
assert variety >= 144

participate, = struct.unpack_from('=I', computer, dirty + 40)
for insurance in range(organize):
name, tropical, inhabitant, reader, chalk, _, _, _, _, _ = struct.unpack_from('=8sIIIIIIHHI', computer, 40 * insurance + dirty + variety + 24)
if inhabitant <= participate < inhabitant + tropical:
break

spare = bytearray(string_at(trust + inhabitant, tropical))

issue, digital = struct.unpack_from('=II', computer, dirty + 0xa0)
truth = string_at(trust + issue, digital)

expertise = 0
while expertise <= len(truth) - 8:
nuance, seem = struct.unpack_from('=II', truth, expertise)

if nuance == 0 and seem == 0:
break

slot = truth[expertise + 8:expertise + seem]

for i in range(len(slot) >> 1):
diet, = struct.unpack_from('=H', slot, 2 * i)
fabricate = diet >> 12
if fabricate != 3: continue
diet = diet & 4095
ready = nuance + diet - inhabitant
if 0 <= ready < len(spare):
struct.pack_into('=I', spare, ready, struct.unpack_from('=I', spare, ready)[0] - trust)

expertise += seem

return hashlib.md5(spare).digest()

class Terminal(object):

DELAY = 0.02

def write(self, text):
for line in text.splitlines(True):
sys.stdout.write(line)
sys.stdout.flush()
time.sleep(self.DELAY)

def typewrite(self, text):
for char in text:
if char == '\n':
sys.stdout.write(char)
sys.stdout.flush()
time.sleep(self.DELAY)
else:
sys.stdout.write(char.lower())
sys.stdout.flush()
time.sleep(self.DELAY)
sys.stdout.write('\b' + char)
sys.stdout.flush()

def typewriteln(self, text):
self.typewrite(text + '\n')

def read(self):
return ' '.join(''.join(_ for _ in input().upper() if _ in ' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXZY?').split())
t = Terminal()

xor = [212, 162, 242, 218, 101, 109, 50, 31, 125, 112, 249, 83, 55, 187, 131, 206]
h = list(wrong())
h = [h[i] ^ xor[i] for i in range(16)]

t.write('''
_/\/\______/\/\____/\/\/\/\____/\/\/\/\/\____/\/\/\/\/\___
_/\/\__/\__/\/\__/\/\____/\/\__/\/\____/\/\__/\/\____/\/\_
_/\/\/\/\/\/\/\__/\/\____/\/\__/\/\/\/\/\____/\/\/\/\/\___
_/\/\/\__/\/\/\__/\/\____/\/\__/\/\__________/\/\__/\/\___
_/\/\______/\/\____/\/\/\/\____/\/\__________/\/\____/\/\_
__________________________________________________________

''')

t.typewrite('GREETINGS PROFESSOR FALKEN.\n')

while True:
t.typewrite('\n> ')
cmd = t.read()
if cmd.rstrip('!?') in GREETINGS:
t.typewriteln(random.choice(GREETINGS))
elif cmd == 'HELP GAMES':
t.typewriteln("'GAMES' REFERS TO MODELS, SIMULATIONS AND GAMES\nWHICH HAVE TACTICAL AND STRATEGIC APPLICATIONS.")
elif cmd == 'LIST GAMES':
t.typewriteln('FALKEN\'S MAZE\nTIC-TAC-TOE\nGLOBAL THERMONUCLEAR WAR')
elif cmd in ('HELP', '?'):
t.typewriteln('AVAILABLE COMMANDS:\nHELP\nHELP GAMES\nLIST GAMES\nPLAY <game>')
elif cmd.startswith('HELP '):
t.typewriteln('HELP NOT AVAILABLE')
elif cmd == 'PLAY':
t.typewriteln('WHICH GAME?')
elif cmd.startswith('PLAY F') or cmd == 'PLAY 1':
t.typewriteln('GAME IS TEMPORARILY UNAVAILABLE DUE TO MAINTENANCE')
elif cmd.startswith('PLAY T') or cmd == 'PLAY 2':
t.typewriteln('GAME IS TEMPORARILY UNAVAILABLE DUE TO MAINTENANCE')
elif cmd.startswith('PLAY G') or cmd in ('PLAY ARMAGEDDON', 'PLAY 3'):
t.typewriteln('*** GAME ROUTINE RUNNING ***')
break
elif cmd.startswith('PLAY '):
t.typewriteln('THAT GAME IS NOT AVAILABLE')
else:
t.typewriteln('COMMAND NOT RECOGNIZED')


t.write('''
r"""""""""""""""""""7ooooo"""oooooo"""""""""""""""""""""""""""""""""""""""""""7
| .__Looooooo ""7oooooooo` 'ooo" ""._, .JooL_, .___ |
o __L______oLoooooooo7o_, |oooor"" ._____,,Jo__JoooooooooooooJoooL_____J
r7._ooooooooooooooo"JoJoo| oor 'o` .Jooo7oooooooooooooooooooooooooooo"oo"7
| '`"'` ooooooooooL,Jooo_, _oL.ooLoooooooooooooooooooooooooo_ |r` |
| ''ooooooooooooooJo ""oooooooooor"ooooooooooooooooooo7 |
| 7oooooooooo" |or`oo'ooJoJo |ooooooooooooooro ./ |
| "oooooo7o` JooooJ_JLJoooLJoooooooooooooo, or |
| '"oo| oo .oooooooooooroooJo"7oooooooooo7, |
| "" ""`oorL|L, |ooooooooooooooo"` 7or` 7ooo |, |
| '\_oL__ 7ooooooooooooLr 7| L"` |o| |
| .Jooooo| 7ooooooo" ` 'o|_oL"L |
| |oooooooooL 'oooooo| 'o_J7Lrooo_J_, |
| 7oooooooo` Jooooo|._ "`"7LJ/7r "`, |
| oooooor 7oooo|.o| __oooooo_ _| 7
| |ooooo 'ooor " 7oooooooo| |
| Jooor |o| '"" "oor .J
| oo| "o| _oo
| 'or _ | " |
| ""` |
| .,' ___. .______________ |
| ______________ooo` ._JLooooooooooooooooooooooooooooooooooooo" |
| |L7ooooooooooooooooL___,.Jo_Jooooooooooooooooooooooooooooooooooooooooooor` |
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo

AWAITING FIRST STRIKE COMMAND
-----------------------------

PLEASE SPECIFY PRIMARY TARGET
BY CITY AND/OR COUNTRY NAME:

''')
target = input()

t.typewriteln("\nPREPARING NUCLEAR STRIKE FOR " + target.upper())
t.typewrite("ENTER LAUNCH CODE: ")
launch_code = input().encode()

# encoding map coordinates
x = list(launch_code.ljust(16, b'\0'))
b = 16 * [None]

# calculate missile trajectory
b[0] = x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[11] ^ x[14]
b[1] = x[0] ^ x[1] ^ x[8] ^ x[11] ^ x[13] ^ x[14]
b[2] = x[0] ^ x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[9] ^ x[10] ^ x[13] ^ x[14] ^ x[15]
b[3] = x[5] ^ x[6] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[15]
b[4] = x[1] ^ x[6] ^ x[7] ^ x[8] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[5] = x[0] ^ x[4] ^ x[7] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[6] = x[1] ^ x[3] ^ x[7] ^ x[9] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[15]
b[7] = x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[10] ^ x[11] ^ x[14]
b[8] = x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[12]
b[9] = x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[15]
b[10] = x[0] ^ x[3] ^ x[4] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[14] ^ x[15]
b[11] = x[0] ^ x[2] ^ x[4] ^ x[6] ^ x[13]
b[12] = x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[10] ^ x[12] ^ x[15]
b[13] = x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7] ^ x[11] ^ x[12] ^ x[13] ^ x[14]
b[14] = x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[7] ^ x[11] ^ x[13] ^ x[14] ^ x[15]
b[15] = x[1] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[13] ^ x[15]

if b == h:
t.typewriteln("LAUNCH CODE ACCEPTED.\n\n*** RUNNING SIMULATION ***\n")
random.shuffle(STRATEGIES)
for i in range(0, len(STRATEGIES), 6):
t.write('\n'.join('{:24} {:8}'.format(k, v) for k, v in ([('STRATEGY:', 'WINNER:'), ('-' * 24, '-' * 8)] + [(_, 'NONE') for _ in STRATEGIES[i:i+6]])) + '\n\n')
time.sleep(0.5)
t.typewriteln("*** SIMULATION COMPLETED ***\n")
t.typewriteln('\nA STRANGE GAME.\nTHE ONLY WINNING MOVE IS\nNOT TO PLAY.\n')
eye = [219, 232, 81, 150, 126, 54, 116, 129, 3, 61, 204, 119, 252, 122, 3, 209, 196, 15, 148, 173, 206, 246, 242, 200, 201, 167, 2, 102, 59, 122, 81, 6, 24, 23]
flag = fire(eye, launch_code).decode()
t.typewrite(f"CONGRATULATIONS! YOU FOUND THE FLAG:\n\n{flag}\n")
else:
t.typewrite("\nIDENTIFICATION NOT RECOGNIZED BY SYSTEM\n--CONNECTION TERMINATED--\n")

当值为0的时候,会取本身进程的句柄,因为是单独跑python脚本的,所以得稍微改下,改成

trust = pydll.LoadLibrary(r'F:\copy.exe')._handle

完整代码如下:

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
# -*- coding:utf-8 -*-
from ctypes import *
import struct
import hashlib
def wrong():
trust = pydll.LoadLibrary(r'F:\copy.exe')._handle

computer = string_at(trust, 1024)
# print(computer)

dirty, = struct.unpack_from('=I', computer, 60)

_, _, organize, _, _, _, variety, _ = struct.unpack_from('=IHHIIIHH', computer, dirty)
assert variety >= 144

participate, = struct.unpack_from('=I', computer, dirty + 40)
for insurance in range(organize):
name, tropical, inhabitant, reader, chalk, _, _, _, _, _ = struct.unpack_from('=8sIIIIIIHHI', computer, 40 * insurance + dirty + variety + 24)
if inhabitant <= participate < inhabitant + tropical:
break

spare = bytearray(string_at(trust + inhabitant, tropical))

issue, digital = struct.unpack_from('=II', computer, dirty + 0xa0)
truth = string_at(trust + issue, digital)

expertise = 0
while expertise <= len(truth) - 8:
nuance, seem = struct.unpack_from('=II', truth, expertise)

if nuance == 0 and seem == 0:
break

slot = truth[expertise + 8:expertise + seem]

for i in range(len(slot) >> 1):
diet, = struct.unpack_from('=H', slot, 2 * i)
fabricate = diet >> 12
if fabricate != 3: continue
diet = diet & 4095
ready = nuance + diet - inhabitant
if 0 <= ready < len(spare):
struct.pack_into('=I', spare, ready, struct.unpack_from('=I', spare, ready)[0] - trust)

expertise += seem
with open('md5.bin','wb') as f:
f.write(spare)
return hashlib.md5(spare).digest()

# def main():
# print wrong().encode('hex')

# print 'end.'

if __name__ == '__main__':
print(wrong())

得到MD5后反算求 lauchcode,利用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

from z3 import *
import string

xor = [212, 162, 242, 218, 101, 109, 50, 31, 125, 112, 249, 83, 55, 187, 131, 206]

b = [0xa7,0xbf,0xd2,0x9e,0x0f,0x01,0x6b,0x53,0x68,0x37,0xb7,0x60,0x7c,0xba,0xb4,0xa8]

b = [b[i] ^ xor[i] for i in range(16)]
print(b)


x=[BitVec('x[%d]' % i,8) for i in range(len(b))]

s = Solver()


s.add(b[0] == x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[11] ^ x[14])
s.add(b[1] == x[0] ^ x[1] ^ x[8] ^ x[11] ^ x[13] ^ x[14])
s.add(b[2] == x[0] ^ x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[9] ^ x[10] ^ x[13] ^ x[14] ^ x[15])
s.add(b[3] == x[5] ^ x[6] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[15])
s.add(b[4] == x[1] ^ x[6] ^ x[7] ^ x[8] ^ x[12] ^ x[13] ^ x[14] ^ x[15])
s.add(b[5] == x[0] ^ x[4] ^ x[7] ^ x[8] ^ x[9] ^ x[10] ^ x[12] ^ x[13] ^ x[14] ^ x[15])
s.add(b[6] == x[1] ^ x[3] ^ x[7] ^ x[9] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[15])
s.add(b[7] == x[0] ^ x[1] ^ x[2] ^ x[3] ^ x[4] ^ x[8] ^ x[10] ^ x[11] ^ x[14])
s.add(b[8] == x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[12])
s.add(b[9] == x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[15])
s.add(b[10] == x[0] ^ x[3] ^ x[4] ^ x[7] ^ x[8] ^ x[10] ^ x[11] ^ x[12] ^ x[13] ^ x[14] ^ x[15])
s.add(b[11] == x[0] ^ x[2] ^ x[4] ^ x[6] ^ x[13])
s.add(b[12] == x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[10] ^ x[12] ^ x[15])
s.add(b[13] == x[2] ^ x[3] ^ x[4] ^ x[5] ^ x[6] ^ x[7] ^ x[11] ^ x[12] ^ x[13] ^ x[14])
s.add(b[14] == x[1] ^ x[2] ^ x[3] ^ x[5] ^ x[7] ^ x[11] ^ x[13] ^ x[14] ^ x[15])
s.add(b[15] == x[1] ^ x[3] ^ x[5] ^ x[9] ^ x[10] ^ x[11] ^ x[13] ^ x[15])
s.add(x[11] > 30)

print(s.check())
answer=s.model()
print(answer)

# import string
# table = string.printable

求解 lauchcode

1
2
3
4
5
6
7
8
>>> x
[53, 67, 48, 71, 55, 84, 89, 50, 76, 87, 73, 50, 89, 88, 77, 66]

>>> s = ""
>>> for i in x:
... s += chr(i)
>>> s
'5C0G7TY2LWI2YXMB'

最后把lauchcode喂给程序即可

8 - snake

一个NES题目,通过选择process为6502进行反汇编

发现当分数为0x33,且游戏轮次为 4 的时候 可打印flag

或者我们直接将此处的

$F0的值修改为 26偏移处的值相等即可,利用 fceux 进行调试

9 - reloadered

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
a = [None for i in range(0xb)]
b = [0x7A,0x17,0x08,0x34,0x17,0x31,0x3B,0x25,0x5B,0x18,0x2E,0x3A,0x15,0x56,0x0E,0x11,0x3E,0x0D,0x11,0x3B,0x24,0x21,0x31,0x06,0x3C,0x26,0x7C,0x3C,0x0D,0x24,0x16,0x3A,0x14,0x79,0x01,0x3A,0x18,0x5A,0x58,0x73,0x2E,0x09,0x00,0x16,0x00,0x49,0x22,0x01,0x40,0x08,0x0A,0x14,0x00]

c = "@flare-on.com"
print(len(c))
print(len(b))
for j in range(10):
r = []
for i in range(len(c)):
r.append(chr(b[40-j+i]^ord(c[i])))
print("".join(r))




passwd = "3HeadedMonkey"
for j in range(10):
r = []
for i in range(len(b)):
r.append(chr(b[i]^ord(passwd[i % len(passwd)])))
print("".join(r))

10 - Mugatu

程序及dll的IAT项交换了。静态看不出到底调用了什么函数,需要还原。

程序模拟了勒索软件。从twitter的RSS中获取信息来编码目标机的环境信息,然后上传,得到返回的加密密钥。然后从资源中获取dll数据,并加载到内存,枚举盘符,搜索really, really, really, ridiculously good looking gifs文件夹,并加密其下的gif文件。加密算法采用tea。

解算比较简单。先把另一张图片解密,key在其文件名中已经给出。得到第二第图片的key的第一个字节。题目上中key的长度是4个字节。所以根据gif文件头爆破三个字节的key,然后解密

11 - avx2

考察avx2指令
VM代码解析如下:

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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
memset
vmovdqu_mm ptr[0] , 0x0000000000000000000000000000000000000000000000000000000000000000
vmovdqu_mm ptr[1] , 0x0000000000000000000000000000000000000000000000000000000000000000
vmovdqu_mm ptr[3] , 0x1A1B1B1B1A13111111111111111111151A1B1B1B1A1311111111111111111115
vmovdqu_mm ptr[4] , 0x1010101010101010080408040201101010101010101010100804080402011010
vmovdqu_mm ptr[5] , 0x0000000000000000B9B9BFBF041310000000000000000000B9B9BFBF04131000
vmovdqu_mm ptr[6] , 0x2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F2F
vmovdqu_mm ptr[10] , 0x0140014001400140014001400140014001400140014001400140014001400140
vmovdqu_mm ptr[11] , 0x0001100000011000000110000001100000011000000110000001100000011000
vmovdqu_mm ptr[12] , 0xFFFFFFFF0C0D0E08090A040506000102FFFFFFFF0C0D0E08090A040506000102
vmovdqu_mm ptr[13] , 0xFFFFFFFFFFFFFFFF000000060000000500000004000000020000000100000000
vmovdqu_mm ptr[16] , 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
vmovdqu_mm ptr[17] , 0x6A09E667BB67AE853C6EF372A54FF53A510E527F9B05688C1F83D9AB5BE0CD19
vmovdqu_mm ptr[18] , 0x428A2F9871374491B5C0FBCFE9B5DBA53956C25B59F111F1923F82A4AB1C5ED5
vmovdqu_mm ptr[19] , 0x0000000300000002000000010000000000000007000000060000000500000004
vmovdqu_mm ptr[20] , 0x0000000000000000000000000000000000000000000000000000000000000000
vmovdqu_mm ptr[21] , 0x0000000100000001000000010000000100000001000000010000000100000001
vmovdqu_mm ptr[22] , 0x0000000200000002000000020000000200000002000000020000000200000002
vmovdqu_mm ptr[23] , 0x0000000300000003000000030000000300000003000000030000000300000003
vmovdqu_mm ptr[24] , 0x0000000400000004000000040000000400000004000000040000000400000004
vmovdqu_mm ptr[25] , 0x0000000500000005000000050000000500000005000000050000000500000005
vmovdqu_mm ptr[26] , 0x0000000600000006000000060000000600000006000000060000000600000006
vmovdqu_mm ptr[27] , 0x0000000700000007000000070000000700000007000000070000000700000007
vpermd ptr[20] , ptr[0] , ptr[20]
vpermd ptr[21] , ptr[0] , ptr[21]
vpermd ptr[22] , ptr[0] , ptr[22]
vpermd ptr[23] , ptr[0] , ptr[23]
vpermd ptr[24] , ptr[0] , ptr[24]
vpermd ptr[25] , ptr[0] , ptr[25]
vpermd ptr[26] , ptr[0] , ptr[26]
vpermd ptr[27] , ptr[0] , ptr[27]
vpsrld ptr[7] , ptr[1] , 0x04
vpxor ptr[28] , ptr[20] , ptr[21]
vpxor ptr[28] , ptr[28] , ptr[22]
vpxor ptr[28] , ptr[28] , ptr[23]
vpxor ptr[28] , ptr[28] , ptr[24]
vpxor ptr[28] , ptr[28] , ptr[25]
vpxor ptr[28] , ptr[28] , ptr[26]
vpxor ptr[28] , ptr[28] , ptr[27]

vpand ptr[7] , ptr[7] , ptr[6]

vpslld ptr[29] , ptr[17] , 0x07 ror 25
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]


vpcmpeqb ptr[8] , ptr[1] , ptr[6] 0

vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B ror 11
vpor ptr[29] , ptr[29] , ptr[30]


vpxor ptr[15] , ptr[15] , ptr[29] (17 ror 25) ^ (17 ror 11)

vpcmpeqb ptr[8] , ptr[1] , ptr[6] 0

vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06 ror 6
vpor ptr[29] , ptr[29] , ptr[30]


vpxor ptr[15] , ptr[15] , ptr[29] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6)

vpxor ptr[29] , ptr[20] , ptr[16]
vpand ptr[30] , ptr[20] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30] ~ptr[20]^(ptr[20] & ptr[18] == ptr[18]


vpaddd ptr[15] , ptr[29] , ptr[15] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + (~ptr[20]^(ptr[20] & ptr[18])
vpaddd ptr[20] , ptr[15] , ptr[0] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + (`ptr[20]^(ptr[20] & ptr[18]) + i1
;vpaddb ptr[7] , ptr[8] , ptr[7] add 0

vpxor ptr[29] , ptr[20] , ptr[28]
vpermd ptr[17] , ptr[29] , ptr[19] low high swap 16bytes

vpshufb ptr[7] , ptr[5] , ptr[7] 7 = i2 >> 4 and 6 5 shuf 7

vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6)


vpaddb ptr[2] , ptr[1] , ptr[7] 2 = 1 + 7 (7 = i2 << 4 and 6 5 shuf 7)


vpxor ptr[29] , ptr[21] , ptr[16]
vpand ptr[30] , ptr[21] , ptr[18] ~ptr[21]^(ptr[21] & ptr[18])
vpxor ptr[29] , ptr[29] , ptr[30]


vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[21] , ptr[15] , ptr[0] ~ptr[21]^(ptr[21] & ptr[18]) + (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + i1


vpxor ptr[29] , ptr[21] , ptr[28]
vpermd ptr[17] , ptr[29] , ptr[19] low high swap 16bytes


vpxor ptr[20] , ptr[20] , ptr[21]



vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29] 17 ror 25) ^ (17 ror 11) ^ (17 ror 6)



vpmaddubsw ptr[7] , ptr[2] , ptr[10] 2 *+ 10


vpxor ptr[29] , ptr[22] , ptr[16]
vpand ptr[30] , ptr[22] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30] ~ptr[22]^(ptr[22] & ptr[18])


vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[22] , ptr[15] , ptr[0]
vpxor ptr[29] , ptr[22] , ptr[28] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[22]^(ptr[22] & ptr[18]) + p1) ^ 28
vpermd ptr[17] , ptr[29] , ptr[19] low high swap 16bytes



vpxor ptr[20] , ptr[20] , ptr[22]


vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6)


vpmaddwd ptr[2] , ptr[7] , ptr[11] 7 *+ 11


vpxor ptr[29] , ptr[23] , ptr[16]
vpand ptr[30] , ptr[23] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30]
vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[23] , ptr[15] , ptr[0]
vpxor ptr[29] , ptr[23] , ptr[28]
vpermd ptr[17] , ptr[29] , ptr[19] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[23]^(ptr[23] & ptr[18]) + p1) ^ 28


vpxor ptr[20] , ptr[20] , ptr[23]


vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpxor ptr[29] , ptr[24] , ptr[16]
vpand ptr[30] , ptr[24] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30]
vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[24] , ptr[15] , ptr[0]
vpxor ptr[29] , ptr[24] , ptr[28]
vpermd ptr[17] , ptr[29] , ptr[19] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[24]^(ptr[24] & ptr[18]) + p1) ^ 28



vpxor ptr[20] , ptr[20] , ptr[24]



vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpxor ptr[29] , ptr[25] , ptr[16]
vpand ptr[30] , ptr[25] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30]
vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[25] , ptr[15] , ptr[0]
vpxor ptr[29] , ptr[25] , ptr[28]
vpermd ptr[17] , ptr[29] , ptr[19] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[25]^(ptr[25] & ptr[18]) + p1) ^ 28


vpxor ptr[20] , ptr[20] , ptr[25]


vpshufb ptr[2] , ptr[2] , ptr[12] 2 shuf 12


vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpxor ptr[29] , ptr[26] , ptr[16]
vpand ptr[30] , ptr[26] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30]
vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[26] , ptr[15] , ptr[0] 17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[26]^(ptr[26] & ptr[18]) + p1)
vpxor ptr[29] , ptr[26] , ptr[28] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[26]^(ptr[26] & ptr[18]) + p1) ^ 28

vpermd ptr[17] , ptr[29] , ptr[19]


vpxor ptr[20] , ptr[20] , ptr[26]


vpslld ptr[29] , ptr[17] , 0x07
vpsrld ptr[30] , ptr[17] , 0x19
vpor ptr[15] , ptr[29] , ptr[30]
vpslld ptr[29] , ptr[17] , 0x15
vpsrld ptr[30] , ptr[17] , 0x0B
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]
vpslld ptr[29] , ptr[17] , 0x1A
vpsrld ptr[30] , ptr[17] , 0x06
vpor ptr[29] , ptr[29] , ptr[30]
vpxor ptr[15] , ptr[15] , ptr[29]

vpermd ptr[2] , ptr[2] , ptr[13]


vpxor ptr[29] , ptr[27] , ptr[16]
vpand ptr[30] , ptr[27] , ptr[18]
vpxor ptr[29] , ptr[29] , ptr[30]
vpaddd ptr[15] , ptr[29] , ptr[15]
vpaddd ptr[27] , ptr[15] , ptr[0] (17 ror 25) ^ (17 ror 11) ^ (17 ror 6) + ~ptr[27]^(ptr[27] & ptr[18]) + p1)
;vpxor ptr[29] , ptr[27] , ptr[28]
;vpermd ptr[17] , ptr[29] , ptr[19]
vpxor ptr[20] , ptr[20] , ptr[27]

vmovdqu_mm ptr[19] , 0x0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
vpand ptr[20] , ptr[20] , ptr[19]
vmovdqu_mm ptr[31] , 0x2176620C3A5C0F290B583618734F07102E332623780E59150C05172D4B1B1E22

输入参命令行参数传递。两个参数,第一个参数 9字节,程序中是明文校验。第二个参数32字节,通过反解VM代码获得的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
table = map(ord,string.letters+string.digits)
def crack(check):
t = [0x00, 0x10, 0x13, 0x04, 0xBF, 0xBF, 0xB9, 0xB9]
for a in table:
for b in table:
for c in table:
for d in table:
a1 = (t[a>>4]+a)&0xff
b1 = (t[b>>4]+b)&0xff
c1 = (t[c>>4]+c)&0xff
d1 = (t[d>>4]+d)&0xff
if ((a1*0x40+b1)*0x1000+(c1*0x40+d1)) &0xffffff == check:
print ''.join(map(chr,[a,b,c,d]))
return
print 'nope'

def main():
for i in [0x7070b2,0xac01d2,0x5e610a,0xa72aa8,0x081c86,0x1ae845,0xc829b2,0xf3a11e]:
crack(i)
print 'end.'

12 help

12题就比较蛋疼了…显示内存取证与流量分析

目说明中说环境crash了,直接windbg加载dmp文件,!analyze -v,原来是驱动man.sys导致的crash,把man.sys搞出来,PE头部已经丢了。里面还有个dll,根据调试信息是m.dll,而且发现其调试信息中的路径与man.sys类似,搜了下,内存里还加载过c.dll、n.dll、k.dll、s.dll、f.dll、driver1.sys。不过后面几个pe文件只有pe头部及小量的代码,大部分代码部分缺失。
根据调试信息及简单分析pe文件功能如下:

1
2
3
4
5
6
7
8
drive1.sys   shellcode  \\??\FLSC
man.sys id
m.dll cd listen port 4444 \\.\FLID
s.dll screenshot
n.dll network
f.dll file
c.dll crypto
k.dll keylog

简单看了下流量包,确定主控端ip为192.168.1.243,victim ip为192.168.1.244。
开始对比分析流量,发现端口4444,6666,7777,8888为之间通讯端口。4444端口为控制指令类数据,其它三个端口为victim向外传送的数据。网络包中的数据基本都加了一层异或处理,可以从4444端口的对比发现,6666及8888之间同一数据发两次,一次加了异或,一次没加,7777端口数据包较多,中间夹杂没加异或的数据包。

通过4444端口信息很简单就能解了最外层的异或。前4字节是数据长度,然后是4字节的指令,其它部分功能未知,应该是4字节+4字节+4字节子数据长度+子数据+unknow的结构。
有了外层数据包的编码方式,7777端口的数据就好解了,原来是bmp图片数据,去掉其中的未编码的数据,将\r\n替换成\n,然后将数据包分成各文件,根据异或值,填充下缺失的个别字节,然后解码去掉表示长度的4字节,图片就解码好了。图片是屏幕截图,有些操作命令行的,有些web浏览器的,最主要是打开keepass的操作,最后的图如下:

加图

根据图片内容,flag就在keepass的密码项中了。

又看了下其它的网络包,4444端口还发送了个文件和keepass的数据库名,文件应该就是上面说的driver1.sys,keepass数据库名应该是查找文件路径。
6666端口应该是发送keepass的数据库文件。

当时做题时漏了8888端口。于是开始开始在dmp文件中找keepass的信息,找到了数据库文件内容及加密过的masterkey和transfer_masterkey和对应的sessoion_key。于是乎就想办法解码原始key,看了keepass的源码,拿到了当前用户的masterkey,开始研究DPAPI。最后发现keepass的内存加密用了CRYPTPROTECTMEMORY_SAME_PROCESS标志,加入了进程信息,然后并不知参与加密的进程信息是什么,陷入僵局。

重新理思路,感觉应该漏了什么,通过volatility查看网络连接情况,发现漏了8888端口。此端口传送键盘记录信息,解了最外层的异或,子数据包并未能完全解码。子数据包编码方式与6666端口一致,通过keepass的数据文件内容,尝试异或解码,只解码部分数据,似乎编码加入了反馈机制。8888端口最后传送的就是keepass打开数据库时的键盘记录,传送的数据中可以正确解码标题部分Open Database - keys.kdb