본문 바로가기

system

[how2heap translation] house_of_lore.c

House of Lore - Malloc Maleficarum 의 확장된 공격

이 PoC 는 glibc 의 smallbin corruption 에 대해서도 다룬다.

 

 

이것은 glibc malloc 에서 동작하는 체크를 우회하기 위한 업그레이드 버전이다.

ubuntu 14.04.4 - 32bit - glibc-2.23 환경에서 테스트 되었다.

 

가장 먼저 stack_buffer_1 과 stack_buffer_2 의 주소 값들을 초기화한다.

그리고, victim chunk 를 100byte 크기만큼 할당한다.

victim : 0x804c008

 

 

victim_chunk 포인터 변수에 victim - 2 의 주소를 넣는다.

stack_buffer_1 : 0xbffff6c0

stack_buffer_2 : 0xbffff6b4

 

stack 에 fake chunk 를 만들어준다. small bin corrupted 체크를 우회하기 위해 fwd pointer 를 victim_chunk 로 설정한다. 

bk pointer 를 stack_buffer_2 로 설정한다. 그리고 fwd pointer 는 stack_buffer_1 을 가리켜야 한다.

이렇게 설정하게 되면 bck = victim->bk 체크를 우회할 수 있다.

 

 

free 함수 진행 중에 top chunk 와의 병합을 피하기 위해서 large chunk 를 하나 할당한다.

large chunk : 0x804c070

 

victim(0x804c008) 을 free 하고 그것은 unsorted bin 에 삽입될 것이다.

 

 

unsorted bin 안의 victim's fwd 와 bk 포인터들은 nil..

victim->fwd : 0xb7fc0450

victim->bk : 0xb7fc0450

 

이제 unsorted bin 또는 small bin 에 영향을 받지 않는 청크를 malloc 으로 할당하자.

이는 victim(0x804c008) 은 smallbin 의 맨 앞쪽에 삽입될 것이다.

 

 

p2 : 0x804c460

victim->fwd : 0xb7fc04b0

victim->bk : 0xb7fc04b0

 

victim chunk 는 정리되어지고 fwd 와 bk 포인터들은 업데이트 되었다.

 

 

이제 victim->bk pointer 를 stack_buffer_1 의 주소로 덮어써서 취약점을 에뮬레이팅 한다.

 

 

이제 처음 free 되었던 chunk 의 size 만큼 할당한다. 이는 덮어써진 victim chunk 를 return 하고 bin->bk 에 victim->bk 포인터가 들어간다.

결과적으로 bk 포인터를 조작하여 한번 더 malloc 을 했을 때 glibc 가 bin->bk 에 있는 chunk 를 리턴하게 된다.

 

The fwd pointer of stack_buffer_2 has changed after the last malloc to 0xb7fc04b0

p4 is 0xbffff6c8 and should be on the stack!

 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

문서를 보면서 따라했지만 조금 헷갈려서 내가 이해한 내용 정리.. (잘못 이해했다면 알려주시길..)

1. small bin 크기의 chunk 할당. -> top chunk 와의 병합을 피하기 위해 large chunk 하나 더 할당.

2. bck->fd != victim 을 우회하기 위해서 stack 에 fake chunk 설정해야함.

 

3. 이 fake chunk 가 어떻게 bck->fd != victim 을 우회할 수 있는지 그림을 통해 보자.

현재 p3 = malloc(100); 을 하기 바로 직전의 메모리 모습이다.

우리가 이전에 free 했던 chunk 와 같은 크기의 small bin chunk 를 할당할 때,

 

bck = victim->bk;

if (__glibc_unlikely(bck->fd != victim)) {

 

위와 같은 검증 과정을 거치게 된다. 이 때 victim : 0x0804c000 이고, victim->bk 는 우리가 overwrite 했던 stack_buffer_1(0xbffff6c0) 의 주소이다. 즉 bck = 0xbffff6c0 이 되고, bck->fd == 0xbffff6c0 + 0x8 과 동일하다.

위의 그림에서 0xbffff6c0 + 0x8 의 값은 0x0804c000 이고, bck->fd == victim 은 같으므로 검증을 우회한다.

즉, stack_buffer_1[2] = victim_chunk 를 넣은 이유는 이러한 검증 과정 우회를 위한 것이다.

 

4. 정상적으로 위의 검증을 우회하면

...

bin->bk = bck;

...

malloc 이 정상적으로 수행이 되고 이전에 free 했던 영역을 반환 받는다. 그리고 bin->bk 에 0xbffff6c0 값이 들어가게 되고, 마지막 malloc 은 glibc malloc 을 속여 bin->bk 에 삽입된 위치의 chunk 를 반환해야 한다.

즉, void *p4 = malloc(100); 을 수행하면서 p4 :0xbffff6c8 을 반환받는다.