LinkHands

Name: Loading...
Difficulty: Loading...
Category: Loading...
Release: Loading...
Solves: Loading...
First Blood: First Blood User Loading... - Loading...
Creator: Creator Loading...
Description: Loading...


rosehacks@pwny$ cat linkhands.txt
We were tasked with uncovering a flag hidden in memory within a CTF challenge. 
The primary obstacle was that the program asked for two memory addresses and 
allowed us to overwrite one with the other—this type of vulnerability is known
as an arbitrary write. By exploiting this, we could manipulate memory pointers 
and trick the program into revealing the flag.

What we did:

rosehacks@pwny$ cat solution.txt
* Use an arbitrary write vulnerability to modify a pointer in the program's memory.
* Make the program read hidden memory locations and reveal the entire flag.

Can you read this: ?–>?

Weakness

The program presented us with the following prompt:

The cultists look expectantly to you - who will you link hands with? 0x0021 0x0022


This input prompt was directly tied to the arbitrary write vulnerability, where we could provide two memory addresses, and the program would overwrite one with the other.Here’s the core code that allowed this:

iVar1 = __isoc99_sscanf(local_58, "%p %p", &local_68, &local_60);
if (iVar1 == 2) {
    *local_68 = local_60;  // Arbitrary write: overwrites value at local_68 with local_60
}


Explanation:

The program reads two pointers (local_68 and local_60) from user input. If both pointers are valid, it writes the value of local_60 to the memory location at local_68. This is an arbitrary write vulnerability, meaning we can control which memory locations are modified.

First Attempt: Access The Flag’s Starting Point

Our first step was to identify where the flag was stored. We started by analyzing the memory structure of the program and pointing the vulnerable pointer to a known address in the .data section. The key was manipulating the pointer PTR_PTR_00404190, which controlled the program’s memory reads during the output process. This pointer was used in a loop to traverse memory and print characters:

ppuVar4 = &PTR_PTR_00404190;
do {
    putchar((int)*(char *)(ppuVar4 + 1));  // Print characters
    ppuVar4 = (undefined **)*ppuVar4;     // Move to the next pointer
} while (ppuVar4 != (undefined **)0x0);  // Stop when a NULL pointer is reached


We realized that by controlling PTR_PTR_00404190, we could decide where the program started printing from. We pointed it at a likely address in the .data section (0x404040), and this yielded the first part of the flag: H. However, this only printed the first character, which told us that the flag was likely stored contiguously in memory—but not fully read in our initial attempts.

Traversing Memory with Arbitrary Writes

By using the arbitrary write vulnerability, we could continuously modify the memory pointer to read further into memory, revealing more characters of the flag. We tried various memory addresses in sequence, inching our way through memory. For example:

  • Address: 0x404040 gave us H.
  • Address: 0x40403f, 0x40403e, and others allowed us to reveal the middle and final parts of the flag.

With each attempt, we revealed more of the flag, one piece at a time:

  • First character: H
  • Last portion: 41n_0e343f537ebc}
The Full Flag

After inspecting different addresses using Ghidra and analyzing how memory was laid out in the .data section, we realized that the flag was spread across multiple addresses. We iteratively used our arbitrary write to print out pieces of memory, stitching together the full flag. By controlling the pointer traversal, we were able to reveal: • The first character (H) • Middle parts of the flag that were hidden in nearby memory • And finally, the closing characters (41n_0e343f537ebc}) After piecing together all the parts, we revealed the full flag.

Tools and Techniques for Future Reference

  1. Ghidra for Memory Analysis We used Ghidra to examine the .data section and identify potential addresses where the flag might be stored. This allowed us to focus our memory exploration efforts on the right addresses.
  2. Arbitrary Write Exploitation The arbitrary write allowed us to modify critical memory pointers. By pointing PTR_PTR_00404190 to specific memory addresses, we could read out hidden data from memory—revealing parts of the flag that were otherwise inaccessible.
  3. Manual Memory Exploration By systematically changing memory addresses during the pointer manipulation process, we were able to extract the flag piece by piece. This method required trial and error, but each attempt revealed new pieces of the puzzle.
LinkHands has been pwn3d!