Unsorted Bin Attack

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 ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

์ž์„ธํ•œ ๋‚ด์šฉ์€ unsorted bin์ด ๋ฌด์—‡์ธ์ง€ ์ด ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

Bins & Memory Allocations

Unsorted ๋ฆฌ์ŠคํŠธ๋Š” ์ฒญํฌ์˜ bk ์ฃผ์†Œ์— unsorted_chunks (av)์˜ ์ฃผ์†Œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ณต๊ฒฉ์ž๊ฐ€ unsorted bin ์•ˆ์˜ ์ฒญํฌ์—์„œ bk ํฌ์ธํ„ฐ์˜ ์ฃผ์†Œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๊ทธ๋Š” ๊ทธ ์ฃผ์†Œ๋ฅผ ์ž„์˜์˜ ์ฃผ์†Œ์— ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด Glibc ์ฃผ์†Œ๋ฅผ leak ํ•˜๊ฑฐ๋‚˜ ์ผ๋ถ€ ๋ฐฉ์–ด๋ฅผ ์šฐํšŒํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์•ฝํ•˜์ž๋ฉด, ์ด ๊ณต๊ฒฉ์€ ์ž„์˜์˜ ์ฃผ์†Œ์— ํฐ ์ˆซ์ž ํ•˜๋‚˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด ํฐ ์ˆซ์ž๋Š” ํž™ ์ฃผ์†Œ๋‚˜ Glibc ์ฃผ์†Œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ ๋ชฉํ‘œ๋Š” ๋” ํฐ ์‚ฌ์ด์ฆˆ์˜ fast bin์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด global_max_fast ์˜€์Šต๋‹ˆ๋‹ค(์ฆ‰ unsorted bin attack์—์„œ fast bin attack์œผ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ).

  • Modern note (glibc โ‰ฅ 2.39): global_max_fast became an 8โ€‘bit global. Blindly writing a pointer there via an unsorted-bin write will clobber adjacent libc data and will not reliably raise the fastbin limit anymore. Prefer other targets or other primitives when running against glibc 2.39+. See โ€œModern constraintsโ€ below and consider combining with other techniques like a large bin attack or a fast bin attack once you have a stable primitive.

Tip

T> aking a look to the example provided in https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle and using 0x4000 and 0x5000 instead of 0x400 and 0x500 as chunk sizes (to avoid Tcache) itโ€™s possible to see that nowadays the error malloc(): unsorted double linked list corrupted is triggered.

Therefore, this unsorted bin attack now (among other checks) also requires to be able to fix the doubled linked list so this is bypassed victim->bk->fd == victim or not victim->fd == av (arena), which means that the address where we want to write must have the address of the fake chunk in its fd position and that the fake chunk fd is pointing to the arena.

Caution

์ด ๊ณต๊ฒฉ์€ unsorted bin(๋”ฐ๋ผ์„œ small, large๋„ ํฌํ•จ)์„ ์†์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด์ œ ์šฐ๋ฆฌ๋Š” fast bin์—์„œ์˜ ํ• ๋‹น๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋” ๋ณต์žกํ•œ ํ”„๋กœ๊ทธ๋žจ์€ ๋‹ค๋ฅธ ํ• ๋‹น์„ ํ•˜์—ฌ ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ์Œ). ๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ ค๋ฉด ๊ฐ™์€ ํฌ๊ธฐ๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ํฌ๋ž˜์‹œํ•ฉ๋‹ˆ๋‹ค.

global_max_fast๋ฅผ ๋ฎ์–ด์“ฐ๋ฉด ์ด ๊ฒฝ์šฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, fast bin์ด ์ต์Šคํ”Œ๋กœ์ž‡์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ๋ชจ๋“  ํ• ๋‹น์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ์ „๋žต์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

