2026 SPACE WAR - 02.TAURUS CTF 문제 풀이

0. 개요

문제 이름 : draft
문제 유형 : Pwnable

이 문제는 일반적인 heap 취약점이 아니라,
스택 lifetime 관리 실패로 인해 발생한 dangling pointer를 이용하는 문제다.

핵심은 매우 단순하다.
스택에 있던 데이터를 전역 포인터로 들고 있다가, 함수가 끝난 뒤에도 계속 사용하는 구조

이를 이용해:

  • 스택 메모리 leak
  • 스택 return address overwrite
  • libc ROP 실행

까지 이어지는 exploit chain을 구성할 수 있다.


1. 프로그램 구조

메뉴 구성:

  • compose
  • peek
  • amend
  • discard
  • quit

처음 보기에는 단순한 메모 프로그램처럼 보이지만,
내부 구현이 문제의 핵심이다.


2. 핵심 취약점

2-1. compose (문제의 시작)

1
2
3
4
5
6
7
8
void compose() {
char buf[0x80];

read_line(buf, 0x80);

global_draft_ptr = buf;
global_draft_len = strlen(buf);
}

buf는 스택 변수 그런데 이 주소를 전역 변수에 저장

결과

함수 종료 → buf 소멸 → global_draft_ptr는 dangling pointer
죽은 스택 프레임을 계속 참조


2-2. peek (스택 leak)

  • *(global_draft_ptr + off + i)

문제점:

  • off 검증 없음
  • 이미 invalid pointer 사용

결과:

  • 임의 offset으로 스택 메모리 읽기 가능
  • stack leak 가능

2-3. amend (스택 overwrite)

global_draft_ptr[global_draft_len + i] = ch;

문제점:

  • 여전히 dangling pointer 사용
  • write 위치 제한 없음

결과:
스택 위쪽 arbitrary write
return address overwrite 가능


3. 취약점 정리

이 문제는 두 가지가 결합된다.

  1. dangling stack pointer 생성
  2. read/write primitive 제공

결과:

  • peek → stack leak
  • amend → stack overwrite

4. 스택 leak

peek를 이용하면 다음 값들이 노출된다.

offset 0x88 → canary
offset 0x90 → saved rbp
offset 0x98 → PIE return
offset 0xd8 → libc return

계산:
libc_base = leaked_ret - 0x2a1ca
pie_base = leaked_ret - 0x178e

ROP 준비 완료


5. 공격 전략

5-1. 왜 amend의 return을 덮는가

일반적인 방법:
main return overwrite

하지만 더 쉬운 방법:
amend 함수의 return 바로 덮기

스택 구조:
[canary]
[saved rbp]
[saved rip]

여기만 정확히 덮으면 바로 ROP


5-2. 공격 흐름

  1. compose → dangling pointer 생성
  2. peek → canary + libc leak
  3. amend → 자신의 return overwrite
  4. 함수 종료 → ROP 실행

6. ROP 구성

사용 gadget (libc):
ret
pop rdi ; ret
system
exit

실행 명령:
cat /home/ctf/flag

ROP 체인:
ret
pop rdi
&”cat /home/ctf/flag”
system
exit

ret는 stack alignment 용


7. 익스플로잇 흐름

전체 흐름:

  1. compose (빈 문자열)
  2. peek → stack leak
  3. libc base 계산
  4. amend → payload writereturn → ROP 실행
  5. flag 출력

8. 전체 공격 흐름 정리

  1. 스택 dangling pointer 생성
  2. peek로 stack leak
    3 canary + libc 주소 획득
  3. amend로 stack overwrite
  4. return address 조작
  5. ROP 실행
  6. flag 획득

9. 포인트

이 문제의 포인트는 다음이다.

  • heap이 아니라 stack lifetime bug
  • local buffer를 global pointer로 저장
  • 함수 종료 후에도 계속 사용
  • read + write primitive 제공

매우 전형적인 실수지만 강력한 취약점


10. 정리

스택 버퍼의 lifetime을 잘못 관리하여 발생한 dangling pointer를 이용해 stack leak과 return overwrite를 수행하고 libc ROP로 flag를 획득하는 문제


11. 최종 플래그

1
hspace{my_dr4ft_0utl1v3d_1ts_0wn_st4ck_fr4me}