Avoiding Code Injection With Find And Xargs
Code injection attacks take advantage of vulnerabilities in web applications to inject malicious code. This code gets executed by the application and allows the attacker to access resources or data that they should not have access to. Code injection can lead to data theft, corruption, or deletion. Some common examples include SQL injection, OS command injection, and LDAP injection.
The find and xargs commands in Linux can be vulnerable to injection attacks if used incorrectly. find searches for files matching specified criteria and xargs takes the results from find and passes them as arguments to a specified command. If arguments are not properly quoted or validated, an attacker could inject code that gets executed when xargs passes the arguments to the command.
Define what code injection is and why it’s dangerous
Code injection occurs when untrusted input is passed to an interpreter as part of a command or query. Attackers can craft the input in such a way that it changes how the command or query is interpreted, allowing them to execute arbitrary commands. This takes advantage of loose input validation on insecurely designed applications.
There are several types of code injection:
- SQL injection: Inserting database commands into input fields for execution
- OS command injection: Inserting shell commands into application parameters
- LDAP injection: Manipulating LDAP queries to access unauthorized data
Dangers arising from code injection include:
- Remote code execution on servers, potentially gaining admin access
- Accessing sensitive data from databases, files, etc.
- Manipulating or destroying data
- Pivoting deeper into systems for lateral movement
- Maintaining persistence on systems
Explain how find and xargs can lead to code injection if used improperly
The find command recursively searches file system directories for matching files. By itself, find is safe from code injection. However, the results can then be piped to xargs, which converts the results into an executable command.
If xargs is provided unsanitized input from find, like filenames or paths, it could then execute harmful commands by expanding those paths. For example, if find discovers a file named "; rm -rf /;"
, and directly pipes this to xargs without sanitizing, xargs may delete the root file system when executing the command. Delimiters like “;” can separate multiple commands for xargs to run multiple injections in a single execution.
Some ways attackers can exploit improper use of find and xargs:
- Craft malicious filenames like
"; malicious command;"
to inject when run by xargs - Poison the paths searched by find to inject payloads into results
- Use unquoted parameters for easy shell expansions
Following best practices is key to preventing code injection from untrusted input when using find and xargs in scripts or one-liners.
Quoting Arguments to find and xargs
Give examples of unquoted arguments allowing code injection
If xargs arguments are not properly quoted, attackers can inject arbitrary commands which will execute when passed to the system shell for expansion. For example:
find . -print | xargs grep pattern
Here the results from find are passed without quoting to xargs, which then passes them to the grep command. An attacker could inject code like so:
touch '/tmp/exploit; rm -rf /; echo exploit' find . -print | xargs grep exploit # xargs now executes code injected by the attacker
Likewise, improper quoting with find can expose it directly to shell expansion before execution:
find $INPUT -name "*.txt" -print
If $INPUT is user-supplied without sanitizing, they could enter:
; rm -rf /;
Causing rm -rf / to execute when find runs the unsanitized input.
Demonstrate proper quoting of arguments to prevent expansions
To prevent code injection and malicious expansions, both find and xargs arguments should be properly quoted. Here is an example:
find . -name "*.txt" -print0 | xargs -0 -I {} grep pattern '{}'
The -print0 flag to find outputs null delimited results that won’t be split or expanded by shells. Xargs -0 consumes the null delimited input safely. Argument {} is quoted to prevent shell interpretation.
Single and double quotes around arguments prevent unwanted expansions:
find '$INPUT' -name "*.txt" -print
$INPUT is now quoted and will not expand. This helps sanitize find inputs safely.
Using find Safely with xargs
Explain dangers of piping find directly to xargs
Piping find directly to xargs can lead to code injection if filenames or paths contain malicious commands. For example:
find /home -name '*.png' -print | xargs rm
Here the found filenames matching *.png get passed unsanitized to xargs rm. An attacker could place a specially crafted filename like ';rm -rf /;#
that executes arbitrary commands when xargs passes it to rm.
In addition, spaces in filenames can cause args to split in unexpected ways. Newlines and special characters can also affect scripts that don’t expect them.
Alternative delimiters should be used instead of unquoted arguments to xargs. Where possible, found names should be sanitized before reaching potentially dangerous system commands.
Show safer alternatives like -print0 and -0 for null delimiters
Instead of using unquoted find arguments, using null delimiters prevents splits, spaces, newlines and special characters from affecting downloads.
find . -name '*.png' -print0 | xargs -0 rm
find -print0 uses null characters to separate filenames before output instead of standard delimiters. xargs -0 consumes this null delimited input safely without spliiting or glob expansion.
Other options like -exec and -delete also invoke commands safely after checks:
find /home -name '*.png' -exec rm '{}' \;
Overall when piping find to xargs or other commands, proper delimiting and quoting is necessary to prevent expansion or splitting that could expose code injection vulnerabilities.
Validating Inputs and Sanitizing Data
Emphasize importance of data validation before piping to commands
Before passing user inputs and external data to find/xargs parameters, proper validation and sanitization should occur to prevent code injection:
- Validate expected input formats – whitelist allowable characters
- Sanitize with escapes or strips of bad characters
- Encode interpreting dangerous characters like <, >, |, ; etc
- Quote arguments to prevent glob and variable expansion
For robust solutions, defense in depth with multiple protections should be used. Higher level policies can enforce principle of least privilege regarding access and analysis of sensitive file repositories. Multi-factor authentication also prevents unauthorized access for uploading malicious payloads.
Give examples of sanitizing filenames and input to prevent code execution
User input with potential code injections:
$INPUT="/tmp/file; rm -rf /; echo"
Strip executables with whitelist of allowable filenames:
SANITIZED=`echo "$INPUT" | sed -e 's/[;&|<>]/_/g;`
Sanitized input:
$SANITIZED = "/tmp/file_rm-rf_/echo"
Likewise, found filenames can be sanitized before xargs:
find . -name \* -print0 | sed "s/['\';|&]//g" | xargs -0 rm
This strips bad characters from names before deleting with rm avoiding code injection. Similar methods should sanitize paths and parameters to inoculate against untrusted inputs expanding to harmful commands.
Employing Shell Parameter Expansion Carefully
Warn against uncontrolled parameter expansion
Bash shell allows variables to expand to commands if parameters reference environmental variables and special characters:
$FOO='*; rm -rf /' echo $FOO # Runs rm -rf / after expanding
Accessing environmental variables should be done safely:
ID="$UNTRUSTED_VAR" grep pattern "$ID" # Potential code injection trigger
Unquoted expansions of untrusted variables can lead to arbitrary command execution. Use plain data references without touching the shell when possible.
Provide guidelines on quoting expansion like “$@” vs “$*”
Bash expands positional parameters like $1 differently depending on quoting:
"$@" - $1 to $N as separate quoted arguments "$*" - Concatenates parameters as single quoted argument
This matters when passing unsanitized parameters or filenames:
find . -name \* -print0 | xargs -I '{}' echo "$@" # Separates names - safer find . -name \* -print0 | xargs -I '{}' echo "$*" # Concatenates - exposes injections
Always prefer “$@” form for passing unnamed positional parameters securely.
In general avoid unquoted expansion of names, paths and variables if sourced externally. Validate then quote or sanitize first.
Verifying Expected Behavior and Outputs
Highlight testing outputs before relying on scripts
Before deploying find/xargs scripts to production systems, thorough testing helps verify expected control flows to prevent logic flaws. Test with valid and invalid sample input data:
- Echo outputs to check escaping/encoding
- Dry run fake commands like : > /dev/null to prevent real impact
- Start from non-privilege accounts first
- Check exit codes and return values at each step
Monitor system resources during testing to detect abnormal activities from potentially malicious actions.
Check exit codes and return values at each stage
Tools like set can enforce exit codes and return values halting scripts if issues occur:
find /home \( -name '*.png' -o -name '*.jpg' \) -print0 | { set -eo pipefail; xargs -0 mv -t /images/ {}; }
-e exits immediately if any command fails
-o requires exit code 0 to proceed
pipefail catches errors in pipelines
These best practices help minimize reach of unintended behaviour before it impacts production systems. Auditing logs for errors provides visibility so scripts can be locked down further as needed.