guyinatuxedo์˜ ์ฝ”๋“œ๋Š” ์ด๋ฅผ ๋งค์šฐ ์ž˜ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ malloc๋“ค์„ Tcache์— ๋น ์ง€์ง€ ์•Š๋„๋ก ์ถฉ๋ถ„ํžˆ ํฐ ๋ฉ”๋ชจ๋ฆฌ๋กœ ๋ฐ”๊พธ๋ฉด ์•ž์„œ ์–ธ๊ธ‰ํ•œ ์˜ค๋ฅ˜์ธ malloc(): unsorted double linked list corrupted ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ์“ฐ๊ธฐ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๋ฐฉ์‹

  • Unsorted-bin ์“ฐ๊ธฐ๋Š” free ์‹œ์—, ํ•ด์ œ๋œ ์ฒญํฌ๊ฐ€ unsorted ๋ฆฌ์ŠคํŠธ์˜ ํ—ค๋“œ์— ์‚ฝ์ž…๋  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฝ์ž… ๋™์•ˆ, allocator๋Š” bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งŒ์•ฝ free(victim)์„ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— victim->bk๋ฅผ (mchunkptr)(TARGET - 0x10)์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋งˆ์ง€๋ง‰ ๋ฌธ์žฅ์ด ์“ฐ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค: *(TARGET) = victim.
  • ์ดํ›„ allocator๊ฐ€ unsorted bin์„ ์ฒ˜๋ฆฌํ•  ๋•Œ, ์ •ํ•ฉ์„ฑ ๊ฒ€์‚ฌ๋กœ ์–ธ๋งํฌํ•˜๊ธฐ ์ „์— bck->fd == victim๊ณผ victim->fd == unsorted_chunks(av) ๊ฐ™์€ ๊ฒƒ๋“ค์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์‚ฝ์ž… ์‹œ ์ด๋ฏธ bck->fd(์šฐ๋ฆฌ์˜ TARGET)์— victim์„ ์ผ๊ธฐ ๋•Œ๋ฌธ์—, ์ด ์“ฐ๊ธฐ๊ฐ€ ์„ฑ๊ณตํ–ˆ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ๊ฒ€์‚ฌ๋Š” ๋งŒ์กฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„๋Œ€์  ์ œ์•ฝ (glibc โ‰ฅ 2.33)

