주소 공간 배치 무작위화

**주소 공간 배치 무작위화**(address space layout randomization, **ASLR**)는 메모리 손상 취약점 공격을 방지하는 컴퓨터 보안 기술이다. 공격자가 예를 들어 메모리 내 특정 취약점 공격 함수로 코드 실행을 안정적으로 리디렉션하는 것을 방지하기 위해, ASLR은 실행 파일의 기반과 스택, 힙 및 라이브러리의 위치를 포함하여 프로세스의 주요 데이터 영역의 주소 공간 위치를 무작위로 배열한다. 커널에 적용될 때 이 기술은 커널 주소 공간 배치 무작위화(KASLR)라고 불린다.

## 역사
리눅스 PaX 프로젝트는 "ASLR"이라는 용어를 처음 만들었고, 2001년 7월에 리눅스 커널용 패치로 ASLR의 첫 번째 설계와 구현을 발표했다. 이는 2002년 10월부터 커널 스택 무작위화를 위한 패치를 제공하여 완전한 구현으로 평가된다.

ASLR을 기본적으로 지원한 첫 번째 주류 운영체제는 2003년의 OpenBSD 버전 3.4였고, 그 다음으로 2005년의 리눅스였다.

## 이점
주소 공간 무작위화는 공격자가 대상 주소를 예측하기 어렵게 만들어 일부 유형의 보안 공격을 방해한다. 예를 들어, Return-to-libc 공격을 실행하려는 공격자는 실행할 코드를 찾아야 하며, 스택에 삽입된 셸코드를 실행하려는 다른 공격자는 스택을 먼저 찾아야 한다. 두 경우 모두 시스템은 공격자의 관점에서 관련 메모리 주소를 예측할 수 없게 만든다. 이 값들은 추측해야 하며, 잘못된 추측은 일반적으로 애플리케이션 충돌로 인해 복구할 수 없다.

### 효과
주소 공간 배치 무작위화는 공격자가 무작위로 배치된 영역의 위치를 추측할 가능성이 낮다는 점에 기반한다. 검색 공간을 늘림으로써 보안이 강화된다. 따라서 주소 공간 무작위화는 난수 오프셋에 더 많은 엔트로피가 존재할 때 더 효과적이다. 엔트로피는 무작위화가 발생하는 가상 메모리 영역 공간의 양을 늘리거나 무작위화가 발생하는 기간을 줄임으로써 증가한다. 기간은 일반적으로 가능한 한 짧게 구현되므로 대부분의 시스템은 VMA 공간 무작위화를 늘려야 한다.

무작위화를 무력화하려면 공격자는 공격하려는 모든 영역의 위치를 성공적으로 추측해야 한다. 사용자 정의 코드나 유용한 데이터를 로드할 수 있는 스택 및 힙과 같은 데이터 영역의 경우, 코드에는 NOP 슬라이드를 사용하고 데이터에는 반복 복사본을 사용하여 둘 이상의 상태를 공격할 수 있다. 이렇게 하면 영역이 몇 가지 값 중 하나로 무작위화될 경우 공격이 성공할 수 있다. 반대로 라이브러리 기반 및 주 실행 파일과 같은 코드 영역은 정확히 발견되어야 한다. 종종 이러한 영역은 혼합되어 있으며, 예를 들어 스택 프레임이 스택에 삽입되고 라이브러리가 반환된다.

다음 변수들을 선언할 수 있다:
* E_s (스택 최상단의 엔트로피 비트)
* E_m (`mmap() ` 기반의 엔트로피 비트)
* E_x (주 실행 파일 기반의 엔트로피 비트)
* E_h (힙 기반의 엔트로피 비트)
* A_s (스택 엔트로피에 대한 시도당 공격 비트)
* A_m (`mmap() ` 기반 엔트로피에 대한 시도당 공격 비트)
* A_x (주 실행 파일 엔트로피에 대한 시도당 공격 비트)
* A_h (힙 기반 엔트로피에 대한 시도당 공격 비트)
* \alpha (시도 횟수)
* N (총 엔트로피: N = (E_s-A_s) + (E_m-A_m) + (E_x-A_x) + (E_h-A_h)\,)

