.............................................................................................................................................................................................................................................................미리보기 스포 방지.....................................................................................................................................................
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
release 부분에서 occupied에 대한 검사가 따로 없어서
UAF와 엮어서 double free가 가능하다는 것 까지는 파악하였고, safe link 가 돼있다는 것 까지는 알아냈습니다.
payload 구성을 cat의 포인터 배열을 통해 free의 got 를 system으로 덮어 system(/bin/sh)를 실행하는것이 답이라 생각하고 디버깅 중입니다.
다만 double free 이후에 이후에 할당된 청크를 조작하기 위해 처음 free 이후 see를 통해 xor 할 alue 를 알아넀다고 생각하고
1 0 (cat[0]에 처음 할당)
4 0 (cat[0] free)
2 0 (save link 의 xor 값 읽어서 변수 xorV로 저장)
1 1 (cat[1] 에 cat[0] 로 할당되었던 청크 할당)
4 0 (cat[1] 과 같은 청크이므로 free 가능)
3 1 'a'* 9 (cat[1] 을 통해 fd bk 값 오염)
4 0 (cat[1] 의 청크 double free)
1 2 (cat[2] 에 double free 된 청크 1번 할당)
3 2 p64(cats주소 혹은 GOT 값과 xorV가 xor 된 값)(safe link의 양식에 맞는 할당을 원하는 주소)
1 3 (cat[3] 에 double free 된 청크 2번째 할당. 이후 청크는 제가 조작한 cats 로 들어갈 것으로 생각)
1 4
마지막 1 4 과정에서 제가 원한 주소가 할당이 되어 cat[4] 가 제가 임의로 쓰고 읽을 수 있는 주소가 될 것이라고 기대했습니다. 하지만 새롭게 heap chunk 가 할당되었습니다.
제가 어디서 잘못 접근한 것인지 혹은 해결 방법에 대한 힌트를 조금 알려주실 수 있으실까요??
우리가 유심히 봐야 할 부분은 __libc_malloc()함수 부분입니다.
void *
__libc_malloc (size_t bytes)
{
mstate ar_ptr;
void *victim;
_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
"PTRDIFF_MAX is not more than half of SIZE_MAX");
if (!__malloc_initialized)
ptmalloc_init ();
#if USE_TCACHE
/* int_free also calls request2size, be careful to not pad twice. */
size_t tbytes;
if (!checked_request2size (bytes, &tbytes))
{
__set_errno (ENOMEM);
return NULL;
}
size_t tc_idx = csize2tidx (tbytes);
MAYBE_INIT_TCACHE ();
DIAG_PUSH_NEEDS_COMMENT;
if (tc_idx < mp_.tcache_bins
&& tcache
&& tcache->counts[tc_idx] > 0)
{
victim = tcache_get (tc_idx);
return tag_new_usable (victim);
}
DIAG_POP_NEEDS_COMMENT;
__libc_malloc함수는 초기에 tcache_perthread_struct head chunk를 구성합니다. (MAYBE_INIT_TCACHE) 이후 새로운 chunk에 대해서 할당이 요청되면, 아래부분
DIAG_PUSH_NEEDS_COMMENT;
if (tc_idx < mp_.tcache_bins
&& tcache
&& tcache->counts[tc_idx] > 0)
{
victim = tcache_get (tc_idx);
return tag_new_usable (victim);
}
DIAG_POP_NEEDS_COMMENT;
여기에서 기존에 들어있는 tcachebin이 있는지 확인하고 전역변수 victim을 tcache_get으로 가져온 chunk 주소로 설정하고 끝납니다.
중요한것은 tchache_get함수의 구조입니다.
static __always_inline void *
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
if (__glibc_unlikely (!aligned_OK (e)))
malloc_printerr ("malloc(): unaligned tcache chunk detected");
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
--(tcache->counts[tc_idx]);
e->key = 0;
return (void *) e;
}
tcache_get()함수는 tcachebin에 있는 chunk를 가져올때 tcache->counts를 -1합니다. 현재 질문자님 환경은 하나의 chunk를 가지고 DFB를 체인하여 fd를 조작하려는 것 같습니다. 하지만 하나의 chunk를 여러번 free하는 것은 가능하겠으나, tcache->counts는 계속 0에 머물러 있기 때문에 .. 아마 tcachebin의 fd를 조작해도 그쪽으로는 malloc하지않고 top chunk에서 split 하여 chunk를 할당하는 것으로 보입니다.
감이 좀 잡히시는지요..? chunk를 한번 여러개 만들어 보시면 될겁니다.