ํ˜„์žฌ glibc์—์„œ unsortedโ€‘bin ์“ฐ๊ธฐ๋ฅผ ์‹ ๋ขฐ์„ฑ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•˜๋ ค๋ฉด:

  • Tcache ๊ฐ„์„ญ: tcache์— ํ•ด๋‹นํ•˜๋Š” ์‚ฌ์ด์ฆˆ์˜ ๊ฒฝ์šฐ free๋Š” tcache๋กœ ๋ถ„๊ธฐ๋˜์–ด unsorted bin์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ
    • ์š”์ฒญ์„ MAX_TCACHE_SIZE๋ณด๋‹ค ํฌ๊ฒŒ ํ•˜๊ฑฐ๋‚˜(๊ธฐ๋ณธ์ ์œผ๋กœ 64โ€‘bit์—์„œ โ‰ฅ 0x410), ๋˜๋Š”
    • ํ•ด๋‹น tcache bin์„ ์ฑ„์›Œ์„œ(7๊ฐœ ํ•ญ๋ชฉ) ์ถ”๊ฐ€ free๊ฐ€ ๊ธ€๋กœ๋ฒŒ bin์— ๋„๋‹ฌํ•˜๋„๋ก ํ•˜๊ฑฐ๋‚˜, ๋˜๋Š”
    • ํ™˜๊ฒฝ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด tcache๋ฅผ ๋น„ํ™œ์„ฑํ™”(์˜ˆ: GLIBC_TUNABLES glibc.malloc.tcache_count=0)ํ•ฉ๋‹ˆ๋‹ค.
  • Unsorted ๋ฆฌ์ŠคํŠธ์˜ ์ •ํ•ฉ์„ฑ ๊ฒ€์‚ฌ: ๋‹ค์Œ allocator ๊ฒฝ๋กœ์—์„œ unsorted bin์„ ๊ฒ€์‚ฌํ•  ๋•Œ glibc๋Š”(๋‹จ์ˆœํ™”) ๋‹ค์Œ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค:
    • bck->fd == victim ๋ฐ victim->fd == unsorted_chunks(av); ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด malloc(): unsorted double linked list corrupted๋กœ abortํ•ฉ๋‹ˆ๋‹ค.
  • ์ด๋Š” ํƒ€๊ฒŸ ์ฃผ์†Œ๊ฐ€ ๋‘ ๋ฒˆ์˜ ์“ฐ๊ธฐ๋ฅผ ๊ฒฌ๋ŽŒ์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค: ๋จผ์ € free ์‹œ์— *(TARGET) = victim; ๋‚˜์ค‘์— ์ฒญํฌ๊ฐ€ ์ œ๊ฑฐ๋  ๋•Œ *(TARGET) = unsorted_chunks(av)(allocator๊ฐ€ bck->fd๋ฅผ ๋‹ค์‹œ bin ํ—ค๋“œ๋กœ ๋ฎ์–ด์”€). ๋‹จ์ˆœํžˆ ํฐ ๋น„์˜(้ž้›ถ) ๊ฐ’์„ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•œ ํƒ€๊ฒŸ์„ ์„ ํƒํ•˜์„ธ์š”.
  • ํ˜„๋Œ€ ์ต์Šคํ”Œ๋กœ์ž‡์—์„œ์˜ ์ „ํ˜•์ ์ธ ์•ˆ์ •์  ํƒ€๊ฒŸ
    • โ€œํฐโ€ ๊ฐ’์„ ํ”Œ๋ž˜๊ทธ/ํ•œ๊ณ„๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋˜๋Š” ์ „์—ญ ์ƒํƒœ.
    • ๊ฐ„์ ‘ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ(์˜ˆ: ์ดํ›„์˜ [fast bin attack](Fast Bin Attack)์„ ์œ„ํ•ด ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ํ›„์† writeโ€‘whatโ€‘where๋กœ ํ”ผ๋ฒ—ํ•˜๊ธฐ ์œ„ํ•œ ์ค€๋น„).
    • ์ƒˆ๋กœ์šด glibc์—์„œ __malloc_hook/__free_hook๋Š” 2.34์—์„œ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค โ€” ์ด๋“ค์„ ๋ชฉํ‘œ๋กœ ์‚ผ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. glibc โ‰ฅ 2.39์—์„œ๋Š” global_max_fast ์—ญ์‹œ ํ”ผํ•˜์‹ญ์‹œ์˜ค(๋‹ค์Œ ๋…ธํŠธ ์ฐธ์กฐ).
  • global_max_fast์— ๊ด€ํ•˜์—ฌ ์ตœ๊ทผ glibc์—์„œ๋Š”
    • glibc 2.39+์—์„œ๋Š” global_max_fast๊ฐ€ 8โ€‘bit ์ „์—ญ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ ๋ฐฉ์‹๋Œ€๋กœ ํž™ ํฌ์ธํ„ฐ๋ฅผ ์—ฌ๊ธฐ์— ์“ฐ๋Š” ํŠธ๋ฆญ์€ ๋” ์ด์ƒ ๊น”๋”ํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์ธ์ ‘ํ•œ allocator ์ƒํƒœ๋ฅผ ์†์ƒ์‹œํ‚ฌ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ „๋žต์„ ์„ ํƒํ•˜์„ธ์š”.

์ตœ์†Œ ์ต์Šคํ”Œ๋กœ์ž‡ ๋ ˆ์‹œํ”ผ (modern glibc)

๋ชฉํ‘œ: ํฌ๋ž˜์‹œ ์—†์ด unsortedโ€‘bin ์‚ฝ์ž… ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์‚ฌ์šฉํ•ด ํž™ ํฌ์ธํ„ฐ ํ•˜๋‚˜๋ฅผ ์ž„์˜ ์ฃผ์†Œ์— ๋‹จ์ผ ์ž„์˜ ์“ฐ๊ธฐ๋กœ ๋‹ฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • Layout/grooming
    • tcache๋ฅผ ์šฐํšŒํ•  ๋งŒํผ ํฐ ์‚ฌ์ด์ฆˆ๋กœ A, B, C ํ• ๋‹น(์˜ˆ: 0x5000). C๋Š” top chunk์™€์˜ ํ†ตํ•ฉ(consolidation)์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์†์ƒ(Corruption)
    • A์—์„œ B์˜ ์ฒญํฌ ํ—ค๋”๋กœ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐํ•˜์—ฌ B->bk = (mchunkptr)(TARGET - 0x10)์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋ฆฌ๊ฑฐ(Trigger)
    • free(B). ์‚ฝ์ž… ์‹œ allocator๊ฐ€ bck->fd = B๋ฅผ ์‹คํ–‰ํ•˜๋ฏ€๋กœ ๊ฒฐ๊ณผ์ ์œผ๋กœ *(TARGET) = B๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  • ์ดํ›„(Continuation)
    • ๊ณ„์† ํ• ๋‹น์„ ์ง„ํ–‰ํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์ด unsorted bin์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด allocator๊ฐ€ ๋‚˜์ค‘์— *(TARGET) = unsorted_chunks(av)๋กœ ๋ฎ์–ด์“ธ ๊ฒƒ์ž„์„ ์˜ˆ์ƒํ•˜์„ธ์š”. ๋‘ ๊ฐ’ ๋ชจ๋‘ ์ผ๋ฐ˜์ ์œผ๋กœ ํฐ ๊ฐ’์ด๋ฉฐ, ๋‹จ์ง€ โ€œํฐโ€ ๊ฒƒ์„ ๊ฒ€์‚ฌํ•˜๋Š” ํƒ€๊ฒŸ์—์„œ๋Š” ์ด๊ฒƒ๋งŒ์œผ๋กœ๋„ ์‚ฌ์ด์ฆˆ/ํ•œ๊ณ„ ์˜๋ฏธ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Pseudocode skeleton:

