diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/AdditionalTargetAttributes.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/AdditionalTargetAttributes.java index f85924d2..3eb0c858 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/AdditionalTargetAttributes.java +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/AdditionalTargetAttributes.java @@ -20,5 +20,6 @@ package io.securecodebox.scanprocesses.amassnmap; public enum AdditionalTargetAttributes { - NMAP_CONFIGURATION_PROFILE + NMAP_CONFIGURATION_PROFILE, + NMAP_HTTP_HEADERS } diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/FilterHttpSecurityHeaders.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/FilterHttpSecurityHeaders.java new file mode 100644 index 00000000..a2735031 --- /dev/null +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/FilterHttpSecurityHeaders.java @@ -0,0 +1,149 @@ +package io.securecodebox.scanprocesses.amassnmap; + +import io.securecodebox.model.execution.ScanProcessExecution; +import io.securecodebox.model.execution.ScanProcessExecutionFactory; +import io.securecodebox.model.findings.Finding; +import io.securecodebox.model.findings.Severity; +import io.securecodebox.scanprocesses.amassnmap.util.HttpHeaderStrategy; +import io.securecodebox.scanprocesses.amassnmap.util.HttpHeaders; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.JavaDelegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; + + +@Component +public class FilterHttpSecurityHeaders implements JavaDelegate { + + private static final Logger LOG = LoggerFactory.getLogger(FilterHttpSecurityHeaders.class); + + @Autowired + ScanProcessExecutionFactory processExecutionFactory; + + + private static final HttpHeaderStrategy[] httpStrategies = new HttpHeaderStrategy[] { + requireHttpServersToRedirectToHttps() + }; + + private static final HttpHeaderStrategy[] httpsStrategies = new HttpHeaderStrategy[] { + requireStrictTransportSecurityHeader(), + requireContentSecurityPolicyHeader(), + requirePermittedCrossDomainPolicies(), + requireFrameOptionsToBeDenied(), + requireXssProtectionToBeEnabled(), + requireContentTypeOptionsToEqualNosniff() + }; + + + @Override + public void execute(DelegateExecution delegateExecution) throws Exception { + final ScanProcessExecution process = processExecutionFactory.get(delegateExecution); + final ArrayList findings = new ArrayList<>(); + final long tStart = System.currentTimeMillis(); + process.getFindings().stream() + .forEach(finding -> { + if (HttpHeaders.headersPresentInFinding(finding)) { + final HttpHeaders headers = HttpHeaders.fromFinding(finding); + findings.addAll(applyStrategies (headers, finding)); + } else { + findings.add(finding); + } + }); + final long tStrategiesApplied = System.currentTimeMillis(); + final int numberOfAdditionalFindings = findings.size() - process.getFindings().size(); + clearFindings(process); + findings.forEach(changedFinding -> process.appendFinding(changedFinding)); + LOG.debug("http-headers strategies yielded {} additional findings; finding them took {}ms, storing them {}ms", numberOfAdditionalFindings, tStrategiesApplied - tStart, System.currentTimeMillis() - tStrategiesApplied); + } + + private ArrayList applyStrategies(HttpHeaders headers, Finding finding) { + final ArrayList changedFindings = new ArrayList<>(); + changedFindings.add(finding); + + final String name = finding.getName(); + + if (name.equals("http")) { + for (HttpHeaderStrategy httpStrategy : httpStrategies) { + changedFindings.addAll(httpStrategy.apply(headers, finding)); + } + } else if (name.equals("https")) { + for (HttpHeaderStrategy httpsStrategy : httpsStrategies) { + changedFindings.addAll(httpsStrategy.apply(headers, finding)); + } + } + + return changedFindings; + } + + + private static HttpHeaderStrategy requireHttpServersToRedirectToHttps() { + return new HttpHeaderStrategy("Location") + .ifPresent() + .modifyFinding((value, finding) -> { + finding.setSeverity(Severity.INFORMATIONAL); + finding.setName(finding.getName() + " with redirect to " + value); + finding.setDescription(finding.getDescription() + " with redirect to " + value); + }) + .ifMissing() + .createFinding(Severity.HIGH, "missing redirect to https"); + } + + private static HttpHeaderStrategy requireStrictTransportSecurityHeader() { + return new HttpHeaderStrategy("Strict-Transport-Security") + .ifMissingCreateFinding(Severity.MEDIUM); + } + + private static HttpHeaderStrategy requireContentSecurityPolicyHeader() { + return new HttpHeaderStrategy("Content-Security-Policy") + .ifMissingCreateFinding(Severity.MEDIUM); + } + + private static HttpHeaderStrategy requirePermittedCrossDomainPolicies() { + return new HttpHeaderStrategy("X-Permitted-Cross-Domain-Policies") + .ifMissingCreateFinding(Severity.MEDIUM); + } + + private static HttpHeaderStrategy requireFrameOptionsToBeDenied() { + return new HttpHeaderStrategy("X-Frame-Options") + .ifMissing() + .createFinding(Severity.MEDIUM, "X-Frame-Options header missing") + .ifTrue(value -> !value.toLowerCase().contains("deny")) + .createFinding(Severity.MEDIUM, "X-Frame-Options header misconfigured", value -> "X-Frame-Options should be 'deny', instead it is set to '" + value + "'"); + } + + private static HttpHeaderStrategy requireXssProtectionToBeEnabled() { + return new HttpHeaderStrategy("X-XSS-Protection") + .ifMissing() + .createFinding(Severity.LOW, "X-XSS-Protection header missing") + .ifTrue(value -> value.startsWith("0")) + .createFinding(Severity.LOW, "X-XSS-Protection manually disabled"); + } + + private static HttpHeaderStrategy requireContentTypeOptionsToEqualNosniff() { + return new HttpHeaderStrategy("X-Content-Type-Options") + .ifMissing() + .createFinding(Severity.LOW, "X-Content-Type-Options header missing") + .ifTrue(value -> !value.equalsIgnoreCase("nosniff")) + .createFinding(Severity.LOW, "X-Content-Type-Options misconfigured", value -> "X-Conntent-Type-Options should be set to 'nosniff' instead of '" + value + "'"); + } + + + private void clearFindings(ScanProcessExecution process) { + if (!process.getFindings().isEmpty()) { + LOG.debug("Clearing findings. The process had {}", process.getFindings().size()); + process.clearFindings(); + } + } + + + private static final HttpHeaderStrategy requireHeader (final String header, final Severity severity) { + return new HttpHeaderStrategy(header) + .ifMissing() + .createFinding(severity, header + " header missing"); + } + +} diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/NmapConfigProfile.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/NmapConfigProfile.java index e059c561..b3d5a9cf 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/NmapConfigProfile.java +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/NmapConfigProfile.java @@ -21,8 +21,9 @@ public enum NmapConfigProfile { HTTP_PORTS("-Pn -p 80,8080,443,8443"), - TOP_100_PORTS("-Pn --top-ports 100"); - + HTTP_PORTS_WITH_HTTP_HEADERS("-Pn -p 80,8080,443,8443 --script=http-headers"), + TOP_100_PORTS("-Pn --top-ports 100"), + TOP_100_PORTS_WITH_HTTP_HEADERS("-Pn --top-ports 100 --script=http-headers"); private final String parameter; NmapConfigProfile(final String parameter) { diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/TransformAmassResultsToNmapInput.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/TransformAmassResultsToNmapInput.java index 181ee4bb..c6f94520 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/TransformAmassResultsToNmapInput.java +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/TransformAmassResultsToNmapInput.java @@ -64,7 +64,10 @@ public void execute(DelegateExecution execution) throws Exception { originalTargetRestorer.storeOriginalTargetInSeparateProcessVariable(originalTarget, execution); String nmapProfile = (String) originalTarget.getAttributes().get(AdditionalTargetAttributes.NMAP_CONFIGURATION_PROFILE.name()); - String nmapParameters = getNmapParameters(nmapProfile); + Boolean nmapHttpHeaders = (Boolean) originalTarget.getAttributes().get(AdditionalTargetAttributes.NMAP_HTTP_HEADERS.name()); + if (nmapHttpHeaders == null) nmapHttpHeaders = false; + String nmapParameters = getNmapParameters(nmapProfile, nmapHttpHeaders); + List newTargets = new ArrayList<>(); for (Finding finding : findings) { @@ -81,6 +84,7 @@ public void execute(DelegateExecution execution) throws Exception { execution.setVariable(DefaultFields.PROCESS_TARGETS.name(), objectValue); execution.setVariable("NMAP_CONFIGURATION_TYPE","default"); + execution.setVariable("PARSE_HTTP_HEADERS", nmapHttpHeaders); LOG.debug("Finished TransformAmassResultsToNmapInput Service Task. Continue with nmap scan"); @@ -89,8 +93,9 @@ public void execute(DelegateExecution execution) throws Exception { } } - private String getNmapParameters(String nmapProfile) { - String defaultNmapParameters = NmapConfigProfile.HTTP_PORTS.getParameter(); + private String getNmapParameters(String nmapProfile, boolean withHttpHeaders) { + String defaultNmapParameters = (withHttpHeaders ? NmapConfigProfile.HTTP_PORTS_WITH_HTTP_HEADERS : NmapConfigProfile.HTTP_PORTS).getParameter(); + if(nmapProfile == null) { LOG.info("No nmap profile set for combined amass-nmap test. Use http ports as default"); return defaultNmapParameters; @@ -98,9 +103,17 @@ private String getNmapParameters(String nmapProfile) { switch (NmapConfigProfile.valueOf(nmapProfile)) { case HTTP_PORTS: - return NmapConfigProfile.HTTP_PORTS.getParameter(); + if (withHttpHeaders) { + return NmapConfigProfile.HTTP_PORTS_WITH_HTTP_HEADERS.getParameter(); + } else { + return NmapConfigProfile.HTTP_PORTS.getParameter(); + } case TOP_100_PORTS: - return NmapConfigProfile.TOP_100_PORTS.getParameter(); + if (withHttpHeaders) { + return NmapConfigProfile.TOP_100_PORTS_WITH_HTTP_HEADERS.getParameter(); + } else { + return NmapConfigProfile.TOP_100_PORTS.getParameter(); + } default: LOG.info("Invalid nmap profile set for combined amass-nmap test. Use http ports as default"); return defaultNmapParameters; diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategy.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategy.java new file mode 100644 index 00000000..c7834ef9 --- /dev/null +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategy.java @@ -0,0 +1,228 @@ +package io.securecodebox.scanprocesses.amassnmap.util; + +import io.securecodebox.model.findings.Finding; +import io.securecodebox.model.findings.OsiLayer; +import io.securecodebox.model.findings.Severity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +public final class HttpHeaderStrategy { + private static final Logger LOG = LoggerFactory.getLogger(HttpHeaderStrategy.class); + + private final String header; + private final ArrayList tests = new ArrayList<>(); + + + public HttpHeaderStrategy (String header) { + this.header = header; + } + + /** + * Creates a finding if the header is present + * @return + */ + public HttpHeaderStrategyExpression ifPresent () { + final HttpHeaderStrategyExpression expression = new HttpHeaderStrategyExpression(this, value -> value != null); + tests.add (expression); + return expression; + } + + /** + * Creates a finding if the header is missing + * @return + */ + public HttpHeaderStrategyExpression ifMissing () { + final HttpHeaderStrategyExpression expression = new HttpHeaderStrategyExpression(this, value -> value == null); + tests.add (expression); + return expression; + } + + /** + * Convenience method, chaining {@link #ifMissing()} and {@link HttpHeaderStrategyExpression#createFinding(Severity, String)} + * @param severity + * @return + */ + public HttpHeaderStrategy ifMissingCreateFinding (Severity severity) { + return this.ifMissing().createFinding(severity, this.header + " header missing"); + } + + /** + * Performs a lambda-based check; will not execute if header not present + * @param test lambda expression function(String headerValue) -> Boolean + * @return + */ + public HttpHeaderStrategyExpression ifTrue (Function test) { + final HttpHeaderStrategyExpression expression = new HttpHeaderStrategyExpression(this, value -> value != null && test.apply(value)); + tests.add (expression); + return expression; + } + + + /** + * Apply strategy to a finding + * @param headers + * @param finding + * @return + */ + public ArrayList apply (HttpHeaders headers, Finding finding) { + final ArrayList additionalFindings = new ArrayList<>(); + for (HttpHeaderStrategyExpression test : tests) { + final String value = headers.get(this.header); + if (test.test.apply(value)) { + if (test.findingNameAndDescriptionGenerator != null) { + test.findingNameAndDescriptionGenerator.accept(value, (name, description) + -> additionalFindings.add(createApplicationLevelFinding(finding, name, test.severity, description))); + } else { + test.findingModifier.accept(value, finding); + } + } + } + return additionalFindings; + } + + + /** + * Helper class; it is the state of a strategy having a logical expression (condition) but no name/description of + * the finding to create (if condition resolves to true) + */ + public final class HttpHeaderStrategyExpression { + private final Function test; + private final HttpHeaderStrategy strategy; + private Severity severity = Severity.INFORMATIONAL; + private BiConsumer> findingNameAndDescriptionGenerator = null; + private BiConsumer findingModifier = null; + + /** + * Private constructor only to be called from class HttpHeaderStrategy + * @param strategy + * @param test + */ + private HttpHeaderStrategyExpression (HttpHeaderStrategy strategy, Function test) { + this.strategy = strategy; + this.test = test; + } + + /** + * Shortcut for {@link #createFinding(Severity, String, String)}; name is also used as description + * @param severity severity of the created finding + * @param name name and Description of the created finding + * @return + */ + public HttpHeaderStrategy createFinding (Severity severity, String name) { + return this.createFinding(severity, name, name); + } + + /** + * Creates a finding with static name / description. If description depends on the value of the header's value + * please use {@link #createFinding(Severity, String, BiConsumer)} + * @param severity + * @param name + * @param description + * @return + */ + public HttpHeaderStrategy createFinding (Severity severity, String name, String description) { + this.severity = severity; + this.findingNameAndDescriptionGenerator = (value, callback) -> callback.accept(name, description); + return strategy; + } + + /** + * Similar to {@link #createFinding(Severity, String, String)}, but description is generated through the + * consumer function and can depend on the value of the header. + * @param severity severity of the finding + * @param name name of the finding + * @param consumer function(String headerValue, function(String findingDescription) -> void) -> void + * @return + */ + public HttpHeaderStrategy createFinding (Severity severity, String name, BiConsumer> consumer) { + this.severity = severity; + this.findingNameAndDescriptionGenerator = (value, generateFinding) -> { + consumer.accept(value, description -> { + generateFinding.accept(name, description); + }); + }; + return this.strategy; + } + + /** + * See {@link #createFinding(Severity, String, BiConsumer)} + * @param severity + * @param name + * @param consumer + * @return + */ + public HttpHeaderStrategy createFinding (Severity severity, String name, Function consumer) { + this.severity = severity; + this.findingNameAndDescriptionGenerator = (headerValue, generateFinding) -> { + generateFinding.accept(name, consumer.apply(headerValue)); + }; + return this.strategy; + } + + /** + * Similar to {@link #createFinding(Severity, String, BiConsumer)}, but the consumer generates both the name and + * the description for the finding. + * @param severity severity of the finding + * @param consumer function(String headerValue, function(String findingName, String findingDescription) -> void) -> void + * @return + */ + public HttpHeaderStrategy createFinding (Severity severity, BiConsumer> consumer) { + this.severity = severity; + this.findingNameAndDescriptionGenerator = consumer; + return strategy; + } + + public HttpHeaderStrategy modifyFinding (BiConsumer consumer) { + this.findingModifier = consumer; + return this.strategy; + } + + } + + + /** + * Creates a finding on OsiLayer.APPLICATION, copying most values (all attributes) from a given, existing finding + * @param copyDetails + * @param name + * @param severity + * @param description + * @return + */ + private Finding createApplicationLevelFinding (final Finding copyDetails, final String name, final Severity severity, final String description) { + final Finding fnd = createCopyOfFinding(copyDetails); + fnd.setName(name); + fnd.setCategory("Http Header"); + fnd.setOsiLayer(OsiLayer.APPLICATION); + fnd.addAttribute("protocol", "http"); + fnd.setDescription(description); + fnd.setSeverity(severity); + return fnd; + } + + /** + * Creates a copy of a finding, omitting name, category, description, osi-layer and severity + * @param copyDetails + * @return + */ + private Finding createCopyOfFinding (final Finding copyDetails) { + final Finding fnd = new Finding(); + fnd.setId(UUID.randomUUID()); + fnd.setLocation(copyDetails.getLocation()); + fnd.setReference(copyDetails.getReference()); + copyDetails.getAttributes().keySet().forEach(key -> { + Object value = copyDetails.getAttributes().get(key); + if (value instanceof Serializable) { + fnd.addAttribute(key, (Serializable) value); + } + }); + return fnd; + } + +} diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaders.java b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaders.java new file mode 100644 index 00000000..96263a1b --- /dev/null +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaders.java @@ -0,0 +1,53 @@ +package io.securecodebox.scanprocesses.amassnmap.util; + +import io.securecodebox.model.findings.Finding; + +import java.util.HashMap; +import java.util.Map; + +public final class HttpHeaders { + + private final HashMap headers = new HashMap<>(); + + public HttpHeaders(String rawHeaders) { + final String[] lines = rawHeaders.split ("\\r?\\n"); + for (int i = 0; i < lines.length; i++) { + final String line = lines[i]; + + // double-newline = end of http header section (ignore if first line; nmap bug) + if (line.length() == 0) { + if (i == 0) continue; + else break; + } + + int colonPos = line.indexOf(':'); + if (colonPos < 0) continue; + final String + k = line.substring(0, colonPos).trim(), + v = line.substring(colonPos + 1).trim(); + headers.put(k, v); + } + } + + public boolean has (String key) { + return headers.containsKey(key); + } + + public String get (String key) { + return headers.get(key); + } + + public static boolean headersPresentInFinding (Finding finding) { + Map attributes = finding.getAttributes(); + if (attributes == null) return false; + Object scripts = attributes.get("scripts"); + if (scripts == null || !(scripts instanceof Map)) return false; + return ((Map)scripts).containsKey("http-headers"); + } + + public static HttpHeaders fromFinding (Finding finding) { + if (!headersPresentInFinding(finding)) return null; + return new HttpHeaders(((Map)finding.getAttributes().get("scripts")).get("http-headers")); + } + +} diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/bpmn/combined_amass_nmap_process.bpmn b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/bpmn/combined_amass_nmap_process.bpmn index 8592a4b4..cdc8693f 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/bpmn/combined_amass_nmap_process.bpmn +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/bpmn/combined_amass_nmap_process.bpmn @@ -1,5 +1,5 @@ - + @@ -29,7 +29,7 @@ SequenceFlow_0p5mwz6 - SequenceFlow_0x38sun + SequenceFlow_133ju0r SequenceFlow_0mvz7h9 @@ -47,7 +47,6 @@ SequenceFlow_1r4mrzm SequenceFlow_0y61th0 - ${PROCESS_AUTOMATED == false} @@ -70,17 +69,35 @@ SequenceFlow_0mvz7h9 - ${PROCESS_RESULT_APPROVED == 'approved'} + - ${PROCESS_RESULT_APPROVED != 'approved'} + - SequenceFlow_0x38sun + SequenceFlow_0v9j7z6 + SequenceFlow_020pm77 SequenceFlow_0k50e6l + + SequenceFlow_0gqomie + SequenceFlow_0v9j7z6 + + + + SequenceFlow_133ju0r + SequenceFlow_020pm77 + SequenceFlow_0gqomie + + + ${PARSE_HTTP_HEADERS == false} + + + ${PARSE_HTTP_HEADERS == true} + + @@ -91,15 +108,18 @@ - - + + - - + + + + + @@ -108,42 +128,41 @@ - - + + - + - + - + - + - + - - - - - - - + + + - + - - + + + + + @@ -152,52 +171,97 @@ - + - + - + - - + + - + - + - + - - + + - + - - - + + + - + - - + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/approve-results.html b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/approve-results.html index 1e027a0a..fa94e1e7 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/approve-results.html +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/approve-results.html @@ -74,14 +74,18 @@

{{ address }} ({{ port.attributes.ip_address }}) - {{ port.category === 'Open Port' ? port.attributes.port : '' }} - {{ port.category === 'Open Port' ? port.attributes.service : port.name}} - {{ port.category === 'Open Port' ? port.attributes.protocol : '' }} + {{ (port.category === 'Open Port' || port.category === 'Http Header') ? port.attributes.port : '' }} + {{ (port.category === 'Open Port' && !port.name) ? port.attributes.service : port.name}} + {{ (port.category === 'Open Port' || port.category === 'Http Header') ? port.attributes.protocol : '' }} - + Open + + + {{ port.description.includes('missing') ? 'Missing' : 'Misconfigured' }} + diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/configure-target.html b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/configure-target.html index 65f20baf..8e87ebb4 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/configure-target.html +++ b/scb-scanprocesses/combined-amass-nmap-process/src/main/resources/forms/amass-nmap/configure-target.html @@ -83,6 +83,13 @@

Please configure the Combined Amass-Nmap Scan

+ +
+ + + diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocess/amassnmap/CombinedAmassNmapProcessTest.java b/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocess/amassnmap/CombinedAmassNmapProcessTest.java index 75de7d34..540e7d45 100644 --- a/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocess/amassnmap/CombinedAmassNmapProcessTest.java +++ b/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocess/amassnmap/CombinedAmassNmapProcessTest.java @@ -109,6 +109,7 @@ public void init() { //Creating a map of default variables for the process defaultVariables.put(DefaultFields.PROCESS_AUTOMATED.name(), true); defaultVariables.put(DefaultFields.PROCESS_CONTEXT.name(), "BodgeIT"); + defaultVariables.put("PARSE_HTTP_HEADERS", false); /* Mocking everything in the BPMN Model diff --git a/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategyTest.java b/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategyTest.java new file mode 100644 index 00000000..98307d92 --- /dev/null +++ b/scb-scanprocesses/combined-amass-nmap-process/src/test/java/io/securecodebox/scanprocesses/amassnmap/util/HttpHeaderStrategyTest.java @@ -0,0 +1,76 @@ +package io.securecodebox.scanprocesses.amassnmap.util; + +import io.securecodebox.model.findings.Finding; +import io.securecodebox.model.findings.OsiLayer; +import io.securecodebox.model.findings.Severity; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.junit.Assert.*; + +public class HttpHeaderStrategyTest { + private HttpHeaders headers; + private Finding finding; + + @Before + public void init () { + final StringBuilder rawHeaders = new StringBuilder(); + rawHeaders.append("Content-Type: text/imaginary\n"); + rawHeaders.append("Location: https://localhost:443/\n"); + rawHeaders.append("Done: yeah;\n\n"); + headers = new HttpHeaders(rawHeaders.toString()); + + finding = new Finding(); + finding.setName("DefaultName"); + finding.setId(UUID.randomUUID()); + finding.setDescription("DefaultDescription"); + finding.setOsiLayer(OsiLayer.NOT_APPLICABLE); + finding.setCategory("DefaultCategory"); + } + + @Test + public void testHttpHeaders () { + assertTrue(headers.has("Content-Type")); + assertEquals("text/imaginary", headers.get("Content-Type")); + assertTrue(headers.has("Location")); + assertEquals("https://localhost:443/", headers.get("Location")); + assertTrue(headers.has("Done")); + assertEquals("yeah;", headers.get("Done")); + assertFalse(headers.has("Nothing")); + assertNull(headers.get("Nothing")); + } + + @Test + public void testExistingHeader () { + HttpHeaderStrategy strategy = createStrategy("Location"); + ArrayList findings = strategy.apply(headers, finding); + + assertEquals(2, findings.size()); + assertEquals(findings.get(0).getName(), "Location header present"); + assertEquals(findings.get(1).getName(), "Does not start with 0"); + } + + @Test + public void testNonExistantHeader () { + HttpHeaderStrategy strategy = createStrategy("Nothing"); + ArrayList findings = strategy.apply(headers, finding); + + assertEquals(1, findings.size()); + assertEquals(findings.get(0).getName(), "Nothing header missing"); + } + + private HttpHeaderStrategy createStrategy(String headerName) { + return new HttpHeaderStrategy(headerName) + + .ifPresent () + .createFinding (Severity.MEDIUM, headerName + " header present") + + .ifMissingCreateFinding(Severity.MEDIUM) + + .ifTrue(value -> !value.startsWith ("0")) + .createFinding (Severity.MEDIUM, "Does not start with 0", value -> "Actual value: " + value); + } +} \ No newline at end of file diff --git a/scb-scanprocesses/nmap-process/src/main/resources/bpmn/nmap_process.bpmn b/scb-scanprocesses/nmap-process/src/main/resources/bpmn/nmap_process.bpmn index 306bd86c..53d5239f 100644 --- a/scb-scanprocesses/nmap-process/src/main/resources/bpmn/nmap_process.bpmn +++ b/scb-scanprocesses/nmap-process/src/main/resources/bpmn/nmap_process.bpmn @@ -1,5 +1,5 @@ - + @@ -78,7 +78,9 @@ ${PROCESS_AUTOMATED == true} - + + + SequenceFlow_PortscanConfigured SequenceFlow_DefaultConfig SequenceFlow_AutomatedStart @@ -92,8 +94,9 @@ - results in a generic format - + + results in a generic format + diff --git a/scb-scanprocesses/nmap-process/src/main/resources/forms/nmap/approve-port-scanner-results.html b/scb-scanprocesses/nmap-process/src/main/resources/forms/nmap/approve-port-scanner-results.html index 876044ee..f02437e0 100644 --- a/scb-scanprocesses/nmap-process/src/main/resources/forms/nmap/approve-port-scanner-results.html +++ b/scb-scanprocesses/nmap-process/src/main/resources/forms/nmap/approve-port-scanner-results.html @@ -91,14 +91,18 @@

{{ address }} ({{ port.attributes.ip_address }}) - {{ port.category === 'Open Port' ? port.attributes.port : '' }} - {{ port.category === 'Open Port' ? port.attributes.service : port.name}} - {{ port.category === 'Open Port' ? port.attributes.protocol : '' }} + {{ (port.category === 'Open Port' || port.category === 'Http Header') ? port.attributes.port : '' }} + {{ (port.category === 'Open Port' && !port.name) ? port.attributes.service : port.name}} + {{ (port.category === 'Open Port' || port.category === 'Http Header') ? port.attributes.protocol : '' }} - + Open + + + {{ port.description.includes('missing') ? 'Missing' : 'Misconfigured' }} +