What is the recommended method of sanitizing user_input_parameter passed to the shell like
subprocess.Popen(['sudo', 'rm -rf', user_input_parameter])
The command should accept all parameters but malicious activies like breaking out of the command should be mitigated.
Python's implementation of subprocess protects against shell injection, documentation says so:
17.5.2. Security Considerations
Unlike some other popen functions, this implementation will never
implicitly call a system shell. This means that all characters,
including shell metacharacters, can safely be passed to child
processes. If the shell is invoked explicitly, via shell=True, it is
the application’s responsibility to ensure that all whitespace and
metacharacters are quoted appropriately to avoid shell injection
vulnerabilities.
When using shell=True, the shlex.quote() function can be used to
properly escape whitespace and shell metacharacters in strings that
are going to be used to construct shell commands.
This will however NOT protect against a user passing a malicious input - in your case for example deleting something that was not intended to be deleted. I would not pass user input to the command directly like that - you should verify if whatever you want to be deleted is being deleted and not something completely different. That is however part of application's logic already - regarding shell injection (breaking out of the command) - that should be fine with subprocess.
I made this little example:
#!/usr/bin/env python3
import subprocess
user_input_parameter = '/; id'
subprocess.Popen(['ls', user_input_parameter])
Which outputs this when executed:
$ python3 asdf.py
ls: /; id: No such file or directory
$
To demonstrate subprocess passes the input as an argument to the parameter.
All of this is true only if shell=False (default as of writing this answer) for subprocess methods, otherwise you basically enable shell (bash, etc.) execution and allow for injection to happen if inputs are not properly sanitized.
Btw, you need to pass each parameter separately, so you would need to run it like this (but please don't do that):
subprocess.Popen(['sudo', 'rm', '-rf', user_input_parameter])
Related
I was trying to mimic a module system in my bash scripts separate files containing utility functions for string, date, system, etc. which I can import in my main script and do my work. The only thing I miss is, I want to create a namespace style separation on import. So for example, if I import the string-utils file, all functions defined in it should work only when I prepend a string. at the beginning of each function name in my main script. I realize I could just name all my functions as for example string.contains rather than only contains in the utility file itself, but it's not clean and I don't want to do that. I want to somehow declare the function prefix at the time of import. Something like import * from utils/string as string. Is there a way I can do that? Thanks!
From a practical view point, you are trying to eat your soup using a fork. Bash is not meant for employing name spaces. If you insist in doing something similar, I suggest that the autor of your sourced file cooperates in establishing your idea of a "namespace". For instance, if you your sourced file starts with
# This is file function_library.sh
: ${module:=''} # Default: No namespace
fun1() { # Define function without namespace
....
}
# Rename the function to be in namespace, based on the answer in
# https://stackoverflow.com/questions/1203583/how-do-i-rename-a-bash-function
eval "$(echo "${module}_fun1()"; declare -f fun1 | tail -n +2)"
and so on. When sourcing the file, you do a
module=my_name # set namespace
. function_library.sh
This is not only cumbersome, it is also odd that the importer defines the namespace of a library. A more common concept in namespaces is that the imported module itselt fould define, which namespace it is in, and this would make the awkward renaming unnecessary.
You will need to modify the content of the files where your functions are defined. You could do this on the fly with a text processor like awk, for example, but this depends on how your functions are declared. Example if they are always declared starting on a separate line with syntax:
function foo {
...
}
Then, you can preprocess the file with:
$ source <(awk -v prefix="foo." '$1 == "function" {$2 = prefix $2} 1' foo.sh)
If your function declarations are less regular you will have to use a more complicated preprocessor. And, more importantly, this is very fragile. If the functions declared in the sourced file are themselves called in the sourced file, or their name used in one way or another (aliases, arrays of function names, whatever), things will get much more complex: you will need to catch all these references and update them too.
I'm building a command-line interface using the argparse library to parse user input. At one stage, I'd like to take user input such as "'test', x=False" and use it in a function such as func('test', x=False).
I've tried using ast.literal_eval to do this but it encounters a syntax error at the equals sign. (I did ast.literal_eval("("+args+")") where args was above example)
Does anyone know of a safe way to parse the user input like that? Preferably without eval although worst-case scenario I could use eval as, well, it's a CLI tool.
Edit (to people that have said to use input manually(): I need the tool to parse input from when the command is run (it's a python module that I want to be able to be called like python3 -m hmcli.raw --args "'test', x=False" where the args can be flexible as the function used can differ.
Answering to the following question:
Allowed characters in linux environment variable names #aiden-bell writes that the following patterns gives all allowed shell variable names in BASH : [a-zA-Z_]+[a-zA-Z0-9_]*
I found this to be true. In fact I can export value _="Just for fun". Unfortunately though, whenever I print it I get __bp_preexec_invoke_exec
I went through this thread and while it is instructive it doesn't actually answer my question. Irrespective of whatever the shell might do with the variable $_, can I use it for my own means? Also, whatever exactly is __bp_preexec_invoke_exec? Thanks and regards.
You can assign to the special parameter _, but the shell will also update its value after each command. Typically, you only use it as a dummy variable where you don't care about the result, such as in something like
while read _ second _ ; do ...; done < input.txt
where you only care about the second column of each input line.
From the man page:
_ At shell startup, set to the absolute pathname used to invoke
the shell or shell script being executed as passed in the envi-
ronment or argument list. Subsequently, expands to the last
argument to the previous command, after expansion. Also set to
the full pathname used to invoke each command executed and
placed in the environment exported to that command. When check-
ing mail, this parameter holds the name of the mail file cur-
rently being checked.
Say you're building an app that runs a shell command based on unverified input.
Concatenating the arguments as a string is obviously a massive security risk, but is it the same case with the args option?
The docs don't mention anything about this. I ran a quick test:
var child = require("child_process");
child.spawn("touch", ["./filename", "&& touch ./hacked"]);
filename is created, but hacked isn't. Does that mean I can plug anything in the args array and assume it's safe?
I think the issue you're seeing isn't that it's sanitizing your input for you, I think it's that you can't use spaces in your arguments. See this answer.
I couldn't find anything online that gave any indication that your child spawning arguments are sanitized.
Good Afternoon Everyone,
This is probably a no-brainer but, I'm currently having issues passing a variable to a program in my bash script.
Here's what I'm trying to do:
regions=ne,se,vt,ma,sw,nw and so on and so forth
After that variable has been defined in my bash script, I'd then like to pass that variable into GrADS, where my script will read each of the regions one after the other until it reaches the end.
The most reliable means of passing variables I've found is to generate a text file with the code (or just the string) you want to pass from within the code. Alternatively, you could call GrADS (?) from within whatever program is generating the variable, and pass "$regions" as an argument.