#ctf-wiki

##off-by-one

1-只能修改一个字节,溢出可控字节,通过修改堆块大小造成堆重叠从而覆盖或泄露其他数据。

2-溢出NULL字节可以使prev_inuse位被清0,前块会被认为是free块,从而造成堆重叠。

下面以该题作为演示

Asis CTF 2016 b00ks

__int64 __fastcall over_one(_BYTE *chunk, int size)
{
  int i; // [rsp+14h] [rbp-Ch]

  if ( size <= 0 )
    return 0LL;
  for ( i = 0; ; ++i )
  {
    if ( read(0, chunk, 1uLL) != 1 )
      return 1LL;
    if ( *chunk == 10 )
      break;
    ++chunk;
    if ( i == size )
      break;
  }
  *chunk = 0;
  return 0LL;
}

这里最后有NULL溢出。

.data:0000000000202010 chunk_array     dq offset unk_202060    ; DATA XREF: find_temp:loc_B38↑o
.data:0000000000202010                                         ; delet:loc_C1B↑o ...
.data:0000000000202018 off_202018      dq offset unk_202040    ; DATA XREF: change+15↑o

这里可以发现off_202018(author)与chunk_array只相差了0x20个字,因此我们可以写入0x20个字符,然后打印溢出chunk_array所存储的地址。

关键的地方来了,我们可以通过适当的调整size大小,使得prt_des的后两位正好是00,然后再修改author,使得chunk_array【0】指向了ptr_des。若此时我们再在des中伪造了一个结构体,并使chunk_array可以索引到book2,这样就形成了堆重叠。可以分配edit book1 ,book2来修改free_hook。

那么我们先create两个book,经过调试发现,当name_size为0x20时ptr_des的位置符合需求。而第二个book有通过vmmap泄露libc_base 的功能,所以需要很大的空间,使系统单独映射一段内存从而泄露libc

1.首先通过填满author泄露chunk_array【1】所存储的struct_book1 的地址。

2.在book1的des段填充数据使其存储book2的ptr_name ptr_des

3.然后通过打印泄露出book2的各种地址

4.之后再次填充author使得chunk_array【1】指向了book1的des段。

5.最后edit_book1写入free_hook,再edit_book2写入one_gadget,然后执行free函数即可get_shell

调试libc偏移