문서의 각 단락이 어느 리비전에서 마지막으로 수정되었는지 확인할 수 있습니다. 왼쪽의 정보 칩을 통해 작성자와 수정 시점을 파악하세요.

W^X | |
정의 | 메모리 보호 기법 중 하나로, 메모리 페이지가 쓰기(W)와 실행(X) 권한을 동시에 가질 수 없도록 하는 보안 정책 |
유형 | 컴퓨터 보안 메모리 보호 |
주요 용도 | 버퍼 오버플로우 공격을 통한 악성 코드 실행 방지 |
관련 분야 | 운영체제 컴퓨터 아키텍처 |
최초 등장 | OpenBSD 3.3[1] |
상세 정보 | |
동작 원리 | 프로그램이 메모리에 코드를 쓰고(Write) 그 위치를 실행(Execute)하려 할 때, 두 작업 사이에 페이지 권한을 변경해야 하도록 설계됨 이는 대부분의 악성 코드가 취약점을 통해 메모리에 코드를 쓴 후 바로 실행하는 패턴을 차단함 |
구현 운영체제 | OpenBSD Linux (NX 비트) macOS (OS X 10.5 "Leopard"부터) Microsoft Windows (Windows XP SP2부터 Data Execution Prevention) |
하드웨어 지원 | NX 비트 (No-eXecute bit) AMD의 AMD64 아키텍처 Intel의 IA-32 아키텍처 (XD 비트) |
우회 기법 | Return-oriented programming (ROP) Just-in-time 컴파일 (JIT)을 이용한 코드 캐시 쓰기 메모리 권한을 변경하는 시스템 호출 (예: mprotect) 이용 |

W^X는 메모리 보호 기법의 하나로, 운영체제가 메모리 페이지에 대해 쓰기(W) 권한과 실행(X) 권한을 동시에 부여하지 못하도록 강제하는 보안 정책이다. 이 기법의 핵심은 어떤 메모리 영역이 쓰기가 가능하면 실행할 수 없고, 실행이 가능하면 쓰기를 할 수 없게 하는 데 있다. 이는 버퍼 오버플로우 공격과 같이 취약한 프로그램에 악성 코드를 주입하고 해당 메모리 영역을 실행하는 공격을 근본적으로 차단하기 위한 목적으로 설계되었다.
이 기법은 OpenBSD 프로젝트에서 처음으로 구현되어 널리 알려졌다. 최초로 공식 적용된 버전은 2003년 5월 1일에 출시된 OpenBSD 3.3이다. 이후 리눅스 커널의 PaX나 Exec Shield, macOS 및 iOS의 관련 보호 기능, 마이크로소프트 윈도우의 데이터 실행 방지(DEP) 등 다양한 현대 운영체제와 컴퓨터 아키텍처에 핵심적인 보안 기능으로 채택되었다.
W^X 정책은 컴퓨터 보안을 강화하는 중요한 도구로, 특히 코드 인젝션 공격을 효과적으로 억제한다. 메모리 영역이 '쓰기 가능'이면서 '실행 가능'한 상태, 즉 공격자가 악성 코드를 쓴 후 바로 실행할 수 있는 조건을 허용하지 않음으로써 보안 위협을 사전에 예방한다. 이는 응용 프로그램과 시스템 커널 모두의 안전성을 높이는 데 기여한다.

