Files
HIP7CTF_Writeups/echo_chamber.md
m0rph3us1987 a79656b647 Added writeups
2026-03-08 12:22:39 +01:00

106 lines
3.9 KiB
Markdown

# Echo Chamber
Hello there! Welcome to the write-up for **Echo Chamber**. This is a classic "pwn" challenge that demonstrates a very common but powerful vulnerability: the **Format String Vulnerability**.
In this challenge, we are given a compiled binary. When we don't have the original source code, we use tools like **Ghidra** to decompile the binary and see what the program is doing "under the hood."
---
## 1. Initial Reconnaissance
When we run the program, it asks for some input and "echoes" it back:
```text
Welcome to the Echo Chamber!
Give me a phrase, and I will shout it back: Hello!
You said: Hello!
```
The developer's description gives us a hint:
> "The developer claims it's perfectly secure because 'it doesn't execute any code, it just prints text.'"
This is a classic "famous last words" situation in security! Let's look at the decompiled code to see why.
## 2. Analyzing the Decompiled Code (Ghidra)
Opening the binary in Ghidra, we find the `vuln()` function. Here is the pseudo-code it gives us:
```c
void vuln(void)
{
char acStack_a0 [64]; // Our input buffer
char local_60 [72]; // Where the flag is stored
FILE *local_18;
local_18 = fopen64("flag.txt","r");
if (local_18 == (FILE *)0x0) {
puts("Flag file is missing!");
exit(0);
}
// 1. The flag is read into local_60
fgets(local_60,0x40,local_18);
fclose(local_18);
puts("Welcome to the Echo Chamber!");
printf("Give me a phrase, and I will shout it back: ");
// 2. Our input is read into acStack_a0
fgets(acStack_a0,0x40,(FILE *)stdin);
printf("You said: ");
// 3. VULNERABILITY: Our input is passed directly to printf!
printf(acStack_a0);
putchar(10);
return;
}
```
Do you see that line `printf(acStack_a0);`? This is our "Golden Ticket."
## 3. The Vulnerability: Format Strings
In C, `printf` expects its first argument to be a **format string** (like `"%s"` or `"Hello %s"`). If a developer passes user input directly to `printf`, the user can provide their own format specifiers.
When `printf` sees a specifier like `%p` (print pointer) or `%x` (print hex), it looks for the next argument on the **stack**. If we don't provide any arguments, `printf` will just start leaking whatever is already on the stack!
### Where is the flag?
Looking at the Ghidra output, notice that both `acStack_a0` (our input) and `local_60` (the flag) are **local variables**. This means they are both stored on the stack right next to each other.
## 4. Exploiting the "Echo"
If we send a string of format specifiers like `%p %p %p %p %p %p...`, we can trick `printf` into printing the contents of the stack. Since the flag is sitting on the stack, it will eventually be printed!
Try providing this as input:
`%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p`
The program will respond with a series of hex addresses. Some of these values will actually be the ASCII characters of our flag.
### Little Endianness
When you see the hex values, remember that modern systems use **Little Endian** byte ordering. This means the bytes are stored in reverse order.
For example, if you see `0x7b67616c66`, and you convert those bytes from hex to ASCII:
- `66` = `f`
- `6c` = `l`
- `61` = `a`
- `67` = `g`
- `7b` = `{`
The value `0x7b67616c66` represents `flag{` in reverse!
## 5. Putting it all Together
To solve the challenge:
1. Connect to the service.
2. Send many `%p` specifiers to leak the stack.
3. Identify the hex values that look like printable text (starting with `0x...` and containing ASCII values).
4. Reverse the bytes (Endianness) and convert them to characters.
5. Combine the parts to find the flag!
## Lessons Learned
Even if a program "just prints text," it's not safe if it uses `printf` incorrectly. The fix is simple: always use `printf("%s", buffer);`. This ensures the input is treated as a literal string, not as code or instructions for the function.
Happy Hacking!