공격자가 성공할 확률을 계산하려면 시그니처 기반 IPS, 사법 기관 또는 다른 요인에 의해 중단되지 않고 수행된 시도 횟수 를 가정해야 한다. 무차별 대입 공격의 경우 데몬을 다시 시작할 수 없다. 또한 관련 비트 수와 각 시도에서 공격되는 비트 수를 계산하여 공격자가 무력화해야 하는 비트 수를 남겨야 한다.

다음 공식은  비트 엔트로피에 대한 주어진  시도 집합의 성공 확률을 나타낸다.
* g \left ( \alpha\, \right ) = 1 - { \left ( 1 - {2^{-N}} \right ) ^ \alpha\,} \,\text{ if } 0 \le \, \alpha\, (고립된 추측; 각 시도 후 주소 공간이 재무작위화된다)
* b \left ( \alpha\, \right ) = \frac{\alpha\,} \,\text{ if } 0 \le \, \alpha\, \le \, {2^N} (동일한 주소 공간을 가진 프로그램 복사본에 대한 체계적인 무차별 대입)

많은 시스템에서 2^N은 수천 또는 수백만이 될 수 있다. 32비트 시스템에서 일반적인 엔트로피 양 N은 8비트이다. 2004년 컴퓨터 속도 기준으로 샤참(Shacham)과 동료들은 "... 16비트 주소 무작위화는 몇 분 내에 무차별 대입 공격으로 무력화될 수 있다."고 언급했다. (저자들의 주장은 지연 없이 동일한 애플리케이션을 여러 번 공격할 수 있는 능력에 따라 달라진다. grsecurity에 포함된 ASLR의 적절한 구현은 이러한 무차별 대입 공격을 불가능하게 만드는 여러 방법을 제공한다. 한 가지 방법은 실행 파일이 특정 횟수 이상 충돌한 경우 구성 가능한 시간 동안 실행을 방지하는 것이다.)  64비트 시스템에서는 이 수치가 일반적으로 최소 수백만에 달한다.

안드로이드 및 다른 시스템들은 ASLR의 한 형태인 라이브러리 로드 순서 무작위화를 구현하며, 이는 라이브러리가 로드되는 순서를 무작위화한다. 이는 매우 적은 엔트로피를 제공한다. 필요한 라이브러리당 제공되는 엔트로피 비트 수의 근사치는 아래에 나와 있으며, 이는 다양한 라이브러리 크기를 아직 고려하지 않았으므로 실제 얻는 엔트로피는 다소 더 높다. 공격자는 일반적으로 하나의 라이브러리만 필요하다. 여러 라이브러리의 경우 계산이 더 복잡하며 아래에도 나와 있다. 공격자가 하나의 라이브러리만 사용하는 경우는 l = 1일 때 더 복잡한 공식의 단순화이다.
*  (로드된 라이브러리 수)
*  (공격자가 사용하는 라이브러리 수)
* 
E_m = \begin{cases} \log_2 \left (l \right ) &\text{ if } \beta\, = 1, l \ge \, 1 \\
\sum_{i=l}^{l - \left ( \beta\, - 1 \right )} \log_2 \left (i \right ) &\text{ if } \beta\, \ge \, 1, l \ge \, 1
\end{cases}


이 값들은 이 큰 경우에도 낮은 경향이 있는데, 가장 중요한 이유는 공격자가 일반적으로 C 표준 라이브러리만 사용할 수 있고 따라서 \beta\, = 1이라고 가정할 수 있기 때문이다. 그러나 적은 수의 라이브러리에도 불구하고 여기서 몇 비트의 엔트로피가 얻어진다. 따라서 라이브러리 로드 순서 무작위화를 VMA 주소 무작위화와 결합하여 몇 비트의 추가 엔트로피를 얻는 것은 잠재적으로 흥미롭다. 이 추가 엔트로피 비트는 다른 mmap() 세그먼트에는 적용되지 않고 라이브러리에만 적용된다.

