mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-08-30 19:59:48 +02:00
462 lines
16 KiB
Python
462 lines
16 KiB
Python
import datetime
|
|
|
|
from django.db import models
|
|
from django.db.models import JSONField
|
|
from django.core.serializers import serialize
|
|
from django.http import JsonResponse
|
|
from django.utils import timezone
|
|
from django.apps import apps
|
|
from django.contrib.postgres.fields import ArrayField
|
|
|
|
from targetApp.models import Domain
|
|
from scanEngine.models import EngineType
|
|
|
|
from reNgine.utilities import *
|
|
|
|
|
|
class ScanHistory(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
start_scan_date = models.DateTimeField()
|
|
scan_status = models.IntegerField()
|
|
results_dir = models.CharField(max_length=100, blank=True)
|
|
domain = models.ForeignKey(Domain, on_delete=models.CASCADE)
|
|
scan_type = models.ForeignKey(EngineType, on_delete=models.CASCADE)
|
|
celery_id = models.CharField(max_length=100, blank=True)
|
|
subdomain_discovery = models.BooleanField(null=True, default=False)
|
|
dir_file_fuzz = models.BooleanField(null=True, default=False)
|
|
port_scan = models.BooleanField(null=True, default=False)
|
|
fetch_url = models.BooleanField(null=True, default=False)
|
|
vulnerability_scan = models.BooleanField(null=True, default=False)
|
|
osint = models.BooleanField(null=True, default=False)
|
|
screenshot = models.BooleanField(null=True, default=True)
|
|
stop_scan_date = models.DateTimeField(null=True, blank=True)
|
|
used_gf_patterns = models.CharField(max_length=500, null=True, blank=True)
|
|
|
|
# osint is directly linked to scan history and not subdomains
|
|
emails = models.ManyToManyField('Email', related_name='emails', blank=True)
|
|
employees = models.ManyToManyField('Employee', related_name='employees', blank=True)
|
|
dorks = models.ManyToManyField('Dork', related_name='dorks', blank=True)
|
|
|
|
def __str__(self):
|
|
# debug purpose remove scan type and id in prod
|
|
return self.domain.name
|
|
|
|
def get_subdomain_count(self):
|
|
return Subdomain.objects.filter(scan_history__id=self.id).count()
|
|
|
|
def get_subdomain_change_count(self):
|
|
last_scan = ScanHistory.objects.filter(id=self.id).filter(
|
|
scan_type__subdomain_discovery=True).order_by('-start_scan_date')
|
|
|
|
scanned_host_q1 = Subdomain.objects.filter(
|
|
target_domain__id=self.domain.id).exclude(
|
|
scan_history__id=last_scan[0].id).values('name')
|
|
|
|
scanned_host_q2 = Subdomain.objects.filter(
|
|
scan_history__id=last_scan[0].id).values('name')
|
|
|
|
new_subdomains = scanned_host_q2.difference(scanned_host_q1).count()
|
|
removed_subdomains = scanned_host_q1.difference(scanned_host_q2).count()
|
|
|
|
return [new_subdomains, removed_subdomains]
|
|
|
|
|
|
def get_endpoint_count(self):
|
|
return EndPoint.objects.filter(scan_history__id=self.id).count()
|
|
|
|
def get_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).count()
|
|
|
|
def get_info_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).filter(
|
|
severity=0).count()
|
|
|
|
def get_low_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).filter(
|
|
severity=1).count()
|
|
|
|
def get_medium_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).filter(
|
|
severity=2).count()
|
|
|
|
def get_high_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).filter(
|
|
severity=3).count()
|
|
|
|
def get_critical_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history__id=self.id).filter(
|
|
severity=4).count()
|
|
|
|
def get_progress(self):
|
|
'''
|
|
formulae to calculate
|
|
count number of true things to do, for http crawler, it is always +1
|
|
divided by total scan activity associated - 2 (Start and Stop)
|
|
'''
|
|
number_of_steps = sum([
|
|
self.subdomain_discovery,
|
|
self.dir_file_fuzz,
|
|
self.port_scan,
|
|
self.fetch_url,
|
|
self.vulnerability_scan,
|
|
self.osint,
|
|
self.screenshot,
|
|
True
|
|
])
|
|
steps_done = len(self.scanactivity_set.all())
|
|
if steps_done and number_of_steps:
|
|
return round((number_of_steps / (steps_done))*100, 2)
|
|
|
|
def get_completed_ago(self):
|
|
if self.stop_scan_date:
|
|
return self.get_time_ago(self.stop_scan_date)
|
|
|
|
def get_total_scan_time_in_sec(self):
|
|
if self.stop_scan_date:
|
|
return (self.stop_scan_date - self.start_scan_date).seconds
|
|
|
|
def get_elapsed_time(self):
|
|
return self.get_time_ago(self.start_scan_date)
|
|
|
|
def get_time_ago(self, time):
|
|
duration = timezone.now() - time
|
|
days, seconds = duration.days, duration.seconds
|
|
hours = days * 24 + seconds // 3600
|
|
minutes = (seconds % 3600) // 60
|
|
seconds = seconds % 60
|
|
if not hours and not minutes:
|
|
return '{} seconds'.format(seconds)
|
|
elif not hours:
|
|
return '{} minutes'.format(minutes)
|
|
elif not minutes:
|
|
return '{} hours'.format(hours)
|
|
return '{} hours {} minutes'.format(hours, minutes)
|
|
|
|
|
|
class Subdomain(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
scan_history = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
target_domain = models.ForeignKey(
|
|
Domain, on_delete=models.CASCADE, null=True, blank=True)
|
|
name = models.CharField(max_length=1000)
|
|
is_imported_subdomain = models.BooleanField(default=False)
|
|
is_important = models.BooleanField(default=False, null=True, blank=True)
|
|
http_url = models.CharField(max_length=1000, null=True, blank=True)
|
|
screenshot_path = models.CharField(max_length=1000, null=True, blank=True)
|
|
http_header_path = models.CharField(max_length=1000, null=True, blank=True)
|
|
discovered_date = models.DateTimeField(blank=True, null=True)
|
|
cname = models.CharField(max_length=1500, blank=True, null=True)
|
|
is_cdn = models.BooleanField(default=False, blank=True, null=True)
|
|
http_status = models.IntegerField(default=0)
|
|
content_type = models.CharField(max_length=100, null=True, blank=True)
|
|
response_time = models.FloatField(null=True, blank=True)
|
|
webserver = models.CharField(max_length=1000, blank=True, null=True)
|
|
content_length = models.IntegerField(default=0, blank=True, null=True)
|
|
page_title = models.CharField(max_length=1000, blank=True, null=True)
|
|
technologies = models.ManyToManyField('Technology', related_name='technologies', blank=True)
|
|
ip_addresses = models.ManyToManyField('IPAddress', related_name='ip_addresses', blank=True)
|
|
directories = models.ManyToManyField('DirectoryScan', related_name='directories', blank=True)
|
|
|
|
|
|
def __str__(self):
|
|
return str(self.name)
|
|
|
|
@property
|
|
def get_endpoint_count(self):
|
|
return EndPoint.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).count()
|
|
|
|
@property
|
|
def get_info_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).filter(severity=0).count()
|
|
|
|
@property
|
|
def get_low_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).filter(severity=1).count()
|
|
|
|
@property
|
|
def get_medium_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).filter(severity=2).count()
|
|
|
|
@property
|
|
def get_high_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).filter(severity=3).count()
|
|
|
|
@property
|
|
def get_critical_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).filter(severity=4).count()
|
|
|
|
@property
|
|
def get_total_vulnerability_count(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name).count()
|
|
|
|
@property
|
|
def get_vulnerabilities(self):
|
|
return Vulnerability.objects.filter(
|
|
scan_history=self.scan_history).filter(
|
|
subdomain__name=self.name)
|
|
|
|
@property
|
|
def get_todos(self):
|
|
TodoNote = apps.get_model('recon_note', 'TodoNote')
|
|
notes = TodoNote.objects.filter(scan_history__id=self.scan_history.id).filter(subdomain__id=self.id)
|
|
return notes.values()
|
|
|
|
|
|
class SubScan(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
start_scan_date = models.DateTimeField()
|
|
status = models.IntegerField()
|
|
celery_id = models.CharField(max_length=100, blank=True)
|
|
scan_history = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
subdomain = models.ForeignKey(Subdomain, on_delete=models.CASCADE)
|
|
dir_file_fuzz = models.BooleanField(null=True, default=False)
|
|
port_scan = models.BooleanField(null=True, default=False)
|
|
fetch_url = models.BooleanField(null=True, default=False)
|
|
vulnerability_scan = models.BooleanField(null=True, default=False)
|
|
osint = models.BooleanField(null=True, default=False)
|
|
stop_scan_date = models.DateTimeField(null=True, blank=True)
|
|
|
|
|
|
def get_completed_ago(self):
|
|
if self.stop_scan_date:
|
|
return get_time_taken(timezone.now(), self.stop_scan_date)
|
|
|
|
def get_total_time_taken(self):
|
|
if self.stop_scan_date:
|
|
return get_time_taken(self.stop_scan_date, self.start_scan_date)
|
|
|
|
def get_elapsed_time(self):
|
|
return get_time_taken(timezone.now(), self.start_scan_date)
|
|
|
|
def get_task_name_str(self):
|
|
if self.dir_file_fuzz:
|
|
return "Directory and File fuzzing"
|
|
elif self.port_scan:
|
|
return "Port Scan"
|
|
elif self.fetch_url:
|
|
return "Endpoint Gathering"
|
|
elif self.vulnerability_scan:
|
|
return "Vulnerability Scan"
|
|
elif self.osint:
|
|
return "OSINT"
|
|
else:
|
|
return "Unknown"
|
|
|
|
|
|
class EndPoint(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
scan_history = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
target_domain = models.ForeignKey(
|
|
Domain, on_delete=models.CASCADE, null=True, blank=True)
|
|
subdomain = models.ForeignKey(
|
|
Subdomain,
|
|
on_delete=models.CASCADE,
|
|
null=True,
|
|
blank=True)
|
|
http_url = models.CharField(max_length=5000)
|
|
content_length = models.IntegerField(default=0, null=True, blank=True)
|
|
page_title = models.CharField(max_length=1000, null=True, blank=True)
|
|
http_status = models.IntegerField(default=0, null=True, blank=True)
|
|
content_type = models.CharField(max_length=100, null=True, blank=True)
|
|
discovered_date = models.DateTimeField(blank=True, null=True)
|
|
response_time = models.FloatField(null=True, blank=True)
|
|
webserver = models.CharField(max_length=1000, blank=True, null=True)
|
|
is_default = models.BooleanField(null=True, blank=True, default=False)
|
|
matched_gf_patterns = models.CharField(max_length=2000, null=True, blank=True)
|
|
technologies = models.ManyToManyField('Technology', related_name='technology')
|
|
# used for subscans
|
|
endpoint_subscan_ids = models.ManyToManyField('SubScan', related_name='endpoint_subscan_ids')
|
|
|
|
def __str__(self):
|
|
return self.http_url
|
|
|
|
|
|
class VulnerabilityTags(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
name = models.CharField(max_length=100)
|
|
|
|
|
|
class VulnerabilityReference(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
url = models.CharField(max_length=500)
|
|
|
|
|
|
class Vulnerability(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
scan_history = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
subdomain = models.ForeignKey(
|
|
Subdomain,
|
|
on_delete=models.CASCADE,
|
|
null=True,
|
|
blank=True)
|
|
endpoint = models.ForeignKey(
|
|
EndPoint,
|
|
on_delete=models.CASCADE,
|
|
blank=True,
|
|
null=True)
|
|
target_domain = models.ForeignKey(
|
|
Domain, on_delete=models.CASCADE, null=True, blank=True)
|
|
template = models.CharField(max_length=100)
|
|
template_url = models.CharField(max_length=200, null=True, blank=True)
|
|
template_id = models.CharField(max_length=200, null=True, blank=True)
|
|
matcher_name = models.CharField(max_length=500, null=True, blank=True)
|
|
name = models.CharField(max_length=500)
|
|
severity = models.IntegerField()
|
|
description = models.CharField(max_length=10000, null=True, blank=True)
|
|
|
|
extracted_results = ArrayField(
|
|
models.CharField(max_length=1000), blank=True, null=True
|
|
)
|
|
references = ArrayField(
|
|
models.CharField(max_length=500), blank=True, null=True
|
|
)
|
|
tags = ArrayField(
|
|
models.CharField(max_length=50), blank=True, null=True
|
|
)
|
|
cve_ids = ArrayField(
|
|
models.CharField(max_length=50), blank=True, null=True
|
|
)
|
|
cwe_ids = ArrayField(
|
|
models.CharField(max_length=50), blank=True, null=True
|
|
)
|
|
cvss_metrics = models.CharField(max_length=150, null=True, blank=True)
|
|
cvss_score = models.FloatField(null=True, blank=True, default=None)
|
|
curl_command = models.CharField(max_length=1500, null=True, blank=True)
|
|
type = models.CharField(max_length=50, null=True, blank=True)
|
|
http_url = models.CharField(max_length=1000, null=True)
|
|
discovered_date = models.DateTimeField(null=True)
|
|
open_status = models.BooleanField(null=True, blank=True, default=True)
|
|
hackerone_report_id = models.CharField(max_length=50, null=True, blank=True)
|
|
# used for subscans
|
|
vuln_subscan_ids = models.ManyToManyField('SubScan', related_name='vuln_subscan_ids')
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def get_severity(self):
|
|
return self.severity
|
|
|
|
|
|
class ScanActivity(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
scan_of = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
title = models.CharField(max_length=1000)
|
|
time = models.DateTimeField()
|
|
status = models.IntegerField()
|
|
|
|
def __str__(self):
|
|
return str(self.title)
|
|
|
|
|
|
class Technology(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
name = models.CharField(max_length=100, blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
return str(self.name)
|
|
|
|
|
|
class IpAddress(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
address = models.CharField(max_length=100, blank=True, null=True)
|
|
is_cdn = models.BooleanField(default=False)
|
|
ports = models.ManyToManyField('Port', related_name='ports')
|
|
# this is used for querying which ip was discovered during subcan
|
|
ip_subscan_ids = models.ManyToManyField('SubScan', related_name='ip_subscan_ids')
|
|
|
|
def __str__(self):
|
|
return str(self.address)
|
|
|
|
|
|
class Port(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
number = models.IntegerField(default=0)
|
|
service_name = models.CharField(max_length=100, blank=True, null=True)
|
|
description = models.CharField(max_length=1000, blank=True, null=True)
|
|
is_uncommon = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
return str(self.service_name)
|
|
|
|
|
|
class DirectoryFile(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
length = models.IntegerField(default=0)
|
|
lines = models.IntegerField(default=0)
|
|
http_status = models.IntegerField(default=0)
|
|
words = models.IntegerField(default=0)
|
|
name = models.CharField(max_length=500, blank=True, null=True)
|
|
url = models.CharField(max_length=2000, blank=True, null=True)
|
|
content_type = models.CharField(max_length=100, blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
return str(self.name)
|
|
|
|
|
|
class DirectoryScan(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
command_line = models.CharField(max_length=1000, blank=True, null=True)
|
|
directory_files = models.ManyToManyField('DirectoryFile', related_name='directory_files', blank=True)
|
|
# this is used for querying which ip was discovered during subcan
|
|
dir_subscan_ids = models.ManyToManyField('SubScan', related_name='dir_subscan_ids', blank=True)
|
|
|
|
|
|
class MetaFinderDocument(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
scan_history = models.ForeignKey(ScanHistory, on_delete=models.CASCADE)
|
|
target_domain = models.ForeignKey(
|
|
Domain, on_delete=models.CASCADE, null=True, blank=True)
|
|
subdomain = models.ForeignKey(
|
|
Subdomain,
|
|
on_delete=models.CASCADE,
|
|
null=True,
|
|
blank=True)
|
|
doc_name = models.CharField(max_length=1000, null=True, blank=True)
|
|
url = models.CharField(max_length=5000, null=True, blank=True)
|
|
title = models.CharField(max_length=1000, null=True, blank=True)
|
|
author = models.CharField(max_length=1000, null=True, blank=True)
|
|
producer = models.CharField(max_length=1000, null=True, blank=True)
|
|
creator = models.CharField(max_length=1000, null=True, blank=True)
|
|
os = models.CharField(max_length=1000, null=True, blank=True)
|
|
http_status = models.IntegerField(default=0, null=True, blank=True)
|
|
creation_date = models.CharField(max_length=1000, blank=True, null=True)
|
|
modified_date = models.CharField(max_length=1000, blank=True, null=True)
|
|
|
|
|
|
class Email(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
address = models.CharField(max_length=200, blank=True, null=True)
|
|
password = models.CharField(max_length=200, blank=True, null=True)
|
|
|
|
class Employee(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
name = models.CharField(max_length=1000, null=True, blank=True)
|
|
designation = models.CharField(max_length=1000, null=True, blank=True)
|
|
|
|
|
|
class Dork(models.Model):
|
|
id = models.AutoField(primary_key=True)
|
|
type = models.CharField(max_length=500, null=True, blank=True)
|
|
description = models.CharField(max_length=1500, null=True, blank=True)
|
|
url = models.CharField(max_length=1500, null=True, blank=True)
|