W^X는 메모리 보호 기법의 하나로, 메모리 페이지가 쓰기 권한과 실행 권한을 동시에 가질 수 없도록 강제하는 정책이다. 이는 버퍼 오버플로우와 같은 메모리 오염 취약점을 악용한 공격을 방지하기 위한 핵심 보안 모델로 발전했다. 전통적으로 운영체제는 프로그램의 코드 영역을 쓰기 가능하면서도 실행 가능하게 설정하는 경우가 있었는데, 이는 JIT 컴파일이나 셀프 수정 코드와 같은 특정 기능에 필요했기 때문이다. 그러나 이러한 관대한 권한 설정은 공격자가 데이터 영역에 악성 코드를 쓴 후 이를 실행하는 것을 가능하게 하는 보안상의 치명적 허점이 되었다.
W^X의 개념은 이러한 위협에 대한 대응으로 등장했다. 기본 원리는 단순하지만 강력하다. 하나의 메모리 페이지는 쓰기 가능하거나 실행 가능하거나, 아니면 아무 권한도 없어야 하며, 절대 두 권한을 동시에 가질 수 없다. 이는 공격자가 스택이나 힙과 같은 데이터 영역에 셸코드를 주입하더라도, 해당 영역이 실행 불가능하게 설정되어 있으면 코드를 실행할 수 없게 막는다. 이 정책은 운영체제 커널 수준에서 메모리 페이지의 권한 비트를 엄격히 관리함으로써 구현된다.
이 기법의 등장 배경에는 인터넷의 확산과 함께 원격 코드 실행 취약점을 통한 공격이 빈번해진 것이 있다. 웹 브라우저나 네트워크 서버와 같은 소프트웨어는 외부로부터의 입력을 처리하는 과정에서 버퍼 오버플로우에 취약할 수 있다. W^X는 이러한 공격 벡터를 근본적으로 차단하여, 취약점이 존재하더라도 실제 악성 코드의 실행으로 이어지는 것을 방지하는 추가적인 방어층을 제공한다. 이는 컴퓨터 보안에서 중요한 '다층 방어' 전략의 한 예가 된다.
W^X는 최초로 OpenBSD 프로젝트에서 2003년 5월 1일에 출시된 OpenBSD 3.3에 구현되었다[2]. 이후 이 개념은 리눅스 커널의 PaX나 Exec Shield, macOS 및 iOS의 관련 보호 기능, 그리고 마이크로소프트 윈도우의 데이터 실행 방지와 같은 형태로 현대 대부분의 주요 운영체제와 프로세서 아키텍처에 널리 채택되었다.

하드웨어에서 W^X를 지원한다는 것은 프로세서의 메모리 관리 장치(MMU)가 메모리 페이지에 대한 쓰기 권한과 실행 권한을 별도로 제어할 수 있는 기능을 갖추고 있음을 의미한다. 이는 운영체제가 소프트웨어적으로만 이 정책을 시행하는 것보다 더 강력하고 효율적인 보호를 가능하게 한다.
초기 x86 아키텍처에서는 메모리 페이지의 권한 비트가 읽기, 쓰기, 실행을 명확히 구분하지 않았으나, 이후 등장한 NX 비트(No-eXecute bit)와 같은 하드웨어 기능이 이를 가능하게 했다. AMD는 이를 "실행 방지"(Execute Disable)라는 이름으로, 인텔은 "XD 비트"(eXecute Disable)라는 이름으로 각자의 CPU에 도입하였다. ARM 아키텍처 역시 비슷한 시기에 PXN(Privileged Execute Never) 및 XN(Execute Never) 비트를 도입하여 하드웨어 수준의 W^X 지원을 제공하기 시작했다.
이러한 하드웨어 지원은 운영체제 커널이 특정 메모리 영역을 '쓰기 가능' 또는 '실행 가능' 중 하나로만 설정할 수 있게 하여, 악의적인 코드가 데이터 영역(예: 스택 또는 힙)에 주입되어 실행되는 것을 근본적으로 차단한다. 따라서 버퍼 오버플로우 공격을 통한 익스플로잇 성공 가능성을 크게 낮춘다.
하드웨어 지원이 없는 구형 시스템에서는 운영체제가 소프트웨어 에뮬레이션 방식을 사용하여 W^X 정책을 시행할 수 있지만, 이는 성능 오버헤드가 발생하고 완전한 보호를 보장하기 어려운 한계가 있다. 따라서 현대적인 컴퓨터 보안에서는 하드웨어 수준의 W^X 지원이 필수적인 요소로 자리 잡았다.
W^X 정책을 소프트웨어적으로 구현하는 방식은 주로 운영체제의 메모리 관리자가 담당한다. 핵심 원리는 프로세스의 가상 메모리 공간에서 각 메모리 페이지에 부여된 권한을 엄격히 제어하는 것이다. 운영체제는 페이지가 코드로서 실행되려면 실행(X) 권한을 부여하고, 데이터를 쓰기 위해서는 쓰기(W) 권한을 부여하지만, 이 두 권한이 동시에 활성화되는 것을 시스템적으로 금지한다. 이는 커널 수준에서 메모리 맵을 관리하고 페이지 테이블 항목의 권한 비트를 설정함으로써 달성된다.
구체적인 구현은 시스템 호출과 링커, 로더의 동작을 수정하는 것을 포함한다. 예를 들어, 프로그램이 동적으로 코드를 생성하거나 수정해야 하는 경우(예: JIT 컴파일), 소프트웨어 구현은 해당 메모리 페이지에 대해 일시적으로 쓰기 권한을 부여한 후 코드를 작성하고, 즉시 쓰기 권한을 제거하고 실행 권한만을 설정하는 방식으로 동작한다. 이 과정은 원자적이어야 하며, 공격자가 쓰기와 실행이 동시에 가능한 짧은 창을 이용하지 못하도록 설계되어야 한다.
하드웨어 지원이 없는 오래된 CPU 아키텍처에서는 소프트웨어 구현에 한계가 있을 수 있다. 이러한 경우 에뮬레이션이나 특정 메모리 영역에 대한 감시를 통해 유사한 보호를 제공하려 시도할 수 있지만, 성능 저하가 크거나 완전한 보호를 보장하기 어려울 수 있다. 따라서 현대적인 구현은 가능한 한 MMU의 하드웨어 기능을 활용하여 효율적으로 W^X 정책을 적용한다.

