hacktricks/binary-exploitation/libc-heap/double-free.md

6.3 KiB

더블 프리

{% hint style="success" %} AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks 지원
{% endhint %}

기본 정보

메모리 블록을 두 번 이상 해제하면 할당기의 데이터가 꼬일 수 있고 공격의 가능성이 열립니다. 다음은 그 과정입니다: 메모리 블록을 해제하면 해당 블록은 빈 청크 목록(예: "빠른 빈")으로 돌아갑니다. 같은 블록을 두 번 연속으로 해제하면 할당기가 이를 감지하고 오류를 발생시킵니다. 그러나 다른 청크를 해제한 후에 두 번 해제하면 더블 프리 확인이 우회되어 손상을 일으킵니다.

이제 malloc을 사용하여 새로운 메모리를 요청하면 할당기가 두 번 해제된 블록을 제공할 수 있습니다. 이는 두 개의 다른 포인터가 동일한 메모리 위치를 가리키도록 할 수 있습니다. 공격자가 이러한 포인터 중 하나를 제어하면 해당 메모리의 내용을 변경할 수 있으며, 이는 보안 문제를 일으키거나 코드 실행을 허용할 수 있습니다.

예시:

#include <stdio.h>
#include <stdlib.h>

int main() {
// Allocate memory for three chunks
char *a = (char *)malloc(10);
char *b = (char *)malloc(10);
char *c = (char *)malloc(10);
char *d = (char *)malloc(10);
char *e = (char *)malloc(10);
char *f = (char *)malloc(10);
char *g = (char *)malloc(10);
char *h = (char *)malloc(10);
char *i = (char *)malloc(10);

// Print initial memory addresses
printf("Initial allocations:\n");
printf("a: %p\n", (void *)a);
printf("b: %p\n", (void *)b);
printf("c: %p\n", (void *)c);
printf("d: %p\n", (void *)d);
printf("e: %p\n", (void *)e);
printf("f: %p\n", (void *)f);
printf("g: %p\n", (void *)g);
printf("h: %p\n", (void *)h);
printf("i: %p\n", (void *)i);

// Fill tcache
free(a);
free(b);
free(c);
free(d);
free(e);
free(f);
free(g);

// Introduce double-free vulnerability in fast bin
free(h);
free(i);
free(h);


// Reallocate memory and print the addresses
char *a1 = (char *)malloc(10);
char *b1 = (char *)malloc(10);
char *c1 = (char *)malloc(10);
char *d1 = (char *)malloc(10);
char *e1 = (char *)malloc(10);
char *f1 = (char *)malloc(10);
char *g1 = (char *)malloc(10);
char *h1 = (char *)malloc(10);
char *i1 = (char *)malloc(10);
char *i2 = (char *)malloc(10);

// Print initial memory addresses
printf("After reallocations:\n");
printf("a1: %p\n", (void *)a1);
printf("b1: %p\n", (void *)b1);
printf("c1: %p\n", (void *)c1);
printf("d1: %p\n", (void *)d1);
printf("e1: %p\n", (void *)e1);
printf("f1: %p\n", (void *)f1);
printf("g1: %p\n", (void *)g1);
printf("h1: %p\n", (void *)h1);
printf("i1: %p\n", (void *)i1);
printf("i2: %p\n", (void *)i1);

return 0;
}

이 예에서는 tcache를 여러 해제된 청크(7)로 채운 후 청크 h를 해제한 다음 청크 i를 해제하고 다시 h를 해제하여 이중 해제(또는 Fast Bin dup로 알려진)를 발생시킵니다. 이는 reallocating 시 메모리 주소가 겹치게되어 두 개 이상의 포인터가 동일한 메모리 위치를 가리킬 수 있는 가능성을 엽니다. 한 포인터를 통해 데이터를 조작하면 다른 포인터에 영향을 미칠 수 있어 심각한 보안 위험과 악용 가능성이 생깁니다.

실행하면 i1i2가 동일한 주소를 가지는 것을 확인할 수 있습니다:

초기 할당:
a: 0xaaab0f0c22a0
b: 0xaaab0f0c22c0
c: 0xaaab0f0c22e0
d: 0xaaab0f0c2300
e: 0xaaab0f0c2320
f: 0xaaab0f0c2340
g: 0xaaab0f0c2360
h: 0xaaab0f0c2380
i: 0xaaab0f0c23a0
재할당 후:
a1: 0xaaab0f0c2360
b1: 0xaaab0f0c2340
c1: 0xaaab0f0c2320
d1: 0xaaab0f0c2300
e1: 0xaaab0f0c22e0
f1: 0xaaab0f0c22c0
g1: 0xaaab0f0c22a0
h1: 0xaaab0f0c2380
i1: 0xaaab0f0c23a0
i2: 0xaaab0f0c23a0

예시

  • Dragon Army. Hack The Box
  • 크기 0x70을 제외한 Fast-Bin 크기의 청크만 할당할 수 있으며 일반적인 __malloc_hook 덮어쓰기를 방지합니다.
  • 대신 0x56으로 시작하는 PIE 주소를 Fast Bin dup의 대상으로 사용합니다(1/2 확률).
  • PIE 주소가 저장된 곳 중 하나는 main_arena에 있으며 Glibc 내부에 있으며 __malloc_hook 근처에 있습니다.
  • main_arena의 특정 오프셋을 대상으로 하여 해당 위치에 청크를 할당하고 __malloc_hook에 도달할 때까지 계속 청크를 할당합니다.
  • zero_to_hero. PicoCTF
  • Tcache bins 및 널 바이트 오버플로우를 사용하여 이중 해제 상황을 달성할 수 있습니다:
  • 크기 0x110의 세 개의 청크(A, B, C)를 할당합니다.
  • B를 해제합니다.
  • A를 해제하고 다시 할당하여 널 바이트 오버플로우를 사용합니다.
  • 이제 B의 크기 필드는 0x111이 아닌 0x100이므로 다시 해제할 수 있습니다.
  • 크기가 0x110인 Tcache-bin 하나와 주소가 동일한 크기가 0x100인 하나가 있습니다. 따라서 이중 해제가 발생합니다.
  • Tcache 독려를 사용하여 이중 해제를 활용합니다.

참고 자료