| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- #
- # Copyright 2014 Hewlett-Packard Development Company, L.P.
- #
- # SPDX-License-Identifier: Apache-2.0
- r"""
- ========================================
- B609: Test for use of wildcard injection
- ========================================
- Python provides a number of methods that emulate the behavior of standard Linux
- command line utilities. Like their Linux counterparts, these commands may take
- a wildcard "\*" character in place of a file system path. This is interpreted
- to mean "any and all files or folders" and can be used to build partially
- qualified paths, such as "/home/user/\*".
- The use of partially qualified paths may result in unintended consequences if
- an unexpected file or symlink is placed into the path location given. This
- becomes particularly dangerous when combined with commands used to manipulate
- file permissions or copy data off of a system.
- This test plugin looks for usage of the following commands in conjunction with
- wild card parameters:
- - 'chown'
- - 'chmod'
- - 'tar'
- - 'rsync'
- As well as any method configured in the shell or subprocess injection test
- configurations.
- **Config Options:**
- This plugin test shares a configuration with others in the same family, namely
- `shell_injection`. This configuration is divided up into three sections,
- `subprocess`, `shell` and `no_shell`. They each list Python calls that spawn
- subprocesses, invoke commands within a shell, or invoke commands without a
- shell (by replacing the calling process) respectively.
- This test will scan parameters of all methods in all sections. Note that
- methods are fully qualified and de-aliased prior to checking.
- .. code-block:: yaml
- shell_injection:
- # Start a process using the subprocess module, or one of its wrappers.
- subprocess:
- - subprocess.Popen
- - subprocess.call
- # Start a process with a function vulnerable to shell injection.
- shell:
- - os.system
- - os.popen
- - popen2.Popen3
- - popen2.Popen4
- - commands.getoutput
- - commands.getstatusoutput
- # Start a process with a function that is not vulnerable to shell
- injection.
- no_shell:
- - os.execl
- - os.execle
- :Example:
- .. code-block:: none
- >> Issue: Possible wildcard injection in call: subprocess.Popen
- Severity: High Confidence: Medium
- CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
- Location: ./examples/wildcard-injection.py:8
- 7 o.popen2('/bin/chmod *')
- 8 subp.Popen('/bin/chown *', shell=True)
- 9
- >> Issue: subprocess call - check for execution of untrusted input.
- Severity: Low Confidence: High
- CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
- Location: ./examples/wildcard-injection.py:11
- 10 # Not vulnerable to wildcard injection
- 11 subp.Popen('/bin/rsync *')
- 12 subp.Popen("/bin/chmod *")
- .. seealso::
- - https://security.openstack.org
- - https://en.wikipedia.org/wiki/Wildcard_character
- - https://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt
- - https://cwe.mitre.org/data/definitions/78.html
- .. versionadded:: 0.9.0
- .. versionchanged:: 1.7.3
- CWE information added
- """
- import bandit
- from bandit.core import issue
- from bandit.core import test_properties as test
- from bandit.plugins import injection_shell # NOTE(tkelsey): shared config
- gen_config = injection_shell.gen_config
- @test.takes_config("shell_injection")
- @test.checks("Call")
- @test.test_id("B609")
- def linux_commands_wildcard_injection(context, config):
- if not ("shell" in config and "subprocess" in config):
- return
- vulnerable_funcs = ["chown", "chmod", "tar", "rsync"]
- if context.call_function_name_qual in config["shell"] or (
- context.call_function_name_qual in config["subprocess"]
- and context.check_call_arg_value("shell", "True")
- ):
- if context.call_args_count >= 1:
- call_argument = context.get_call_arg_at_position(0)
- argument_string = ""
- if isinstance(call_argument, list):
- for li in call_argument:
- argument_string = argument_string + " %s" % li
- elif isinstance(call_argument, str):
- argument_string = call_argument
- if argument_string != "":
- for vulnerable_func in vulnerable_funcs:
- if (
- vulnerable_func in argument_string
- and "*" in argument_string
- ):
- return bandit.Issue(
- severity=bandit.HIGH,
- confidence=bandit.MEDIUM,
- cwe=issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION,
- text="Possible wildcard injection in call: %s"
- % context.call_function_name_qual,
- lineno=context.get_lineno_for_call_arg("shell"),
- )
|