**Address Space Layout Randomization (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 버전을 알고 있다고 가정). 이 예제 공격은 여기의 예제에서 추출되었습니다 (자세한 내용은 해당 페이지를 확인하세요).
ret2plt와 마찬가지로 포맷 문자열 취약점을 통해 임의 읽기가 가능하면 GOT에서 libc 함수의 주소를 외부로 유출할 수 있습니다. 다음은 여기에서 예제를 확인하세요:
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 임의 읽기에 대한 자세한 정보를 찾을 수 있습니다:
vsyscall 메커니즘은 일부 시스템 호출을 사용자 공간에서 실행하여 성능을 향상시키는 데 사용됩니다. 이러한 시스템 호출은 기본적으로 커널의 일부이지만 vsyscalls의 주요 장점은 고정 주소에 있습니다. 이러한 고정된 특성으로 인해 공격자는 주소를 결정하고 이를 악용하기 위해 정보 누출 취약점이 필요하지 않습니다.
그러나 여기에는 특별히 흥미로운 가젯이 없을 것입니다 (예를 들어 ret;과 같은 것을 얻을 수는 있습니다)
예를 들어, 공격자는 악용 내에서 주소 0xffffffffff600800을 사용할 수 있습니다. ret 명령으로 직접 이동하려는 시도는 몇 가지 가젯을 실행한 후 불안정성이나 충돌로 이어질 수 있지만, vsyscall 섹션에서 제공되는 syscall의 시작으로 이동하는 것은 성공적일 수 있습니다. 공격자가 실행을 vsyscall 주소로 이끄는 ROP 가젯을 신중하게 배치함으로써, ASLR을 우회하지 않고도 악용의 이 부분에서 코드 실행을 달성할 수 있습니다.