#### 엔트로피 감소
공격자는 단순한 정보 유출부터 공격당 여러 비트의 엔트로피를 공격하는 것(힙 스프레이 등)까지 다양한 방법을 사용하여 무작위화된 주소 공간에 존재하는 엔트로피를 감소시킬 수 있다. 이에 대해 할 수 있는 일은 거의 없다.

포맷 문자열 취약점을 이용하여 메모리 레이아웃에 대한 정보를 유출하는 것이 가능하다. printf와 같은 포맷 문자열 함수는 작업을 수행하기 위해 가변 인수 목록을 사용한다. 포맷 지정자는 인수 목록이 어떻게 생겼는지 설명한다. 인수가 일반적으로 전달되는 방식 때문에 각 포맷 지정자는 스택 프레임의 상단에 더 가까워진다. 결국 반환 포인터와 스택 프레임 포인터를 추출할 수 있으며, 이는 취약한 라이브러리의 주소와 알려진 스택 프레임의 주소를 드러내 공격자에게 장애물이었던 라이브러리 및 스택 무작위화를 제거할 수 있다.

스택이나 힙의 엔트로피를 감소시킬 수도 있다. 스택은 일반적으로 16바이트에 정렬되어야 하므로 이것이 가능한 가장 작은 무작위화 간격이다. 반면 힙은 페이지 정렬되어야 하며, 일반적으로 4096바이트이다. 공격을 시도할 때 이러한 간격으로 중복 공격을 정렬할 수 있다. 셸코드 삽입 시 NOP 슬라이드가 사용될 수 있고, 시스템으로 반환을 시도할 때 * 문자열은 임의의 개수의 슬래시로 *로 대체될 수 있다. 제거되는 비트 수는 공격된  간격에 대해 정확히 \log_2\!\left (n \right )이다.

이러한 감소는 스택이나 힙의 데이터 양에 의해 제한된다. 예를 들어, 스택은 일반적으로 로 제한되며 훨씬 적게 증가한다. 이는 최대 를 허용하지만, 더 보수적인 추정치는 4–의 스택 스터핑에 해당하는 약 8–이다. 반면 힙은 메모리 할당자의 동작에 의해 제한된다. glibc의 경우 128KB 이상의 할당은 mmap을 사용하여 생성되므로 공격자는 5비트 감소로 제한된다. 이것은 무차별 대입 공격 시에도 제한 요인이 된다. 수행할 공격 횟수는 줄어들 수 있지만, 공격 크기가 증가하여 경우에 따라 침입 탐지 시스템에 동작이 드러날 수 있다.

### 한계

ASLR로 보호되는 주소는 다양한 측면 채널을 통해 유출될 수 있어 완화 유틸리티를 제거한다. 최근 공격은 CPU 분기 예측 버퍼(BTB) 또는 메모리 관리 장치(MMU) 페이지 테이블 워킹에서 유출된 정보를 사용했다. 이러한 종류의 ASLR 공격이 완화될 수 있는지는 분명하지 않다. 완화할 수 없다면 ASLR의 이점은 감소하거나 사라진다.

### 경험적 분석

2024년 8월, 리눅스, macOS, 윈도우를 포함한 주요 데스크톱 플랫폼에 대한 경험적 분석 논문이 발표되었는데, 이는 다양한 프로세스, 스레드 및 시스템 재시작에 걸쳐 메모리 객체 배치 가변성을 조사한 것이다. 결과에 따르면 2024년 현재 일부 시스템(리눅스 배포판 등)은 강력한 무작위화를 제공하지만, 윈도우 및 macOS와 같은 다른 시스템은 실행 코드 및 라이브러리와 같은 주요 영역을 적절히 무작위화하지 못하는 경우가 많다. 또한 리눅스 5.18 버전 이후 라이브러리의 엔트로피가 크게 감소했음을 발견했으며, 공격자가 공격 복잡도를 크게 줄이는 데 활용할 수 있는 상관 관계 경로를 식별했다.

## 구현
여러 주류 범용 운영체제가 ASLR을 구현하고 있다.

