Off by one overflow
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 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
단지 1바이트 오버플로우에 접근할 수 있다는 것은 공격자가 다음 청크의 size 필드를 변경할 수 있음을 의미합니다. 이는 실제로 어떤 청크들이 free되는지를 조작할 수 있게 하며, 잠재적으로 다른 합법적인 청크를 포함하는 청크를 생성할 수 있습니다. 익스플로잇 방법은 double free 또는 overlapping chunks와 유사합니다.
There are 2 types of off by one vulnerabilities:
- Arbitrary byte: 이 유형은 해당 바이트를 임의의 값으로 덮어쓸 수 있게 합니다
- Null byte (off-by-null): 이 유형은 해당 바이트를 오직 0x00으로만 덮어쓸 수 있게 합니다
- A common example of this vulnerability can be seen in the following code where the behavior of
strlenandstrcpyis inconsistent, which allows set a 0x00 byte in the beginning of the next chunk. - This can be expoited with the House of Einherjar.
- If using Tcache, this can be leveraged to a double free situation.
Off-by-null
```c // From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/ int main(void) { char buffer[40]=""; void *chunk1; chunk1 = malloc(24); puts("Get Input"); gets(buffer); if(strlen(buffer)==24) { strcpy(chunk1,buffer); } return 0; } ```다른 검사들과 함께, 이제 chunk가 free될 때마다 이전 previous size가 metadata의 chunk에 설정된 size와 비교되므로 이 공격은 2.28 버전부터 상당히 복잡해졌다.
Code example:
- https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c
- 이 공격은 Tcaches 사용으로 인해 더 이상 동작하지 않는다.
- 또한, 더 큰 chunks를 사용해(따라서 tcaches가 관여하지 않는) 악용을 시도하면 다음 오류가 발생한다:
malloc(): invalid next size (unsorted)
Goal
- 하나의 chunk가 다른 chunk 내부에 포함되도록 만들어, 두 번째 chunk에 대한 쓰기 접근으로 내부에 포함된 chunk를 덮어쓸 수 있게 한다
Requirements
- size metadata 정보를 변경할 수 있는 Off by one overflow
General off-by-one attack
- 세 개의 chunk
A,B및C를 할당한다(예: 크기 0x20). 그리고 top-chunk와의 consolidation을 방지하기 위해 추가 하나를 더 할당한다. C를 free한다(0x20 Tcache free-list에 삽입됨).A를 사용해B에 overflow를 발생시킨다. off-by-one을 악용해B의size필드를 0x21에서 0x41로 변경한다.- 이제
B는 free된 chunkC를 포함하게 된다. B를 free하고 0x40 크기의 chunk를 할당하면(해당 위치에 다시 배치된다).C는 여전히 free 상태이므로 그 안의fd포인터를 수정할 수 있다 (Tcache poisoning)
Off-by-null attack
- 연속으로 3개의 메모리 chunk(a, b, c)를 할당한 뒤 중간 chunk를 free한다. 첫 번째 chunk에는 off by one overflow 취약점이 있고 공격자는 이를 0x00으로 악용한다(이전 바이트가 0x10이었다면 중간 chunk가 실제보다 0x10 작다고 표시하게 된다).
- 그 다음 중간에 free된 chunk(b) 안에 더 작은 두 개의 chunk를 추가로 할당한다. 그러나
b + b->size가 가리키는 주소가 실제보다 작기 때문에 c chunk는 업데이트되지 않는다. - 그 후 b1과 c가 free된다.
c - c->prev_size가 여전히 b(현재 b1)를 가리키므로 두 개는 하나의 chunk로 병합된다. 하지만 b2는 b1과 c 사이에 여전히 남아 있다. - 마지막으로 새로 malloc을 수행하면 실제로 b2를 포함하는 이 메모리 영역을 회수하게 되어, 새 malloc의 소유자가 b2의 내용을 제어할 수 있게 된다.
This image explains perfectly the attack:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
Modern glibc hardening & bypass notes (>=2.32)
- Safe-Linking은 이제 모든 singly linked bin 포인터를
fd = ptr ^ (chunk_addr >> 12)로 저장해 보호하므로, size의 하위 바이트만 뒤집는 off-by-one은 보통 Tcache poisoning이 동작하기 전에 XOR 마스크를 재계산하기 위한 heap leak이 필요하다. - 실제로 leak 없이 쓸 수 있는 트릭은 포인터를 “double-protect“하는 것이다: 이미 제어하는 포인터를
PROTECT_PTR로 인코딩한 뒤, 같은 기법을 재사용해 위조한 포인터를 인코딩하면 정렬 검사(alignment check)가 새로운 주소를 노출하지 않고도 통과한다. - safe-linking + single-byte corruptions 작업 흐름:
- victim chunk를 제어하는 이미 가진 free된 chunk를 완전히 덮을 때까지 확장한다 (overlapping-chunk 설정).
- heap 포인터(stdout, UAF, 부분적으로 제어된 struct 등)를 leak하고 키
heap_base >> 12를 도출한다. - free-list 포인터를 쓰기 전에 재인코딩한다 — 인코딩된 값을 user data 안에 배치하고 single-byte 쓰기만 가능한 경우 나중에 memcpy로 옮긴다.
- 위조 포인터가 올바르게 인코딩되면 Tcache bin attacks와 결합해 할당을
__free_hook이나tcache_perthread_struct엔트리로 리다이렉트한다.
최신 익스플로잇을 디버깅할 때 인코드/디코드 단계를 연습하기 위한 최소한의 헬퍼:
def protect(ptr, chunk_addr):
return ptr ^ (chunk_addr >> 12)
def reveal(encoded, chunk_addr):
return encoded ^ (chunk_addr >> 12)
chunk = 0x55555555c2c0
encoded_fd = protect(0xdeadbeefcaf0, chunk)
print(hex(reveal(encoded_fd, chunk))) # 0xdeadbeefcaf0
최근 실제 표적: glibc __vsyslog_internal off-by-one (CVE-2023-6779)
- 2024년 1월 Qualys는 CVE-2023-6779을 상세히 설명했는데, 이는
__vsyslog_internal()내부의 off-by-one 취약점으로syslog()/vsyslog()의 포맷 문자열이INT_MAX를 초과할 때 발생하여 종료\0이 glibc 2.37–2.39 시스템에서 인접 청크의 가장 하위size바이트를 손상시킨다 (Qualys advisory). - 그들의 Fedora 38 exploit pipeline:
- 과도하게 긴
openlog()ident을 만들어vasprintf가 공격자가 제어하는 데이터 옆에 힙 버퍼를 반환하게 한다. - 이웃 청크의
size | prev_inuse바이트를 파괴하기 위해syslog()를 호출하고, 해당 청크를 free한 뒤 공격자 데이터와 중첩되도록 consolidation을 강제한다. - 중첩된 뷰를 이용해
tcache_perthread_struct메타데이터를 손상시키고 다음 할당이__free_hook를 가리키게 만든 다음system또는 root 권한을 위한 one_gadget으로 덮어쓴다.
- 테스트 하니스에서 손상 쓰기를 재현하려면, 거대한
argv[0]으로 fork하고openlog(NULL, LOG_PID, LOG_USER)를 호출한 다음syslog(LOG_INFO, "%s", payload)를 호출하라. 여기서payload = b"A" * 0x7fffffff;pwndbg의heap bins는 즉시 단일 바이트 덮어쓰기를 보여준다. - Ubuntu는 이 버그를 CVE-2023-6779로 추적하며, 이 동일한 INT truncation이 이 취약점을 신뢰할 수 있는 off-by-one primitive로 만든다고 문서화한다.
기타 예제 및 참고자료
- https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
- Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
- Off-by-one은
strlen이 다음 청크의size필드를 고려하기 때문에 발생한다. - Tcache가 사용되므로 일반적인 off-by-one 공격으로 Tcache poisoning을 통해 arbitrary write primitive를 얻을 수 있다.
- Asis CTF 2016 b00ks
- 문자열 끝의 0x00 바이트가 다음 필드에 의해 덮어써지기 때문에 off-by-one을 악용하여 힙에서 주소를 leak하는 것이 가능하다.
- Arbitrary write는 off by one 쓰기를 악용해 포인터가 가짜 포인터를 가진 가짜 struct가 만들어질 다른 위치를 가리키게 함으로써 얻는다. 그 다음 이 struct의 포인터를 따라가면 arbitrary write를 얻을 수 있다.
- 힙이 mmap으로 확장되면 mmap이 할당하는 메모리는 libc로부터 고정된 오프셋을 가지므로 libc 주소가 leak된다.
- 마지막으로 arbitrary write를 악용해
__free_hook주소에 one gadget을 써넣는다. - plaidctf 2015 plaiddb
- 사용자 입력 라인을 읽는
getline함수에 NULL off by one 취약점이 있다. 이 함수는 콘텐츠의 “key“를 읽는 데 사용되고 콘텐츠 자체를 읽는 데는 사용되지 않는다. - In the writeup 초기 5개의 청크가 생성된다:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400)는 top chunk와 consolidating되는 것을 피하기 위한 것이다
- 그다음 chunk 1, 5, 3이 free되어, 다음과 같이 된다:
-
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- 그 후 chunk3 (0x1f8)을 악용하여 null off-by-one을 이용해 prev_size를 `0x4e0`으로 쓴다.
- 초기에 할당된 chunks 1, 2, 5, 3의 크기와 그들 청크 4개의 헤더 크기 합이 `0x4e0`인 것을 주목하라: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- 그 다음 chunk 4가 free되어 시작지점까지 모든 청크를 소비하는 청크가 생성된다:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- 그 후 원래의 chunk 1을 채우기 위해 `0x200` 바이트를 할당한다
- 그리고 또 다른 0x200 바이트가 할당되어 chunk2가 파괴되므로, 따라서 fucking leak가 없어서 동작하지 않는다? 아마 이건 하면 안 될 것이다
- 그 다음 0x58개의 "a"로 다른 청크를 할당( chunk2를 덮어쓰고 chunk5에 도달)하고 chunk5의 fast bin 청크의 `fd`를 `__malloc_hook`를 가리키도록 수정한다
- 그 다음 0x68 크기의 청크를 할당하여 `__malloc_hook`에 있는 가짜 fast bin 청크가 다음 fast bin 청크가 되게 한다
- 마지막으로 새로운 0x68 fast bin 청크가 할당되고 `__malloc_hook`가 `one_gadget` 주소로 덮어써진다
## References
- [Qualys Security Advisory – CVE-2023-6246/6779/6780](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt)
- [Ubuntu Security – CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779)
- [Breaking Safe-Linking in Modern Glibc – Google CTF 2022 "saas" analysis](https://blog.csdn.net/2402_86373248/article/details/148717274)
> [!TIP]
> AWS 해킹 배우기 및 연습하기:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP 해킹 배우기 및 연습하기: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Azure 해킹 배우기 및 연습하기: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>HackTricks 지원하기</summary>
>
> - [**구독 계획**](https://github.com/sponsors/carlospolop) 확인하기!
> - **💬 [**디스코드 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 참여하거나 **트위터** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**를 팔로우하세요.**
> - **[**HackTricks**](https://github.com/carlospolop/hacktricks) 및 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.**
>
> </details>
HackTricks

