

이것저것 걸려있긴 하다.
하지만, NX가 걸려있지 않은 것을 보아 Canary만 우회할 수 있다면 쉘코드를 실행시킬 수 있을 것 같다.
소스코드 분석해보겠다.
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\\n", buf);
printf("Distance between buf and $rbp: %ld\\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
buf[0x50] 으로 배열을 선언한다. 넉넉하다.
0x60만큼 빈공간이 선언됐고, push rbp가 보이기 때문에,
[ 버퍼(0x60 bytes) ] [ 카나리(8) ] [ 저장된 RBP(8) ] [ 리턴주소(8) ]
^ ^ ^ ^
| | | +-- buf의 시작 주소(또는 NOP 슬레드 중간)
| | +-- 임의(더미)
| +-- 복원한 정확한 카나리 8바이트
+-- 여기 앞부분에 x64 쉘코드를 놓고, 남는 공간은 NOP(0x90)로 패딩
의 스택 구조를 가지고 있을 것이다.
여기서 canary의 위치는 rbp-0x8이고, canary의 마지막 값은 \\x00 이기 때문에 해당 값만 덮기 위해서 A*89을 준다.

체크해보면, 해당 값의 끝값이 A(41)로 덮혔고, 이 실행에선 canary의 값이 0x3b4db137e8db0a00 라고 볼 수 있다.
물론, canary의 값은 매번 바뀐다.
따라서, 한번의 익스 실행 과정에서 canary leak + bof까지 한번에 진행해야한다는 것을 알 수 있다.