# Ghost Whisper

<figure><img src="https://175785160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fv5xJ9SHBm6KJIr4fPHYU%2Fuploads%2Frd5sneUhjhbm3O5q31gd%2Fimage.png?alt=media&#x26;token=3821cd27-058e-43b1-8db0-48db4086e75e" alt=""><figcaption></figcaption></figure>

### Description

An OS command-injection vulnerability exists in the web application's message-processing workflow. Due to incorrect input handling and the order of text transformations, certain Unicode characters (for example, "smart" or fullwidth quotes) can be converted into ordinary shell metacharacters just before the application runs a system command. An attacker can exploit this vulnerability to execute arbitrary shell commands within the web process, potentially leading to the disclosure of sensitive data (including environment variables and flags), full container/process compromise, and service disruption.

### Exploitation

To identify potential vulnerabilities within an application, analysing the source code is an effective approach as it reveals insecure coding practices, such as improper input validation or the misuse of certain libraries. In this scenario, we are presented with a web application that accepts user input, which is then parsed by the program, potentially influencing the contents returned to the user.

### Vulnerable Code Analysis

The application constructs a shell pipeline using untrusted input inside a single-quoted shell literal:

```python
with os.popen(f"echo -n '{whisperMsg}' | hexdump") as stream:
```

Before that, it attempts to sanitize ASCII single quotes with:

```python
whisperMsg = unicodedata.normalize("NFKC", whisperMsg.replace("'", "_"))
```

Because the code calls `replace("'", "_")` before Unicode normalization, visually-similar Unicode quote characters (for example, `U+FF07 Fullwidth Apostrophe`) are not replaced and are converted by **NFKC** into ASCII apostrophes. This allows an attacker to inject `＇ (U+FF07)`characters that become ASCII `"'"` after normalization, closing the single-quoted literal and enabling arbitrary shell injection.

### Root cause

Order-of-operations bug: input sanitation `replace("'", "_")` occurs before Unicode canonicalization (NFKC). Unicode characters that normalize to ASCII single quote are not sanitized and can be converted into a dangerous character after sanitization. Additionally, the use of `os.popen/shell` interpolation with unsanitized user input permits shell metacharacter interpretation.

### PoC

A payload containing full-width quotes is URL-encoded and sent as the message. After decoding and normalization, those characters become ordinary single quotes (`'`), which closes the intended quoted string in the constructed shell command and allows injection of commands. The output is then returned in the web response.

<figure><img src="https://175785160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fv5xJ9SHBm6KJIr4fPHYU%2Fuploads%2FzLOPp56Y3J7lgRScGk5J%2FScreenshot%202025-11-06%20113723.png?alt=media&#x26;token=5a048651-93cb-4114-9a14-0467664ec05b" alt=""><figcaption></figcaption></figure>

As the response contains the process user (the ID output), this PoC conclusively demonstrates that injected shell commands were executed in the web process.

The objective to prove the vulnerability was to get the content of the environment variable that had been set as follow :

```python
os.environ["FLAG"] = flag
```

A command to print the variable has been used. Here is the poc code :

```python
＇;echo $FLAG; ＇

or

＇;printenv; ＇

```

### Risk

This vulnerability enables unauthenticated remote command execution in the web process with trivial, low-effort payloads. Likelihood of exploitation: high.

Impact: full container/process compromise, disclosure of secrets (env vars, files), service disruption, and potential lateral movement if host isolation is weak.

Business consequences include data loss, regulatory exposure, service outage, and reputational damage.

### Remediation

1. Replace `os.popen()` with `subprocess.run()` or an equivalent function that does not invoke a shell. Pass user input as data (stdin or arguments).
2. Apply Unicode normalization before any replacement or sanitization, so no dangerous characters are reintroduced after cleaning.
3. Accept only expected characters (letters, numbers, limited punctuation). Reject or escape all others. Implement a strict allowlist policy for user inputs.

### Reference

1. <https://www.compart.com/en/unicode/U+FF07>
2. <https://dojo-yeswehack.com/challenge-of-the-month/dojo-46>