// 64-bit glibc 2.35โ€“2.38 style layout (tcache bypass via large sizes)
void *A = malloc(0x5000);
void *B = malloc(0x5000);
void *C = malloc(0x5000); // guard

// overflow from A into Bโ€™s metadata (prev_size/size/.../bk). You must control B->bk.
*(size_t *)((char*)B - 0x8) = (size_t)(TARGET - 0x10); // write fake bk

free(B); // triggers *(TARGET) = B (unsorted-bin insertion write)

Note

โ€ข ๋งŒ์•ฝ size๋กœ tcache๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์—†๋‹ค๋ฉด, ์„ ํƒํ•œ ํฌ๊ธฐ์˜ tcache bin์„ (7๋ฒˆ frees) ์ฑ„์šด ํ›„ ์†์ƒ๋œ chunk๋ฅผ free ํ•˜์—ฌ free๊ฐ€ unsorted๋กœ ๊ฐ€๊ฒŒ ํ•˜์„ธ์š”. โ€ข ๋งŒ์•ฝ ํ”„๋กœ๊ทธ๋žจ์ด ๋‹ค์Œ allocation์—์„œ unsorted-bin ๊ฒ€์ฆ ๋•Œ๋ฌธ์— ์ฆ‰์‹œ abortํ•œ๋‹ค๋ฉด, victim->fd๊ฐ€ ์—ฌ์ „ํžˆ bin head์™€ ๊ฐ™์€์ง€, ๊ทธ๋ฆฌ๊ณ  ์ฒซ ๋ฒˆ์งธ ์“ฐ๊ธฐ ์ดํ›„์— ๋‹น์‹ ์˜ TARGET์ด ์ •ํ™•ํ•œ victim ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ๋‹ค์‹œ ํ™•์ธํ•˜์„ธ์š”.

Unsorted Bin Infoleak Attack

