시스템 해킹/dream hack

[dream hack] ASLR

ruming 2021. 2. 26. 22:00

Linux Exploitation & Mitigation Part 2

1. ASLR

Address Space Layout Randomization 

라이브러리, 힙, 스택 영역 등의 주소를 바이너리가 실행될 때마다 랜덤하게 바꿔 RTL과 같이 정해진 주소를 이용한 공격을 막기 위한 보호 기법이다. NX bit는 바이너리의 컴파일 옵션에 따라 적용 여부가 결정되었지만 ASLR은 서버의 설정 파일에 의해 보호 기법의 적용이 결정된다.

 

Ubuntu 16.04에서는 다음 파일의 값을 확인하면 서버의 ASLR 설정 여부를 알 수 있다.

/proc/sys/kernel/randomize_va_space

설정 파일 값의 의미

0 : ASLR을 적용하지 않음

1 : 스택, 힙 메모리를 랜덤화

2 : 스택, 힙, 라이브러리 메모리를 랜덤화

 

해당 파일의 값이 2가 아니라면 루트 권한으로 다음 명령어를 실행해 ASLR 보호 기법을 적용할 수 있다.

# cat /proc/sys/kernel/randomize_va_space 
0
# echo 2 > /proc/sys/kernel/randomize_va_space
# cat /proc/sys/kernel/randomize_va_space
2
#

 

example3.c - 프로세스 자신의 메모리 맵을 읽어 출력해주는 코드

//example3.c
//gcc -o example3 example3.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);
}

example3의 실행 결과

 

서버에 ASLR이 켜져 있을 때, 라이브러리, 힙, 스택 영역의 주소가 랜덤하게 바뀌는 것을 확인 가능

라이브러리 주소가 계속 바뀌기 때문에 정적 주소를 이용한 공격은 사용할 수 없다. 하지만 바이너리 코드 영역의 주소는 변하지 않기 때문에 이를 이용해 익스플로잇이 가능함. (ASLR 우회)

 

 

example4.c 

//gcc -o example4 example4.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;
}

scanf함수로 32바이트 크기의 배열 buf에 데이터를 입력받음. 이때, "%s" 포맷 스트링을 사용하기 때문에 입력 길이의 제한이 없어 스택 버퍼 오버플로우 취약점이 발생. 

 

바이너리에 NX bit가 적용되어 있는지 확인

$ readelf -a ./example4 | grep STACK
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10

readelf로 확인한 스택 메모리의 권한은 RW로, 바이너리에 NX bit가 적용되어 있음. + 서버에 ASLR 보호 기법 적용됨.

 

스택 오버플로우 취약점을 이용해 스택의 리턴 주소 덮기

$ gdb -q ./example4 
Reading symbols from ./example4...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x0804845b <+0>:	push   ebp
   0x0804845c <+1>:	mov    ebp,esp
   0x0804845e <+3>:	sub    esp,0x20
   0x08048461 <+6>:	mov    ecx,0x0
   0x08048466 <+11>:	mov    eax,0x20
   0x0804846b <+16>:	and    eax,0xfffffffc
   0x0804846e <+19>:	mov    edx,eax
   0x08048470 <+21>:	mov    eax,0x0
   0x08048475 <+26>:	mov    DWORD PTR [ebp+eax*1-0x20],ecx
   0x08048479 <+30>:	add    eax,0x4
   0x0804847c <+33>:	cmp    eax,edx
   0x0804847e <+35>:	jb     0x8048475 <main+26>
   0x08048480 <+37>:	push   0x8048540
   0x08048485 <+42>:	call   0x8048320 <puts@plt>
   0x0804848a <+47>:	add    esp,0x4
   0x0804848d <+50>:	push   0x804854d
   0x08048492 <+55>:	call   0x8048320 <puts@plt>
   0x08048497 <+60>:	add    esp,0x4
   0x0804849a <+63>:	lea    eax,[ebp-0x20]
   0x0804849d <+66>:	push   eax
   0x0804849e <+67>:	push   0x8048559
   0x080484a3 <+72>:	call   0x8048340 <__isoc99_scanf@plt>
   0x080484a8 <+77>:	add    esp,0x8
   0x080484ab <+80>:	mov    eax,0x0
   0x080484b0 <+85>:	leave  
   0x080484b1 <+86>:	ret    
End of assembler dump.
(gdb) r
Starting program: ~/Linux_Exploitation_Mitigation/example4 
Hello World!
Hello ASLR!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) p/x $eip
$1 = 0x42424242
(gdb) 

main함수의 디스어셈블리 결과 :

scanf함수의 2번째 인자인 buf 배열의 주소는 ebp-0x20

ebp 레지스터가 가리키는 위치에는 스택 프레임 포인터가 존재, ebp+4에 main함수의 리턴 주소 위치

입력으로 "A"*36+"BBBB"를 넣었을 때 main함수가 리턴한 이후 eip 레지스터의 값이 0x42424242로 바뀐 것을 확인 가능.

 

NX bit 걸림 → 프로그램이 비정상 종료하지 않기 위해 실행 권한이 있는 코드 영역으로 덮어야 함

 

example4의 메모리 맵

08048000-08049000 r-xp 00000000 08:01 150622                             /example4
08049000-0804a000 r--p 00000000 08:01 150622                             /example4
0804a000-0804b000 rw-p 00001000 08:01 150622                             ~/example4
0804b000-0806c000 rw-p 00000000 00:00 0                                  [heap]
f7e02000-f7e03000 rw-p 00000000 00:00 0 
f7e03000-f7fb3000 r-xp 00000000 08:01 1183815                            /lib/i386-linux-gnu/libc-2.23.so
f7fb3000-f7fb5000 r--p 001af000 08:01 1183815                            /lib/i386-linux-gnu/libc-2.23.so
f7fb5000-f7fb6000 rw-p 001b1000 08:01 1183815                            /lib/i386-linux-gnu/libc-2.23.so
f7fb6000-f7fb9000 rw-p 00000000 00:00 0 
f7fd3000-f7fd4000 rw-p 00000000 00:00 0 
f7fd4000-f7fd7000 r--p 00000000 00:00 0                                  [vvar]
f7fd7000-f7fd9000 r-xp 00000000 00:00 0                                  [vdso]
f7fd9000-f7ffc000 r-xp 00000000 08:01 1183801                            /lib/i386-linux-gnu/ld-2.23.so
f7ffc000-f7ffd000 r--p 00022000 08:01 1183801                            /lib/i386-linux-gnu/ld-2.23.so
f7ffd000-f7ffe000 rw-p 00023000 08:01 1183801                            /lib/i386-linux-gnu/ld-2.23.so
fffdd000-ffffe000 rw-p 00000000 00:00 0                                  [stack]

 

ASLR 참고 : linux 환경에서의 메모리 보호기법을 알아보자

 

 

'시스템 해킹 > dream hack' 카테고리의 다른 글

[dream hack] SSP  (0) 2021.02.28
[dream hack] PLT, GOT Section  (0) 2021.02.27
[dream hack] NX bit  (0) 2021.02.20
[dream hack] NOP Sled  (0) 2021.02.18
[dream hack] Return address overwrite  (0) 2021.02.18