sean cassidy : Don't Pipe to your Shell

in: programming

Piping wget or curl to bash or sh is stupid. Like this:

wget -O - | sudo sh

It's everywhere. Sometimes they tell you to ignore certificates as well (looking at you, Salt). That's dumb.

The main reason I think it's dumb (other than running arbitrary commands on your machine that could change based on user agent to trick you) is its failure mode.

What happens if the connection closes mid stream? Let's find out.

(echo -n "echo \"Hello\""; cat) | nc -l -p 5555

This will send a command to whoever connects, but won't send the newline. Then, it'll hang. Let's connect the client:

nc localhost 5555 | sh

At first, nothing happens. Great. What will happen if we kill -9 the listening netcat? Will sh execute the partial command in its buffer?


nc localhost 5555 | sh

But what about wget, or curl?

wget -O - http://localhost:5555 | sh
--2013-10-31 16:22:38--  http://localhost:5555/
Resolving localhost (localhost)...
Connecting to localhost (localhost)||:5555... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: `STDOUT'

    [          <=>                                                  ] 12          --.-K/s   in 8.6s

2013-10-31 16:22:47 (1.40 B/s) - written to stdout [12]


What if that partial command wasn't a harmless echo but instead one of these:

rm -rf $TMP_DIR

Harmless, right? And what if the connection closes immediately after 'rm -rf $TMP' is sent? It'll delete everything in the temp directory, which is certainly harmful.

This might be unlikely, but the results of this happening, even once, could be catastrophic.

Friends don't let friends pipe to sh.

Update: I updated the last example because it really made no sense. Thanks to player2 and ZackMcAck on reddit.

Sean is a software engineer and aspiring writer who is passionate about doing things right.

Follow @ex509