힙 오버플로우

Reading time: 6 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

기본 정보

힙 오버플로우는 스택 오버플로우와 비슷하지만 힙에서 발생합니다. 기본적으로 이는 힙에 데이터를 저장하기 위해 예약된 공간이 있고 저장된 데이터가 예약된 공간보다 크다는 것을 의미합니다.

스택 오버플로우에서는 명령 포인터나 스택 프레임과 같은 일부 레지스터가 스택에서 복원될 것이며 이를 악용할 수 있는 가능성이 있습니다. 힙 오버플로우의 경우, 기본적으로 힙 청크에 저장된 민감한 정보는 없습니다. 그러나 민감한 정보나 포인터일 수 있으므로, 이 취약점의 중요성어떤 데이터가 덮어씌워질 수 있는지와 공격자가 이를 어떻게 악용할 수 있는지에 따라 달라집니다.

tip

오버플로우 오프셋을 찾기 위해 스택 오버플로우와 동일한 패턴을 사용할 수 있습니다.

스택 오버플로우 vs 힙 오버플로우

스택 오버플로우에서는 취약점이 발생할 때 스택에 존재할 데이터와 배열이 상당히 신뢰할 수 있습니다. 이는 스택이 선형적이며, 항상 충돌하는 메모리에서 증가하고, 프로그램 실행의 특정 위치에서 스택 메모리는 보통 유사한 종류의 데이터를 저장하며 각 함수에서 사용되는 스택 부분의 끝에 특정 구조와 포인터가 있기 때문입니다.

그러나 힙 오버플로우의 경우, 사용된 메모리는 선형적이지 않으며 할당된 청크는 보통 메모리의 분리된 위치에 있습니다 (서로 인접하지 않음) 크기별로 할당을 구분하는 빈과 존 때문에 그리고 이전의 해제된 메모리가 새로운 청크를 할당하기 전에 사용되기 때문입니다. 힙 오버플로우에 취약한 객체와 충돌할 객체를 아는 것은 복잡합니다. 따라서 힙 오버플로우가 발견되면, 오버플로우될 수 있는 객체와 메모리에서 다음에 올 객체를 만들기 위한 신뢰할 수 있는 방법을 찾아야 합니다.

이러한 방법 중 하나는 힙 그루밍으로, 예를 들어 이 포스트에서 사용됩니다. 이 포스트에서는 iOS 커널에서 메모리 청크를 저장할 공간이 부족할 때, 커널 페이지로 확장하고 이 페이지를 예상 크기의 청크로 나누어 순서대로 사용되는 방법을 설명합니다 (iOS 버전 9.2까지, 이후에는 이러한 청크가 무작위로 사용되어 공격의 악용을 어렵게 만듭니다).

따라서 힙 오버플로우가 발생하는 이전 포스트에서는, 오버플로우된 객체가 피해자 객체와 충돌하도록 강제하기 위해 여러 kalloc이 여러 스레드에 의해 강제되어 모든 무료 청크가 채워지고 새로운 페이지가 생성되도록 시도합니다.

특정 크기의 객체로 이 채우기를 강제하기 위해, iOS 맥 포트와 관련된 아웃 오브 라인 할당이 이상적인 후보입니다. 메시지의 크기를 조정함으로써 kalloc 할당의 크기를 정확히 지정할 수 있으며, 해당 맥 포트가 파괴되면 해당 할당이 즉시 kfree로 반환됩니다.

그런 다음 이러한 자리 표시자 중 일부를 해제할 수 있습니다. kalloc.4096 무료 목록은 후입선출 방식으로 요소를 해제합니다, 이는 기본적으로 일부 자리 표시자가 해제되고 익스플로잇이 오버플로우에 취약한 객체를 할당하려고 할 때, 이 객체가 피해자 객체 뒤에 올 가능성이 높다는 것을 의미합니다.

예제 libc

이 페이지에서는 다음 청크의 prev in use 비트와 prev size의 위치를 덮어쓰는 방법을 보여주는 기본 힙 오버플로우 에뮬레이션을 찾을 수 있습니다. 이를 통해 사용 중인 청크를 통합(사용되지 않는 것처럼 보이게 함)하고 다시 할당하여 다른 포인터에서 사용 중인 데이터를 덮어쓸 수 있습니다.

protostar heap 0에서의 또 다른 예제는 힙 오버플로우를 악용하여 승리 함수 호출을 통해 플래그를 얻는 매우 기본적인 CTF 예제를 보여줍니다.

protostar heap 1 예제에서는 버퍼 오버플로우를 악용하여 근처 청크에 주소를 덮어쓸 수 있는 방법을 보여줍니다. 여기서 사용자의 임의 데이터가 기록될 것입니다.

예제 ARM64

페이지 https://8ksec.io/arm64-reversing-and-exploitation-part-1-arm-instruction-set-simple-heap-overflow/에서는 오버플로우된 청크의 다음 청크에 실행될 명령이 저장된 힙 오버플로우 예제를 찾을 수 있습니다. 따라서, 다음과 같은 간단한 익스플로잇으로 이를 덮어써서 실행될 명령을 수정할 수 있습니다:

bash
python3 -c 'print("/"*0x400+"/bin/ls\x00")' > hax.txt

다른 예시

  • Auth-or-out. Hack The Box
  • 우리는 Integer Overflow 취약점을 사용하여 Heap Overflow를 발생시킵니다.
  • 우리는 오버플로우된 청크의 struct 내부에 있는 함수에 대한 포인터를 손상시켜 system과 같은 함수를 설정하고 코드 실행을 얻습니다.

실제 사례: CVE-2025-40597 – __sprintf_chk의 오용

SonicWall SMA100 펌웨어 10.2.1.15에서 리버스 프록시 모듈 mod_httprp.so0x80-byte 힙 청크를 할당한 다음 __sprintf_chk를 사용하여 여러 문자열을 연결합니다:

c
char *buf = calloc(0x80, 1);
/* … */
__sprintf_chk(buf,               /* destination (0x80-byte chunk) */
-1,                /* <-- size argument   !!! */
0,                 /* flags */
"%s%s%s%s",      /* format */
"/", "https://", path, host);

__sprintf_chk_FORTIFY_SOURCE의 일부입니다. 양수 size 매개변수를 받으면 결과 문자열이 대상 버퍼에 맞는지 확인합니다. **-1 (0xFFFFFFFFFFFFFFFF)**을 전달함으로써 개발자들은 효과적으로 경계 검사를 비활성화하여 강화된 호출을 다시 고전적인, 안전하지 않은 sprintf로 되돌렸습니다.

따라서 지나치게 긴 Host: 헤더를 제공하면 공격자가 0x80 바이트 청크를 오버플로우하고 다음 힙 청크의 메타데이터를 덮어쓸 수 있습니다 (할당자에 따라 tcache / fast-bin / small-bin). 충돌은 다음과 같이 재현할 수 있습니다:

python
import requests, warnings
warnings.filterwarnings('ignore')
requests.get(
'https://TARGET/__api__/',
headers={'Host': 'A'*750},
verify=False
)

실용적인 악용은 heap grooming을 요구하여 취약한 청크 바로 뒤에 제어 가능한 객체를 배치해야 하지만, 근본 원인은 두 가지 중요한 교훈을 강조합니다:

  1. _FORTIFY_SOURCE는 만능 해결책이 아닙니다 – 오용하면 보호 기능이 무효화될 수 있습니다.
  2. 항상 올바른 버퍼 크기_chk 계열에 전달해야 합니다 (또는, 더 나은 방법은 snprintf를 사용하는 것입니다).

References

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기