#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
struct my_page {
char name[16];
int age;
};
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);
}
int main()
{
struct my_page my_page;
char flag_buf[56];
int idx;
memset(flag_buf, 0, sizeof(flag_buf));
initialize();
while(1)
{
printf("1. Join\n");
printf("2. Print information\n");
printf("3. GIVE ME FLAG!\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
printf("Name: ");
read(0, my_page.name, sizeof(my_page.name));
printf("Age: ");
scanf("%d", &my_page.age);
break;
case 2:
printf("Name: %s\n", my_page.name);
printf("Age: %d\n", my_page.age);
break;
case 3:
fp = fopen("/flag", "r");
fread(flag_buf, 1, 56, fp);
break;
default:
break;
}
}
}
이번 문제는 memory_leakage를 사용하여 플래그를 획득하는 문제입니다. case 1에서는 my_page.name에 최대 16바이트 크기의 입력값을 입력하고 my_page.age에 정수를 입력합니다. case 2에서는 저장된 변수를 출력합니다. case 3에서는 flag 값을 flag_buf에 저장합니다.
문제 풀이 동작은 다음과 같습니다. case 2의 printf("Name: %s\n", my_page.name);에서 %s는 널 바이트가 나올 때 까지 문자를 출력합니다. 하지만 case 1의 read(0, my_page.name, sizeof(my_page.name));에서는 16바이트 만큼의 문자를 입력받을 수 있으므로 my_page.name의 마지막 문자에 0이 아닌 다른 문자가 존재하면 널 바이트가 나올 때 까지 쓰레기 값을 출력하게 됩니다. gdb를 이용하여 변수들의 주소를 확인하면 아래와 같습니다.
mypage.name : 0xffffd4b0
mypage.age : 0xffffd4c0
flag_buf : 0xffffd4c4
mypage.name와 mypage.age의 차이가 16바이트 이므로 mypage.name의 마지막 문자열이 널 바이트가 아닌 경우 바로 뒤에 있는 mypage.age 값도 출력하게 됩니다. 그리고 mypage.age의 값은 최대 4바이트 크기로 널 바이트가 없을 경우 flag_buf에 있는 값까지 출력하게 됩니다. 따라서 아래와 같이 입력 값을 순서대로 입력하면 플래그가 출력됩니다. 286331153은 16진수로 0x11111111이고 널 바이트인 0x00이 아닌 값으로 4바이트를 모두 채우기 위함입니다.
'시스템 해킹 > 드림핵' 카테고리의 다른 글
[Dreamhack] basic_heap_overflow (0) | 2021.07.20 |
---|---|
[Dreamhack] out_of_bound (0) | 2021.07.18 |
[Dreamhack] basic_exploitation_002 (0) | 2021.07.17 |
[Dreamhack] sint (0) | 2021.07.15 |
[Dreamhack] basic_exploitation_003 (0) | 2021.05.22 |
댓글