W^X는 메모리 보호의 핵심 원칙으로, 버퍼 오버플로우와 같은 메모리 취약점을 악용한 공격을 효과적으로 차단한다. 이 기법의 기본 아이디어는 데이터 영역과 코드 영역을 명확히 분리하는 데 있다. 즉, 프로그램이 데이터를 쓰는 메모리 영역에서는 코드를 실행할 수 없도록 강제함으로써, 공격자가 스택이나 힙과 같은 데이터 영역에 주입한 악성 코드를 실행하는 것을 근본적으로 방지한다. 이는 코드 인젝션 공격에 대한 매우 강력한 방어선을 구축한다.
이 정책은 특히 쉘코드를 이용한 공격에 취약한 C 프로그래밍 언어와 같은 언어로 작성된 프로그램의 보안을 크게 향상시킨다. 공격자는 프로그램의 취약점을 통해 악성 명령어를 메모리에 쓰는 것은 가능할 수 있지만, W^X가 활성화된 환경에서는 해당 메모리 영역을 실행 가능하게 만드는 것이 차단된다. 결과적으로, 권한 상승이나 원격 코드 실행과 같은 심각한 보안 위협이 성공할 가능성을 현저히 낮춘다.
또한 W^X는 JIT 컴파일과 같은 정상적인 동적 코드 생성 작업에도 제약을 가할 수 있지만, 이는 안전한 메모리 영역을 별도로 마련하고 엄격한 권한 전환 절차를 통해 관리함으로써 해결된다. 이러한 설계는 시스템의 전반적인 보안 모델을 강화하여, 단일 응용 프로그램의 취약점이 전체 시스템의 무결성을 훼손하는 것을 방지하는 데 기여한다. 따라서 W^X는 현대 운영체제와 프로세서가 제공하는 필수적인 보안 기반 시설의 일부가 되었다.

W^X 정책을 적용하면 메모리 페이지의 권한을 전환하는 오버헤드가 발생하여 성능에 영향을 미칠 수 있다. 특히 JIT 컴파일을 사용하는 자바스크립트 엔진이나 가상 머신과 같이 코드를 동적으로 생성하고 실행하는 소프트웨어에서 성능 저하가 두드러질 수 있다. 이는 쓰기 가능한 메모리에 코드를 생성한 후, 실행하기 전에 해당 페이지의 권한을 쓰기에서 실행으로 명시적으로 변경해야 하기 때문이다. 일부 하드웨어에서는 이러한 권한 변경이 TLB 플러시를 유발하여 추가적인 성능 비용을 초래하기도 한다.
호환성 측면에서는 W^X가 기존 소프트웨어의 동작을 방해할 수 있다. 예를 들어, 실행 파일에 쓰기 가능한 코드 세그먼트가 있거나, 셀프 수정 코드를 사용하는 레거시 애플리케이션은 W^X 환경에서 정상적으로 작동하지 않을 수 있다. 또한, 보호 모드에서 실행되는 일부 오래된 바이너리나 특정 보안 소프트웨어가 메모리에 코드를 주입하는 방식을 사용한다면 호환성 문제가 발생할 수 있다.
이러한 성능 및 호환성 문제를 완화하기 위해 운영체제나 하드웨어는 다양한 최적화와 예외 조치를 도입한다. 대표적으로 리눅스 커널은 mprotect() 시스템 호출을 통한 권한 변경을 최소화하거나, 하드웨어 지원이 있는 경우 더 효율적인 권한 관리 방식을 사용한다. 호환성을 위해 일부 플랫폼에서는 특정 메모리 영역에 대해 W^X 정책을 완화하거나, 개발자에게 PIE와 같은 보안 컴파일 옵션의 사용을 권장하여 기존 코드의 수정 없이 정책을 준수할 수 있도록 한다.

