Repository: PyCQA/bandit (python)

Issue:
New plugin to check for use of pyghmi
**Is your feature request related to a problem? Please describe.**
IPMI is known to be a non-secure protocol.  

https://www.cisa.gov/uscert/ncas/alerts/TA13-207A

**Describe the solution you'd like**
New check plugin to detect use of pyghmi (python IPMI library).

**Describe alternatives you've considered**
N/A

**Additional context**
N/A


Pull request description:
 Add new plugin to check use of pyghmi
Merge branch 'feat/pyghmi' of ssh://github.com/stannum-l/bandit into ipmi
Signed-off-by: Eric Brown <browne@vmware.com>

This patch set adds a new bandit plugin to check the use of pyghmi.

Closes #356

Signed-off-by: Tin Lam tin@irrational.io


Patch:
diff --git a/bandit/blacklists/imports.py b/bandit/blacklists/imports.py
index a123d2b..3363c7f 100644
--- a/bandit/blacklists/imports.py
+++ b/bandit/blacklists/imports.py
@@ -212,6 +212,17 @@ of pyca/cryptography which has more support among the Python community.
 |      |                     | - Cryptodome.Util                  |           |
 +------+---------------------+------------------------------------+-----------+
 
+B415: import_pyghmi
+-------------------
+An IPMI-related module is being imported. IPMI is considered insecure. Use
+an encrypted protocol.
+
++------+---------------------+------------------------------------+-----------+
+| ID   |  Name               |  Imports                           |  Severity |
++======+=====================+====================================+===========+
+| B415 | import_pyghmi       | - pyghmi                           | high      |
++------+---------------------+------------------------------------+-----------+
+
 """
 from bandit.blacklists import utils
 from bandit.core import issue
@@ -410,4 +421,16 @@ def gen_blacklist():
         )
     )
 
+    sets.append(
+        utils.build_conf_dict(
+            "import_pyghmi",
+            "B415",
+            issue.Cwe.CLEARTEXT_TRANSMISSION,
+            ["pyghmi"],
+            "An IPMI-related module is being imported. IPMI is considered "
+            "insecure. Use an encrypted protocol.",
+            "HIGH",
+        )
+    )
+
     return {"Import": sets, "ImportFrom": sets, "Call": sets}
diff --git a/examples/pyghmi.py b/examples/pyghmi.py
new file mode 100644
index 0000000..44eb197
--- /dev/null
+++ b/examples/pyghmi.py
@@ -0,0 +1,5 @@
+from pyghmi.ipmi import command
+
+cmd = command.Command(bmc="bmc",
+                      userid="userid",
+                      password="ZjE4ZjI0NTE4YmI2NGJjZDliOGY3ZmJiY2UyN2IzODQK")
diff --git a/examples/sql_statements-py36.py b/examples/sql_statements-py36.py
deleted file mode 100644
index 5903205..0000000
--- a/examples/sql_statements-py36.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import sqlalchemy
-
-# bad
-query = "SELECT * FROM foo WHERE id = '%s'" % identifier
-query = "INSERT INTO foo VALUES ('a', 'b', '%s')" % value
-query = "DELETE FROM foo WHERE id = '%s'" % identifier
-query = "UPDATE foo SET value = 'b' WHERE id = '%s'" % identifier
-query = """WITH cte AS (SELECT x FROM foo)
-SELECT x FROM cte WHERE x = '%s'""" % identifier
-# bad alternate forms
-query = "SELECT * FROM foo WHERE id = '" + identifier + "'"
-query = "SELECT * FROM foo WHERE id = '{}'".format(identifier)
-query = f"SELECT * FROM foo WHERE id = {tmp}"
-
-# bad
-cur.execute("SELECT * FROM foo WHERE id = '%s'" % identifier)
-cur.execute("INSERT INTO foo VALUES ('a', 'b', '%s')" % value)
-cur.execute("DELETE FROM foo WHERE id = '%s'" % identifier)
-cur.execute("UPDATE foo SET value = 'b' WHERE id = '%s'" % identifier)
-# bad alternate forms
-cur.execute("SELECT * FROM foo WHERE id = '" + identifier + "'")
-cur.execute("SELECT * FROM foo WHERE id = '{}'".format(identifier))
-cur.execute(f"SELECT * FROM foo WHERE id {tmp}")
-
-# good
-cur.execute("SELECT * FROM foo WHERE id = '%s'", identifier)
-cur.execute("INSERT INTO foo VALUES ('a', 'b', '%s')", value)
-cur.execute("DELETE FROM foo WHERE id = '%s'", identifier)
-cur.execute("UPDATE foo SET value = 'b' WHERE id = '%s'", identifier)
-
-# bug: https://bugs.launchpad.net/bandit/+bug/1479625
-def a():
-    def b():
-        pass
-    return b
-
-a()("SELECT %s FROM foo" % val)
-
-# real world false positives
-choices=[('server_list', _("Select from active instances"))]
-print("delete from the cache as the first argument")


Test patch:
diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py
index c0a8030..ecfe878 100644
--- a/tests/functional/test_functional.py
+++ b/tests/functional/test_functional.py
@@ -385,41 +385,21 @@ class FunctionalTests(testtools.TestCase):
 
     def test_sql_statements(self):
         """Test for SQL injection through string building."""
-        filename = "sql_statements{}.py"
-        if sys.version_info <= (3, 6):
-            filename = filename.format("")
-            expect = {
-                "SEVERITY": {
-                    "UNDEFINED": 0,
-                    "LOW": 0,
-                    "MEDIUM": 14,
-                    "HIGH": 0,
-                },
-                "CONFIDENCE": {
-                    "UNDEFINED": 0,
-                    "LOW": 8,
-                    "MEDIUM": 6,
-                    "HIGH": 0,
-                },
-            }
-        else:
-            filename = filename.format("-py36")
-            expect = {
-                "SEVERITY": {
-                    "UNDEFINED": 0,
-                    "LOW": 0,
-                    "MEDIUM": 16,
-                    "HIGH": 0,
-                },
-                "CONFIDENCE": {
-                    "UNDEFINED": 0,
-                    "LOW": 9,
-                    "MEDIUM": 7,
-                    "HIGH": 0,
-                },
-            }
-
-        self.check_example(filename, expect)
+        expect = {
+            "SEVERITY": {
+                "UNDEFINED": 0,
+                "LOW": 0,
+                "MEDIUM": 14,
+                "HIGH": 0,
+            },
+            "CONFIDENCE": {
+                "UNDEFINED": 0,
+                "LOW": 8,
+                "MEDIUM": 6,
+                "HIGH": 0,
+            },
+        }
+        self.check_example("sql_statements.py", expect)
 
     def test_ssl_insecure_version(self):
         """Test for insecure SSL protocol versions."""
@@ -851,6 +831,14 @@ class FunctionalTests(testtools.TestCase):
         }
         self.check_example("pycryptodome.py", expect)
 
+    def test_blacklist_pyghmi(self):
+        """Test calling pyghmi methods"""
+        expect = {
+            "SEVERITY": {"UNDEFINED": 0, "LOW": 1, "MEDIUM": 0, "HIGH": 1},
+            "CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 1, "HIGH": 1},
+        }
+        self.check_example("pyghmi.py", expect)
+
     def test_snmp_security_check(self):
         """Test insecure and weak crypto usage of SNMP."""
         expect = {