Heap 3

July 14, 20253 minutes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FLAGSIZE_MAX 64
// Create struct
typedef struct {
char a[10];
char b[10];
char c[10];
char flag[5];
} object;
int num_allocs;
object *x;
void check_win() {
if(!strcmp(x->flag, "pico")) {
printf("YOU WIN!!11!!\n");
// Print flag
char buf[FLAGSIZE_MAX];
FILE *fd = fopen("flag.txt", "r");
fgets(buf, FLAGSIZE_MAX, fd);
printf("%s\n", buf);
fflush(stdout);
exit(0);
} else {
printf("No flage for u :(\n");
fflush(stdout);
}
// Call function in struct
}
void print_menu() {
printf("\n1. Print Heap\n2. Allocate object\n3. Print x->flag\n4. Check for win\n5. Free x\n6. "
"Exit\n\nEnter your choice: ");
fflush(stdout);
}
// Create a struct
void init() {
printf("\nfreed but still in use\nnow memory untracked\ndo you smell the bug?\n");
fflush(stdout);
x = malloc(sizeof(object));
strncpy(x->flag, "bico", 5);
}
void alloc_object() {
printf("Size of object allocation: ");
fflush(stdout);
int size = 0;
scanf("%d", &size);
char* alloc = malloc(size);
printf("Data for flag: ");
fflush(stdout);
scanf("%s", alloc);
}
void free_memory() {
free(x);
}
void print_heap() {
printf("[*] Address -> Value \n");
printf("+-------------+-----------+\n");
printf("[*] %p -> %s\n", x->flag, x->flag);
printf("+-------------+-----------+\n");
fflush(stdout);
}
int main(void) {
// Setup
init();
int choice;
while (1) {
print_menu();
if (scanf("%d", &choice) != 1) exit(0);
switch (choice) {
case 1:
// print heap
print_heap();
break;
case 2:
alloc_object();
break;
case 3:
// print x
printf("\n\nx = %s\n\n", x->flag);
fflush(stdout);
break;
case 4:
// Check for win condition
check_win();
break;
case 5:
free_memory();
break;
case 6:
// exit
return 0;
default:
printf("Invalid choice\n");
fflush(stdout);
}
}
}
Al principio del codigo se declara un tipo de struct al cual se le llama object
typedef struct {
char a[10];
char b[10];
char c[10];
char flag[5];
} object;
Luego se declara x como ese objeto
object *x;
Con malloc reserva tamaño en el heap concretamente 35 bytes (a[10] + b[10] + c[10] + flag[5] = 35), lurgo con strncpy se guarda bico en flag
void init() {
printf("\nfreed but still in use\nnow memory untracked\ndo you smell the bug?\n");
fflush(stdout);
x = malloc(sizeof(object));
strncpy(x->flag, "bico", 5);
}
El programa solo imprime la flag si x->flag es igual a pico.
La opción 5 hace free(x), con lo que el bloque de memoria que ocupaba x en el heap queda disponible para futuras asignaciones, pero x sigue apuntando a esa dirección. La opción 2 pide un tamaño y hace malloc(size) devolviendo seguramente el mismo bloque de memoria que tenia x si se pone el mismo size que tenia x. Luego scanf("%s", alloc) escribe en ese bloque lo que el usuario indique. Con estas dos opciones se puede hacer un uaf (use‑after‑free)
La estructura ocupa 35 bytes en total, con flag empezando en el offset 30. Al pasar como dato una cadena con 30 bytes de relleno más “pico”: Se estara escribiendo “pico” justo donde antes estaba x->flag.
Ahora flag ya vale pico y ya se puede ver la flag con la opción 4