| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
- Router
- UART
- exploit
- 라우터
- 익스플로잇
- protection ring
- Kernel
- memory
- hardware hakcing
- tl mr 100
- Slab free list poisoning
- e
- mips
- linux ring 권한 구조
- physmap
- 공유기
- mr 100
- exit handler overwrite
- System Management Mode
- tp link
- SMM
- Cross-cache attack
- ROP
- Pwnable
- fini array
- 커널
- openwrt
- kernel exploit
- Today
- Total
haehet
heap exploit 정리 본문
지금까지 heap 관련된 공부를 해오면서 중요하다 생각한 부분을 정리하고자 한다. glibc 2.35를 기준으로 했으며 약간 내용이 두서가 없을 수도 있다.
1. tcache key && safe-linking
if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next), ++cnt)
{
if (cnt >= mp_.tcache_count)
malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}
}
tcache에는 fd옆에 key라는 변수가 있다. 만약 free할 때 fd 다음 위치에 key변수가 있으면 double free로 처리한다. 따라서 tcache dup을 하기 위해서는 key를 조금이라도 바꿔야한다.
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
tcache는 fd를 저장할 때 다음과 같이 현재 현재주소 >> 12와 주소를 xor해서 저장한다. 따라서 우리가 원하는 주소에 할당을 받기 위해서는 xor된 값을 넣어줘야 하므로 heap주소를 leak해야 한다.
위에서 설명한 것 말고도 tcache counts라는게 있어서 free된 개수를 넘어서 할당을 요청하면 free 목록에서 가져오지 않을 수 있다.
2. unsorted bin
어려운 힙 문제일수록 이 unsortedbin을 이용해야 해야하는게 많은 것 같다.
struct malloc_chunk {
size_t prev_size;
size_t size;
struct malloc_chunk* fd;
struct malloc_chunk* bk;
...
};
unsorted bin은 다음과 같은 구조를 가지는데 이때 fd, bk에는 main arena의 주소가 들어가므로 이 주소를 읽으면 libc leak이 가능해진다. 많은 heap 문제에서 libc leak을 할 때 이것을 이용한다. (간접적으로 size filed를 조작 후 free 해서 leak하는 방식도 많이 쓰인다.)
2-1. unsortedbin division
if (in_smallbin_range (nb) &&
bck == unsorted_chunks (av) &&
victim == av->last_remainder &&
(unsigned long) (size) > (unsigned long) (nb + MINSIZE))
{
/* split and reattach remainder */
remainder_size = size - nb;
remainder = chunk_at_offset (victim, nb);
unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;
av->last_remainder = remainder;
remainder->bk = remainder->fd = unsorted_chunks (av);
if (!in_smallbin_range (remainder_size))
{
remainder->fd_nextsize = NULL;
remainder->bk_nextsize = NULL;
}
set_head (victim, nb | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_head (remainder, remainder_size | PREV_INUSE);
set_foot (remainder, remainder_size);
check_malloced_chunk (av, victim, nb);
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
또한 unsorted bin이 있는 경우에는 unsorted bin에서 분할하여 청크를 나눠준다. 이를 이용하면 heap feng shui를 할 수 있다.
2-2. malloc consolidate
malloc consolidate는 다음 두가지 상황에서 일어난다.
// largebin 이상의 크기가 할당 되었을 때
else
{
idx = largebin_index (nb);
if (atomic_load_relaxed (&av->have_fastchunks))
malloc_consolidate (av);
}
// top chunk 확장 직후 0x10000이상 크기
if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
if (atomic_load_relaxed (&av->have_fastchunks))
malloc_consolidate(av);
malloc consolidate가 중요한 이유는 fast bin이 있을 때 이걸 호출하면 fast bin을 small bin, large bin으로 보낼 수 있다. 이때 이 fd 값은 libc 주소 또는 다른 heap 주소(safe-linking X)를 담고 있어서 leak하기 쉽다. 특정 상황에서 fd 위치에 문자열을 넣고 출력을 할 때 오염이 안된 주소를 leak하고 싶을 때 좋다. 또한 free 시 모든 chunk 중 unsorted bin을 먼저 확인하기 때문에 unsorted bin을 오염시킨 상황(fd 조작 등)이라면 빨리 복구하는 게 좋다.
2-3. large bin attack
large bin의 bk next size를 조작가능하면 원하는 주소에 큰 값을 넣을 수 있다.
https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c
how2heap/glibc_2.35/large_bin_attack.c at master · shellphish/how2heap
A repository for learning various heap exploitation techniques. - shellphish/how2heap
github.com
3. fastbin, calloc
3-1. fast bin dup
fastbin dup도 tcache 공격과 마찬가지로 safe-linking을 우회해야 한다. fast bin dup은 A - B - A 형식으로 하면 double free가 가능하다. 하지만 size에 대한 검증 부분이 있어서 할당 받고자 하는 곳에 size 필드가 있어야 검증에 안걸린다.
if (__glibc_likely (victim != NULL)) // size 체크
{
size_t victim_idx = fastbin_index (chunksize (victim));
if (__builtin_expect (victim_idx != idx, 0))
malloc_printerr ("malloc(): memory corruption (fast)");
check_remalloced_chunk (av, victim, nb);
또한 malloc를 이용해 할당을 하고 있다면 fastbin에서 tcache로 가져오기 때문에 fast bin dup 대신 Tcache Stashing Unlink Attack을 사용하면된다. https://github.com/shellphish/how2heap/blob/master/glibc_2.35/tcache_stashing_unlink_attack.c
fast bin dup을 사용하기 위해서는 calloc 함수를 사용해야 가능하다.
3-2. braking calloc
calloc는 is mapped bit가 설정되어 있으면 해당 청크를 0으로 초기화 하지 않는다. 이를 이용하면 leak을 쉽게 할 수 있다.
이번 글에서는 heap에 대한 다양한 기법에 대해 알아보았다. 이 기법 외에도 다른 기법, 알아야 할 사항이 많으니 더 공부를 하도록 하자.
references: https://elixir.bootlin.com/glibc/glibc-2.35/source/malloc/malloc.c#L4420, https://github.com/shellphish/how2heap
'Pwnable' 카테고리의 다른 글
| MIPS Architecture Exploitation (0) | 2026.05.01 |
|---|---|
| tcache_perthread_struct overwriting (0) | 2026.01.26 |
| FSOP 정리 (0) | 2025.11.08 |
| side channel attack(with assembly) (0) | 2025.10.02 |
| 프로그램 시작, 종료 과정 및 관련 취약점 분석 (0) | 2025.08.23 |