### 안드로이드
안드로이드 4.0 아이스크림 샌드위치는 메모리 관리 문제로 인한 취약점 공격으로부터 시스템 및 서드파티 애플리케이션을 보호하기 위해 주소 공간 배치 무작위화(ASLR)를 제공한다. 위치 독립 실행 파일 지원은 안드로이드 4.1에 추가되었다. 안드로이드 5.0은 비PIE 지원을 중단하고 모든 동적 링크 바이너리가 위치 독립적이어야 한다. 라이브러리 로드 순서 무작위화는 2015년 10월 26일 안드로이드 오픈 소스 프로젝트에 수용되었고, 안드로이드 7.0 릴리스에 포함되었다.

### DragonFly BSD
DragonFly BSD는 2010년에 추가된 OpenBSD 모델 기반의 ASLR을 구현하고 있다. 기본적으로 비활성화되어 있으며, sysctl vm.randomize_mmap을 1로 설정하여 활성화할 수 있다.

### FreeBSD
ASLR 지원은 FreeBSD 13.0에 등장했다. 13.2부터 기본적으로 활성화된다.

### iOS (아이폰, 아이팟 터치, 아이패드)
애플은 iOS 4.3(2011년 3월 출시)에 ASLR을 도입했다.

KASLR은 iOS 6에 도입되었다. 무작위화된 커널 베이스는 이며, 여기서 은 iBoot(2단계 iOS 부트 로더)에 의해 생성된 SHA1(랜덤 데이터)의 랜덤 바이트이다.

### 리눅스
리눅스 커널은 2005년 6월에 릴리스된 커널 버전 2.6.12부터 약한 형태의 ASLR을 기본으로 활성화했다. 리눅스 커널의 PaX 및 Exec Shield 패치셋은 더 완전한 구현을 제공한다. 리눅스용 Exec Shield 패치는 16바이트 주기의 19비트 스택 엔트로피와 4096바이트 1페이지 주기의 8비트 mmap 기반 무작위화를 제공한다. 이로 인해 스택 기반은 524,288개의 가능한 위치를 포함하는 8MB 너비의 영역에 배치되고, mmap 기반은 256개의 가능한 위치를 포함하는 1MB 너비의 영역에 배치된다.

ASLR은 `personality(2)`를 사용하여 실행 도메인을 변경함으로써 특정 프로세스에 대해 비활성화할 수 있다. 여러 sysctl 옵션이 메인라인 ASLR의 동작을 제어한다. 예를 들어, 는 무작위화할 대상을 제어하며, 가장 강력한 옵션은 2이다. 는 mmap에 대해 무작위화할 비트 수를 제어한다.

위치 독립 실행 파일 (PIE)은 메인 실행 바이너리에 대한 무작위 기반 주소를 구현하며, 2004년 4월 18일부터 적용되었다. 이는 공유 라이브러리에 사용되는 것과 동일한 주소 무작위화를 메인 실행 파일에 제공한다. PIE 기능은 동일한 실행 파일에 대해 prelink 기능과 함께 사용할 수 없다. prelink 도구는 런타임이 아닌 prelink 시간에 무작위화를 구현하는데, 이는 설계상 prelink가 동적 링커가 처리하기 전에 라이브러리 재배치를 처리하여 프로그램의 여러 실행에 대해 한 번만 재배치가 발생하도록 하는 것을 목표로 하기 때문이다. 결과적으로 실제 주소 공간 무작위화는 prelink의 목적을 무효화한다.

2014년에 마르코-기스베르트(Marco-Gisbert)와 리폴(Ripoll)은 PIE 실행 파일에 대한 리눅스 ASLR을 약화시키는 offset2lib 기술을 공개했다. 리눅스 커널은 PIE 실행 파일을 라이브러리 바로 다음에 로드한다. 결과적으로 실행 파일과 라이브러리 함수 사이에 고정된 오프셋이 존재한다. 공격자가 실행 파일 내 함수의 주소를 찾는 방법을 찾으면 라이브러리 주소도 알려지게 된다. 그들은 400번 미만의 시도로 주소를 찾는 공격을 시연했다. 그들은 실행 파일의 라이브러리 상대적 배치를 무작위화하기 위한 새로운  옵션을 제안했지만, 2024년 현재까지 업스트림에 통합되지 않았다.

