CVE-2021-38606: Use of Insufficiently Random Values (CWE-330)
value: reNgine through 0.5 relies on a predictable directory name.
CWE description: The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers.
CVSS v3 base score: 9.8
Published: 2021-08-12T16:15Z
Repository: https://github.com/yogeshojha/rengine
Language: Python
Files changed: web/reNgine/tasks.py, web/startScan/views.py
Commit date: 2021-08-11 22:04:49 +0530
Commit message: Predictable directory name fixed, reported by Rob - 303sec, Thanks!

Diff: diff --git a/web/reNgine/tasks.py b/web/reNgine/tasks.py
index 0714176..09f39c8 100644
--- a/web/reNgine/tasks.py
+++ b/web/reNgine/tasks.py
@@ -2,10 +2,11 @@ import os
 import traceback
 import yaml
 import json
 import csv
 import validators
+import random
 import requests
 import logging
 import metafinder.extractor as metadata_extractor
 import whatportis
 import subprocess
@@ -95,12 +96,11 @@ def initiate_scan(
 
     if notification and notification[0].send_scan_status_notif:
         send_notification('reNgine has initiated recon for target {} with engine type {}'.format(domain.name, engine_object.engine_name))
 
     try:
-        current_scan_dir = domain.name + '_' + \
-            str(datetime.datetime.strftime(timezone.now(), '%Y_%m_%d_%H_%M_%S'))
+        current_scan_dir = domain.name + '_' + str(random.randint(100000000000, 999999999999))
         os.mkdir(current_scan_dir)
         task.results_dir = current_scan_dir
         task.save()
     except Exception as exception:
         logger.error(exception)
@@ -255,11 +255,11 @@ def initiate_scan(
     else:
         task.scan_status = 2
     task.stop_scan_date = timezone.now()
     task.save()
     # cleanup results
-    # delete_scan_data(results_dir)
+    delete_scan_data(results_dir)
     return {"status": True}
 
 
 def skip_subdomain_scan(task, domain, results_dir):
     # store default target as subdomain
@@ -1332,11 +1332,11 @@ def vulnerability_scan(
 
                         # send report to hackerone
                         if Hackerone.objects.all().exists() and severity != 'info' and severity \
                             != 'low' and vulnerability.target_domain.h1_team_handle:
                             hackerone = Hackerone.objects.all()[0]
-                            
+
                             if hackerone.send_critical and severity == 'critical':
                                 send_hackerone_report(vulnerability.id)
                             elif hackerone.send_high and severity == 'high':
                                 send_hackerone_report(vulnerability.id)
                             elif hackerone.send_medium and severity == 'medium':
diff --git a/web/startScan/views.py b/web/startScan/views.py
index e0996f1..c7c5fc2 100644
--- a/web/startScan/views.py
+++ b/web/startScan/views.py
@@ -256,14 +256,12 @@ def export_urls(request, scan_id):
 
 
 def delete_scan(request, id):
     obj = get_object_or_404(ScanHistory, id=id)
     if request.method == "POST":
-        delete_dir = obj.domain.name + '_' + \
-            str(datetime.datetime.strftime(obj.start_scan_date, '%Y_%m_%d_%H_%M_%S'))
-        delete_path = settings.TOOL_LOCATION + 'scan_results/' + delete_dir
-        os.system('rm -rf ' + delete_path)
+        delete_dir = obj.results_dir
+        os.system('rm -rf /usr/src/scan_results/' + delete_dir)
         obj.delete()
         messageData = {'status': 'true'}
         messages.add_message(
             request,
             messages.INFO,
@@ -611,11 +609,14 @@ def delete_scans(request):
     if request.method == "POST":
         list_of_scan_id = []
 
         for key, value in request.POST.items():
             if key != "scan_history_table_length" and key != "csrfmiddlewaretoken":
-                ScanHistory.objects.filter(id=value).delete()
+                obj = get_object_or_404(ScanHistory, id=value)
+                delete_dir = obj.results_dir
+                os.system('rm -rf /usr/src/scan_results/' + delete_dir)
+                obj.delete()
         messages.add_message(
             request,
             messages.INFO,
             'All Scans deleted!')
     return HttpResponseRedirect(reverse('scan_history'))

Vulnerable code:         current_scan_dir = domain.name + '_' + \
            str(datetime.datetime.strftime(timezone.now(), '%Y_%m_%d_%H_%M_%S'))
    # delete_scan_data(results_dir)
                            
        delete_dir = obj.domain.name + '_' + \
            str(datetime.datetime.strftime(obj.start_scan_date, '%Y_%m_%d_%H_%M_%S'))
        delete_path = settings.TOOL_LOCATION + 'scan_results/' + delete_dir
        os.system('rm -rf ' + delete_path)
                ScanHistory.objects.filter(id=value).delete()
Fixed code: import random
        current_scan_dir = domain.name + '_' + str(random.randint(100000000000, 999999999999))
    delete_scan_data(results_dir)

        delete_dir = obj.results_dir
        os.system('rm -rf /usr/src/scan_results/' + delete_dir)
                obj = get_object_or_404(ScanHistory, id=value)
                delete_dir = obj.results_dir
                os.system('rm -rf /usr/src/scan_results/' + delete_dir)
                obj.delete()