The shell is an interpreter you did not need
Command injection has a property that makes it more serious than any other injection: it is not confined to one subsystem. SQL injection gives an attacker the database account's privileges. Command injection gives them the application process's — meaning every file it can read, every API it can call, and an outbound connection.
But this lesson is not about severity. It is about something simpler: in almost every case, you did not need a shell.
When you write Process.Start("bash", $"-c \"convert {file} out.png\"") you are doing two things: invoking convert, and starting a full interpreter to parse a command string first. The second is the thing you did not need and the thing that creates the hole. A shell is what understands ;, |, &&, $(...), ` `, > and *` — and each of those is an escape route.
If you invoke convert directly with an argument array, no shell exists, so no character carries special meaning. ; rm -rf / becomes a very strange filename, and convert reports that it cannot find it.
This is the same principle as SQL parameterisation, and it is worth stating plainly because it recurs at every interpreter:
| Interpreter | Wrong way | Right way |
|---|---|---|
| SQL | Concatenate into the statement | Parameters |
| Shell | Concatenate into a command line | An argument array, no shell |
| HTML | Concatenate into markup | Encode for the context |
| XML | The default parser | Disable external entities |
Why shell escaping is a dead end, even with a library for it: escape correctly for which shell? bash, sh, cmd.exe and PowerShell have four different rule sets, and cmd.exe is famously impossible to escape correctly in all cases. Remove the shell and the question stops existing.
Comments
Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.
You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.
Loading comments…