OpenBSD는 W^X 정책을 최초로 도입하고 대중화한 운영체제이다. 이 운영체제는 2003년 5월 1일에 출시된 OpenBSD 3.3 버전부터 W^X를 기본 보안 기능으로 포함시켰다. 이는 메모리 페이지가 쓰기와 실행 권한을 동시에 가질 수 없도록 강제하여, 버퍼 오버플로우와 같은 메모리 오염 취약점을 악용한 공격을 효과적으로 차단하기 위한 목적이었다.
OpenBSD의 구현은 하드웨어의 메모리 관리 장치 지원을 적극 활용한다. 해당 아키텍처가 페이지 단위의 권한 설정을 지원할 경우, 커널은 코드를 로드하는 시점에 해당 페이지를 쓰기 가능하게 설정하고, 코드 로드가 완료되면 실행 가능하지만 쓰기는 불가능하게 권한을 변경한다. 이 방식은 소프트웨어 에뮬레이션에 의존하는 것보다 성능 저하가 적고 강제력이 뛰어나다.
OpenBSD의 철학은 보안을 기본값으로 설정하는 것이며, W^X 정책은 이러한 철학의 대표적인 실현 사례이다. 이 정책은 시스템의 모든 실행 파일과 공유 라이브러리에 적용되어, 악의적인 코드 주입 및 실행 시도를 근본적으로 방해한다. 결과적으로 OpenBSD는 높은 보안성으로 평가받으며, 이후 다른 주요 운영체제들이 유사한 메모리 보호 기법을 채택하는 데 영향을 미쳤다.
리눅스 커널은 W^X 보호를 점진적으로 도입했다. 초기에는 NX 비트를 지원하는 x86-64 아키텍처에서 이를 활용하는 방향으로 발전했으며, 이후 PaX나 Exec Shield와 같은 별도의 보안 패치를 통해 기능이 보강되기도 했다. 최신 리눅스 커널은 mmap 및 mprotect 시스템 호출을 통해 메모리 영역의 권한을 변경할 때 W^X 정책을 적용하여, 쓰기 가능한 페이지가 동시에 실행되는 것을 방지한다.
주요 구현 방식으로는 하드웨어 기반의 NX 비트 지원이 있으며, 이는 AMD의 "Enhanced Virus Protection"이나 인텔의 "Execute Disable Bit"과 같은 기능으로 알려져 있다. 하드웨어 지원이 없는 오래된 x86 프로세서의 경우, 소프트웨어 기반의 에뮬레이션을 통해 유사한 보호를 제공하기도 하지만, 이는 성능 저하를 동반할 수 있다.
리눅스 배포판들은 커널의 W^X 지원을 바탕으로 사용자 공간 프로그램에도 이 정책을 적용한다. 대표적인 예가 GCC 컴파일러와 GNU 링커를 통해 활성화되는 -z noexecstack 옵션이다. 이 옵션은 프로그램의 스택 메모리 영역에 실행 권한을 부여하지 않도록 하여, 스택 버퍼 오버플로우 공격을 통한 쉘코드 실행을 근본적으로 차단하는 데 기여한다.
macOS는 애플이 개발한 운영체제로, W^X 보안 정책을 적극적으로 도입하고 강화해 왔다. 이 정책은 애플의 XNU 커널과 시스템 라이브러리 수준에서 구현되어, 메모리 페이지가 쓰기와 실행 권한을 동시에 갖지 못하도록 강제한다. 이를 통해 버퍼 오버플로우와 같은 메모리 손상 취약점을 악용해 임의 코드를 실행하는 공격을 효과적으로 차단한다.
macOS에서 W^X는 하드웨어와 소프트웨어를 결합한 다층적 접근 방식으로 적용된다. 인텔 및 애플 실리콘 ARM 아키텍처의 메모리 관리 유닛이 제공하는 NX 비트 하드웨어 기능을 활용하여 실행 불가능한 메모리 영역을 표시한다. 동시에 커널과 링커는 프로그램 로딩 시 코드와 데이터 세그먼트를 명확히 분리하고, 주소 공간 배치 난수화와 같은 다른 보안 기법과 통합되어 보호를 강화한다.
주요 적용 사례로는 시스템 바이너리, 사파리의 자바스크립트 JIT 컴파일러 메모리, 그리고 게이트키퍼 및 시스템 무결성 보호와의 통합을 들 수 있다. 특히 JIT 컴파일과 같이 실행 가능한 메모리를 동적으로 생성해야 하는 경우, macOS는 특별히 할당된 'JIT 메모리' 영역을 사용하며, 이 영역은 필요 시에만 실행 권한이 부여되고 즉시 철회되는 방식으로 W^X 정책을 유지한다. 이러한 구현은 macOS의 전반적인 보안 모델의 핵심 요소로 자리 잡았다.
마이크로소프트의 윈도우 운영체제는 W^X 원칙을 실행 방지 보호라는 이름으로 구현한다. 이 기능은 데이터 실행 방지의 핵심 구성 요소로, 특히 버퍼 오버플로우 공격을 통한 셸코드 실행을 차단하는 데 목적이 있다.
윈도우의 실행 방지 보호는 하드웨어와 소프트웨어 수준에서 모두 동작한다. 하드웨어 지원이 가능한 시스템에서는 CPU의 NX 비트 기능을 활용하여 메모리 페이지에 실행 불가능 표시를 한다. 이 경우 커널이 페이지 테이블 엔트리의 해당 비트를 설정한다. 하드웨어 지원이 없는 오래된 시스템을 위해 소프트웨어 기반 에뮬레이션도 제공되지만, 성능과 보호 수준에서 제한이 따른다.
이 정책은 기본적으로 운영체제의 핵심 이미지와 특정 시스템 프로세스에 적용된다. 개발자는 링커의 /NXCOMPAT 옵션을 사용해 자신의 애플리케이션에 이 보호 기능을 명시적으로 활성화할 수 있다. 윈도우 비스타부터는 모든 사용자 모드 프로세스에 대해 실행 방지 보호가 기본적으로 켜져 있으며, 주소 공간 배치 난수화 등의 다른 보안 기능과 함께 통합되어 동작한다.

