Bash Security – Why Command Injection Fails

bashSecurity

Why does command injection not work in

$ bash -c "ls \$1" bash '.; echo hello'
ls: cannot access '.;': No such file or directory
ls: cannot access 'echo': No such file or directory
ls: cannot access 'hello': No such file or directory

while

$ bash -c "eval ls \$1" bash '.; echo hello'

works?

In the first command, does the first bash perform parameter expansion on $1, word splitting on the result of expanding $1, and then execute the commands?

Thanks.

Originated from Ways to provide arguments to a command executed by `bash -c`

related to Why is this code injection not working?

Best Answer

This is the same process as in "run any command which will pass untrusted data to commands which interpret arguments as commands".

Your first command,

bash -c "ls \$1" bash '.; echo hello'

is processed as follows:

  • bash runs with the arguments -c, ls $1, bash, .; echo hello. bash reads its arguments, notes the -c option with the command ls $1, and the extra arguments bash and .; echo hello;

  • when bash expands ls $1, it expands to ls with the arguments .;, echo, hello and runs that.

The semi-colon would have had to be processed before variable expansion to cause bash to run two different commands.

Your second command,

bash -c "eval ls \$1" bash '.; echo hello'

is processed as follows:

  • bash runs with the arguments -c, eval ls $1, bash, .; echo hello. bash reads its arguments, notes the -c option with the command eval ls $1 etc.

  • after expansion it runs eval with the arguments ls, .;, echo, hello;

  • eval then causes the arguments to be re-parsed, resulting in the execution of ls . followed by echo hello.

Related Question