(미할당)
🧟 해제 후 사용(UAF) 시뮬레이터 KISA A-5 · 해제된 자원 사용
객체가 해제됐는데 그 객체를 가리키던 포인터(이제 댕글링)가 계속 사용됩니다. 공격자가 해제된 슬롯에 조작된 객체를 재할당하면, 피해자가 낡은 포인터를 역참조할 때 공격자 데이터를 읽거나 실행하게 됩니다 — 전형적인 vtable/함수포인터 탈취.
① 힙 단계별 실행: 해제 → 재사용 → 역참조 VULNERABLE
Session 객체가 함수 포인터
onRender()를 가집니다. 단계를 진행하며 같은 힙 슬롯이 해제된 뒤 공격자에게 점거되는 동안 p가 계속 그 슬롯을 가리키는 것을 보세요.
피해자 포인터
Session* p
= 0x0
= 0x0
char* q (attacker)
= 0x0
= 0x0
힙 슬롯 @ 0xA10
0xA10
② 안전: 해제 후 NULL + 스마트 포인터 SECURE
free(p) 직후 p = NULL로 설정하면, 이후 사용은 공격자 데이터를 조용히 실행하는 대신 결정적으로(NULL 역참조) 크래시됩니다. 더 나은 방법: std::unique_ptr는 댕글링 사용 자체를 소유권/컴파일 단계에서 차단합니다.
③ 취약 vs 안전 코드
VULNERABLE — C++
Session* p = new Session(); // 0xA10
delete p; // 슬롯 해제, p는 그대로 0xA10
// ... 공격자가 같은 크기 버퍼 할당 → 0xA10 재사용 ...
char* q = (char*) malloc(sizeof(Session));
fill_with_payload(q); // q->vptr = &system
p->onRender(); // ← 해제된 포인터 역참조
// = 공격자가 심은 함수 포인터 호출 → RCE
SECURE — C / C++
// 1) 해제 후 즉시 무효화 Session* p = new Session(); delete p; p = nullptr; // 이후 p->... 는 결정적 크래시 if (p) p->onRender(); // NULL 가드로 안전 // 2) 소유권을 타입으로 강제 (권장) auto p = std::make_unique<Session>(); // p가 스코프를 벗어나면 자동 해제, // 댕글링/이중해제 자체가 발생하지 않음 p->onRender();
방어 핵심: 해제 직후 포인터를 NULL/nullptr로 무효화 · RAII 스마트 포인터(
unique_ptr/shared_ptr)로 소유권·수명을 타입으로 강제 · 소유 raw 포인터를 공유하지 말 것 · CI에서 강화 할당자/ASAN으로 UAF 조기 탐지.
⚠️ 교육용 시뮬레이션입니다. 힙·포인터·주소는 모두 mock JS 객체이며 실제 메모리를 할당·해제·역참조하지 않습니다.