W^X 정책을 우회하려는 공격 기법이 존재하며, 이에 대한 대응책도 함께 발전해왔다. 대표적인 우회 기법으로는 JIT 컴파일을 악용하는 방법이 있다. JIT 컴파일러는 성능 최적화를 위해 런타임에 코드를 생성하고 실행하는데, 이 과정에서 쓰기 가능한 메모리 영역에 생성된 코드를 실행해야 한다. 공격자는 이를 악용해 악성 코드를 쓰기 가능한 메모리에 배치하고 JIT 엔진을 트리거하여 실행시킬 수 있다. 이에 대한 대응으로 Chrome의 V8 엔진과 같은 현대적 JIT 구현체는 W^X 원칙을 준수하면서도 성능을 유지하기 위해 메모리 권한을 상황에 따라 빠르게 전환하는 기법을 사용한다.
또 다른 우회 벡터는 공유 라이브러리와 가상 메모리 관리의 특성을 이용하는 것이다. 공격자는 ROP나 JOP와 같은 코드 재사용 공격을 통해 이미 실행 권한이 있는 시스템 라이브러리의 코드 조각들을 연결하여 악성 행위를 수행한다. 이는 W^X가 직접적인 코드 주입을 차단하더라도, 합법적으로 메모리에 존재하는 코드를 잘라서 엮는 방식으로 우회한다. 이를 방지하기 위해 ASLR과 같은 주소 공간 배치 난독화 기술이 W^X와 함께 결합되어 사용된다. ASLR은 라이브러리와 실행 파일이 메모리에 로드되는 주소를 무작위화하여 공격자가 필요한 코드 가젯의 위치를 예측하기 어렵게 만든다.
커널 수준에서의 우회 시도에 대응하기 위해, 리눅스 커널은 커널 모듈이 로드된 후 해당 메모리 영역의 쓰기 권한을 제거하는 방식으로 W^X를 적용한다. 또한, ret2dir과 같은 고급 공격은 커널의 물리 메모리 매핑을 악용하려 시도한다. 이러한 공격에 대항하기 위해 운영체제는 사용자 공간과 커널 공간의 페이지 테이블을 철저히 분리하거나, 쓰기 가능한 커널 메모리가 실행되지 않도록 하는 하드웨어 기능인 SMAP과 SMEP를 활용한다. 지속적인 공격 기법의 진화에 따라 W^X는 단일 기술이 아닌 메모리 보안을 위한 다층적 방어 체계의 핵심 구성 요소로서 그 역할을 수행하고 있다.
