Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shell injection #4

Closed
sepandhaghighi opened this issue Jun 1, 2023 · 5 comments · Fixed by #9
Closed

Shell injection #4

sepandhaghighi opened this issue Jun 1, 2023 · 5 comments · Fixed by #9
Assignees
Labels
bug Something isn't working

Comments

@sepandhaghighi
Copy link
Member

Description

We use subprocess to play sound in Linux and macOS (__play_linux and __play_mac functions) so we should prevent possible shell injections from sound_path.

  1. It's better to implement this method as a decorator (like @input_check)
  2. We know that sound_path should be a path
@sepandhaghighi sepandhaghighi added this to the nava v0.1 milestone Jun 1, 2023
@sepandhaghighi sepandhaghighi added the bug Something isn't working label Jun 1, 2023
@sepandhaghighi
Copy link
Member Author

@AHReccese Please take a look at this issue.
If you have a solution, please explain it to us, then I will assign this issue to you.

@sadrasabouri sadrasabouri assigned AHReccese and unassigned AHReccese Jun 2, 2023
@AHReccese
Copy link
Member

@sepandhaghighi
Yes, I do
here is mine:

0- Check input is a valid file path with proper sound-associated format(such as mp3 and ...)
1- Use shlex.quote() to quote the file path argument
2- Using subprocess.run() instead of subprocess.check_call

By using shlex.quote() to escape your command-line arguments, you prevent any special characters in the arguments from being interpreted by the shell as commands or operators. This is important because unescaped special characters can be used in a shell injection attack to execute arbitrary commands on the system running the script.

For example, consider the following code:

import subprocess

# user_input is untrusted input from the user
user_input = "hello; rm -rf /"

subprocess.check_call(f"echo {user_input}")

If the user enters the string "hello; rm -rf /", this code will execute the following command:

echo hello; rm -rf /
This command will output the string "hello" and then delete all files on the root directory of the file system (/).

However, if we modify the code to use shlex.quote() to escape the user input like this:

import shlex
import subprocess

# user_input is untrusted input from the user
user_input = "hello; rm -rf /"

subprocess.check_call(f"echo {shlex.quote(user_input)}")

Then the echo command will receive the escaped string as an argument, like this:

echo 'hello; rm -rf /'
Now, the semicolon and the rm command are no longer interpreted by the shell as separate commands to be executed. Instead, they are treated as part of a single argument to the echo command, which will simply output the string "hello; rm -rf /".

subprocess.run() and subprocess.check_call() are two of these functions. Both functions are used to run a command and wait for it to complete before returning control to the Python program.

The difference between the two functions lies in how they handle errors.

subprocess.run(): This function returns a CompletedProcess object that contains information about the command that was executed. If the command fails, the CompletedProcess object will contain information about the error, such as the error code returned by the command.

subprocess.check_call(): This function raises a CalledProcessError exception if the command fails. This means that if you use check_call() and the command fails, your Python program will immediately stop executing and raise an exception.

So, why use subprocess.run() over subprocess.check_call() with shell=False?

One reason is that subprocess.run() is more flexible than subprocess.check_call(). With run(), you can specify various options, such as redirecting the command's output to a file or merging its output with the Python program's output.

Another reason is that subprocess.run() provides more detailed information about the command that was executed, including the command's arguments, the working directory in which the command was run, and the environment variables that were set.

Finally, subprocess.run() allows you to capture the output of the command, either as text or as bytes, which can be useful if you need to process the output in some way.

Overall, subprocess.run() is a more versatile and informative function than subprocess.check_call(). However, if you want your Python program to immediately stop executing if the command fails, then check_call() may be a better choice.

@sepandhaghighi
Copy link
Member Author

sepandhaghighi commented Jun 6, 2023

@AHReccese Thanks for your effort 🔥

  1. Nice approach 💯
  2. Perfect 💯
  3. You are right, but consider that in normal mode (not debug mode) we should print a general error to the user (something like Sound can not play due to some issues.), we will add debug mode in the next version, so we can work on this change there.

SH

AHReccese added a commit that referenced this issue Jun 7, 2023
check sound file existance added

quote the file path in a decorator pattern manner

associated docstrings added
sadrasabouri pushed a commit that referenced this issue Jun 8, 2023
* Fix Shell injection issue (#4)

check sound file existance added

quote the file path in a decorator pattern manner

associated docstrings added

* quote and path_check decorator as a function added

nava params renamed

associated docstrings updated

* requested changes applied

* requested changes applied

* requested changes applied
@AHReccese
Copy link
Member

@sadrasabouri @sepandhaghighi
If it's possible, please close this issue.

@sepandhaghighi
Copy link
Member Author

@sadrasabouri @sepandhaghighi If it's possible, please close this issue.

We will close it after version 0.1 release 🔥

@sadrasabouri sadrasabouri mentioned this issue Jun 9, 2023
@sepandhaghighi sepandhaghighi linked a pull request Jun 10, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants