[Pwn] Pwnable · 작성: 2026-07-19 19:31:03 · 조회 5
Stack Canary(스택 카나리)는 스택 버퍼 오버플로우로 리턴 주소가 덮이는 걸 막기 위한 보호 기법이다. 이름은 탄광에서 유독가스를 미리 감지하려고 데려간 카나리아 새에서 따왔다 — "뭔가 잘못됐다"를 미리 알려주는 역할이다.
함수 프롤로그(시작 부분)에서 지역 변수 바로 앞, 리턴 주소 바로 뒤에 랜덤 값을 하나 심어두고, 함수가 끝나기 직전(에필로그)에 그 값이 그대로인지 검사한다.
[ 지역 변수 buf ]
[ Canary ] <- 여기 값이 바뀌면 오버플로우가 있었다는 뜻
[ saved RBP ]
[ 리턴 주소 ]
버퍼 오버플로우로 리턴 주소까지 덮으려면 필연적으로 카나리 위치도 지나가야 하므로, 카나리 값이 바뀌면 프로그램은 리턴하기 전에 __stack_chk_fail을 호출해서 강제 종료한다. 즉 정확한 카나리 값을 모르면 오버플로우 자체는 되어도 익스플로잇으로 이어지지 않는다.
Format String 취약점이나 별도의 읽기 취약점으로 카나리 값을 먼저 알아낸 뒤, 그 값을 그대로 페이로드에 포함시켜 검사를 통과시킨다. 카나리는 항상 널바이트(0x00)로 시작하는데, 이건 printf류 문자열 출력 함수가 널바이트에서 멈추기 때문에 문자열 형태로 흘러나가는 걸 막기 위한 설계다.
구조체 안에 취약한 버퍼와 함수 포인터가 같이 있는 경우처럼, 스택 레이아웃에 따라 카나리를 지나지 않고도 원하는 값을 덮을 수 있는 경로가 있다면 그쪽을 노린다.
카나리 값은 TLS에 저장되는데, 별도의 임의 쓰기(arbitrary write) 취약점이 있다면 TLS에 저장된 마스터 카나리 값 자체를 덮어써서 이후 모든 함수의 검사를 무력화하는 방법도 있다 (상당히 고급 기법).
$ checksec ./vuln
Canary : Enabled
gdb에서 카나리 위치를 직접 확인하려면:
pwndbg> canary
Canary : 0x4a1b2c3d4e5f6700
카나리가 있으면 항상 "이걸 먼저 leak할 방법이 있는가"부터 찾는 게 순서다. 다음 글에서 다루는 NX 우회(ROP)와 결합해서 쓰는 경우가 대부분이다.