대략적인 구성이 이렇게 되어있고 a.out 이라는 실행파일이 있다.

a.out 를 열어보면 'Can you read the flag?' 라는 문구를 출력하고
Falg value address 주소 값을 반환하는데 이건 여러번 실행해도 같은 주소값을 반환한다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#define FLAG_PATH "./flag"
#define FLAG_SIZE 0x40
void alarm_handler() { exit(-1); }
void initialize()
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(60);
}
char flag_buf[FLAG_SIZE];
void read_flag() {
int fd = open(FLAG_PATH, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
ssize_t r = read(fd, flag_buf, FLAG_SIZE - 1);
if (r < 0) {
perror("read");
close(fd);
exit(1);
}
flag_buf[r] = '\0';
close(fd);
}
int main() {
initialize();
char buf[1024];
memset(buf,0x0,1024);
read_flag();
printf("Can you read the flag?\n");
printf("Flag value address : %p\n",flag_buf);
printf("Please answer this question (YES/NO) : ");
read(0, buf, 1024);
printf("Your opinion: ");
printf(buf);
return 0;
}
같은 메모리 주소값을 반환한다는 것은 어떤 의미를 가질까?
바로 전역변수라는 것이다. 지역변수의 경우 각 함수 내에서 변수값을 가져오기 때문에 함수가 실행되는 시점에 따라 변소 주소값이 변환된다.
그에 반해 전역변수는 어느 함수든 같은 위치에 있는 값을 가져와야 데이터 혼선이 없기 때문에 실행 시 항상 동일한 위치에 정해지게 된다.
그 전역 변수 선언이 바로 char flag_buf[FLAG_SIZE]; 이곳이다.
그럼 이제 메모리 주소값을 알기 때문에 큰 문제없이 접근이 가능하다.
필자는 gdb를 이용하여 해당 변수에 접근하겠다.
# main 우선 브레이크 포인트 걸기
(gdb) b main
# 프로그램 실행 시 main 첫 부분에 브레이크
(gdb) r
# main 내 read_flag()함수가 있기 때문에 해당 부분까지 실행해야 로딩
(gdb) n
# flag_buf의 메모리 주소 확인
(gdb) p &flag_buf
# 메모리 내 값 확인
(gdb) x/s &flag_buf

그 결과 FLAG{fIrst_M3Mory_re4D1}라는 값을 추출에 성공함