2022년 5월에 릴리스된 리눅스 커널 5.18은 32비트 및 64비트 구현의 효율성을 감소시켰다. 리눅스 파일 시스템은 파일 지원 mmap에 응답하기 위해 `thp_get_unmapped_area`를 호출한다. 5.18의 변경으로 2MB보다 큰 파일은 2MB 정렬 주소를 반환하도록 하여 거대 페이지에 의해 잠재적으로 지원될 수 있도록 했다. (이전에는 증가된 정렬이 DAX(Direct Access) 매핑에만 적용되었다.) 그동안 C 라이브러리(libc)는 시간이 지남에 따라 크기가 이 2MB 임계값을 초과하게 되었고, 이로 인해 이 라이브러리들은 이전처럼 (일반적으로) 4KB 페이지 경계에 정렬되는 대신 이제 2MB 정렬되어 9비트의 엔트로피 손실이 발생했다. 32비트 리눅스의 경우 많은 배포판에서 libc 배치에 무작위화가 전혀 나타나지 않는다. 64비트 리눅스의 경우 28비트의 엔트로피가 19비트로 감소했다. 이에 대응하여 우분투는  설정을 늘렸다. 마틴 두샤(Martin Doucha)는 이 문제를 감지하기 위한 리눅스 테스트 프로젝트 테스트 케이스를 추가했다.

#### 커널 주소 공간 배치 무작위화
커널 주소 공간 배치 무작위화(KASLR)는 부팅 시 커널 코드 배치 위치를 무작위화하여 리눅스 커널 이미지에 대한 주소 공간 무작위화를 가능하게 한다. KASLR은 2014년 3월 30일에 릴리스된 커널 버전 3.14에서 리눅스 커널 메인라인에 병합되었다. 컴파일되면 커널의 부트 매개변수 중 하나로 을 지정하여 부팅 시 비활성화할 수 있다.

x86 프로세서에는 커널 주소를 유출할 수 있는 여러 부채널 공격이 존재한다. 2017년 말, 이러한 공격을 무력화하기 위해 커널 페이지 테이블 격리 (KPTI, 일명 KAISER)가 개발되었다. 그러나 이 방법은 분기 예측기 구조의 충돌을 이용하는 부채널 공격으로부터 보호할 수 없다.

, 세분화된 커널 주소 공간 배치 무작위화(또는 함수 단위 KASLR, FGKASLR)는 KASLR의 확장으로, 함수를 별도의 섹션에 배치하고 부팅 시 재정렬하여 함수 수준까지 무작위화하는 것을 계획하고 있다.

### 마이크로소프트 윈도우

마이크로소프트의 윈도우 비스타 (제조 출시 2006년 11월, 일반 출시 2007년 1월) 및 이후 버전은 ASLR을 ASLR 활성화에 특별히 링크된 실행 파일 및 동적 링크 라이브러리에만 활성화한다. 호환성을 위해 다른 애플리케이션에는 기본적으로 활성화되어 있지 않다. 일반적으로 오래된 소프트웨어만 호환되지 않으며, 레지스트리 항목 를 편집하거나, 마이크로소프트의 EMET을 설치하여 ASLR을 완전히 활성화할 수 있다.

힙, 스택, 프로세스 환경 블록, 그리고 Win32 스레드 정보 블록의 위치도 무작위화된다. 시만텍의 보안 백서에 따르면 32비트 윈도우 비스타의 ASLR은 예상만큼 강력하지 않을 수 있으며, 마이크로소프트는 구현상의 약점을 인정했다.

WehnTrust 및 Ozone과 같은 호스트 기반 침입 차단 시스템도 윈도우 XP 및 윈도우 서버 2003 운영체제에 ASLR을 제공한다. WehnTrust는 오픈 소스이다. Ozone의 구현에 대한 완전한 세부 정보는 제공되지 않는다.

