2020.05 라온화이트햇 핵심연구팀 이영주 [email protected]

Introduce

다양한 환경에서 메모리 보호기법을 조사하였습니다. 많은 메모리 보호기법이 존재하기 때문에 각 보호기법에 대한 우회 방법에 대해서는 간략하게 다뤘습니다.

INDEX

  1. Window
  2. Linux
  3. Kernel

1. ASLR(Address Space Layout Randomization)

ASLR은 실행파일과 관련된 공유 라이브러리, 스택, 힙이 매핑되는 메모리 영역의 주소를 랜덤으로 배치하는것입니다. 이를 통해 공격자가 고정된 주소를 이용하여 실행 흐름을 변경하거나 원하는 데이터를 가져오는 것을 막을 수 있습니다. ASLR은 Linux 환경에서 /proc/self/maps를 읽어서 가장 쉽게 확인할 수 있습니다.

raon@raon:~/test$ cat /proc/self/maps
55abfd61b000-55abfd61d000 r--p 00000000 103:02 2752672                   /usr/bin/cat
55abfd61d000-55abfd622000 r-xp 00002000 103:02 2752672                   /usr/bin/cat
55abfd622000-55abfd625000 r--p 00007000 103:02 2752672                   /usr/bin/cat
55abfd625000-55abfd626000 r--p 00009000 103:02 2752672                   /usr/bin/cat
55abfd626000-55abfd627000 rw-p 0000a000 103:02 2752672                   /usr/bin/cat
55abfdf39000-55abfdf5a000 rw-p 00000000 00:00 0                          [heap]
7ff2b516f000-7ff2b5191000 rw-p 00000000 00:00 0 
7ff2b5191000-7ff2b5846000 r--p 00000000 103:02 2753788                   /usr/lib/locale/locale-archive
7ff2b5846000-7ff2b586b000 r--p 00000000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7ff2b586b000-7ff2b59e3000 r-xp 00025000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7ff2b59e3000-7ff2b5a2d000 r--p 0019d000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7ff2b5a2d000-7ff2b5a30000 r--p 001e6000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7ff2b5a30000-7ff2b5a33000 rw-p 001e9000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7ff2b5a33000-7ff2b5a39000 rw-p 00000000 00:00 0 
7ff2b5a4e000-7ff2b5a4f000 r--p 00000000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7ff2b5a4f000-7ff2b5a71000 r-xp 00001000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7ff2b5a71000-7ff2b5a79000 r--p 00023000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7ff2b5a7a000-7ff2b5a7b000 r--p 0002b000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7ff2b5a7b000-7ff2b5a7c000 rw-p 0002c000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7ff2b5a7c000-7ff2b5a7d000 rw-p 00000000 00:00 0 
7ffd5fbf9000-7ffd5fc1b000 rw-p 00000000 00:00 0                          [stack]
7ffd5fd14000-7ffd5fd17000 r--p 00000000 00:00 0                          [vvar]
7ffd5fd17000-7ffd5fd18000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
raon@raon:~/test$ cat /proc/self/maps
56196357a000-56196357c000 r--p 00000000 103:02 2752672                   /usr/bin/cat
56196357c000-561963581000 r-xp 00002000 103:02 2752672                   /usr/bin/cat
561963581000-561963584000 r--p 00007000 103:02 2752672                   /usr/bin/cat
561963584000-561963585000 r--p 00009000 103:02 2752672                   /usr/bin/cat
561963585000-561963586000 rw-p 0000a000 103:02 2752672                   /usr/bin/cat
561964938000-561964959000 rw-p 00000000 00:00 0                          [heap]
7fe9c9dbe000-7fe9c9de0000 rw-p 00000000 00:00 0 
7fe9c9de0000-7fe9ca495000 r--p 00000000 103:02 2753788                   /usr/lib/locale/locale-archive
7fe9ca495000-7fe9ca4ba000 r--p 00000000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7fe9ca4ba000-7fe9ca632000 r-xp 00025000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7fe9ca632000-7fe9ca67c000 r--p 0019d000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7fe9ca67c000-7fe9ca67f000 r--p 001e6000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7fe9ca67f000-7fe9ca682000 rw-p 001e9000 103:02 2756186                   /usr/lib/x86_64-linux-gnu/libc-2.30.so
7fe9ca682000-7fe9ca688000 rw-p 00000000 00:00 0 
7fe9ca69d000-7fe9ca69e000 r--p 00000000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7fe9ca69e000-7fe9ca6c0000 r-xp 00001000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7fe9ca6c0000-7fe9ca6c8000 r--p 00023000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7fe9ca6c9000-7fe9ca6ca000 r--p 0002b000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7fe9ca6ca000-7fe9ca6cb000 rw-p 0002c000 103:02 2756182                   /usr/lib/x86_64-linux-gnu/ld-2.30.so
7fe9ca6cb000-7fe9ca6cc000 rw-p 00000000 00:00 0 
7ffe55212000-7ffe55234000 rw-p 00000000 00:00 0                          [stack]
7ffe5539a000-7ffe5539d000 r--p 00000000 00:00 0                          [vvar]
7ffe5539d000-7ffe5539e000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

위의 결과를 통해 실행파일(/usr/bin/cat), 공유 라이브러리, 스택, 힙이 적재되는 메모리 영역이 매번 바뀐다는 것을 알 수 있습니다.

이 기법을 우회할 수 있는 대표적인 방법은 아래와 같습니다.

  1. Brute Force : 주로 예측해야 하는 주소 길이가 작은 x86 실행파일에서 사용되며 동적 할당되는 heap 영역을 이용하는 경우가 많습니다. 이 방법을 통해 확률적으로 원하는 주소를 예측할 수 있습니다.
  2. Memory Leak : ASLR의 경우 메모리 영역이 매번 변경되는 것이므로 Memory Leak 취약점을 통해 특정 주소를 알 수 있다면 offset 계산을 통해 그 메모리 영역에 있는 다른 주소들도 예측할 수 있습니다.