IT/시스템 보안

[Heap overflow] Heap overflow의 과정, Exploit, Countermeasures

kykyky 2024. 4. 21. 01:19

💡Heap overflow의 과정

 

✅예시 프로그램 코드

 

 

 

✅after strcpy(c, ...)

 

 

 

✅after free(b)

chunk B에 fd, bk 포인터가 생기며,

이것이 bin_forward, bin_back과 연결됨으로써, free된 chunk B는 bin에 들어간다.

 

 

✅after strcpy(a, ...) 

chunk A에, 이것의 크기에 비해 과분한 양의 string이 들어간다.

🚩

따라서 string은 chunk A의 data 공간을 다 채우고 나서 higher address 방향으로 흘러넘쳐 chunk B를 corrupt시킨다.

 

 

✅after free(a) 

chunk A도 free되어 fd, bk 포인터가 생겼고,

이 포인터들이 기존의 bin (free chunk list)과 연결됨으로써 chunk A도 list에 삽입된다.

 

🚩

이때, 두 free chunk A와 B는 chunk B의 unlink()를 통해 merge된다.

 

✅unlink()의 동작을 좀더 자세히 살펴보자.

세 node (chunk 1~3)가 이어진 double linked list가 있다 하면,

chunk 2를 이 list에서 없애는 것은

chunk 1, 3이 이제는 chunk 2를 못본 체하고 서로 연결되게 함으로써 구현된다.

 

(P->fd)->bk = P->bk
(P->bk)->fd = P->fd

 

이때 메모리는 아래와 같다.

chunk 1 chunk 2 chunk 3
address value address value address value
lower address          
$ prev_size   prev_size @ prev_size
  size   size   size
$ + 8 fd   fd = @   fd
  bk   bk = $ @ + 12 bk
higher address          

 

따라서, 식 ☆은 아래와 같아진다.

🚩

[@ + 12] = P->bk

[$ + 8] = P->fd

 

이제 다시 제대로된 표현으로 써보면...

[(P->fd) + 12] = P->bk

[(P->bk) + 8] = P->fd

 

 

💡Exploit

위 과정이 그래서 왜?! 공격에 활용되는 건지 알아보자.

 

✅by strcpy(a, ...)

chunk B의 fd field, bk field를 원하는 값으로 조작한다.

 

✅by free(a) 

이미 free돼있었던 chunk B의 바로 이전 인접한 chunk A가 free됨으로써, chunk B가 free list로부터 unlink될 수 있게 해준다.

 

✅by unlinking 

[(P->fd) + 12] = P->bk의 관계식이 성립된다.

위에서 chunk B의 fd와 bk를 원하는 값으로 조작한 것은, 이 단계에서 fd와 bk를 원하는 값으로 설정하기 위함이었던 것이다.

 

✅ 셸코드 실행

🚩

만약, 위 조작을 자알 해서 P->fd를 'printf()의 GOT 주소 - 12', P->bk를 '셸코드의 주소'로 조작한다면,

[printf()의 GOT 주소] = '셸코드의 주소' 가 됨으로써 GOT overwrite가 일어난다.

앞으로 printf()를 호출할 때면 나의 악의적 셸코드가 실행되는 것이다.

(물론, GOT 말고도 다른 위치도 충분히 오염시킬 수 있다: Return address, 함수 포인터, ...)

 

 

 

💡Countermeasures

 

✅Sanity check of heap metadata

마치 stack 영역의 canary와 비슷한 기능이다.

magic 값이 변경되면 corruption을 감지한다.

 

✅heap section의 execution 권한 없애기 

하지만 ROP, return to libc 공격에는 여전히 취약하다.

 

✅ASLR