regscale-cli 6.16.2.0__py3-none-any.whl → 6.16.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/api_handler.py +4 -11
- regscale/integrations/commercial/crowdstrike.py +0 -1
- regscale/integrations/commercial/qualys.py +50 -61
- regscale/integrations/commercial/servicenow.py +1 -0
- regscale/integrations/commercial/snyk.py +2 -2
- regscale/integrations/commercial/synqly/ticketing.py +29 -0
- regscale/integrations/commercial/veracode.py +1 -1
- regscale/integrations/scanner_integration.py +53 -18
- regscale/models/integration_models/cisa_kev_data.json +50 -7
- regscale/models/integration_models/flat_file_importer/__init__.py +29 -8
- regscale/models/integration_models/snyk.py +141 -15
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/veracode.py +91 -48
- regscale/models/regscale_models/user.py +3 -4
- regscale/utils/version.py +3 -5
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/RECORD +22 -22
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.16.2.0.dist-info → regscale_cli-6.16.3.0.dist-info}/top_level.txt +0 -0
regscale/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "6.16.
|
|
1
|
+
__version__ = "6.16.3.0"
|
|
@@ -67,18 +67,11 @@ class APIHandler(Application):
|
|
|
67
67
|
:return: The version string
|
|
68
68
|
:rtype: str
|
|
69
69
|
"""
|
|
70
|
+
from regscale.utils.version import RegscaleVersion
|
|
71
|
+
|
|
72
|
+
rs_version = RegscaleVersion()
|
|
70
73
|
if self._regscale_version is None:
|
|
71
|
-
|
|
72
|
-
response = self.get("/assets/json/version.json")
|
|
73
|
-
if response.status_code == 200:
|
|
74
|
-
version_data = response.json()
|
|
75
|
-
self._regscale_version = version_data.get("version", "Unknown")
|
|
76
|
-
else:
|
|
77
|
-
logger.error(f"Failed to fetch version. Status code: {response.status_code}")
|
|
78
|
-
self._regscale_version = "Unknown"
|
|
79
|
-
except Exception as e:
|
|
80
|
-
logger.error(f"Error fetching version: {e}")
|
|
81
|
-
self._regscale_version = "Unknown"
|
|
74
|
+
self._regscale_version = rs_version.current_version
|
|
82
75
|
return self._regscale_version
|
|
83
76
|
|
|
84
77
|
def _make_request(
|
|
@@ -1010,7 +1010,6 @@ def create_new_control_implementation(
|
|
|
1010
1010
|
cim = ControlImplementation(
|
|
1011
1011
|
controlOwnerId=user_id,
|
|
1012
1012
|
dateLastAssessed=get_current_datetime(),
|
|
1013
|
-
implementation=control.get("implementation", None),
|
|
1014
1013
|
status=status,
|
|
1015
1014
|
controlID=control["id"],
|
|
1016
1015
|
parentId=parent_id,
|
|
@@ -27,9 +27,9 @@ from regscale.core.app.utils.app_utils import (
|
|
|
27
27
|
save_data_to,
|
|
28
28
|
)
|
|
29
29
|
from regscale.core.app.utils.file_utils import download_from_s3
|
|
30
|
-
from regscale.models.app_models.click import regscale_ssp_id
|
|
31
30
|
from regscale.models import Asset, Issue, Search, regscale_models
|
|
32
31
|
from regscale.models.app_models.click import NotRequiredIf, save_output_to
|
|
32
|
+
from regscale.models.app_models.click import regscale_ssp_id
|
|
33
33
|
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
34
34
|
from regscale.models.integration_models.qualys import (
|
|
35
35
|
Qualys,
|
|
@@ -611,11 +611,7 @@ def get_scan_results(scans: Any, task: TaskID) -> dict:
|
|
|
611
611
|
:return: dictionary of detailed Qualys scans
|
|
612
612
|
:rtype: dict
|
|
613
613
|
"""
|
|
614
|
-
|
|
615
|
-
config = app.config
|
|
616
|
-
|
|
617
|
-
# set the auth for the QUALYS_API session
|
|
618
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
614
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
619
615
|
|
|
620
616
|
scan_data = {}
|
|
621
617
|
# check number of scans requested
|
|
@@ -636,7 +632,7 @@ def get_scan_results(scans: Any, task: TaskID) -> dict:
|
|
|
636
632
|
}
|
|
637
633
|
# get the scan data via API
|
|
638
634
|
res = QUALYS_API.get(
|
|
639
|
-
url=urljoin(
|
|
635
|
+
url=urljoin(qualys_url, "/api/2.0/fo/scan/"),
|
|
640
636
|
headers=HEADERS,
|
|
641
637
|
params=params,
|
|
642
638
|
)
|
|
@@ -664,11 +660,7 @@ def get_detailed_scans(days: int) -> list:
|
|
|
664
660
|
:return: list of results from Qualys API
|
|
665
661
|
:rtype: list
|
|
666
662
|
"""
|
|
667
|
-
|
|
668
|
-
config = app.config
|
|
669
|
-
|
|
670
|
-
# set the auth for the QUALYS_API session
|
|
671
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
663
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
672
664
|
|
|
673
665
|
today = datetime.now()
|
|
674
666
|
scan_date = today - timedelta(days=days)
|
|
@@ -684,12 +676,12 @@ def get_detailed_scans(days: int) -> list:
|
|
|
684
676
|
"scan_datetime_since": scan_date.strftime("%Y-%m-%dT%H:%I:%S%ZZ"),
|
|
685
677
|
}
|
|
686
678
|
res = QUALYS_API.get(
|
|
687
|
-
url=urljoin(
|
|
679
|
+
url=urljoin(qualys_url, "/api/2.0/fo/scan/summary/"),
|
|
688
680
|
headers=HEADERS,
|
|
689
681
|
params=params,
|
|
690
682
|
)
|
|
691
683
|
response = QUALYS_API.get(
|
|
692
|
-
url=urljoin(
|
|
684
|
+
url=urljoin(qualys_url, "/api/2.0/fo/scan/vm/summary/"),
|
|
693
685
|
headers=HEADERS,
|
|
694
686
|
params=params2,
|
|
695
687
|
)
|
|
@@ -708,6 +700,34 @@ def get_detailed_scans(days: int) -> list:
|
|
|
708
700
|
return res_data
|
|
709
701
|
|
|
710
702
|
|
|
703
|
+
def _get_config():
|
|
704
|
+
"""
|
|
705
|
+
Get the Qualys configuration
|
|
706
|
+
|
|
707
|
+
:return: Qualys configuration
|
|
708
|
+
:rtype: dict
|
|
709
|
+
"""
|
|
710
|
+
app = check_license()
|
|
711
|
+
config = app.config
|
|
712
|
+
return config
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def _get_qualys_api():
|
|
716
|
+
"""
|
|
717
|
+
Get the Qualys API session
|
|
718
|
+
|
|
719
|
+
:return: Qualys API session
|
|
720
|
+
:rtype: Session
|
|
721
|
+
"""
|
|
722
|
+
config = _get_config()
|
|
723
|
+
|
|
724
|
+
# set the auth for the QUALYS_API session
|
|
725
|
+
QUALYS_API.auth = (config.get("qualysUserName"), config.get("qualysPassword"))
|
|
726
|
+
QUALYS_API.verify = config.get("qualysVerify", True)
|
|
727
|
+
qualys_url = config.get("qualysUrl")
|
|
728
|
+
return qualys_url, QUALYS_API
|
|
729
|
+
|
|
730
|
+
|
|
711
731
|
def import_total_cloud_data_from_qualys_api(security_plan_id: int, include_tags: str, exclude_tags: str):
|
|
712
732
|
"""
|
|
713
733
|
Function to get the total cloud data from Qualys API
|
|
@@ -717,10 +737,7 @@ def import_total_cloud_data_from_qualys_api(security_plan_id: int, include_tags:
|
|
|
717
737
|
"""
|
|
718
738
|
try:
|
|
719
739
|
|
|
720
|
-
|
|
721
|
-
config = app.config
|
|
722
|
-
# set the auth for the QUALYS_API session
|
|
723
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
740
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
724
741
|
params = {
|
|
725
742
|
"action": "list",
|
|
726
743
|
"show_asset_id": "1",
|
|
@@ -733,7 +750,7 @@ def import_total_cloud_data_from_qualys_api(security_plan_id: int, include_tags:
|
|
|
733
750
|
if include_tags:
|
|
734
751
|
params["tag_set_include"] = include_tags
|
|
735
752
|
response = QUALYS_API.get(
|
|
736
|
-
url=urljoin(
|
|
753
|
+
url=urljoin(qualys_url, "/api/2.0/fo/asset/host/vm/detection/"),
|
|
737
754
|
headers=HEADERS,
|
|
738
755
|
params=params,
|
|
739
756
|
)
|
|
@@ -761,17 +778,13 @@ def get_scans_summary(scan_choice: str) -> dict:
|
|
|
761
778
|
:return: Detailed summary of scans from Qualys API as a dictionary
|
|
762
779
|
:rtype: dict
|
|
763
780
|
"""
|
|
764
|
-
|
|
765
|
-
config = app.config
|
|
781
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
766
782
|
urls = []
|
|
767
783
|
|
|
768
|
-
# set the auth for the QUALYS_API session
|
|
769
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
770
|
-
|
|
771
784
|
# set up variables for function
|
|
772
785
|
scan_data = {}
|
|
773
786
|
responses = []
|
|
774
|
-
scan_url = urljoin(
|
|
787
|
+
scan_url = urljoin(qualys_url, "/api/2.0/fo/scan/")
|
|
775
788
|
|
|
776
789
|
# set up parameters for the scans query
|
|
777
790
|
params = {"action": "list"}
|
|
@@ -812,11 +825,7 @@ def get_scan_details(days: int) -> list:
|
|
|
812
825
|
:return: Detailed summary of scans from Qualys API as a dictionary
|
|
813
826
|
:rtype: list
|
|
814
827
|
"""
|
|
815
|
-
|
|
816
|
-
config = app.config
|
|
817
|
-
|
|
818
|
-
# set the auth for the QUALYS_API session
|
|
819
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
828
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
820
829
|
# get since date for API call
|
|
821
830
|
since_date = datetime.now() - timedelta(days=days)
|
|
822
831
|
# set up data and parameters for the scans query
|
|
@@ -835,12 +844,12 @@ def get_scan_details(days: int) -> list:
|
|
|
835
844
|
"scan_datetime_since": since_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
836
845
|
}
|
|
837
846
|
res = QUALYS_API.get(
|
|
838
|
-
url=urljoin(
|
|
847
|
+
url=urljoin(qualys_url, "/api/2.0/fo/scan/summary/"),
|
|
839
848
|
headers=headers,
|
|
840
849
|
params=params,
|
|
841
850
|
)
|
|
842
851
|
response = QUALYS_API.get(
|
|
843
|
-
url=urljoin(
|
|
852
|
+
url=urljoin(qualys_url, "/api/2.0/fo/scan/vm/summary/"),
|
|
844
853
|
headers=headers,
|
|
845
854
|
params=params2,
|
|
846
855
|
)
|
|
@@ -874,11 +883,7 @@ def sync_qualys_assets_and_vulns(
|
|
|
874
883
|
:param Optional[Union[int, str]] asset_group_filter: Filter the Qualys assets by an asset group ID or name, if any
|
|
875
884
|
:rtype: None
|
|
876
885
|
"""
|
|
877
|
-
|
|
878
|
-
config = app.config
|
|
879
|
-
|
|
880
|
-
# set the auth for the QUALYS_API session
|
|
881
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
886
|
+
config = _get_config()
|
|
882
887
|
|
|
883
888
|
# Get the assets from RegScale with the provided SSP ID
|
|
884
889
|
logger.info("Getting assets from RegScale for SSP #%s...", ssp_id)
|
|
@@ -1086,14 +1091,10 @@ def get_qualys_assets_and_scan_results(
|
|
|
1086
1091
|
:return: list of dictionaries containing asset data
|
|
1087
1092
|
:rtype: list
|
|
1088
1093
|
"""
|
|
1089
|
-
|
|
1090
|
-
config = app.config
|
|
1091
|
-
|
|
1092
|
-
# set the auth for the QUALYS_API session
|
|
1093
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
1094
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
1094
1095
|
# set url
|
|
1095
1096
|
if not url:
|
|
1096
|
-
url = urljoin(
|
|
1097
|
+
url = urljoin(qualys_url, "api/2.0/fo/asset/host/vm/detection?action=list&show_asset_id=1")
|
|
1097
1098
|
|
|
1098
1099
|
# check if an asset group filter was provided and append it to the url
|
|
1099
1100
|
if asset_group_filter:
|
|
@@ -1143,12 +1144,7 @@ def get_issue_data_for_assets(asset_list: list) -> Tuple[list[dict], int]:
|
|
|
1143
1144
|
:return: Updated asset list of Qualys assets and their associated vulnerabilities, total number of vulnerabilities
|
|
1144
1145
|
:rtype: Tuple[list[dict], int]
|
|
1145
1146
|
"""
|
|
1146
|
-
|
|
1147
|
-
config = app.config
|
|
1148
|
-
|
|
1149
|
-
# set the auth for the QUALYS_API session
|
|
1150
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
1151
|
-
|
|
1147
|
+
config = _get_config()
|
|
1152
1148
|
with job_progress:
|
|
1153
1149
|
issues = {}
|
|
1154
1150
|
for asset in asset_list:
|
|
@@ -1285,9 +1281,9 @@ def lookup_asset(asset_list: list, asset_id: str = None) -> list[Asset]:
|
|
|
1285
1281
|
:rtype: list[Asset]
|
|
1286
1282
|
"""
|
|
1287
1283
|
if asset_id:
|
|
1288
|
-
results = [
|
|
1284
|
+
results = [asset for asset in asset_list if getattr(asset, "qualysId", None) == asset_id]
|
|
1289
1285
|
else:
|
|
1290
|
-
results = [
|
|
1286
|
+
results = [asset for asset in asset_list]
|
|
1291
1287
|
# Return unique list
|
|
1292
1288
|
return list(set(results)) or []
|
|
1293
1289
|
|
|
@@ -1322,11 +1318,7 @@ def create_regscale_issue_from_vuln(
|
|
|
1322
1318
|
:return: list of RegScale issues to update, and a list of issues to be created
|
|
1323
1319
|
:rtype: Tuple[list[Issue], list[Issue]]
|
|
1324
1320
|
"""
|
|
1325
|
-
|
|
1326
|
-
config = app.config
|
|
1327
|
-
|
|
1328
|
-
# set the auth for the QUALYS_API session
|
|
1329
|
-
QUALYS_API.auth = (config["qualysUserName"], config["qualysPassword"])
|
|
1321
|
+
config = _get_config()
|
|
1330
1322
|
default_status = config["issues"]["qualys"]["status"]
|
|
1331
1323
|
regscale_issues = []
|
|
1332
1324
|
regscale_existing_issues = Issue.get_all_by_parent(parent_id=regscale_ssp_id, parent_module="securityplans")
|
|
@@ -1441,13 +1433,10 @@ def get_asset_groups_from_qualys() -> list:
|
|
|
1441
1433
|
:return: list of assets from Qualys
|
|
1442
1434
|
:rtype: list
|
|
1443
1435
|
"""
|
|
1444
|
-
app = check_license()
|
|
1445
|
-
config = app.config
|
|
1446
1436
|
asset_groups = []
|
|
1447
1437
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
response = QUALYS_API.get(url=urljoin(config["qualysUrl"], "api/2.0/fo/asset/group?action=list"), headers=HEADERS)
|
|
1438
|
+
qualys_url, QUALYS_API = _get_qualys_api()
|
|
1439
|
+
response = QUALYS_API.get(url=urljoin(qualys_url, "api/2.0/fo/asset/group?action=list"), headers=HEADERS)
|
|
1451
1440
|
if response.ok:
|
|
1452
1441
|
logger.debug(response.text)
|
|
1453
1442
|
try:
|
|
@@ -741,6 +741,7 @@ def create_snow_tag(snow_config: ServiceNowConfig, tag_name: str) -> Optional[di
|
|
|
741
741
|
"active": True,
|
|
742
742
|
"sys_class_name": "tag",
|
|
743
743
|
"type": "Standard",
|
|
744
|
+
"viewable_by": "everyone",
|
|
744
745
|
}
|
|
745
746
|
url = urljoin(snow_config.url, "api/now/table/label")
|
|
746
747
|
response = snow_api.post(
|
|
@@ -18,7 +18,7 @@ def snyk():
|
|
|
18
18
|
|
|
19
19
|
@snyk.command(name="import_snyk")
|
|
20
20
|
@FlatFileImporter.common_scanner_options(
|
|
21
|
-
message="File path to the folder containing Snyk .xlsx files to process to RegScale.",
|
|
21
|
+
message="File path to the folder containing Snyk .xlsx or .json files to process to RegScale.",
|
|
22
22
|
prompt="File path for Snyk files",
|
|
23
23
|
import_name="snyk",
|
|
24
24
|
)
|
|
@@ -77,7 +77,7 @@ def import_synk_files(
|
|
|
77
77
|
FlatFileImporter.import_files(
|
|
78
78
|
import_type=Snyk,
|
|
79
79
|
import_name="Snyk",
|
|
80
|
-
file_types=".xlsx",
|
|
80
|
+
file_types=[".xlsx", ".json"],
|
|
81
81
|
folder_path=folder_path,
|
|
82
82
|
regscale_ssp_id=regscale_ssp_id,
|
|
83
83
|
scan_date=scan_date,
|
|
@@ -13,6 +13,17 @@ def ticketing() -> None:
|
|
|
13
13
|
pass
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
@ticketing.command(name="sync_autotask")
|
|
17
|
+
@regscale_id()
|
|
18
|
+
@regscale_module()
|
|
19
|
+
def sync_autotask(regscale_id: int, regscale_module: str) -> None:
|
|
20
|
+
"""Sync Ticketing data between Autotask and RegScale."""
|
|
21
|
+
from regscale.models.integration_models.synqly_models.connectors import Ticketing
|
|
22
|
+
|
|
23
|
+
ticketing_autotask = Ticketing("autotask")
|
|
24
|
+
ticketing_autotask.run_sync(regscale_id=regscale_id, regscale_module=regscale_module)
|
|
25
|
+
|
|
26
|
+
|
|
16
27
|
@ticketing.command(name="sync_jira")
|
|
17
28
|
@regscale_id()
|
|
18
29
|
@regscale_module()
|
|
@@ -111,6 +122,24 @@ def sync_servicenow(regscale_id: int, regscale_module: str, issue_type: str, def
|
|
|
111
122
|
)
|
|
112
123
|
|
|
113
124
|
|
|
125
|
+
@ticketing.command(name="sync_servicenow_sir")
|
|
126
|
+
@regscale_id()
|
|
127
|
+
@regscale_module()
|
|
128
|
+
@click.option(
|
|
129
|
+
"--issue_type",
|
|
130
|
+
type=click.STRING,
|
|
131
|
+
help="servicenow_sir issue type",
|
|
132
|
+
required=True,
|
|
133
|
+
prompt="servicenow_sir issue type",
|
|
134
|
+
)
|
|
135
|
+
def sync_servicenow_sir(regscale_id: int, regscale_module: str, issue_type: str) -> None:
|
|
136
|
+
"""Sync Ticketing data between Servicenow Sir and RegScale."""
|
|
137
|
+
from regscale.models.integration_models.synqly_models.connectors import Ticketing
|
|
138
|
+
|
|
139
|
+
ticketing_servicenow_sir = Ticketing("servicenow_sir")
|
|
140
|
+
ticketing_servicenow_sir.run_sync(regscale_id=regscale_id, regscale_module=regscale_module, issue_type=issue_type)
|
|
141
|
+
|
|
142
|
+
|
|
114
143
|
@ticketing.command(name="sync_torq")
|
|
115
144
|
@regscale_id()
|
|
116
145
|
@regscale_module()
|
|
@@ -83,7 +83,7 @@ def import_veracode_data(
|
|
|
83
83
|
FlatFileImporter.import_files(
|
|
84
84
|
import_type=Veracode,
|
|
85
85
|
import_name="Veracode",
|
|
86
|
-
file_types=[".xml", ".xlsx"],
|
|
86
|
+
file_types=[".xml", ".xlsx", ".json"],
|
|
87
87
|
folder_path=folder_path,
|
|
88
88
|
regscale_ssp_id=regscale_ssp_id,
|
|
89
89
|
scan_date=scan_date,
|
|
@@ -269,6 +269,10 @@ class IntegrationAsset:
|
|
|
269
269
|
other_cloud_identifier: Optional[str] = None
|
|
270
270
|
patch_level: Optional[str] = None
|
|
271
271
|
cpe: Optional[str] = None
|
|
272
|
+
is_latest_scan: Optional[bool] = None
|
|
273
|
+
is_authenticated_scan: Optional[bool] = None
|
|
274
|
+
system_administrator_id: Optional[str] = None
|
|
275
|
+
scanning_tool: Optional[str] = None
|
|
272
276
|
|
|
273
277
|
source_data: Optional[Dict[str, Any]] = None
|
|
274
278
|
url: Optional[str] = None
|
|
@@ -373,6 +377,7 @@ class IntegrationFinding:
|
|
|
373
377
|
cvss_v2_score: Optional[float] = None
|
|
374
378
|
ip_address: Optional[str] = None
|
|
375
379
|
plugin_id: Optional[str] = None
|
|
380
|
+
plugin_text: Optional[str] = None
|
|
376
381
|
dns: Optional[str] = None
|
|
377
382
|
severity_int: int = 0
|
|
378
383
|
security_check: Optional[str] = None
|
|
@@ -410,6 +415,7 @@ class IntegrationFinding:
|
|
|
410
415
|
risk_adjustment: str = "No"
|
|
411
416
|
operational_requirements: Optional[str] = None
|
|
412
417
|
deviation_rationale: Optional[str] = None
|
|
418
|
+
is_cwe: bool = False
|
|
413
419
|
|
|
414
420
|
poam_comments: Optional[str] = None
|
|
415
421
|
vulnerability_id: Optional[int] = None
|
|
@@ -1067,6 +1073,10 @@ class ScannerIntegration(ABC):
|
|
|
1067
1073
|
softwareVersion=asset.software_version,
|
|
1068
1074
|
softwareName=asset.software_name,
|
|
1069
1075
|
softwareVendor=asset.software_vendor,
|
|
1076
|
+
bLatestScan=asset.is_latest_scan,
|
|
1077
|
+
bAuthenticatedScan=asset.is_authenticated_scan,
|
|
1078
|
+
systemAdministratorId=asset.system_administrator_id,
|
|
1079
|
+
scanningTool=asset.scanning_tool,
|
|
1070
1080
|
)
|
|
1071
1081
|
if self.asset_identifier_field:
|
|
1072
1082
|
setattr(new_asset, self.asset_identifier_field, asset.identifier)
|
|
@@ -1587,15 +1597,34 @@ class ScannerIntegration(ABC):
|
|
|
1587
1597
|
bulk_update=True, defaults={"otherIdentifier": self._get_other_identifier(finding, is_poam)}
|
|
1588
1598
|
)
|
|
1589
1599
|
|
|
1600
|
+
self._handle_property_creation_for_issue(issue, finding)
|
|
1601
|
+
return issue
|
|
1602
|
+
|
|
1603
|
+
def _handle_property_creation_for_issue(self, issue: regscale_models.Issue, finding: IntegrationFinding) -> None:
|
|
1604
|
+
"""
|
|
1605
|
+
Handles property creation for an issue based on the finding data
|
|
1606
|
+
|
|
1607
|
+
:param regscale_models.Issue issue: The issue to handle properties for
|
|
1608
|
+
:param IntegrationFinding finding: The finding data
|
|
1609
|
+
:rtype: None
|
|
1610
|
+
"""
|
|
1590
1611
|
if poc := finding.point_of_contact:
|
|
1591
|
-
|
|
1612
|
+
regscale_models.Property(
|
|
1592
1613
|
key="POC",
|
|
1593
1614
|
value=poc,
|
|
1594
1615
|
parentId=issue.id,
|
|
1595
1616
|
parentModule="issues",
|
|
1596
|
-
).create_or_update(
|
|
1617
|
+
).create_or_update()
|
|
1618
|
+
logger.debug("Added POC property %s to issue %s", poc, issue.id)
|
|
1597
1619
|
|
|
1598
|
-
|
|
1620
|
+
if finding.is_cwe:
|
|
1621
|
+
regscale_models.Property(
|
|
1622
|
+
key="CWE",
|
|
1623
|
+
value=finding.plugin_id,
|
|
1624
|
+
parentId=issue.id,
|
|
1625
|
+
parentModule="issues",
|
|
1626
|
+
).create_or_update()
|
|
1627
|
+
logger.debug("Added CWE property %s to issue %s", finding.plugin_id, issue.id)
|
|
1599
1628
|
|
|
1600
1629
|
@staticmethod
|
|
1601
1630
|
def get_consolidated_asset_identifier(
|
|
@@ -1719,15 +1748,16 @@ class ScannerIntegration(ABC):
|
|
|
1719
1748
|
:param IntegrationFinding finding: The finding data that has failed
|
|
1720
1749
|
:rtype: None
|
|
1721
1750
|
"""
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1751
|
+
if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
|
|
1752
|
+
logger.debug("Creating issue for failing finding %s", finding.external_id)
|
|
1753
|
+
found_issue = self.create_or_update_issue_from_finding(
|
|
1754
|
+
title=issue_title,
|
|
1755
|
+
finding=finding,
|
|
1756
|
+
)
|
|
1757
|
+
# Update the control implementation status to NOT_IMPLEMENTED since we have a failing finding
|
|
1758
|
+
if found_issue.controlImplementationIds:
|
|
1759
|
+
for control_id in found_issue.controlImplementationIds:
|
|
1760
|
+
self.update_control_implementation_status_after_close(control_id)
|
|
1731
1761
|
|
|
1732
1762
|
def handle_failing_checklist(
|
|
1733
1763
|
self,
|
|
@@ -2013,6 +2043,7 @@ class ScannerIntegration(ABC):
|
|
|
2013
2043
|
self._results["scan_history"] = scan_history.save()
|
|
2014
2044
|
self.update_result_counts("issues", regscale_models.Issue.bulk_save(progress_context=self.finding_progress))
|
|
2015
2045
|
self.close_outdated_issues(current_vulnerabilities)
|
|
2046
|
+
self._perform_batch_operations(self.finding_progress)
|
|
2016
2047
|
|
|
2017
2048
|
return processed_findings_count
|
|
2018
2049
|
|
|
@@ -2206,7 +2237,8 @@ class ScannerIntegration(ABC):
|
|
|
2206
2237
|
plugInName=finding.cve or finding.plugin_name, # Use CVE if available, otherwise use plugin name
|
|
2207
2238
|
plugInId=finding.plugin_id,
|
|
2208
2239
|
exploitAvailable=None, # Set this if you have information about exploit availability
|
|
2209
|
-
plugInText=finding.
|
|
2240
|
+
plugInText=finding.plugin_text
|
|
2241
|
+
or finding.observations, # or finding.evidence, whichever is more appropriate
|
|
2210
2242
|
port=finding.port if hasattr(finding, "port") else None,
|
|
2211
2243
|
protocol=finding.protocol if hasattr(finding, "protocol") else None,
|
|
2212
2244
|
operatingSystem=asset.operating_system if hasattr(asset, "operating_system") else None,
|
|
@@ -2262,11 +2294,12 @@ class ScannerIntegration(ABC):
|
|
|
2262
2294
|
vulnerability = self.create_vulnerability_from_finding(finding, asset, scan_history)
|
|
2263
2295
|
finding.vulnerability_id = vulnerability.id
|
|
2264
2296
|
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2297
|
+
if ScannerVariables.vulnerabilityCreation.lower() != "noissue":
|
|
2298
|
+
# Handle associated issue
|
|
2299
|
+
self.create_or_update_issue_from_finding(
|
|
2300
|
+
title=finding.title,
|
|
2301
|
+
finding=finding,
|
|
2302
|
+
)
|
|
2270
2303
|
|
|
2271
2304
|
return vulnerability.id
|
|
2272
2305
|
|
|
@@ -2623,6 +2656,8 @@ class ScannerIntegration(ABC):
|
|
|
2623
2656
|
created_count = instance._results.get("assets", {}).get("created_count", 0)
|
|
2624
2657
|
updated_count = instance._results.get("assets", {}).get("updated_count", 0)
|
|
2625
2658
|
dedupe_count = assets_processed - (created_count + updated_count)
|
|
2659
|
+
# Ensure dedupe_count is always a positive value
|
|
2660
|
+
dedupe_count = dedupe_count if dedupe_count >= 0 else dedupe_count * -1
|
|
2626
2661
|
logger.info(
|
|
2627
2662
|
"%d assets processed and %d asset(s) deduped. %d asset(s) created & %d asset(s) updated in RegScale.",
|
|
2628
2663
|
assets_processed,
|
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "CISA Catalog of Known Exploited Vulnerabilities",
|
|
3
|
-
"catalogVersion": "2025.03.
|
|
4
|
-
"dateReleased": "2025-03-
|
|
5
|
-
"count":
|
|
3
|
+
"catalogVersion": "2025.03.27",
|
|
4
|
+
"dateReleased": "2025-03-27T17:55:47.8204Z",
|
|
5
|
+
"count": 1311,
|
|
6
6
|
"vulnerabilities": [
|
|
7
|
+
{
|
|
8
|
+
"cveID": "CVE-2025-2783",
|
|
9
|
+
"vendorProject": "Google",
|
|
10
|
+
"product": "Chromium Mojo",
|
|
11
|
+
"vulnerabilityName": "Google Chromium Mojo Sandbox Escape Vulnerability",
|
|
12
|
+
"dateAdded": "2025-03-27",
|
|
13
|
+
"shortDescription": "Google Chromium Mojo on Windows contains a sandbox escape vulnerability caused by a logic error, which results from an incorrect handle being provided in unspecified circumstances. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera.",
|
|
14
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
15
|
+
"dueDate": "2025-04-17",
|
|
16
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
+
"notes": "https:\/\/chromereleases.googleblog.com\/2025\/03\/stable-channel-update-for-desktop_25.html ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-2783",
|
|
18
|
+
"cwes": []
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cveID": "CVE-2019-9875",
|
|
22
|
+
"vendorProject": "Sitecore",
|
|
23
|
+
"product": "CMS and Experience Platform (XP)",
|
|
24
|
+
"vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
|
|
25
|
+
"dateAdded": "2025-03-26",
|
|
26
|
+
"shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an authenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
|
|
27
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
28
|
+
"dueDate": "2025-04-16",
|
|
29
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
30
|
+
"notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0038556 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9875",
|
|
31
|
+
"cwes": [
|
|
32
|
+
"CWE-502"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"cveID": "CVE-2019-9874",
|
|
37
|
+
"vendorProject": "Sitecore",
|
|
38
|
+
"product": "CMS and Experience Platform (XP)",
|
|
39
|
+
"vulnerabilityName": "Sitecore CMS and Experience Platform (XP) Deserialization Vulnerability",
|
|
40
|
+
"dateAdded": "2025-03-26",
|
|
41
|
+
"shortDescription": "Sitecore CMS and Experience Platform (XP) contain a deserialization vulnerability in the Sitecore.Security.AntiCSRF module that allows an unauthenticated attacker to execute arbitrary code by sending a serialized .NET object in the HTTP POST parameter __CSRFTOKEN.",
|
|
42
|
+
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
43
|
+
"dueDate": "2025-04-16",
|
|
44
|
+
"knownRansomwareCampaignUse": "Unknown",
|
|
45
|
+
"notes": "https:\/\/support.sitecore.com\/kb?id=kb_article_view&sysparm_article=KB0334035 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-9874",
|
|
46
|
+
"cwes": [
|
|
47
|
+
"CWE-502"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
7
50
|
{
|
|
8
51
|
"cveID": "CVE-2025-30154",
|
|
9
52
|
"vendorProject": "reviewdog",
|
|
@@ -14,7 +57,7 @@
|
|
|
14
57
|
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
15
58
|
"dueDate": "2025-04-14",
|
|
16
59
|
"knownRansomwareCampaignUse": "Unknown",
|
|
17
|
-
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: https:\/\/github.com\/reviewdog\/reviewdog\/security\/advisories\/GHSA-qmg3-hpqr-gqvc ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30154",
|
|
60
|
+
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/reviewdog\/reviewdog\/security\/advisories\/GHSA-qmg3-hpqr-gqvc ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30154",
|
|
18
61
|
"cwes": [
|
|
19
62
|
"CWE-506"
|
|
20
63
|
]
|
|
@@ -74,7 +117,7 @@
|
|
|
74
117
|
"requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
|
|
75
118
|
"dueDate": "2025-04-08",
|
|
76
119
|
"knownRansomwareCampaignUse": "Unknown",
|
|
77
|
-
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
|
|
120
|
+
"notes": "This vulnerability affects a common open-source project, third-party library, or a protocol used by different products. For more information, please see: CISA Mitigation Instructions: https:\/\/www.cisa.gov\/news-events\/alerts\/2025\/03\/18\/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ; Additional References: https:\/\/github.com\/tj-actions\/changed-files\/blob\/45fb12d7a8bedb4da42342e52fe054c6c2c3fd73\/README.md?plain=1#L20-L28 ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-30066",
|
|
78
121
|
"cwes": [
|
|
79
122
|
"CWE-506"
|
|
80
123
|
]
|
|
@@ -2964,7 +3007,7 @@
|
|
|
2964
3007
|
{
|
|
2965
3008
|
"cveID": "CVE-2024-4761",
|
|
2966
3009
|
"vendorProject": "Google",
|
|
2967
|
-
"product": "Chromium
|
|
3010
|
+
"product": "Chromium V8",
|
|
2968
3011
|
"vulnerabilityName": "Google Chromium V8 Out-of-Bounds Memory Write Vulnerability",
|
|
2969
3012
|
"dateAdded": "2024-05-16",
|
|
2970
3013
|
"shortDescription": "Google Chromium V8 Engine contains an unspecified out-of-bounds memory write vulnerability via a crafted HTML page. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera. ",
|
|
@@ -14619,7 +14662,7 @@
|
|
|
14619
14662
|
"cveID": "CVE-2020-6572",
|
|
14620
14663
|
"vendorProject": "Google",
|
|
14621
14664
|
"product": "Chrome Media",
|
|
14622
|
-
"vulnerabilityName": "Google Chrome Media
|
|
14665
|
+
"vulnerabilityName": "Google Chrome Media Use-After-Free Vulnerability",
|
|
14623
14666
|
"dateAdded": "2022-01-10",
|
|
14624
14667
|
"shortDescription": "Google Chrome Media contains a use-after-free vulnerability that allows a remote attacker to execute code via a crafted HTML page.",
|
|
14625
14668
|
"requiredAction": "Apply updates per vendor instructions.",
|