์‚ฌ์‹ค ์ด๊ฒƒ์€ ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. unsorted bin์˜ ์ฒญํฌ๋“ค์€ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. unsorted bin์˜ ์ฒซ ๋ฒˆ์งธ ์ฒญํฌ๋Š” ์‹ค์ œ๋กœ **fd**์™€ bk ๋งํฌ๊ฐ€ **main arena (Glibc)**์˜ ์ผ๋ถ€๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ, unsorted bin ์•ˆ์— ์ฒญํฌ๋ฅผ ๋„ฃ๊ณ  ์ด๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด (use after free), ๋˜๋Š” ์ ์–ด๋„ ํ•˜๋‚˜์˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ๋‹ค์‹œ ํ• ๋‹นํ•˜์—ฌ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด, Glibc info leak์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ ์‚ฌํ•œ attack used in this writeup์—์„œ๋Š” 4๊ฐœ ์ฒญํฌ ๊ตฌ์กฐ(A, B, C, D โ€” D๋Š” top chunk์™€์˜ consolidation์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•จ)๋ฅผ ์•…์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. B์—์„œ์˜ null byte overflow๋ฅผ ์ด์šฉํ•ด C๊ฐ€ B๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ B์˜ prev_size ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•ด ํฌ๊ธฐ๊ฐ€ B์˜ ํฌ๊ธฐ ๋Œ€์‹  A+B๊ฐ€ ๋˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ C๋ฅผ ํ•ด์ œํ•˜๊ณ  A+B๋กœ consolidate(ํ•ฉ์ณ์กŒ์Šต๋‹ˆ๋‹ค)ํ–ˆ์ง€๋งŒ B๋Š” ์—ฌ์ „ํžˆ ์‚ฌ์šฉ ์ค‘์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํฌ๊ธฐ A์˜ ์ƒˆ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•œ ๋’ค, libc์—์„œ leaked ๋œ ์ฃผ์†Œ๋“ค์„ B์— ์จ์„œ ๊ฑฐ๊ธฐ์„œ ์œ ์ถœ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ ๋ฐ ๊ธฐํƒ€ ์˜ˆ์ œ

  • https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap
  • ๋ชฉํ‘œ๋Š” ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ 4869๋ณด๋‹ค ํฐ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์จ flag๋ฅผ ์–ป๋Š” ๊ฒƒ์ด๋ฉฐ, PIE๋Š” ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ž„์˜ ํฌ๊ธฐ์˜ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ  ์›ํ•˜๋Š” ํฌ๊ธฐ์˜ heap overflow๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • ๊ณต๊ฒฉ์€ ์„ธ ๊ฐœ์˜ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค: overflow๋ฅผ ์•…์šฉํ•  chunk0, ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋  chunk1, ๊ทธ๋ฆฌ๊ณ  ์ด์ „ ๊ฒƒ๋“ค์ด top chunk์™€ consolidate๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  chunk2.
  • ๊ทธ๋‹ค์Œ chunk1์„ freeํ•˜๊ณ  chunk0์„ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์‹œ์ผœ chunk1์˜ bk ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค: bk = magic - 0x10
  • ๊ทธ ํ›„ chunk3์„ chunk1๊ณผ ๊ฐ™์€ ํฌ๊ธฐ๋กœ ํ• ๋‹นํ•˜๋ฉด unsorted bin attack์ด ๋ฐœ์ƒํ•˜๊ณ  ์ „์—ญ ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด flag๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html
  • merge ํ•จ์ˆ˜๋Š” ์ „๋‹ฌ๋œ ๋‘ ์ธ๋ฑ์Šค๊ฐ€ ๋™์ผํ•˜๋ฉด ํ•ด๋‹น ์˜์—ญ์— realloc์„ ์ˆ˜ํ–‰ํ•œ ๋’ค freeํ•˜์ง€๋งŒ, ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ•ด์ œ๋œ ์˜์—ญ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ, 2๊ฐœ์˜ ์ฒญํฌ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค: ์ž์‹ ๊ณผ ๋ณ‘ํ•ฉ๋  chunk0๊ณผ top chunk์™€์˜ consolidating์„ ๋ง‰๊ธฐ ์œ„ํ•œ chunk1. ๊ทธ๋Ÿฐ ๋‹ค์Œ merge ํ•จ์ˆ˜๊ฐ€ chunk0์œผ๋กœ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜์–ด use after free๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธํ›„ view ํ•จ์ˆ˜๊ฐ€ ์ธ๋ฑ์Šค 2(์‚ฌ์šฉ ํ›„ ํ•ด์ œ๋œ ์ฒญํฌ์˜ ์ธ๋ฑ์Šค)๋กœ ํ˜ธ์ถœ๋˜์–ด libc address๋ฅผ leakํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” **global_max_fast**๋ณด๋‹ค ํฐ ํฌ๊ธฐ๋งŒ mallocํ•˜๋„๋ก ๋ณดํ˜ธ๋˜์–ด ์žˆ์–ด fastbin์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ „์—ญ ๋ณ€์ˆ˜ global_max_fast๋ฅผ ๋ฎ์–ด์“ฐ๊ธฐ ์œ„ํ•ด unsorted bin attack์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋‹ค์Œ edit ํ•จ์ˆ˜๋ฅผ ์ธ๋ฑ์Šค 2(์‚ฌ์šฉ ํ›„ ํ•ด์ œ ํฌ์ธํ„ฐ)๋กœ ํ˜ธ์ถœํ•ด bk ํฌ์ธํ„ฐ๋ฅผ p64(global_max_fast-0x10)๋กœ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ƒˆ ์ฒญํฌ๋ฅผ ๋งŒ๋“ค ๋•Œ ์ด์ „์— ์กฐ์ž‘๋œ free ์ฃผ์†Œ(0x20)๊ฐ€ ์‚ฌ์šฉ๋˜์–ด unsorted bin attack์„ triggerํ•˜๊ณ  global_max_fast๋ฅผ ๋งค์šฐ ํฐ ๊ฐ’์œผ๋กœ ๋ฎ์–ด์จ์„œ ์ด์ œ fast bin์— ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด์ œ fast bin attack์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค:
  • ์šฐ์„  __free_hook ์œ„์น˜์—์„œ fast ํฌ๊ธฐ 200์˜ ์ฒญํฌ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ์Œ์ด ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค:
  • gefโžค  p &__free_hook
    

