?

Log in

No account? Create an account
Shell Variable Injection - Shlomif's Technical Posts Community [entries|archive|friends|userinfo]
Shlomif's Technical Posts Community

[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| Shlomi Fish's Homepage Main Journal Homesite Blog Planet Linux-IL Amir Aharoni in Unicode open dot dot dot ]

Shell Variable Injection [Sep. 18th, 2008|02:32 pm]
Shlomif's Technical Posts Community

shlomif_tech

[shlomif]
[Tags|, , , , , , , , , , , , , , , , ]
[Current Location |Home]
[Current Mood |lazylazy]
[Current Music |UB40 - I Got You Babe]

GuySoft writes in his blog about Unix shell commands to convert video. In the shell commands, he expands variablse like -srate 22050 $infile -o $outfile".flv", without putting them inside double-quotes. In this post, I'd like to demonstrate why this is so dangerous.

When the shell expands a regular variable outside quotes it breaks into words separated by whitespace and then evaluates every word separately. To use a variable as a single token, one must enclose it inside double-quotes: "$MY_VARIABLE".

Now, let's demonstrate what can happen when we don't do it properly. I'm in the home directory of a user called "shelltest on my machine". Let's see what we have there:

[shelltest@telaviv1 ~]$ ls
Desktop/          test-shell-injection.sh*  tmp/
Freecell-Solver/  test-shell-injection.sh~
[shelltest@telaviv1 ~]$ du -s Freecell-Solver/
86M     Freecell-Solver/
[shelltest@telaviv1 ~]$ cat test-shell-injection.sh
#!/bin/sh
mkdir -p $HOME/Backup
cp $1 $HOME/Backup/
rm $1
[shelltest@telaviv1 ~]$

We have the populated "Freecell-Solver" directory, and a shell script called "test-shell-injection.sh" that uses $1 (its first positional argument) unsafely.

Now let's abuse it:

[shelltest@telaviv1 ~]$ ./test-shell-injection.sh "-fr $HOME/Freecell-Solver"
[shelltest@telaviv1 ~]$ ls -l
total 8
drwxrwxr-x 3 shelltest shelltest 28 2008-09-18 14:14 Backup/
drwxr-xr-x 2 shelltest shelltest  6 2008-09-18 14:05 Desktop/
-rwxrwxr-x 1 shelltest shelltest 58 2008-09-18 14:11 test-shell-injection.sh*
-rw-rw-r-- 1 shelltest shelltest 60 2008-09-18 14:09 test-shell-injection.sh~
drwx------ 3 shelltest shelltest 28 2008-09-18 14:07 tmp/
[shelltest@telaviv1 ~]$

Voila! Freecell-Solver is gone. I could have also said ./test-shell-injection.sh "-fr $HOME" to delete the home directory. If the script does something like for I in * ; do ... # Something with $I .. done, then a malicious user can supply a file called "-fr $HOME" (where $HOME is the value of the home directory) in the input to delete the home directory.

In short: when writing shell scripts, always enclose variable expansion in double quotes, unless you are certain that they don't contain whitespace (which implies that you generated them yourselves), or you want to use them as a list (which also requires that you generated them yourselves).

LinkReply

Comments:
[User Picture]From: explodingferret
2008-09-18 01:12 pm (UTC)
Here's a similar example I have seen several times. It involves interesting filenames rather than a badly behaved program argument. It shows the less devious (but also more likely) problem of being given correct but unexpected input, and how not quoting can lead to bizarre errors or, worse, bad behaviour and data loss.

In my test directory I have two files, one that is very important, and another less so. They are named to reflect this:

xand@praxis:~/test$ ls -l
total 4
-rw-r--r-- 1 xand users 0 2008-09-18 13:58 important
-rw-r--r-- 1 xand users 0 2008-09-18 13:58 not important
-rwxr-xr-x 1 xand users 56 2008-09-18 14:03 remove
xand@praxis:~/test$ cat remove
#!/bin/sh

echo "removing $1!"
rm $1
echo "$1 removed!"

xand@praxis:~/test$

As you can see I also have a fancy script to remove files that I don't want. Today I want to remove my 'not important' file. So I do this:
./remove not\ important
Luckily, I used the tab completion feature of my shell to complete the filename, escaping the space, so the filename is passed to the remove script as a single token. So I'm safe... right?

xand@praxis:~/test$ ./remove not\ important
removing not important!
rm: cannot remove `not': No such file or directory
not important removed!
xand@praxis:~/test$ ls -l
total 4
-rw-r--r-- 1 xand users 0 2008-09-18 13:58 not important
-rwxr-xr-x 1 xand users 56 2008-09-18 14:03 remove
xand@praxis:~/test$

Woah! My important file is gone!

Yep, it turns out the problem is in the script:
rm $1
The shell uses the process known as "word splitting" on the unquoted variable expansion, so that rm actually gets two arguments: 'not' and 'important'. Obviously it should have been:
rm "$1"

(( woops, had to delete the first attempt because of mistakes ))
(Reply) (Thread)