Forming sanitary shell commands or system calls in Ruby
Solution 1
It doesn't look like you need a shell for what you're doing. See the documentation for system
here: http://ruby-doc.org/core/classes/Kernel.html#M001441
You should use the second form of system
. Your example above would become:
system 'usermod', '-p', @options['shadow'], @options['username']
A nicer (IMO) way to write this is:
system *%W(usermod -p #{@options['shadow']} #{@options['username']})
The arguments this way are passed directly into the execve
call, so you don't have to worry about sneaky shell tricks.
Solution 2
If you need not just the exit status but also the result you probably want to use Open3.popen3
:
require 'open3'
stdin, stdout, stderr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
stdout.gets
sterr.gets
More information here: Getting output of system() calls in Ruby
Solution 3
I'd suggest looking into the 'shellwords' module. This script:
require 'shellwords'
parts = ['echo', "'hello world'; !%& some stuff", 'and another argument']
command = Shellwords.shelljoin( parts )
puts command
output = `#{ command }`
puts output
outputs the escaped text and the expected output:
echo \'hello\ world\'\;\ \!\%\&\ some\ stuff and\ another\ argument
'hello world'; !%& some stuff and another argument
Solution 4
This is an old question, but since it's pretty much the only real answer you'll find when googling I thought I'd add a caveat. The multi argument version of system seems reasonably safe on Linux, but it is NOT on Windows.
Try system "dir", "&", "echo", "hi!"
on a Windows system. Both dir and echo will be run. Echo could of course just as well be something far less innocuous.
Comments
-
arbales almost 2 years
I'm building a daemon that will help me manage my server(s). Webmin works fine, as does just opening a shell to the server, but I'd prefer to be able to control server operations from a UI I design, and also expose some functionality to end users.
The daemon will pick up actions from a queue and execute them. However, since I'll be accepting input from users, I want to make sure they're not permitted to inject something dangerous into a privileged shell command.
Here's a fragment that exemplifies my problem:
def perform system "usermod -p #{@options['shadow']} #{@options['username']}" end
A gist that explains more: https://gist.github.com/773292
I'm not positive if typical escaping and sanitizing of inputs is enough for this case, and being a designer, I don't have a ton of security-related experience. I know that this is something that should probably be obvious to me, but its not!
How can I ensure that the web application that will create and serialize the actions can't pass dangerous text into the privileged process that receives the actions?
Thanks for the help
arb -
arbales over 13 yearsso, let's say if I exposed this class, completely unfiltered (I won't) to an end user, and they provided a shadow hash and then "username; rm -rf /" as the username — this wouldn't have the effect of obliterating
/
-
cam over 13 yearsCorrect. The arguments are passed directly to the executed program. You can verify this by yourself. Try running
ruby -e 'system *W(ls -l foo; rm -rf /)'
-
arbales over 13 yearsah, well great. It does make perfect sense. I think I have this thought that ensuring an application is secure must naturally be harder than it is, harder than simple steps and facts, as if there exists a dangerous edge case for everything. This is likely because I've never read / learned very much about it.
-
Stuart Nelson almost 11 yearsthis also has the added benefit of using system calls, instead of making the calls through bash and then to the system (saves a little overhead on top of the sanitization)
-
Daniel Le over 2 yearsThe example given by above should read
ruby -e 'system *%w(ls -l foo; rm -rf /)'
instead.