regscale-cli 6.20.1.1__py3-none-any.whl → 6.20.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/__init__.py +1 -1
- regscale/core/app/utils/variables.py +5 -3
- regscale/integrations/commercial/__init__.py +15 -0
- regscale/integrations/commercial/axonius/__init__.py +0 -0
- regscale/integrations/commercial/axonius/axonius_integration.py +70 -0
- regscale/integrations/commercial/burp.py +14 -0
- regscale/integrations/commercial/grype/commands.py +8 -1
- regscale/integrations/commercial/grype/scanner.py +2 -1
- regscale/integrations/commercial/jira.py +288 -137
- regscale/integrations/commercial/opentext/commands.py +14 -5
- regscale/integrations/commercial/opentext/scanner.py +3 -2
- regscale/integrations/commercial/qualys/__init__.py +3 -3
- regscale/integrations/commercial/stigv2/click_commands.py +6 -37
- regscale/integrations/commercial/synqly/assets.py +10 -0
- regscale/integrations/commercial/tenablev2/commands.py +12 -4
- regscale/integrations/commercial/tenablev2/sc_scanner.py +21 -1
- regscale/integrations/commercial/tenablev2/sync_compliance.py +3 -0
- regscale/integrations/commercial/trivy/commands.py +11 -4
- regscale/integrations/commercial/trivy/scanner.py +2 -1
- regscale/integrations/commercial/wizv2/constants.py +4 -0
- regscale/integrations/commercial/wizv2/scanner.py +67 -14
- regscale/integrations/commercial/wizv2/utils.py +24 -10
- regscale/integrations/commercial/wizv2/variables.py +7 -0
- regscale/integrations/jsonl_scanner_integration.py +8 -1
- regscale/integrations/public/cisa.py +58 -63
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +153 -104
- regscale/integrations/scanner_integration.py +30 -8
- regscale/integrations/variables.py +1 -0
- regscale/models/app_models/click.py +49 -1
- regscale/models/app_models/import_validater.py +3 -1
- regscale/models/integration_models/axonius_models/__init__.py +0 -0
- regscale/models/integration_models/axonius_models/connectors/__init__.py +3 -0
- regscale/models/integration_models/axonius_models/connectors/assets.py +111 -0
- regscale/models/integration_models/burp.py +11 -8
- regscale/models/integration_models/cisa_kev_data.json +204 -23
- regscale/models/integration_models/flat_file_importer/__init__.py +36 -176
- regscale/models/integration_models/jira_task_sync.py +27 -0
- regscale/models/integration_models/qualys.py +6 -7
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/__init__.py +2 -1
- regscale/models/regscale_models/control_implementation.py +39 -2
- regscale/models/regscale_models/issue.py +1 -0
- regscale/models/regscale_models/regscale_model.py +49 -1
- regscale/models/regscale_models/risk_issue_mapping.py +61 -0
- regscale/models/regscale_models/task.py +1 -0
- regscale/regscale.py +1 -4
- regscale/utils/graphql_client.py +4 -4
- regscale/utils/string.py +13 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/RECORD +54 -48
- regscale/integrations/commercial/synqly_jira.py +0 -840
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.1.1.dist-info → regscale_cli-6.20.3.0.dist-info}/top_level.txt +0 -0
|
@@ -425,6 +425,8 @@ class IntegrationFinding:
|
|
|
425
425
|
operational_requirements: Optional[str] = None
|
|
426
426
|
deviation_rationale: Optional[str] = None
|
|
427
427
|
is_cwe: bool = False
|
|
428
|
+
affected_controls: Optional[str] = None
|
|
429
|
+
identification: Optional[str] = "Vulnerability Assessment"
|
|
428
430
|
|
|
429
431
|
poam_comments: Optional[str] = None
|
|
430
432
|
vulnerability_id: Optional[int] = None
|
|
@@ -633,6 +635,8 @@ class ScannerIntegration(ABC):
|
|
|
633
635
|
self.plan_id: int = plan_id
|
|
634
636
|
self.tenant_id: int = tenant_id
|
|
635
637
|
self.is_component: bool = is_component
|
|
638
|
+
if self.is_component:
|
|
639
|
+
self.component = regscale_models.Component.get_object(self.plan_id)
|
|
636
640
|
self.components: ThreadSafeList[Any] = ThreadSafeList()
|
|
637
641
|
self.asset_map_by_identifier: ThreadSafeDict[str, regscale_models.Asset] = ThreadSafeDict()
|
|
638
642
|
self.software_to_create: ThreadSafeList[regscale_models.SoftwareInventory] = ThreadSafeList()
|
|
@@ -819,11 +823,12 @@ class ScannerIntegration(ABC):
|
|
|
819
823
|
@abstractmethod
|
|
820
824
|
def fetch_findings(self, *args, **kwargs) -> Iterator[IntegrationFinding]:
|
|
821
825
|
"""
|
|
822
|
-
Fetches findings from the integration
|
|
826
|
+
Fetches findings from the integration.
|
|
823
827
|
|
|
824
|
-
:return:
|
|
825
|
-
:
|
|
828
|
+
:return: An iterator of findings
|
|
829
|
+
:yield: Iterator[IntegrationFinding]
|
|
826
830
|
"""
|
|
831
|
+
pass
|
|
827
832
|
|
|
828
833
|
@abstractmethod
|
|
829
834
|
def fetch_assets(self, *args, **kwargs) -> Iterator[IntegrationAsset]:
|
|
@@ -831,7 +836,7 @@ class ScannerIntegration(ABC):
|
|
|
831
836
|
Fetches assets from the integration
|
|
832
837
|
|
|
833
838
|
:return: An iterator of assets
|
|
834
|
-
:
|
|
839
|
+
:yield: Iterator[IntegrationAsset]
|
|
835
840
|
"""
|
|
836
841
|
|
|
837
842
|
def get_finding_status(self, status: Optional[str]) -> regscale_models.IssueStatus:
|
|
@@ -1024,10 +1029,10 @@ class ScannerIntegration(ABC):
|
|
|
1024
1029
|
logger.warning("Asset has no identifier, skipping")
|
|
1025
1030
|
return
|
|
1026
1031
|
|
|
1027
|
-
component = None
|
|
1032
|
+
component = getattr(self, "component") if self.is_component else None
|
|
1028
1033
|
if component_name:
|
|
1029
1034
|
logger.debug("Searching for component: %s...", component_name)
|
|
1030
|
-
component = self.components_by_title.get(component_name)
|
|
1035
|
+
component = component or self.components_by_title.get(component_name)
|
|
1031
1036
|
if not component:
|
|
1032
1037
|
logger.debug("No existing component found with name %s, proceeding to create it...", component_name)
|
|
1033
1038
|
component = regscale_models.Component(
|
|
@@ -1610,7 +1615,7 @@ class ScannerIntegration(ABC):
|
|
|
1610
1615
|
issue.severityLevel = finding.severity
|
|
1611
1616
|
issue.issueOwnerId = self.assessor_id
|
|
1612
1617
|
issue.securityPlanId = self.plan_id if not self.is_component else None
|
|
1613
|
-
issue.identification =
|
|
1618
|
+
issue.identification = finding.identification
|
|
1614
1619
|
issue.dateFirstDetected = finding.first_seen
|
|
1615
1620
|
issue.dueDate = finding.due_date
|
|
1616
1621
|
issue.description = description
|
|
@@ -1628,6 +1633,7 @@ class ScannerIntegration(ABC):
|
|
|
1628
1633
|
# Get control implementation ID for CCI if it exists
|
|
1629
1634
|
# Only add CCI control ID if it exists
|
|
1630
1635
|
cci_control_ids = [control_id] if control_id is not None else []
|
|
1636
|
+
issue.affectedControls = finding.affected_controls
|
|
1631
1637
|
|
|
1632
1638
|
issue.controlImplementationIds = list(set(finding._control_implementation_ids + cci_control_ids)) # noqa
|
|
1633
1639
|
issue.isPoam = is_poam
|
|
@@ -1790,7 +1796,10 @@ class ScannerIntegration(ABC):
|
|
|
1790
1796
|
:return: True if the issue should be a POAM, False otherwise
|
|
1791
1797
|
:rtype: bool
|
|
1792
1798
|
"""
|
|
1793
|
-
if
|
|
1799
|
+
if (
|
|
1800
|
+
ScannerVariables.vulnerabilityCreation.lower() == "poamcreation"
|
|
1801
|
+
or ScannerVariables.complianceCreation.lower() == "poam"
|
|
1802
|
+
):
|
|
1794
1803
|
return True
|
|
1795
1804
|
if finding.due_date < get_current_datetime():
|
|
1796
1805
|
return True
|
|
@@ -2702,6 +2711,7 @@ class ScannerIntegration(ABC):
|
|
|
2702
2711
|
logger.info("Syncing %s findings...", kwargs.get("title", cls.title))
|
|
2703
2712
|
instance = cls(plan_id=plan_id, **kwargs)
|
|
2704
2713
|
instance.set_keys(**kwargs)
|
|
2714
|
+
instance.ensure_data_types()
|
|
2705
2715
|
# If a progress object was passed, use it instead of creating a new one
|
|
2706
2716
|
instance.finding_progress = kwargs.pop("progress") if "progress" in kwargs else create_progress_object()
|
|
2707
2717
|
instance.enable_finding_date_update = kwargs.get("enable_finding_date_update", False)
|
|
@@ -2771,6 +2781,7 @@ class ScannerIntegration(ABC):
|
|
|
2771
2781
|
logger.info("Syncing %s assets...", kwargs.get("title", cls.title))
|
|
2772
2782
|
instance = cls(plan_id=plan_id, **kwargs)
|
|
2773
2783
|
instance.set_keys(**kwargs)
|
|
2784
|
+
instance.ensure_data_types()
|
|
2774
2785
|
instance.asset_progress = kwargs.pop("progress") if "progress" in kwargs else create_progress_object()
|
|
2775
2786
|
if asset_count := kwargs.get("asset_count"):
|
|
2776
2787
|
instance.num_assets_to_process = asset_count
|
|
@@ -2813,6 +2824,17 @@ class ScannerIntegration(ABC):
|
|
|
2813
2824
|
else:
|
|
2814
2825
|
logger.debug("Unable to set the %s attribute", key)
|
|
2815
2826
|
|
|
2827
|
+
def ensure_data_types(self) -> None:
|
|
2828
|
+
"""
|
|
2829
|
+
A method to enforce kwarg data types.
|
|
2830
|
+
|
|
2831
|
+
:return: None
|
|
2832
|
+
:rtype: None
|
|
2833
|
+
"""
|
|
2834
|
+
# Ensure scan_date is a string
|
|
2835
|
+
if not isinstance(self.scan_date, str):
|
|
2836
|
+
self.scan_date = date_str(self.scan_date)
|
|
2837
|
+
|
|
2816
2838
|
def log_error(self, msg: str, *args) -> None:
|
|
2817
2839
|
"""
|
|
2818
2840
|
Logs an error message
|
|
@@ -25,3 +25,4 @@ class ScannerVariables(metaclass=RsVariablesMeta):
|
|
|
25
25
|
issueDueDates: RsVariableType(dict, "dueDates", default="{'high': 60, 'moderate': 120, 'low': 364}", required=False) # type: ignore # noqa: F722,F821
|
|
26
26
|
maxRetries: RsVariableType(int, "3", default=3, required=False) # type: ignore
|
|
27
27
|
timeout: RsVariableType(int, "60", default=60, required=False) # type: ignore
|
|
28
|
+
complianceCreation: RsVariableType(str, "Assessment|Issue|POAM", default="Assessment", required=False) # type: ignore # noqa: F722,F821
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
"""Module to allow dynamic click arguments and store commonly used click commands"""
|
|
4
4
|
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Callable, Optional, Tuple
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from pathlib import Path
|
|
@@ -128,6 +128,54 @@ def regscale_ssp_id(
|
|
|
128
128
|
)
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
def ssp_or_component_id(
|
|
132
|
+
ssp_kwargs: Optional[dict] = None,
|
|
133
|
+
component_kwargs: Optional[dict] = None,
|
|
134
|
+
) -> Tuple[click.option, click.option]:
|
|
135
|
+
"""
|
|
136
|
+
Function to return click.option for RegScale Component ID and SSP ID, user must provide either SSP ID or Component ID
|
|
137
|
+
|
|
138
|
+
:param Optional[dict] ssp_kwargs: kwargs to pass to click.option for RegScale SSP ID
|
|
139
|
+
:param Optional[dict] component_kwargs: kwargs to pass to click.option for RegScale Component ID
|
|
140
|
+
:return: click.option for RegScale Component ID and SSP ID
|
|
141
|
+
:rtype: click.option
|
|
142
|
+
"""
|
|
143
|
+
if ssp_kwargs is None:
|
|
144
|
+
ssp_kwargs = {}
|
|
145
|
+
if component_kwargs is None:
|
|
146
|
+
component_kwargs = {}
|
|
147
|
+
|
|
148
|
+
def decorator(this_func) -> Callable[[Callable], click.option]:
|
|
149
|
+
"""
|
|
150
|
+
Decorator to return click.option for RegScale Component ID and SSP ID
|
|
151
|
+
"""
|
|
152
|
+
this_func = click.option(
|
|
153
|
+
"-id",
|
|
154
|
+
"-p",
|
|
155
|
+
"--regscale_ssp_id",
|
|
156
|
+
"--plan_id",
|
|
157
|
+
type=click.INT,
|
|
158
|
+
help=ssp_kwargs.pop("help", "The ID number from RegScale of the System Security Plan."),
|
|
159
|
+
prompt=ssp_kwargs.pop("prompt", None),
|
|
160
|
+
cls=NotRequiredIf,
|
|
161
|
+
not_required_if=["component_id"],
|
|
162
|
+
**ssp_kwargs,
|
|
163
|
+
)(this_func)
|
|
164
|
+
this_func = click.option(
|
|
165
|
+
"-c",
|
|
166
|
+
"--component_id",
|
|
167
|
+
type=click.INT,
|
|
168
|
+
help=component_kwargs.pop("help", "The ID number from RegScale of the Component."),
|
|
169
|
+
prompt=component_kwargs.pop("prompt", None),
|
|
170
|
+
cls=NotRequiredIf,
|
|
171
|
+
not_required_if=["regscale_ssp_id"],
|
|
172
|
+
**component_kwargs,
|
|
173
|
+
)(this_func)
|
|
174
|
+
return this_func
|
|
175
|
+
|
|
176
|
+
return decorator
|
|
177
|
+
|
|
178
|
+
|
|
131
179
|
def regscale_id(
|
|
132
180
|
help: str = "Enter the desired ID # from RegScale.",
|
|
133
181
|
required: bool = True,
|
|
@@ -58,6 +58,7 @@ class ImportValidater:
|
|
|
58
58
|
skip_rows: Optional[int] = None,
|
|
59
59
|
prompt: bool = True,
|
|
60
60
|
ignore_unnamed: bool = False,
|
|
61
|
+
warn_extra_headers: bool = True,
|
|
61
62
|
):
|
|
62
63
|
self.ignore_unnamed = ignore_unnamed
|
|
63
64
|
self.prompt = prompt
|
|
@@ -74,6 +75,7 @@ class ImportValidater:
|
|
|
74
75
|
self.keys = keys
|
|
75
76
|
self.worksheet_name = worksheet_name
|
|
76
77
|
self.skip_rows = skip_rows
|
|
78
|
+
self.warn_extra_headers = warn_extra_headers
|
|
77
79
|
if self.file_type not in self._supported_types:
|
|
78
80
|
raise ValidationException(
|
|
79
81
|
f"Unsupported file type: {self.file_type}, supported types are: {', '.join(self._supported_types)}",
|
|
@@ -148,7 +150,7 @@ class ImportValidater:
|
|
|
148
150
|
raise ValidationException(
|
|
149
151
|
f"{', '.join([f'`{header}`' for header in missing_headers])} header(s) not found in {self.file_path}"
|
|
150
152
|
)
|
|
151
|
-
if extra_headers:
|
|
153
|
+
if extra_headers and self.warn_extra_headers:
|
|
152
154
|
logger.warning("Extra headers found in the file: %s", ", ".join(extra_headers))
|
|
153
155
|
|
|
154
156
|
if self.disable_mapping:
|
|
File without changes
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Assets Connector Model"""
|
|
2
|
+
|
|
3
|
+
from typing import Iterator, Optional
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import datetime
|
|
6
|
+
from datetime import date
|
|
7
|
+
import warnings
|
|
8
|
+
import json
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
from pydantic import ConfigDict
|
|
12
|
+
|
|
13
|
+
from regscale.integrations.scanner_integration import (
|
|
14
|
+
IntegrationAsset,
|
|
15
|
+
IntegrationFinding,
|
|
16
|
+
ScannerIntegration,
|
|
17
|
+
ScannerIntegrationType,
|
|
18
|
+
)
|
|
19
|
+
from regscale.models.regscale_models import IssueSeverity, AssetStatus, ControlImplementation, SecurityControl
|
|
20
|
+
from regscale.core.app.api import Api
|
|
21
|
+
from regscale.core.app.application import Application
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AxoniusIntegration(ScannerIntegration):
|
|
25
|
+
from regscale.integrations.variables import ScannerVariables
|
|
26
|
+
|
|
27
|
+
title = "Axonius"
|
|
28
|
+
# Required fields from ScannerIntegration
|
|
29
|
+
asset_identifier_field = "otherTrackingNumber"
|
|
30
|
+
finding_severity_map = {
|
|
31
|
+
"I": IssueSeverity.Critical,
|
|
32
|
+
"II": IssueSeverity.High,
|
|
33
|
+
"III": IssueSeverity.Moderate,
|
|
34
|
+
"IV": IssueSeverity.Low,
|
|
35
|
+
}
|
|
36
|
+
type = (
|
|
37
|
+
ScannerIntegrationType.CHECKLIST
|
|
38
|
+
if ScannerVariables.complianceCreation.lower() == "assessment"
|
|
39
|
+
else ScannerIntegrationType.CONTROL_TEST
|
|
40
|
+
)
|
|
41
|
+
app = Application()
|
|
42
|
+
|
|
43
|
+
def fetch_assets(self, *args, **kwargs) -> Iterator[IntegrationAsset]:
|
|
44
|
+
"""
|
|
45
|
+
Fetches assets from Axonius
|
|
46
|
+
|
|
47
|
+
:yields: Iterator[IntegrationAsset]
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# TEST: Parse Sample Axonius Object
|
|
51
|
+
axonius_object = pd.read_json("regscale/integrations/commercial/axonius/sample_axonius_object.json")
|
|
52
|
+
|
|
53
|
+
for ind, asset in axonius_object.iterrows():
|
|
54
|
+
integration_asset = IntegrationAsset(
|
|
55
|
+
name=asset["hostname"],
|
|
56
|
+
identifier=asset.COMPLIANCE_TABLE[0]["FISMA"],
|
|
57
|
+
serial_number=asset["serial"],
|
|
58
|
+
ip_address=asset["ip"],
|
|
59
|
+
status=AssetStatus.Active,
|
|
60
|
+
asset_category="Software",
|
|
61
|
+
asset_type="Other",
|
|
62
|
+
)
|
|
63
|
+
yield integration_asset
|
|
64
|
+
|
|
65
|
+
def fetch_findings(self, plan_id: int, *args, **kwargs) -> Iterator[IntegrationFinding]:
|
|
66
|
+
"""
|
|
67
|
+
Unused method, but required by the parent class
|
|
68
|
+
|
|
69
|
+
:yields: Iterator[IntegrationFinding]
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
# TEST: Parse Sample Axonius Object
|
|
73
|
+
axonius_object = pd.read_json("regscale/integrations/commercial/axonius/sample_axonius_object.json")
|
|
74
|
+
|
|
75
|
+
for ind, asset in axonius_object.iterrows():
|
|
76
|
+
for finding in asset.COMPLIANCE_TABLE:
|
|
77
|
+
if finding["ComplianceResult"] != "PASSED":
|
|
78
|
+
|
|
79
|
+
# Look for Control Title, Otherwise use Control ID
|
|
80
|
+
existing_implementations = ControlImplementation.get_list_by_parent(
|
|
81
|
+
regscale_id=plan_id, regscale_module="securityplans"
|
|
82
|
+
)
|
|
83
|
+
finding_control = re.search("[A-Z]{2}-\d+\d?(\(\d+\d?\))?", str(finding["800-53r5"]))[ # noqa: W605
|
|
84
|
+
0
|
|
85
|
+
].lower()
|
|
86
|
+
try:
|
|
87
|
+
control_title = [
|
|
88
|
+
control
|
|
89
|
+
for control in existing_implementations
|
|
90
|
+
if control["controlId"].lower() == finding_control
|
|
91
|
+
][0]["title"]
|
|
92
|
+
except Exception:
|
|
93
|
+
control_title = finding["800-53r5"]
|
|
94
|
+
|
|
95
|
+
integration_finding = IntegrationFinding(
|
|
96
|
+
title=f"Assessment Failure for Control ID: {control_title}",
|
|
97
|
+
asset_identifier=finding["FISMA"],
|
|
98
|
+
severity=self.finding_severity_map.get(finding["SEV"], IssueSeverity.NotAssigned),
|
|
99
|
+
identification="Security Control Assessment",
|
|
100
|
+
source_report="Axonius",
|
|
101
|
+
status="Open",
|
|
102
|
+
description=f"Issue for {finding['PLUGIN']}",
|
|
103
|
+
plugin_name=finding["PLUGIN"],
|
|
104
|
+
category="Other",
|
|
105
|
+
control_labels=[finding["800-53r5"]],
|
|
106
|
+
security_check=f"<strong>PLUGIN: </strong>{finding['PLUGIN']}<br><br><strong>FISMA: </strong>{finding['FISMA']}<br><br><strong>Compliance Result: </strong>{finding['ComplianceResult']}<br><br><strong>CCI: </strong>{finding['CCI']}<br><br><strong>800-53r5: </strong>{finding['800-53r5']}<br><br><strong>CSF: </strong>{finding['CSF']}<br><br><strong>VULID: </strong>{finding['VULID']}<br><br><strong>STIG: </strong>{finding['STIG']}",
|
|
107
|
+
baseline=finding["STIG"],
|
|
108
|
+
results=finding["ComplianceResult"],
|
|
109
|
+
affected_controls=finding["800-53r5"],
|
|
110
|
+
)
|
|
111
|
+
yield integration_finding
|
|
@@ -9,10 +9,10 @@ from pathlib import Path
|
|
|
9
9
|
from typing import Any, Generator, List, Optional, TextIO
|
|
10
10
|
from urllib.parse import urlparse
|
|
11
11
|
from xml.etree.ElementTree import Element, ParseError, fromstring, parse
|
|
12
|
+
from logging import getLogger
|
|
12
13
|
|
|
13
14
|
from regscale.core.app.api import Api
|
|
14
15
|
from regscale.core.app.application import Application
|
|
15
|
-
from regscale.core.app.logz import create_logger
|
|
16
16
|
from regscale.core.app.utils.app_utils import check_file_path, get_current_datetime
|
|
17
17
|
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
18
18
|
from regscale.models.integration_models.burp_models import BurpRequest, BurpResponse, Issue, RequestResponse
|
|
@@ -26,7 +26,7 @@ class Burp:
|
|
|
26
26
|
"""Burp Scan information"""
|
|
27
27
|
|
|
28
28
|
def __init__(self, app: Application, file_path: str, encoding="utf-8", **kwargs) -> "Burp":
|
|
29
|
-
logger =
|
|
29
|
+
logger = getLogger("regscale")
|
|
30
30
|
logger.info("Now processing %s", file_path)
|
|
31
31
|
self.integration_assets: Generator[IntegrationAsset, None, None] = (x for x in [])
|
|
32
32
|
self.integration_findings: Generator[IntegrationFinding, None, None] = (x for x in [])
|
|
@@ -293,10 +293,10 @@ class Burp:
|
|
|
293
293
|
:rtype: RequestResponse
|
|
294
294
|
"""
|
|
295
295
|
request_data = item.find(".//request")
|
|
296
|
-
if response_data := item.find(".//response"):
|
|
297
|
-
base64_dat =
|
|
296
|
+
if (response_data := item.find(".//response")) is not None:
|
|
297
|
+
base64_dat = request_data.attrib.get("base64", "false").lower() == "true"
|
|
298
298
|
response_data_is_base64 = BurpResponse.is_base64(response_data.text)
|
|
299
|
-
method = request_data.attrib
|
|
299
|
+
method = request_data.attrib.get("method", "GET")
|
|
300
300
|
request = (
|
|
301
301
|
BurpRequest(dataString=request_data.text, base64=base64_dat, method=method)
|
|
302
302
|
if BurpRequest.is_base64(request_data.text)
|
|
@@ -395,7 +395,8 @@ class Burp:
|
|
|
395
395
|
root = fromstring(html)
|
|
396
396
|
return [link.text.strip() for link in root.iter("a")]
|
|
397
397
|
|
|
398
|
-
|
|
398
|
+
@staticmethod
|
|
399
|
+
def get_domain_name(url: str) -> str:
|
|
399
400
|
"""
|
|
400
401
|
Get the domain name from a URL
|
|
401
402
|
|
|
@@ -407,7 +408,8 @@ class Burp:
|
|
|
407
408
|
domain_name = parsed_url.hostname
|
|
408
409
|
return domain_name
|
|
409
410
|
|
|
410
|
-
|
|
411
|
+
@staticmethod
|
|
412
|
+
def strip_html_tags(text: str) -> str:
|
|
411
413
|
"""
|
|
412
414
|
Strip HTML tags from a string.
|
|
413
415
|
|
|
@@ -420,7 +422,8 @@ class Burp:
|
|
|
420
422
|
clean = re.sub(r"<.*?>", "", text)
|
|
421
423
|
return clean
|
|
422
424
|
|
|
423
|
-
|
|
425
|
+
@staticmethod
|
|
426
|
+
def extract_cve(input_string: str) -> Optional[str]:
|
|
424
427
|
"""
|
|
425
428
|
Extract CVEs from a string.
|
|
426
429
|
|