![]() |
EpiRootkit
By STDBOOL
|
In Epirootkit, userland command execution is handled by the userland.c module. The benefit is immediate: it allows executing shell commands in root mode on the machine, which opens total control over the system.
Warning: This module doesn't allow obtaining a remote interactive shell, but only executing commands like shell scripts. However, as explained in the Reverse Shell section, this functionality is also indeed used in Epirootkit to launch a userland reverse shell with
socat.
Both stdout and stderr are captured and returned to the attacker.
In our context of remote command execution by an attacker, the userland.c module had to meet several criteria:
> output.txt), the module must handle them correctly so they don't conflict with the previously mentioned result retrieval.Use the -s flag for silent execution (returns only exit code).Commands have a timeout to prevent hanging.
The userland.c module relies on using the Linux kernel's call_usermodehelper API to execute shell commands from kernel space. This allows Epirootkit to trigger execution of any command as root, with fine behavior management (redirection, timeout, etc.). Here's how each specification requirement is implemented:
The main function, exec_str_as_command_with_timeout(), receives a user command string (user_cmd), applies various preparations, then triggers its execution using the call_usermodehelper_exec() function via:
This is equivalent to doing:
But this command is launched from kernel space.
Standard output (stdout) and error (stderr) retrieval is ensured by globally defined redirection files, typically:
If the user hasn't included redirections themselves (> or 2>), the module manually redirects these flows to the above files. This allows the attacker to later retrieve execution results. The management code is located in the build_full_command() function, which assembles the final command based on redirection state detected by detect_redirections().
The detect_redirections() function scrutinizes the user command to determine if explicit redirections are already present. It spots > (stdout) and 2> (stderr) patterns. If the user has already handled redirections, the module doesn't add its own, avoiding any conflicting redundancy:
An essential element to avoid blocking is the timeout mechanism. The module builds a timeout command prefix thanks to build_timeout_prefix():
This prefix is automatically inserted into the final shell command. Thus, if the command doesn't finish within the allotted time, it's killed with SIGKILL, and the return code is preserved. Example of generated command:
trim_leading_whitespace().> and 2> via detect_redirections().build_timeout_prefix() builds the command.build_full_command(), integrating:call_usermodehelper_exec().timeout, no risk of leaving blocking/infinite processes in background threads.