> 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-2025/binary-exploitation/echo-valley-medium.md).

# Echo Valley (Medium)

I wasn't able to solve this challenge.&#x20;

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

***

First of all, since the hint notes a format string attack, let's learn that.&#x20;

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

This was in a recent previous CTF so it shouldn't be too new. But basically its the source code not specifying a format specifier, which allows whatever the user inputs as actual code. They could input %p which cause to leak pointers.&#x20;

Anyways, let's look at the source code.&#x20;

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

void print_flag() {
    char buf[32];
    FILE *file = fopen("/home/valley/flag.txt", "r");

    if (file == NULL) {
      perror("Failed to open flag file");
      exit(EXIT_FAILURE);
    }
    
    fgets(buf, sizeof(buf), file);
    printf("Congrats! Here is your flag: %s", buf);
    fclose(file);
    exit(EXIT_SUCCESS);
}

void echo_valley() {
    printf("Welcome to the Echo Valley, Try Shouting: \n");

    char buf[100];

    while(1)
    {
        fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL) {
          printf("\nEOF detected. Exiting...\n");
          exit(0);
        }

        if (strcmp(buf, "exit\n") == 0) {
            printf("The Valley Disappears\n");
            break;
        }

        printf("You heard in the distance: ");
        printf(buf);
        fflush(stdout);
    }
    fflush(stdout);
}

int main()
{
    echo_valley();
    return 0;
}
```

So far this challenge is pretty similar to the last CTF. Infact, when we compile it using gcc, it already notifies us of a format security error.&#x20;

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

Once we connect and try out a format specifier like %

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

***

```c
void echo_valley() {
    printf("Welcome to the Echo Valley, Try Shouting: \n");

    char buf[100];

    while(1)
    {
        fflush(stdout);
        if (fgets(buf, sizeof(buf), stdin) == NULL) {
          printf("\nEOF detected. Exiting...\n");
          exit(0);
        }

        if (strcmp(buf, "exit\n") == 0) {
            printf("The Valley Disappears\n");
            break;
        }

        printf("You heard in the distance: ");
        printf(buf);
        fflush(stdout);
    }
    fflush(stdout);
}
```

fflush(stdout) is a C programming language function call that forces any unwritten data currently held in the standard output stream's temporary buffer to be written to its final destination, such as the console or a file.

fgets() "stores the input into a character array and stops reading when it reaches a newline character, the specified number of characters, or end-of-file (EOF)."

{% embed url="<https://www.geeksforgeeks.org/c/fgets-function-in-c/>" %}

The printflag() function is pretty obvious in what it does. But the echo\_valley() function has the person input up to 100 bytes of data, and once it reaches null (or 0), it exits. Our goal is to jump the the printflag() function.

***

I was kind of lost in what to do, knowing that although there's a format string identifier, what input can we use to exploit it? Like the previous CTF, we'll probably need to calculate a offset from the main or the echo function, since the main function calls the echo.

<figure><img src="/files/fxnckYf8Y3aqZYomIKZa" alt=""><figcaption><p>The "checksec" command provides security information about the program</p></figcaption></figure>

&#x20;Hence, we'll be using pwndbg (an extension of GDB).

***

### Solving it

I restarted everything and got the valley.c and valley files. I realized I didn't need to extract valley.c into a file since I could just do it to valley and make it as a executable. To do so, I needed to run "chmod +x valley" on "valley".

{% hint style="info" %}
chmod is "change mode", +x is the execute permission bit&#x20;
{% endhint %}

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

Here we need to know what these memory addresses even mean.

```
Stack Addresses:
0x7fffffffda0
0x7fffffffdd20
0x7fffffffd20
0x7fffffffffff range → stack, live execution 

Libc/Heap
0x7ffff7c29f68
0x7ffff7xxxxxx → typically libc

Program (PIE) addresses
0x555555557968
0x555555554130

Most return addresses live in these PIE addresses or libc
```

That means if we something like this:

<figure><img src="/files/9ll5Yg1imA70AYy6Oibs" alt=""><figcaption></figcaption></figure>

We know that a return address is at 21. This return address is a RGB.

{% hint style="info" %}
RBP, or the base pointer, is a special-purpose register in x86 architecture used to point to the base of the current stack frame in a program
{% endhint %}

Additionally, if we run "`AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p"`

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

We know that our input starts on the 6th of the stack. Since AAAA is "4141414141", if we count from 07fff, we get till 6.&#x20;

{% hint style="info" %}
To get the memory addresses of the functions, while you could use something like Ghidra you could also use the "disass <>" function.
{% endhint %}

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

***

UNFINISHED (Couldn't solve it)
