Skip to content

Commit e016860

Browse files
authored
Merge pull request #241 from rackerlabs/issue-238
Console/Engine updates
2 parents 1d7782a + a5468c7 commit e016860

File tree

12 files changed

+71
-95
lines changed

12 files changed

+71
-95
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,13 @@ virtualenv -p python3.6 .venv
332332
source .venv/bin/activate
333333
pip install pyinstaller
334334
pyinstaller --onefile engine.py --name engine
335+
mv dist/engine .
335336

336337
./engine -v > standalone_engine_binary.txt
337338
echo -e "MD5 `md5sum engine`" >> standalone_engine_binary.txt
338339
echo -e "SHA-256 `sha256sum engine`" >> standalone_engine_binary.txt
340+
341+
rm -rf __pycache__ build dist engine.spec .venv
339342
```
340343

341344
### Engine Execution

ansible-playbooks/roles/console/tasks/main.yml

+6-30
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@
408408
owner: nobody
409409
group: nogroup
410410
recurse: yes
411+
mode: 0777 # Not ideal, but only way to allow Django's www-data user to move files within scan_results.
411412
tags: update_code
412413

413414
- name: Restart NFS service.
@@ -435,18 +436,17 @@
435436
group: root
436437
mode: 0755
437438

438-
- name: Make nmap_to_csv.sh and nmap_to_csv.py executable.
439+
- name: Change Python scripts owner and file permissions.
439440
file:
440441
path: "/home/{{ non_root_user }}/console/scan_results/{{ item }}"
441-
owner: root
442-
group: root
443-
mode: 0700
442+
owner: "{{ non_root_user }}"
443+
group: "{{ non_root_user }}"
444+
mode: 0755
444445
with_items:
445-
- nmap_to_csv.sh
446446
- nmap_to_csv.py
447-
- masscan_json_to_csv.sh
448447
- masscan_json_to_csv.py
449448
- xml_to_json_nmap_results.py
449+
tags: update_code
450450

451451
- name: chown-ing console files to root in "/home/{{ non_root_user }}/console"
452452
file:
@@ -476,30 +476,6 @@
476476
job: "{{ scantron_dir }}/scan_scheduler.sh"
477477
user: root
478478

479-
- name: Add crontab entry for nmap_to_csv.sh
480-
cron:
481-
name: Convert nmap scan files for big data analytics platform ingestion every minute.
482-
disabled: false
483-
minute: "*"
484-
hour: "*"
485-
day: "*"
486-
month: "*"
487-
weekday: "*"
488-
job: "{{ scantron_dir }}/scan_results/nmap_to_csv.sh"
489-
user: root
490-
491-
- name: Add crontab entry for masscan_json_to_csv.sh
492-
cron:
493-
name: Convert masscan json scan files for big data analytics platform ingestion every minute.
494-
disabled: false
495-
minute: "*"
496-
hour: "*"
497-
day: "*"
498-
month: "*"
499-
weekday: "*"
500-
job: "{{ scantron_dir }}/scan_results/masscan_json_to_csv.sh"
501-
user: root
502-
503479
- name: Disable MAILTO for root's crontab.
504480
cronvar:
505481
name: MAILTO

console/django_scantron/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.38"
1+
__version__ = "1.39"

console/django_scantron/api/views.py

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Standard Python libraries.
22
import datetime
3+
import os
34
import pytz
45

56
# Third party Python libraries.
@@ -163,8 +164,33 @@ def partial_update(self, request, pk=None, **kwargs):
163164

164165
return JsonResponse(response_dict)
165166

166-
# Update the scheduled_scan_dict with the most recent scan_status state from the PUT request. When
167-
# originally querying above, the old state is passed to utility.py unless it is updated.
167+
# Setup folder directories.
168+
scan_results_dir = "/home/scantron/console/scan_results"
169+
pending_files_dir = os.path.join(scan_results_dir, "pending")
170+
completed_files_dir = os.path.join(scan_results_dir, "complete")
171+
cancelled_files_dir = os.path.join(scan_results_dir, "cancelled")
172+
173+
if new_scan_status == "cancelled":
174+
# Move scan files to the "cancelled" directory for historical purposes.
175+
utility.move_wildcard_files(
176+
f"{scheduled_scan_dict['result_file_base_name']}*", pending_files_dir, cancelled_files_dir
177+
)
178+
179+
if new_scan_status == "completed":
180+
# Move files from "pending" directory to "complete" directory.
181+
utility.move_wildcard_files(
182+
f"{scheduled_scan_dict['result_file_base_name']}*", pending_files_dir, completed_files_dir
183+
)
184+
185+
# Django compliant pre-formated datetimestamp.
186+
now_datetime = get_current_time()
187+
ScheduledScan.objects.filter(scan_engine=request.user).filter(pk=pk).update(
188+
completed_time=now_datetime
189+
)
190+
191+
# Update the scheduled_scan_dict with the most recent scan_status state from the PATCH request. When
192+
# originally querying above, the old state would passed to utility.py since it hasn't officially been
193+
# updated by Django's .update() yet.
168194
scheduled_scan_dict["scan_status"] = new_scan_status
169195

170196
# Create a redis connection object.

console/django_scantron/templates/base.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ <h1>
303303
"ordering": true,
304304
"info": true,
305305
"autoWidth": true,
306-
"order": [[ 6, "desc"]],
306+
"order": [[ 0, "desc"]],
307307
"pageLength": 100
308308
});
309309
});

console/django_scantron/templates/django_scantron/scheduled_scan_list.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ <h3>
2222
<th>Scan Command</th>
2323
<th>Scan Status</th>
2424
<th>Completion Time</th>
25-
<th>Results File</th>
25+
<th>Result Files</th>
2626
</tr>
2727
</thead>
2828

console/scan_results/masscan_json_to_csv.sh

-8
This file was deleted.

console/scan_results/nmap_to_csv.sh

-8
This file was deleted.

console/utility.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
Utility methods for other scripts to use.
33
"""
44
# Standard Python libraries.
5+
import fnmatch
56
import logging
7+
import os
8+
import shutil
69
from logging import handlers
710

811
# Third party Python libraries.
@@ -11,7 +14,7 @@
1114

1215
# Custom Python libraries.
1316
import django_connector
14-
17+
from scan_results import nmap_to_csv, masscan_json_to_csv
1518

1619
# Setup logging configuration.
1720
logger = logging.getLogger("rq.worker")
@@ -37,7 +40,15 @@
3740
)
3841
# fmt: on
3942

40-
# https://github.com/pennersr/django-allauth/blob/7b81531bc89ae98dc6f687611743db5b36cda9a2/allauth/account/adapter.py#L448
43+
44+
def move_wildcard_files(wildcard_filename, source_directory, destination_directory):
45+
"""Move files with supported fnmatch patterns (* and ?)."""
46+
47+
file_list = os.listdir(source_directory)
48+
49+
for file_name in file_list:
50+
if fnmatch.fnmatch(file_name, wildcard_filename):
51+
shutil.move(os.path.join(source_directory, file_name), os.path.join(destination_directory, file_name))
4152

4253

4354
def process_scan_status_change(scheduled_scan_dict):
@@ -90,5 +101,11 @@ def process_scan_status_change(scheduled_scan_dict):
90101

91102
logger.info(f"Successfully sent email for Scheduled Scan ID: {scheduled_scan_id}")
92103

93-
# 2 Do other stuff
94-
# TODO
104+
# 2) Convert scan results to .csv for big data analytics.
105+
# Calling the functions here instead of relying on cron job that runs every minute. The scripts also moves the
106+
# .xml files from console/scan_results/complete to console/scan_results/processed
107+
if scan_status == "completed":
108+
if scan_binary == "nmap":
109+
nmap_to_csv.main()
110+
elif scan_binary == "masscan":
111+
masscan_json_to_csv.main()

engine/engine

-17 KB
Binary file not shown.

engine/engine.py

+7-37
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
# Standard Python libraries.
99
import argparse
10-
import datetime
11-
import fnmatch
1210
import json
1311
import logging
1412
import os
@@ -22,7 +20,7 @@
2220
import time
2321
import urllib.request
2422

25-
__version__ = "1.02"
23+
__version__ = "1.03"
2624

2725
# Disable SSL/TLS verification.
2826
ssl._create_default_https_context = ssl._create_unverified_context
@@ -37,13 +35,6 @@
3735
SCAN_PROCESS_DICT = {}
3836

3937

40-
def get_current_time():
41-
"""Retrieve a Django compliant pre-formated datetimestamp."""
42-
43-
now_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
44-
return now_datetime
45-
46-
4738
def build_masscan_command(scan_command, target_file, excluded_target_file, json_file, http_useragent):
4839
"""Builds the masscan command."""
4940

@@ -59,16 +50,6 @@ def build_masscan_command(scan_command, target_file, excluded_target_file, json_
5950
return masscan_command
6051

6152

62-
def move_wildcard_files(wildcard_filename, source_directory, destination_directory):
63-
"""Move files with supported fnmatch patterns (* and ?)."""
64-
65-
file_list = os.listdir(source_directory)
66-
67-
for file_name in file_list:
68-
if fnmatch.fnmatch(file_name, wildcard_filename):
69-
shutil.move(os.path.join(source_directory, file_name), os.path.join(destination_directory, file_name))
70-
71-
7253
def check_for_scan_jobs():
7354
"""Check for new scans through the API."""
7455

@@ -179,8 +160,6 @@ def scan_job_handler(scan_job_dict):
179160

180161
# Setup folder directories.
181162
pending_files_dir = os.path.join(scan_results_dir, "pending")
182-
completed_files_dir = os.path.join(scan_results_dir, "complete")
183-
cancelled_files_dir = os.path.join(scan_results_dir, "cancelled")
184163

185164
if scan_binary not in supported_scan_binaries:
186165
ROOT_LOGGER.error(f"Invalid scan binary specified: {scan_binary}")
@@ -248,9 +227,6 @@ def scan_job_handler(scan_job_dict):
248227
SCAN_PROCESS_DICT.pop(scan_binary_process_id)
249228

250229
if scan_status == "cancel":
251-
# Move scan files to the "cancelled" directory for historical purposes.
252-
move_wildcard_files(f"{result_file_base_name}*", pending_files_dir, cancelled_files_dir)
253-
254230
updated_scan_status = "cancelled"
255231

256232
elif scan_status == "pause":
@@ -400,15 +376,9 @@ def scan_job_handler(scan_job_dict):
400376
# check ensures the scan status of a masscan process isn't "paused".
401377
if SCAN_PROCESS_DICT[scan_binary_process_id]["scan_status"] == "started":
402378

403-
# Move files from "pending" directory to "complete" directory.
404-
move_wildcard_files(f"{result_file_base_name}*", pending_files_dir, completed_files_dir)
405-
406-
# Update completed_time, scan_status, and result_file_base_name.
407-
now_datetime = get_current_time()
379+
# Update scan_status.
408380
update_info = {
409-
"completed_time": now_datetime,
410381
"scan_status": "completed",
411-
"result_file_base_name": result_file_base_name,
412382
}
413383

414384
update_scan_information(scan_job, update_info)
@@ -544,11 +514,7 @@ def go(self):
544514
help="Configuration file. Defaults to 'engine_config.json'",
545515
)
546516
parser.add_argument(
547-
"-v",
548-
dest="version",
549-
action="store_true",
550-
required=False,
551-
help="Print engine version",
517+
"-v", dest="version", action="store_true", required=False, help="Print engine version",
552518
)
553519

554520
args = parser.parse_args()
@@ -565,6 +531,10 @@ def go(self):
565531
print(f"Path for masscan cannot be found. Exiting...")
566532
sys.exit(0)
567533

534+
if not os.path.isdir("./logs"):
535+
print("./logs directory does not exist, creating it.")
536+
os.mkdir("./logs", mode=0o700)
537+
568538
# Log level is controlled in engine_config.json and assigned after reading that file.
569539
# Setup file logging
570540
log_file_handler = logging.FileHandler(os.path.join("logs", "engine.log"))

engine/standalone_engine_binary.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
Scantron engine version: 1.02
2-
MD5 d3230abc4947e5bcf57adf531db3707b engine
3-
SHA-256 9e0cd1c160802ddc5abcdf1171efb7aa583842511bcb8811ceed5dac747a25d0 engine
1+
Scantron engine version: 1.03
2+
MD5 af814d01c63926ba7927b5dc6aae894f engine
3+
SHA-256 80e5689497c639bde8d5472f47254b63b55004a279b84f8055ca20c01ec7bf84 engine

0 commit comments

Comments
 (0)