DEV Community

Cover image for Are you building a vulnerable tool? - Introduction to shlex module
Curious Dev Grail
Curious Dev Grail

Posted on

Are you building a vulnerable tool? - Introduction to shlex module

Whenever a newbie enters to the world of the python, due to being extensively used in different area of IT world, whether it is machine learning, web application, or Desktop application etc. He gets into the world of python in such a way, that he starts contributing a vulnerable tool to the community. It is quite important to understand that your simple code can be so dangerous that it may compromise the whole system into wrong hand.

Consider you are building a tool that need to execute some OS command and based on that he needs to perform some further actions. Although the developer intention was to only create a tool that serve the major world in some better way but unintentionally he didn't aware of that without following some guidelines it will leads to destructive result.

Suppose an organization wants to make available all the content locally to their student to browse the content in remote area where they don't have much internet connectivity. And they hire a local developer who said i will do it within an hour, and will do this task in just couple of bucks. That seems more promising to them, as the tool will be ready in just an hour with very few charges. Consider he gives this vulnerable script to the organization:

import subprocess
from urllib.parse import urlparse


def downloader(host):
    parsed_url = urlparse(host)

    command = "mkdir -p $HOME/Downloads/local $HOME/Downloads/local/logs"
    process = subprocess.run(command, shell=True, executable="/bin/bash")

    command = "cd $HOME/Downloads/local && wget -p $HOME/Downloads --recursive" + \
              " --page-requisites --html-extension --convert-links --domains " + \
              f"{parsed_url.hostname}  --no-parent {host} &>logs/output.log"
    process = subprocess.run(command, shell=True, executable="/bin/bash")
    return parsed_url.hostname


if __name__ == "__main__":
    url = input("Enter Url: ").strip()
    domain = downloader(url)
    print(f"Your Local website {domain} is downloaded in Downloads Directory")

This piece of code will make his work of one hour of code to just five to ten minutes. So let's just try to download this https://quotes.toscraper.com
Intended Output

Everything seems to be perfect, until some malicious intended person try to give input something like this https://google.com ; whoami #
Non Intended Output
Whoa! what's it does? It let's you detect who is the current logged in user. If such tool is exposed over rest API how remotely can gain access to system or demolish system which are running this insecure piece of code.
The above unintended action performed particularly called as Command Injection. So how you can make this code a bit secure, in order to work in the similar fashion.
One way is to code it in another way without using shell=True But in that case your code won't be able to use Shell Variables, Pipes, and Glob .
Other way is python provide a way, when you can't avoid using shell = True . A python module known as Shlex. So let's just change the piece of code to incorporate changes regarding shlex.

import subprocess
from urllib.parse import urlparse
import shlex


def downloader(host):
    parsed_url = urlparse(host)

    command = "mkdir -p $HOME/Downloads/local $HOME/Downloads/local/logs"
    subprocess.run(command, shell=True, executable="/bin/bash")

    command = "cd $HOME/Downloads/local && wget  -q --show-progress --progress=bar:force -p $HOME/Downloads --recursive" + \
              " --page-requisites --html-extension --convert-links --domains " + \
              f"{shlex.quote(parsed_url.hostname)}  --no-parent {shlex.quote(host)} &>logs/output.log"
    subprocess.run(command, shell=True, executable="/bin/bash")
    return parsed_url.hostname


if __name__ == "__main__":
    url = input("Enter Url: ").strip()
    domain = downloader(url)
    print(f"Your Local website {domain} is downloaded in Download Directory")

This code work perfectly with the expected input.
Intended Output
But let's just try that non intended output.
Non Intended Output
Even though the results aren't been saved to download directory with this input as it is processed without error checking, but it didn't let user execute secondary command.
That's it folks, coming with new post with next month. Please share with your Python Geeks friend.

Summary

Unintentionally day by day new insecure code being added to our world. Command Injection is one of the serious vulnerabilities that let's compromise a system running vulnerable piece of code with unintended or malicious output. CLI tools build with Python module like subprocess or any other module that interact with OS API are vulnerable to such command injection. Thought there is no sure short way to prevent such command injection, but you can reduce the vulnerability by using module that are prebuild and less introduced in the tutorials. Shlex is one of the pythonic Module.

Referral Links

Shlex: https://docs.python.org/3/library/shlex.html
Command Injection: https://owasp.org/www-community/attacks/Code_Injection
Glob: https://en.wikipedia.org/wiki/Glob_(programming)

Originally Posted at: Are you building a vulnerable tool? — Introduction to shlex module: curious-dev-grail (Medium)

Top comments (0)