2012년 2월에 윈도우 8 이전의 32비트 윈도우 시스템에서 ASLR의 효과가 메모리 부족 상황에서 감소될 수 있다는 점이 지적되었다. 비슷한 효과가 동일한 연구에서 리눅스에서도 달성되었다. 테스트 코드는 Mac OS X 10.7.3 시스템에서 커널 패닉을 일으켰으므로 이 시나리오에서의 ASLR 동작은 불분명하게 남았다.

### NetBSD
사용자 영역의 ASLR 지원은 NetBSD 5.0(2009년 4월 릴리스)에 나타났으며, 2016년 4월 NetBSD-current에서 기본으로 활성화되었다.

amd64의 커널 ASLR 지원은 2017년 10월 NetBSD-current에 추가되어, NetBSD는 KASLR을 지원하는 최초의 BSD 시스템이 되었다.

### OpenBSD
2003년, OpenBSD는 강력한 형태의 ASLR을 지원하고 기본적으로 활성화한 최초의 주류 운영체제가 되었다.
OpenBSD는 PIE 바이너리 지원을 추가하여 2008년에 ASLR 지원을 완료했다. OpenBSD 4.4의 malloc(3)은 OpenBSD의 `mmap` 시스템 호출의 일부로 구현된 ASLR 및 갭 페이지 기능을 활용하여 보안을 향상시키고 use-after-free 버그를 감지하도록 설계되었다. 2013년에 릴리스된 OpenBSD 5.3은 여러 하드웨어 플랫폼에서 기본적으로 위치 독립 실행 파일을 활성화한 최초의 주류 운영체제였으며, OpenBSD 5.7은 기본적으로 위치 독립 정적 바이너리(Static-PIE)를 활성화했다.

### macOS
맥 OS X 레퍼드 10.5(2007년 10월 릴리스)에서 애플은 시스템 라이브러리에 대한 무작위화를 도입했다.

맥 OS X 라이언 10.7(2011년 7월 릴리스)에서 애플은 "모든 애플리케이션에 대해 주소 공간 배치 무작위화(ASLR)가 향상되었습니다. 이제 32비트 앱에도 (힙 메모리 보호와 함께) 사용할 수 있어 64비트 및 32비트 애플리케이션 모두 공격에 더욱 강력해졌습니다."라고 밝히며 구현을 모든 애플리케이션으로 확장했다.

OS X 마운틴 라이언 10.8(2012년 7월 릴리스)부터는 커널, kext 및 영역을 포함한 전체 시스템이 시스템 부팅 중에 무작위로 재배치된다.

### 솔라리스
ASLR은 솔라리스 11.1 (2012년 10월 릴리스)부터 솔라리스에 도입되었다. 솔라리스 11.1의 ASLR은 시스템 전체, 존별, 또는 바이너리별로 설정할 수 있다.

## 취약점 공격
분기 예측 버퍼를 활용한 부채널 공격이 ASLR 보호를 우회하는 것으로 시연되었다. 2017년에는 자바스크립트를 사용하여 웹 브라우저에서 ASLR을 무력화할 수 있는 "ASLR⊕Cache"라는 공격이 시연되었다.

## 같이 보기
* 버퍼 오버플로
* 스택 버퍼 오버플로
* 스택 스매싱 보호
* NX 비트

## 각주

## 외부 링크
* Exploit Mitigation Techniques: an Update After 10 Years  OpenBSD에서
* PaX ASLR 문서
* PaX와 Exec Shield 및 W^X 비교 
* 윈도우 비스타의 주소 공간 배치 무작위화 - 마이클 하워드의 웹 로그
* 윈도우 2000/XP/2003용 ASLR (WehnTrust)
* PaX ASLR 보호 우회
* 주소 공간 배치 무작위화의 효과에 대하여
* 애플리케이션(또는 라이브러리)의 ASLR 및 DEP 지원 테스트
* ASLR 스맥 & 래프 참조 

분류:운영체제 보안