injection_wildcard.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #
  2. # Copyright 2014 Hewlett-Packard Development Company, L.P.
  3. #
  4. # SPDX-License-Identifier: Apache-2.0
  5. r"""
  6. ========================================
  7. B609: Test for use of wildcard injection
  8. ========================================
  9. Python provides a number of methods that emulate the behavior of standard Linux
  10. command line utilities. Like their Linux counterparts, these commands may take
  11. a wildcard "\*" character in place of a file system path. This is interpreted
  12. to mean "any and all files or folders" and can be used to build partially
  13. qualified paths, such as "/home/user/\*".
  14. The use of partially qualified paths may result in unintended consequences if
  15. an unexpected file or symlink is placed into the path location given. This
  16. becomes particularly dangerous when combined with commands used to manipulate
  17. file permissions or copy data off of a system.
  18. This test plugin looks for usage of the following commands in conjunction with
  19. wild card parameters:
  20. - 'chown'
  21. - 'chmod'
  22. - 'tar'
  23. - 'rsync'
  24. As well as any method configured in the shell or subprocess injection test
  25. configurations.
  26. **Config Options:**
  27. This plugin test shares a configuration with others in the same family, namely
  28. `shell_injection`. This configuration is divided up into three sections,
  29. `subprocess`, `shell` and `no_shell`. They each list Python calls that spawn
  30. subprocesses, invoke commands within a shell, or invoke commands without a
  31. shell (by replacing the calling process) respectively.
  32. This test will scan parameters of all methods in all sections. Note that
  33. methods are fully qualified and de-aliased prior to checking.
  34. .. code-block:: yaml
  35. shell_injection:
  36. # Start a process using the subprocess module, or one of its wrappers.
  37. subprocess:
  38. - subprocess.Popen
  39. - subprocess.call
  40. # Start a process with a function vulnerable to shell injection.
  41. shell:
  42. - os.system
  43. - os.popen
  44. - popen2.Popen3
  45. - popen2.Popen4
  46. - commands.getoutput
  47. - commands.getstatusoutput
  48. # Start a process with a function that is not vulnerable to shell
  49. injection.
  50. no_shell:
  51. - os.execl
  52. - os.execle
  53. :Example:
  54. .. code-block:: none
  55. >> Issue: Possible wildcard injection in call: subprocess.Popen
  56. Severity: High Confidence: Medium
  57. CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
  58. Location: ./examples/wildcard-injection.py:8
  59. 7 o.popen2('/bin/chmod *')
  60. 8 subp.Popen('/bin/chown *', shell=True)
  61. 9
  62. >> Issue: subprocess call - check for execution of untrusted input.
  63. Severity: Low Confidence: High
  64. CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
  65. Location: ./examples/wildcard-injection.py:11
  66. 10 # Not vulnerable to wildcard injection
  67. 11 subp.Popen('/bin/rsync *')
  68. 12 subp.Popen("/bin/chmod *")
  69. .. seealso::
  70. - https://security.openstack.org
  71. - https://en.wikipedia.org/wiki/Wildcard_character
  72. - https://www.defensecode.com/public/DefenseCode_Unix_WildCards_Gone_Wild.txt
  73. - https://cwe.mitre.org/data/definitions/78.html
  74. .. versionadded:: 0.9.0
  75. .. versionchanged:: 1.7.3
  76. CWE information added
  77. """
  78. import bandit
  79. from bandit.core import issue
  80. from bandit.core import test_properties as test
  81. from bandit.plugins import injection_shell # NOTE(tkelsey): shared config
  82. gen_config = injection_shell.gen_config
  83. @test.takes_config("shell_injection")
  84. @test.checks("Call")
  85. @test.test_id("B609")
  86. def linux_commands_wildcard_injection(context, config):
  87. if not ("shell" in config and "subprocess" in config):
  88. return
  89. vulnerable_funcs = ["chown", "chmod", "tar", "rsync"]
  90. if context.call_function_name_qual in config["shell"] or (
  91. context.call_function_name_qual in config["subprocess"]
  92. and context.check_call_arg_value("shell", "True")
  93. ):
  94. if context.call_args_count >= 1:
  95. call_argument = context.get_call_arg_at_position(0)
  96. argument_string = ""
  97. if isinstance(call_argument, list):
  98. for li in call_argument:
  99. argument_string = argument_string + " %s" % li
  100. elif isinstance(call_argument, str):
  101. argument_string = call_argument
  102. if argument_string != "":
  103. for vulnerable_func in vulnerable_funcs:
  104. if (
  105. vulnerable_func in argument_string
  106. and "*" in argument_string
  107. ):
  108. return bandit.Issue(
  109. severity=bandit.HIGH,
  110. confidence=bandit.MEDIUM,
  111. cwe=issue.Cwe.IMPROPER_WILDCARD_NEUTRALIZATION,
  112. text="Possible wildcard injection in call: %s"
  113. % context.call_function_name_qual,
  114. lineno=context.get_lineno_for_call_arg("shell"),
  115. )