small bin에서 bck->fd를 조작해서 임의의 주소에 청크를 할당할 수 있는 공격 기법이다.
- small bin 크기의 힙을 할당할 수 있어야함.
- small bin chunk를 조작할 수 있어야 함.
- heap leak이 요구됨.
if (in_smallbin_range (nb))
{
idx = smallbin_index (nb);
bin = bin_at (av, idx);
if ((victim = last (bin)) != bin)
{
if (victim == 0) /* initialization check */
malloc_consolidate (av);
else
{
bck = victim->bk;
if (__glibc_unlikely (bck->fd != victim))
{
errstr = "malloc(): smallbin double linked list corrupted";
goto errout;
}
set_inuse_bit_at_offset (victim, nb);
bin->bk = bck;
bck->fd = bin;
if (av != &main_arena)
set_non_main_arena (victim);
check_malloced_chunk (av, victim, nb);
_int_malloc의 일부이다.
nb가 smallbin range에 들어가면 위 로직이 실행된다.
nb로 smallbin index를 가져오고 idx에 저장한다.
arena의 bins[idx]가 bin에 저장된다.
last 매크로는 아래와 같다.
#define last(b) ((b)->bk)
bin->bk
가 bin
과 같은지 검사한다.
만약 bin->bk
과 bin
이 다르다면, small bin list에서 청크를 빼내는 작업이 진행된다.
victim
은 bin->bk
이고, bck
는 victim->bk
이다.
bck->fd
가 victim
과 같지 않으면 에러를 출력하고 종료된다.
일반적인 상황이라면 victim->bk
는 bck
라서 bck->fd
는 victim
이 되야 한다.
#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->size |= PREV_INUSE)
set_inuse_bit_at_offset 매크로는 위와 같다.
그냥 prev inuse bit를 세팅해주는 역할을 한다.
그리고 마지막으로 bin->bk = bck;
와 bck->fd = bin;
에 의해서 victim이 빠지고, circular doubly linked list가 다시 제대로 돌아온다.
victim->bk
를 fake chunk
로 돌린다.
이때 fake chunk
의 fd
는 victim
을 가리켜야한다.
victim을 가리키기 위해서 heap leak이 필요하다.
두번째 fake chunk는 malloc을 하면서 bck->fd != victim
를 우회하기 위해서 사용된다.