diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java index 9c87c8cfba..88d9cf13cd 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/DefectDojoPersistenceProvider.java @@ -8,7 +8,7 @@ import io.securecodebox.persistence.defectdojo.service.EndpointService; import io.securecodebox.persistence.mapping.DefectDojoFindingToSecureCodeBoxMapper; import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.service.ScanService; +import io.securecodebox.persistence.service.scanresult.ScanResultService; import io.securecodebox.persistence.service.KubernetesService; import io.securecodebox.persistence.service.S3Service; import io.securecodebox.persistence.strategies.VersionedEngagementsStrategy; @@ -33,7 +33,7 @@ public static void main(String[] args) throws Exception { scan.validate(); LOG.info("Downloading Scan Result"); - var scanResultFile = ScanService.downloadScan(scan, persistenceProviderConfig, s3Service); + var scanResultFile = ScanResultService.build(scan, s3Service).getScanResult(persistenceProviderConfig); var config = DefectDojoConfig.fromEnv(); LOG.info("Uploading Findings to DefectDojo at: {}", config.getUrl()); diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java index 96e891c06e..72e26c7b55 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/config/PersistenceProviderConfig.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.ZoneId; import java.util.List; /** @@ -23,6 +24,12 @@ public class PersistenceProviderConfig { final int RAW_RESULT_UPLOAD_ARG_POSITION = 2; final int FINDING_UPLOAD_ARG_POSITION = 3; + // DefectDojo does in contrast to secureCodeBox not pay attention to time zones + // to guarantee consistent results when converting back and forth a time zone + // has to be assumed for DefectDojo. It defaults to the Time Zone of the system clock + @Getter + ZoneId defectDojoTimezoneId = ZoneId.systemDefault(); + // Download Urls @Getter final String rawResultDownloadUrl; diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java index 770ae51fa0..6a3405ecf5 100644 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapper.java @@ -1,62 +1,38 @@ package io.securecodebox.persistence.mapping; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.core.util.DefaultIndenter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; +import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.models.DefectDojoImportFinding; import io.securecodebox.persistence.models.SecureCodeBoxFinding; +import io.securecodebox.persistence.service.KubernetesService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.net.URI; import java.time.Instant; import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; public class SecureCodeBoxFindingsToDefectDojoMapper { - private static final Logger LOG = LoggerFactory.getLogger(SecureCodeBoxFindingsToDefectDojoMapper.class); - private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final ObjectWriter prettyJSONPrinter = new ObjectMapper().findAndRegisterModules().writerWithDefaultPrettyPrinter(); + private static final Logger LOG = LoggerFactory.getLogger(KubernetesService.class); + private final DateTimeFormatter ddDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private final ObjectWriter attributeJsonPrinter = new ObjectMapper().writer(new DefaultPrettyPrinter() + .withObjectIndenter(new DefaultIndenter().withLinefeed("\n"))); + private PersistenceProviderConfig ppConfig; - /** - * Converts a SecureCodeBox Findings JSON String to a DefectDojo Findings JSON String. - * - * @param scbFindingsJson SecureCodeBox Findings JSON File as String - * @return DefectDojo Findings JSON File as String, compatible with the DefectDojo Generic JSON Parser - * @throws IOException - */ - public static String fromSecureCodeboxFindingsJson(String scbFindingsJson) throws IOException { - LOG.debug("Converting SecureCodeBox Findings to DefectDojo Findings"); - ObjectMapper mapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .findAndRegisterModules(); - List DefectDojoImportFindings = new ArrayList<>(); - List secureCodeBoxFindings = mapper.readValue(scbFindingsJson, new TypeReference<>() { - }); - for (SecureCodeBoxFinding secureCodeBoxFinding : secureCodeBoxFindings) { - DefectDojoImportFindings.add(fromSecureCodeBoxFinding(secureCodeBoxFinding)); - } - // create the result where the format has to be {"findings": [finding1, findings2, ...]} - ObjectNode ddFindingJson = mapper.createObjectNode(); - ArrayNode arrayNode = mapper.valueToTree(DefectDojoImportFindings); - ddFindingJson.putArray("findings").addAll(arrayNode); - return ddFindingJson.toString(); + public SecureCodeBoxFindingsToDefectDojoMapper(PersistenceProviderConfig ppConfig){ + this.ppConfig= ppConfig; } - protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severities severity) { + protected String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severities severity) { if (severity == null) { return "Info"; } - switch (severity) { case HIGH: return "High"; @@ -67,7 +43,6 @@ protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severit case INFORMATIONAL: return "Info"; } - return "Info"; } @@ -77,9 +52,8 @@ protected static String convertToDefectDojoSeverity(SecureCodeBoxFinding.Severit * * @param secureCodeBoxFinding Finding in SecureCodeBox format. * @return Finding in DefectDojo Format, compatible with the DefectDojo Generic JSON Parser - * @throws JsonProcessingException */ - protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxFinding secureCodeBoxFinding) throws JsonProcessingException { + public DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxFinding secureCodeBoxFinding){ //set basic Finding info DefectDojoImportFinding result = new DefectDojoImportFinding(); result.setTitle(secureCodeBoxFinding.getName()); @@ -88,8 +62,12 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF // set DefectDojo description as combination of SecureCodeBox Finding description and Finding attributes String description = secureCodeBoxFinding.getDescription(); if (secureCodeBoxFinding.getAttributes() != null) { - String attributesJson = prettyJSONPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes()); - description = description + "\n " + attributesJson; + try { + var attributesJson = attributeJsonPrinter.writeValueAsString(secureCodeBoxFinding.getAttributes()); + description = description + "\n " + attributesJson; + } catch (JsonProcessingException e) { + LOG.warn("Could not write the secureCodeBox Finding Attributes as JSON: ",e); + } } result.setDescription(description); setFindingDate(secureCodeBoxFinding, result); @@ -97,7 +75,7 @@ protected static DefectDojoImportFinding fromSecureCodeBoxFinding(SecureCodeBoxF return result; } - private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + private void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { if (secureCodeBoxFinding.getLocation() != null && !secureCodeBoxFinding.getLocation().isEmpty()) { try { URI.create(secureCodeBoxFinding.getLocation()); @@ -108,8 +86,8 @@ private static void setFindingLocation(SecureCodeBoxFinding secureCodeBoxFinding } } - private static void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { - Instant instant = null; + private void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, DefectDojoImportFinding result) { + Instant instant; if (secureCodeBoxFinding.getIdentifiedAt() != null && !secureCodeBoxFinding.getIdentifiedAt().isEmpty()) { instant = Instant.parse(secureCodeBoxFinding.getIdentifiedAt()); } else if (secureCodeBoxFinding.getParsedAt() != null && !secureCodeBoxFinding.getParsedAt().isEmpty()){ @@ -118,8 +96,8 @@ private static void setFindingDate(SecureCodeBoxFinding secureCodeBoxFinding, De else { instant = Instant.now(); } - LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); - result.setDate(dtf.format(localDateTime)); + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ppConfig.getDefectDojoTimezoneId()); + result.setDate(ddDateFormatter.format(localDateTime)); } private static String capitalize(String str) { diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java deleted file mode 100644 index 3d5864d5dd..0000000000 --- a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/ScanService.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.securecodebox.persistence.service; - -import io.securecodebox.persistence.config.PersistenceProviderConfig; -import io.securecodebox.persistence.defectdojo.models.ScanFile; -import io.securecodebox.persistence.mapping.SecureCodeBoxFindingsToDefectDojoMapper; -import io.securecodebox.persistence.models.Scan; -import io.securecodebox.persistence.util.ScanNameMapping; -import org.apache.commons.io.FilenameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.URL; - -public class ScanService { - private static final Logger LOG = LoggerFactory.getLogger(ScanService.class); - - public static ScanFile downloadScan(Scan scan, PersistenceProviderConfig ppConfig, S3Service s3Service) throws IOException, InterruptedException { - String downloadUrl; - String scanResults; - String scanType = scan.getSpec().getScanType(); - ScanNameMapping scanNameMapping = ScanNameMapping.bySecureCodeBoxScanType(scanType); - if (scanNameMapping == ScanNameMapping.GENERIC) { - LOG.debug("No explicit Parser specified for ScanType {}, using Findings JSON Scan Result", scanType); - downloadUrl = ppConfig.getFindingDownloadUrl(); - var findingsJSON = s3Service.downloadFile(downloadUrl); - scanResults = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeboxFindingsJson(findingsJSON); - } else { - LOG.debug("Explicit Parser is specified for ScanType {}, using Raw Scan Result", scanNameMapping.scanType); - downloadUrl = ppConfig.getRawResultDownloadUrl(); - scanResults = s3Service.downloadFile(downloadUrl); - } - LOG.info("Finished Downloading Scan Result"); - LOG.debug("Scan Result: {}", scanResults); - - return new ScanFile(scanResults, FilenameUtils.getName(new URL(downloadUrl).getPath())); - } -} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java new file mode 100644 index 0000000000..bec1078bd0 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/GenericParserScanResultService.java @@ -0,0 +1,54 @@ +package io.securecodebox.persistence.service.scanresult; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.mapping.SecureCodeBoxFindingsToDefectDojoMapper; +import io.securecodebox.persistence.models.DefectDojoImportFinding; +import io.securecodebox.persistence.models.SecureCodeBoxFinding; +import io.securecodebox.persistence.service.S3Service; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Responsible for returning scan results that are compatible with the DefectDojo Generic JSON Parser + */ +public class GenericParserScanResultService extends ScanResultService { + + private static final ObjectMapper jsonObjectMapper = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).findAndRegisterModules(); + + public GenericParserScanResultService(S3Service s3Service) { + super(s3Service); + } + + /** + * Fetches the secureCodeBox Findings.json file and converts it to a json file that is compatible with + * the DefectDojo Generic JSON Parser. This result as a string is then returned together with a filename + * in a ScanFile object. The ending of the filename is essential as it is evaluated by DefectDojo + * @param ppConfig config where the location of the scan result is specified + * @return + * @throws IOException + * @throws InterruptedException + */ + @Override + public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { + LOG.debug("No explicit Parser specified. Using Findings JSON Scan Result"); + var scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(ppConfig); + var downloadUrl = ppConfig.getFindingDownloadUrl(); + var findingsJSON = s3Service.downloadFile(downloadUrl); + List secureCodeBoxFindings = Arrays.asList(jsonObjectMapper.readValue(findingsJSON, SecureCodeBoxFinding[].class)); + List defectDojoImportFindings = secureCodeBoxFindings.stream().map(scbToDdMapper::fromSecureCodeBoxFinding).collect(Collectors.toList()); + // for the generic defectDojo Parser the findings need to be wrapper in a json object called "findings" + var defectDojoFindingJson = Collections.singletonMap("findings",defectDojoImportFindings); + var scanResult = jsonObjectMapper.writeValueAsString(defectDojoFindingJson); + return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); + } +} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java new file mode 100644 index 0000000000..ba4cc3b49c --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/ScanResultService.java @@ -0,0 +1,33 @@ +package io.securecodebox.persistence.service.scanresult; + +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.models.Scan; +import io.securecodebox.persistence.service.S3Service; +import io.securecodebox.persistence.util.ScanNameMapping; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * Abstract class that forces children to implement a method to get the scan results from a source + * (e.g. download link) specified in the PersistenceProviderConfig. + * It also builds the correct subclass to use, depending on the Scan (especially it's type) + */ +public abstract class ScanResultService { + protected static final Logger LOG = LoggerFactory.getLogger(ScanResultService.class); + protected S3Service s3Service; + protected ScanResultService(S3Service s3Service) { + this.s3Service = s3Service; + } + + public static ScanResultService build(Scan scan, S3Service s3Service){ + ScanNameMapping scanNameMapping = ScanNameMapping.bySecureCodeBoxScanType(scan.getSpec().getScanType()); + if (scanNameMapping.equals(ScanNameMapping.GENERIC)) + return new GenericParserScanResultService(s3Service); + else return new SpecificParserScanResultService(s3Service); + } + + public abstract ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException; +} diff --git a/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java new file mode 100644 index 0000000000..76316210b2 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/main/java/io/securecodebox/persistence/service/scanresult/SpecificParserScanResultService.java @@ -0,0 +1,36 @@ +package io.securecodebox.persistence.service.scanresult; + +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.service.S3Service; +import org.apache.commons.io.FilenameUtils; + +import java.io.IOException; +import java.net.URL; + +/** + * Responsible for returning the raw scan results produced by the secureCodeBox + */ +public class SpecificParserScanResultService extends ScanResultService { + + public SpecificParserScanResultService(S3Service s3Service) { + super(s3Service); + } + + /** + * Fetches the secureCodeBox raw scan results and returns it together with the filename + * in a ScanFile object. The ending of the filename is essential as it is evaluated by DefectDojo. + * This is usually used when DefectDojo natively supports the scanner that produced the raw result. + * @param ppConfig config where the location of the scan result is specified + * @return + * @throws IOException + * @throws InterruptedException + */ + @Override + public ScanFile getScanResult(PersistenceProviderConfig ppConfig) throws IOException, InterruptedException { + LOG.debug("Explicit Parser is specified. Using Raw Scan Result"); + var downloadUrl = ppConfig.getRawResultDownloadUrl(); + var scanResult = s3Service.downloadFile(downloadUrl); + return new ScanFile(scanResult, FilenameUtils.getName(new URL(downloadUrl).getPath())); + } +} diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java index a09b6e8b16..51b24d9a87 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/SecureCodeBoxFindingsToDefectDojoMapperTest.java @@ -1,51 +1,39 @@ package io.securecodebox.persistence.mapping; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import io.securecodebox.persistence.config.PersistenceProviderConfig; import io.securecodebox.persistence.models.SecureCodeBoxFinding; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; +import java.time.ZoneId; import java.util.HashMap; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; - +// Create one instance for the whole class instead for each method to reuse the genericTestFinding in all methods +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(MockitoExtension.class) public class SecureCodeBoxFindingsToDefectDojoMapperTest { - @Test - public void yieldsCorrectResult() throws IOException { - String ddFindingsPath = "kubehunter-dd-findings.json"; - String scbFindingsPath = "kubehunter-scb-findings.json"; - ClassLoader cl = getClass().getClassLoader(); - - File ddFindingsFile = new File(cl.getResource(ddFindingsPath).getFile()); - File scbFindingsFile = new File(cl.getResource(scbFindingsPath).getFile()); - String expectedResult = new String(Files.readAllBytes(ddFindingsFile.toPath())); - String scbFindingsContent = new String(Files.readAllBytes(scbFindingsFile.toPath())); - String result = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeboxFindingsJson(scbFindingsContent); - ObjectMapper mapper = new ObjectMapper(); - JsonNode actualJSON = mapper.readTree(result); - JsonNode expectedJSON = mapper.readTree(expectedResult); - assertNotNull(actualJSON); - // if whitespaces should be ignored in strings, a Custom Comperator could be used - // then the result and expected result would not have to match exactly. - // see https://www.baeldung.com/jackson-compare-two-json-objects - assertEquals(actualJSON, expectedJSON); - } + // test class + private SecureCodeBoxFindingsToDefectDojoMapper scbToDdMapper; + // test data + private SecureCodeBoxFinding genericTestFinding; + // Mock + private PersistenceProviderConfig ppConfig; - @Test - public void correctlyParsesFindings() throws IOException { + @BeforeAll + public void init() { var name = "Name"; var description = "Description"; - var severity = "High"; - var id = "123"; + var id = "e18cdc5e-6b49-4346-b623-28a4e878e154"; var parsedAt = "2020-04-15T12:27:28.153Z"; var location = "ldap://[2001:db8::7]/c=GB?objectClass?one"; var attributes = new HashMap(); @@ -54,21 +42,53 @@ public void correctlyParsesFindings() throws IOException { attributes.put("attribute_1", subAttribute); attributes.put("attribute_2", "2"); attributes.put("attribute_3", "3"); - var scbFinding = SecureCodeBoxFinding.builder().name(name).description(description) + genericTestFinding = SecureCodeBoxFinding.builder().name(name).description(description) .severity(SecureCodeBoxFinding.Severities.HIGH).id(id).location(location).attributes(attributes) .parsedAt(parsedAt).build(); + ppConfig = mock(PersistenceProviderConfig.class); + // usually the default TimeZone on a machine is used to create the DefectDojo Dates. To ensure that the test + // results are the same regardless of the machine the test runs on we assume UTC+0 for tests. + when(ppConfig.getDefectDojoTimezoneId()).thenReturn(ZoneId.of("+0")); + scbToDdMapper = new SecureCodeBoxFindingsToDefectDojoMapper(ppConfig); + } + + @Test + public void correctlyParsesBasicFindingProperties() { + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); + assertEquals(ddFinding.getTitle(), genericTestFinding.getName()); + assertEquals(ddFinding.getUniqueIdFromTool(), genericTestFinding.getId()); + assertEquals(ddFinding.getEndpoints().get(0), genericTestFinding.getLocation()); + } - var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(scbFinding); + @Test + public void correctlyParsesSeverities() { + var nullSeverityFinding = SecureCodeBoxFinding.builder().build(); + var infoSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.INFORMATIONAL).build(); + var lowSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.LOW).build(); + var mediumSeverityFinding = SecureCodeBoxFinding.builder().severity(SecureCodeBoxFinding.Severities.MEDIUM).build(); + var highSeverityFinding = SecureCodeBoxFinding.builder().severity((SecureCodeBoxFinding.Severities.HIGH)).build(); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(nullSeverityFinding).getSeverity(), "Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(infoSeverityFinding).getSeverity(), "Info"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(lowSeverityFinding).getSeverity(), "Low"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(mediumSeverityFinding).getSeverity(), "Medium"); + assertEquals(scbToDdMapper.fromSecureCodeBoxFinding(highSeverityFinding).getSeverity(), "High"); + } - assertEquals(ddFinding.getTitle(), name); - assertEquals(ddFinding.getSeverity(), severity); - assertEquals(ddFinding.getUniqueIdFromTool(), id); - assertEquals(ddFinding.getEndpoints().get(0), location); + @Test + public void correctlyParsesDate() { + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); assertEquals(ddFinding.getDate(), "2020-04-15"); - assertTrue(ddFinding.getDescription().startsWith(description)); + var dateTestFinding = SecureCodeBoxFinding.builder().parsedAt("2030-12-01T14:22:28Z").build(); + var dateTestResultFinding = scbToDdMapper.fromSecureCodeBoxFinding(dateTestFinding); + assertEquals(dateTestResultFinding.getDate(), "2030-12-01"); + } - //Description should consist of description and attributes as JSON - String attributesJson = ddFinding.getDescription().substring(description.length() + 1); + @Test + public void correctlyParsesDescription() throws JsonProcessingException { + var ddFinding = scbToDdMapper.fromSecureCodeBoxFinding(genericTestFinding); + assertTrue(ddFinding.getDescription().startsWith(genericTestFinding.getDescription())); + //Description should consist of the secureCodeBox description and attributes as JSON + String attributesJson = ddFinding.getDescription().substring(genericTestFinding.getDescription().length() + 1); String expectedAttributeJson = "{\n" + " \"attribute_1\" : {\n" + " \"sub_attribute\" : \"1\"\n" + @@ -76,18 +96,14 @@ public void correctlyParsesFindings() throws IOException { " \"attribute_2\" : \"2\",\n" + " \"attribute_3\" : \"3\"\n" + "}"; + // We do not care how exactly the JSON looks as long as it is correct. ObjectMapper mapper = new ObjectMapper(); - var actualJson = mapper.readTree(expectedAttributeJson); - - assertNotNull(actualJson); - assertEquals(mapper.readTree(attributesJson), mapper.readTree(expectedAttributeJson)); + assertEquals(mapper.readTree(expectedAttributeJson), mapper.readTree(attributesJson)); } @Test - public void doesntThrowUnexpectedExceptionOnEmptyFinding() throws JsonProcessingException { + public void doesNotThrowUnexpectedExceptionOnEmptyFinding() { var emptyScbFinding = SecureCodeBoxFinding.builder().build(); - var ddFinding = SecureCodeBoxFindingsToDefectDojoMapper.fromSecureCodeBoxFinding(emptyScbFinding); - assertNull(ddFinding.getTitle()); - assertNull(ddFinding.getDescription()); + assertDoesNotThrow(() -> scbToDdMapper.fromSecureCodeBoxFinding(emptyScbFinding)); } } diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java new file mode 100644 index 0000000000..a3a1a64a78 --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/service/ScanServiceTest.java @@ -0,0 +1,90 @@ +package io.securecodebox.persistence.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.securecodebox.models.V1ScanSpec; +import io.securecodebox.persistence.config.PersistenceProviderConfig; +import io.securecodebox.persistence.defectdojo.models.ScanFile; +import io.securecodebox.persistence.models.Scan; +import io.securecodebox.persistence.service.scanresult.ScanResultService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.time.ZoneId; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class ScanServiceTest { + @Mock + S3Service s3Service; + @Mock + PersistenceProviderConfig ppConfig; + @Mock + Scan scan; + + public static String readResourceAsString(String resourceName) throws IOException { + ClassLoader cl = ScanServiceTest.class.getClassLoader(); + File resourceFile = new File(cl.getResource(resourceName).getFile()); + return Files.readString(resourceFile.toPath()); + } + + /*** + * When a unknown scanner is encountered the findings json has to be converted into defectdojo compatible json and + * the correct file ending must be used so DefectDojo can choose the right parser (usually xml or json) + * @throws IOException + * @throws InterruptedException + */ + @Test + public void correctlyParsesGenericResults() throws IOException, InterruptedException { + // read data + String expectedDdFindingsString = readResourceAsString("kubehunter-dd-findings.json"); + String givenScbFindingsString = readResourceAsString("kubehunter-scb-findings.json"); + + // check if null or empty + assertNotEquals(expectedDdFindingsString, ""); + assertNotEquals(givenScbFindingsString, ""); + String findingsUrl = "https://foo.com/findings.json"; + V1ScanSpec scanSpec = new V1ScanSpec(); + scanSpec.setScanType("some-unknown-scanner-type"); + + // mock methods + when(scan.getSpec()).thenReturn(scanSpec); + when(ppConfig.getFindingDownloadUrl()).thenReturn(findingsUrl); + when(ppConfig.getDefectDojoTimezoneId()).thenReturn(ZoneId.of("+0")); + when(s3Service.downloadFile(findingsUrl)).thenReturn(givenScbFindingsString); + + // test for correctness + var result = ScanResultService.build(scan, s3Service).getScanResult(ppConfig); + // check that the produced and expected JSON are the same. + ObjectMapper mapper = new ObjectMapper(); + assertEquals(mapper.readTree(expectedDdFindingsString), mapper.readTree(result.getContent())); + // file name must have the right ending + assertTrue(result.getName().endsWith(".json")); + } + + /*** + * When a known scanner like nikto is encountered the raw result must be passed and the correct file ending must + * be used so DefectDojo can choose the right parser (usually xml or json) + * @throws IOException + * @throws InterruptedException + */ + @Test + public void correctlyReturnsScannerSpecificResults() throws IOException, InterruptedException { + var rawNiktoScanString = readResourceAsString("nikto-raw-result.json"); + String rawResultDownloadUrl = "https://foo.com/nikto-raw-results.json"; + V1ScanSpec scanSpec = new V1ScanSpec(); + scanSpec.setScanType("nikto"); + when(ppConfig.getRawResultDownloadUrl()).thenReturn(rawResultDownloadUrl); + when(scan.getSpec()).thenReturn(scanSpec); + when(s3Service.downloadFile(rawResultDownloadUrl)).thenReturn(rawNiktoScanString); + ScanFile result = ScanResultService.build(scan, s3Service).getScanResult(ppConfig); + assertEquals(rawNiktoScanString, result.getContent()); + assertTrue(result.getName().endsWith(".json")); + } +} diff --git a/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json b/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json new file mode 100644 index 0000000000..f59e30704f --- /dev/null +++ b/hooks/persistence-defectdojo/hook/src/test/resources/nikto-raw-result.json @@ -0,0 +1,715 @@ +{ + "host": "juice-shop", + "ip": "10.101.101.50", + "port": "3000", + "banner": "", + "vulnerabilities": [ + { + "id": "999986", + "OSVDB": "0", + "method": "GET", + "url": "/", + "msg": "Retrieved access-control-allow-origin header: *" + }, + { + "id": "999997", + "OSVDB": "0", + "method": "GET", + "url": "/ftp/", + "msg": "Entry '/ftp/' in robots.txt returned a non-forbidden or redirect HTTP code (200)" + }, + { + "id": "999996", + "OSVDB": "0", + "method": "GET", + "url": "/robots.txt", + "msg": "\"robots.txt\" contains 1 entry which should be manually viewed." + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tgz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.tar.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.war", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.egg", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.pem", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.cer", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.jks", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/backup.tar.lzma", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.gz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/site.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/database.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.tar.bz2", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/dump.zip", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/archive.sql", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.alz", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/10.101.101.50.tar", + "msg": "Potentially interesting backup/cert file found. " + }, + { + "id": "740001", + "OSVDB": "0", + "method": "HEAD", + "url": "/juice-shop.egg", + "msg": "Potentially interesting backup/cert file found. " + } + ] +}