staticsize_t _IO_obstack_xsputn (FILE *fp, constvoid *data, size_t n) { // 获取bobstack指针 structobstack *obstack = ((struct _IO_obstack_file *) fp)->obstack; // 检查是否有足够的写入空间, 没有的话,进入里面进行调整 if (fp->_IO_write_ptr + n > fp->_IO_write_end) { int size; // 调整缓冲区大小 /* We need some more memory. First shrink the buffer to the space we really currently need. */ obstack_blank_fast (obstack, fp->_IO_write_ptr - fp->_IO_write_end); // 将数据追加到obstack上 /* Now grow for N bytes, and put the data there. */ obstack_grow (obstack, data, n);
/* Setup the buffer pointers again. */ fp->_IO_write_base = obstack_base (obstack); fp->_IO_write_ptr = obstack_next_free (obstack); size = obstack_room (obstack); fp->_IO_write_end = fp->_IO_write_ptr + size; /* Now allocate the rest of the current chunk. */ obstack_blank_fast (obstack, size); } else// 有的话,就直接写入数据了 fp->_IO_write_ptr = __mempcpy (fp->_IO_write_ptr, data, n);
/* Allocate a new current chunk for the obstack *H on the assumption that LENGTH bytes need to be added to the current object, or a new object of length LENGTH allocated. Copies any partial object from the end of the old chunk to the beginning of the new one. */
void _obstack_newchunk (struct obstack *h, int length) { struct _obstack_chunk *old_chunk = h->chunk; struct _obstack_chunk *new_chunk; long new_size; long obj_size = h->next_free - h->object_base; long i; long already; char *object_base;
/* Compute size for new chunk. */ new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100; if (new_size < h->chunk_size) new_size = h->chunk_size;
/* Allocate and initialize the new chunk. */ new_chunk = CALL_CHUNKFUN (h, new_size); if (!new_chunk) (*obstack_alloc_failed_handler)(); .......... }
进入CALL_CHUNKFUN, 所以说这里两条触发路径其实都可以? 回头试试
1 2 3 4 5 6 7 8 9 10 11
/* Define a macro that either calls functions with the traditional malloc/free calling interface, or calls functions with the mmalloc/mfree interface (that adds an extra first argument), based on the state of use_extra_arg. For free, do not use ?:, since some compilers, like the MIPS compilers, do not allow (expr) ? void : void. */
structobstack /* controlcurrentobjectincurrentchunk */ { long chunk_size; /* preferred size to allocate chunks in */ struct _obstack_chunk *chunk;/* address of current struct obstack_chunk */ char *object_base; /* address of object we are building */ char *next_free; /* where to add next char to current object */ char *chunk_limit; /* address of char after current chunk */ union { PTR_INT_TYPE tempint; void *tempptr; } temp; /* Temporary for some macros. */ int alignment_mask; /* Mask of alignment for each object. */ /* These prototypes vary based on 'use_extra_arg', and we use casts to the prototypeless function type in all assignments, but having prototypes here quiets -Wstrict-prototypes. */ struct _obstack_chunk *(*chunkfun) (void *, long); void (*freefun) (void *, struct _obstack_chunk *); void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */ unsigned maybe_empty_object : 1; /* There is a possibility that the current chunk contains a zero-length object. This prevents freeing the chunk if we allocate a bigger chunk to replace it. */ unsigned alloc_failed : 1; /* No longer used, as we now call the failed handler on error, but retained for binary compatibility. */ };
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
/* The following pointers correspond to the C++ streambuf protocol. */ 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; int _flags2; __off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */ unsignedshort _cur_column; signedchar _vtable_offset; char _shortbuf[1];
_IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE };
攻击思路一
利用largebin attack伪造_IO_FILE,记完成伪造的chunk为A(或者别的手法)
chunk A内偏移为0x18处设为1(next_free)
chunk A内偏移为0x20处设为0(chunk_limit)
满足 _o->next_free + __len > __o->chunk_limit
chunk A内偏移为0x28处设为1(_IO_write_ptr)
chunk A内偏移为0x30处设为0 (_IO_write_end)
满足这个条件: fp-> _IO_write_ptr + n > fp-> _IO_write_end