드림핵 시스템해킹 로드맵을 진행하던중 heap에 대한 배경지식 부족으로
Exploit Code이해에 어려움이 있어 이해하고자 여러 자료를 참고삼아 작성한 글입니다.
( 잘못 이해하거나 틀린점에 대한 조언은 언제나 환영입니다! )
Heap
먼저 heap 영역이란, malloc(), calloc() 같은 함수를 통해
동적으로 할당받는 메모리가 위치하는 영역을 말합니다.
보통 지역변수나 전역변수는 변수의 사이즈가 컴파일 시에 결정됩니다.
이렇게 선언된 변수의 사이즈는 고정값으로 변경하지 못하는데 컴파일 시 정해지지 않고
런타임 시에 변수의 사이즈가 정해지는 구조가 있는데 이런경우 힙 영역에 할당이 되는 것입니다.
즉 정리하면 heap 영역은 런타임때 할당메모리 크기가 결정되는
메모리가 위치하는 영역이라 볼 수 있습니다.
이때 힙영역은 스택과 마찬가지로 접근해 사용하고 수정이 가능해야 하기에
읽기, 쓰기 권한이 부여되고 스택에 침범하지 않기 위해 낮은 주소에서 높은 주소 방향으로 확장합니다.
Dynamic Memory Allocator
리눅스에서는 동적 메모리를 관리하기 위해
동적 메모리 할당자( Dynamic Memory Allocator )를 사용하고 있습니다.
이 할당자 (Allocator)는 명시적 할당자와 암시적 할당자로 나뉩니다.
할당자 | 내용 | 사용 예 |
명시적 할당자 (Explicit Allocator) | 개발자가 공간의 할당및 해제를 관리 | glibc 의 malloc, free |
암시적 할당자 (Implicit Allocator) | 개발자가 공간의 할당만 담당하고 Free는 내부적으로 처리 | Java의 GC, Lisp 등 |
할당자도 다시 또 여러 종류로 나뉘는데 참고한 자료를 가져와서 보면 다음과 같습니다.
Explicit Allocator | Description |
dlmalloc | 리눅스 초창기에 사용된 기본 메모리 할당자이다. dlmalloc에서 동일한 시간에 2개의 Thread가 malloc을 호출할 경우, freelist 데이터는 모두 사용가능한 Thread에 둘러싸인 상태로 공유되기 때문에 오로지 하나의 Thread만 임계영역에 들어갈 수 있다. 이러한 이유로 Multi Thread 어플리케이션에서는 성능 저하가 발생한다. |
ptmalloc2 | dlmalloc에서 Threading 지원 기능이 추가되었다. ptmalloc2는 glibc 소스 코드에 통합, 동일한 시간에 2개의 Thread가 malloc을 호출할 경우, 메모리는 각각의 Thread가 분배된 Heap 영역을 일정하게 유지하고, Heap을 유지하기 위한 freelist 데이터 또한 분배되어 있기 때문에 즉시 할당된다. |
Jemalloc | Jason Evans가 만들었으며, Facebook이나, Firefox에서 주로 사용한다. 단편화 방지 및 동시 확장성을 강조한 할당자이다. |
tcmalloc | 구글이 만든 성능 도구에 포함되어 있는 Heap Memory Allocator로서 크롬 및 많은 프로젝트에 사용된다. Multi Thread 환경에서 메모리 풀을 사용하는 속도를 개선하기 위한 목적으로 만들어졌다. 즉, 어플리케이션에서 따로 Thread 별로 메모리 풀 관리를 하지 않아도 되게 구현되어있다. |
주목할 것은 리눅스 유저모드에서 주로 사용되는 할당자 ptmalloc2입니다.
ptmalloc2의 설명을 보면 glibc의 소스코드에 통합되어 있다. 즉 리눅스의 glibc에서 사용되며
Thread가 malloc 호출경우 Heap 영역을 일정하게 유지한다고 합니다.
malloc_Chunk
그러면 위에서 설명한 대로 ptmalloc2를 통해 사용자가 heap 영역을 할당하거나 해제되는데
이때 청크(Chunk) 라는 단위로 이를 관리한다고 합니다.
malloc을 수행했을때의 청크를 살펴보면
( heap 영역은 낮은 주소에서 높은 주소로 확장 )
prev_size , size, p(flag), data 필드로 구성되어 있고
free 됬을때의 청크(chunk)를 보면
data부분이 fd와 bk로 바뀌어 있습니다 각각의 멤버들의 대한 설명을 보면 다음과 같습니다.
Member | Description |
prev_size | 이전 Heap Chunk가 해제되었을 경우 해제된 Heap Chunk의 크기를 저장한다. 해제되기 전까지는 이전 Heap Chunk의 데이터 영역으로 사용된다. |
size | 할당된 현재 Heap Chunk의 크기를 저장하고 있으며, 3개의 비트 Flag가 존재한다. |
Flags ( 3bit ) | - PREV_INUSE (P) : 해당 비트는 이전 Heap Chunk가 해제된 경우 설정된다. 1은 이전 Chunk가 해제되지 않았을 경우이고, 0은 이전 청크가 해제되었을 때 나타내는 값이다. - IS_MMAPPED (M) : 해당 비트는 현재 Chunk가 mmap 시스템 콜을 사용하여 할당된 경우 설정된다. - NON_MAIN_ARENA (N) : 해당 비트는 현재 Chunk가 main_arena 에서 관리하지 않을 경우에 설정된다. |
FD ( Forward Pointer ) | FD 포인터가 위치한 주소가 실제로 데이터 영역의 시작 부분이며, 할당되었을 때에는 사용하지 않는다. Heap Chunk 가 해제되었을 때 동일한 bin 에 존재하는 다음 Heap Chunk를 저장한다. |
BK ( Backward Pointer ) | 동일한 bin에서 이전 Free Chunk의 포인터를 가리킨다. |
bins
멤버의 구조들의 설명을 보다보면 계속 나오고 있는 bin이라는 구조는 무엇인가?
bin은 freelist data structures이며, free chunk들을 수용하는데 사용한다고 합니다.
무슨 말인지 찾아보니 메모리 낭비를 막기위해 해제된 청크를 재사용할수 있게 관리하는 구조라고 말할 수 있습니다.
청크를 관리할때 청크의 크키로 사용하는 bin이 달라지게 되며 Fast bin, unsorted bin, small bin, large bin 등이 있습니다.
각각 Fast bin은 청크의 크기가 16~64byte (x86), 32~128byte (x64) 인 경우,
unsorted bin, small bin은 size < 512byte (x86), size < 1024 (x64) 인경우,
Large bin은 size >= 512byte (x86), size >= 1024 (x64) 인 경우로 나뉩니다.
위에서 설명했듯이 리눅스를 기준으로 ptmalloc를 예시로 보면 128개의 bin이 존재한다고 하며
128개중 62개는 smallbin, 63개는 largebin, 1개는 unsortedbin으로 사용되며 나머지는 사용하지 않는다고 합니다.
Freelist
bin에서 애기한 freelist data structuresd에서
freelist 란 동적으로 메모리를 할당하고 해제할 때 메모리의 관리 효율을 높이기 위해
할당되지 않은 영역( 해제된 영역)을 관리하는 연결리스트라고 합니다.
영역을 해제할때 해제하려는 영역을freelist에 추가해 할당가능한 영역으로 구분해
할당요청이 들어오면 freelist에서 제거하고 해당영역을 사용하는 리스트 구조입니다.
bin은 종류에 따라 각 종류별로 나눠진후 Freelist로 들어가게 됩니다.
arena
arena는 힙 메모리의 인접지역을 말한는데
brk 시스템 콜을 사용하여 할당된 힙을 효율적으로 관리하기 위해 존재하는 malloc_state 구조체입니다.
만약main 스레드로에 생성되었다면 main arena라고 부르게 됩니다.
malloc를 통한 요청은 이 arena를 사용해 해당영역이 꽉찰 때까지 사용하는데
꽉찰 경우 데이터 세그먼트 영역을 확장시켜 Top Counk의 크기를 증가시켜 여분 공간을 가지게 확장합니다.
Top Chunk
Top Chunk는 Arena의 가장 상위 영역에 있는 청크를 말합니다.
맨 처음 malloc 호출시 사용자가 요청한 사이즈 만큼만이 아닌, 충분한 크기의 메모리를 받아오고
이 사이즈를 Top chunk에 넣습니다.
이후 Top Chunk를 분할하여 요청을 처리해 2개로 분할됩니다.
1. 사용자가 요청한 크기
2. 나머지 크기 <- 새로운 Top Chunk
만약 현재 Top Chunk보다 사용자가 요청한 크기가 큰 경우 또는 main_arena의 경우
brk 시스템 콜로 Top Chunk의 크기를 확장 시키고, thread_arena의 경우 mmap으로 새롭게 메모리를 받아오는 것으로
사용자의 요청을 수행하게 됩니다.
드림핵 로드맵 문제를 해결하기 위해 필요한 부분만 골라서 정리한 Heap내용 인데도 상당히 많은 양입니다.
문제를 진행하면서 필요한 내용들을 다음에 추가로 정리하겠습니다.
Reference
1. https://aidencom.tistory.com/194
2. https://jeongzero.oopy.io/bcb0067a-3d2d-4e00-b8e7-499fba15e1bb
3. https://hackyboiz.github.io/2022/01/14/poosic/linux-memory-layout/
'Reference > Pwnable_Study' 카테고리의 다른 글
tcache double free bypass (0) | 2023.02.12 |
---|---|
DFB(Double Free Bug) 취약점 (0) | 2023.01.19 |
OOB(Out of Bounds) 취약점 (1) | 2023.01.07 |
Pwndocker와 LD_PRELOAD, patchelf (libc 제공된 바이너리 문제) (0) | 2023.01.03 |
RELRO 과 Hook Overwrite, PIE (0) | 2023.01.01 |