$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gefโžค x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000

  • ์ด ์œ„์น˜์— ํฌ๊ธฐ 0x200์˜ fast ์ฒญํฌ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์‹คํ–‰๋  ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด ํฌ๊ธฐ 0xfc์˜ ์ƒˆ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ํฌ์ธํ„ฐ๋กœ merged ํ•จ์ˆ˜๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด, fast bin์— ํฌ๊ธฐ 0xfc*2 = 0x1f8์ธ ํ•ด์ œ๋œ ์ฒญํฌ์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ ๋‹ค์Œ ์ด ์ฒญํฌ์—์„œ edit ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ์ด fast bin์˜ fd ์ฃผ์†Œ๋ฅผ ์ด์ „์˜ **__free_hook**์„ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ํ›„ fast bin์—์„œ ์ด์ „์˜ ์“ธ๋ชจ์—†๋Š” ์ฒญํฌ๋ฅผ ๊บผ๋‚ด๊ธฐ ์œ„ํ•ด ํฌ๊ธฐ 0x1f8์˜ ์ฒญํฌ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ , ๋˜ ๋‹ค๋ฅธ ํฌ๊ธฐ 0x1f8์˜ ์ฒญํฌ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด fast bin์˜ ์ฒญํฌ๊ฐ€ __free_hook ์œ„์น˜๋กœ ํ• ๋‹น๋˜์–ด ์ด๋ฅผ system ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฌธ์ž์—ด /bin/sh\x00๋ฅผ ๋‹ด์€ ์ฒญํฌ๋ฅผ delete ํ•จ์ˆ˜๋กœ freeํ•˜๋ฉด, **__free_hook**๊ฐ€ ํ˜ธ์ถœ๋˜์–ด /bin/sh\x00๋ฅผ ์ธ์ž๋กœ system์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html
  • 1B overflow๋ฅผ ์•…์šฉํ•ด ์ฒญํฌ๋ฅผ unsorted bin์—์„œ consolidateํ•˜์—ฌ libc infoleak์„ ์–ป๊ณ , ๊ทธ ํ›„ fast bin attack์„ ์ˆ˜ํ–‰ํ•ด malloc hook์„ one gadget ์ฃผ์†Œ๋กœ ๋ฎ์–ด์“ฐ๋Š” ๋˜ ๋‹ค๋ฅธ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค
  • Robot Factory. BlackHat MEA CTF 2022
  • 0x100๋ณด๋‹ค ํฐ ํฌ๊ธฐ์˜ ์ฒญํฌ๋งŒ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Unsorted Bin attack์œผ๋กœ global_max_fast๋ฅผ ๋ฎ์–ด์”๋‹ˆ๋‹ค (ASLR ๋•Œ๋ฌธ์— 1/16 ํ™•๋ฅ ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค โ€” ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋น„ํŠธ ์ˆ˜์™€ ๊ด€๋ จ).
  • Fast Bin attack์œผ๋กœ ์ „์—ญ ์ฒญํฌ ๋ฐฐ์—ด์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ž„์˜์˜ ์ฝ๊ธฐ/์“ฐ๊ธฐ primitive๋ฅผ ์–ป์–ด GOT์„ ์ˆ˜์ •ํ•˜๊ณ  ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ system์œผ๋กœ ํฌ์ธํŒ…ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ

  • Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
  • global_max_fast and related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c

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 ์ง€์›ํ•˜๊ธฐ