diff --git a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/NmapPortScanner.java b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/NmapPortScanner.java index 1ffe333e7..4fc00ba46 100644 --- a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/NmapPortScanner.java +++ b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/NmapPortScanner.java @@ -117,6 +117,7 @@ public PortScanningReport scan(ScanTarget scanTarget) { .withScript("http-methods", "http.useragent=" + httpClientCliOptions.userAgent) .withTimingTemplate(TimingTemplate.AGGRESSIVE) .withTargetNetworkEndpoint(scanTarget.getNetworkEndpoint()) + .withExtraCommandLineOptions(cliOptions.nmapCmdOpts) .run(commandExecutor); logger.atInfo().log( "Finished nmap scan on target '%s' in %s.", diff --git a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClient.java b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClient.java index 6c006ab5f..1fc9dd2d5 100644 --- a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClient.java +++ b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClient.java @@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.tsunami.common.command.CommandExecutor; import com.google.tsunami.common.command.CommandExecutorFactory; import com.google.tsunami.common.data.NetworkEndpointUtils; @@ -191,6 +192,7 @@ Optional getFlag() { } private final String nmapBinaryPath; + private final List extraCommandArgs = new ArrayList<>(); private final List networkEndpoints = new ArrayList<>(); private final List hostDiscoveryTechniques = new ArrayList<>(); private final List dnsServers = new ArrayList<>(); @@ -321,6 +323,10 @@ ArrayList buildRunCommandArgs() { runCommandArgs.add("-6"); } + if (extraCommandArgs != null) { + runCommandArgs.addAll(extraCommandArgs); + } + networkEndpoints.stream() .map(NmapClient::networkEndpointToCliRepresentation) .forEach(runCommandArgs::add); @@ -354,6 +360,20 @@ public NmapClient withTargetNetworkEndpoint(NetworkEndpoint networkEndpoint) { return this; } + /** + * Sets additional command line options for the Nmap scanning. They are appended at the end of + * nmap command invocation, right before the targets. + * + * @param commandArgs The extra command line options. + */ + @CanIgnoreReturnValue + public NmapClient withExtraCommandLineOptions(List commandArgs) { + if (commandArgs != null) { + this.extraCommandArgs.addAll(commandArgs); + } + return this; + } + /** * Skips the host discovery stage, this causes nmap to perform scanning even if the host is dead. * This method is incompatible with {@link diff --git a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/option/NmapPortScannerCliOptions.java b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/option/NmapPortScannerCliOptions.java index ba90e7682..5b5eca165 100644 --- a/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/option/NmapPortScannerCliOptions.java +++ b/google/portscan/nmap/src/main/java/com/google/tsunami/plugins/portscan/nmap/option/NmapPortScannerCliOptions.java @@ -38,6 +38,11 @@ public final class NmapPortScannerCliOptions implements CliOption { // Splitting and conversion is done by the NmapPortScanner itself. public String portRangesTarget; + @Parameter( + names = "--nmap-cmd-opts", + description = "Additional command line options for Nmap scanning.") + public List nmapCmdOpts; + @Override public void validate() {} } diff --git a/google/portscan/nmap/src/test/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClientTest.java b/google/portscan/nmap/src/test/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClientTest.java index 1dd273884..1dda2936d 100644 --- a/google/portscan/nmap/src/test/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClientTest.java +++ b/google/portscan/nmap/src/test/java/com/google/tsunami/plugins/portscan/nmap/client/NmapClientTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.collect.ImmutableList; import com.google.tsunami.common.command.CommandExecutor; import com.google.tsunami.common.command.CommandExecutorFactory; import com.google.tsunami.common.data.NetworkEndpointUtils; @@ -353,6 +354,32 @@ public void buildRunCommandArgs_withMultipleScript_returnsCorrectCommandLine() { report.getAbsolutePath()); } + @Test + public void buildRunCommandArgs_withExtraCommandLineArgs_returnsCorrectCommandLine() { + client + .withTargetNetworkEndpoint(NetworkEndpointUtils.forIp("1.1.1.1")) + .withExtraCommandLineOptions(ImmutableList.of("--foo", "--bar")) + .withScript("test1", "a", "b") + .withScript("test2", "e", "f"); + + assertThat(client.buildRunCommandArgs()) + .containsExactly( + nmapFile.getAbsolutePath(), + "--script", + "test1", + "--script-args", + "a,b", + "--script", + "test2", + "--script-args", + "e,f", + "--foo", + "--bar", + "1.1.1.1", + "-oX", + report.getAbsolutePath()); + } + @Test public void getResults_onceClientHasRan_returnsNmapRunReport() throws IOException, ExecutionException, InterruptedException, ParserConfigurationException,