#!/usr/local/bin/php
<?php
/**
 * Script to transform multiple nmap XML output files (presumably of the same host/port range with different scan options) into a HTML table
 *
 * The canonical source of the latest version of this script is:
 *  <http://svn.jasonantman.com/misc-scripts/nmap-xml-to-table.php>
 *
 * Copyright 2011 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com> all rights reserved.
 *  Distribution and use of this script is unlimited, provided that you leave this notice intact and send any corrections/additions back to me.
 *
 * This is assuming a relatively simple scan - only one protocol, one or more hosts, one or more ports, and that different scans will be differentiated only by type
 *
 * USAGE: nmap-xml-to-table.php [xml file] [xml file] [...]
 *
 * $LastChangedRevision$
 * $HeadURL$
 *
 */
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past

exec("mkdir /usr/local/www/packages/strikeback/reports");

$dir = 'reports/';
$reports = scandir($dir);
//print_r($reports);

foreach($reports as $i => $value){
	$reports[$i] = "reports/".$reports[$i];	
	$i++;
}

array_shift($reports);
array_shift($reports);
//print_r($reports);
//array_shift($argv); // get rid of script name




//print_r($reports);
$files = array();
//foreach($argv as $file)
foreach($reports as $file)
{
  if(file_exists($file) && is_readable($file))
    {
      $files[] = $file;
    }
  else
    {
      fwrite(STDERR, "File $file does not exist or is not readable, skipping.\n");
    }
}

$results = array();
$scanInfo = array();
$hostAndPort = array();

$count = 0;
foreach($files as $file)
{
  $info = getScanResults($file);
  $results[$count] = $info['hosts'];
  $info['scan']['filename'] = $file;
  $scanInfo[$count] = $info['scan'];
  foreach($info['hosts'] as $host => $portArr)
    {
      if(! isset($hostAndPort[$host])){ $hostAndPort[$host] = array();}
      foreach($portArr as $port => $foo)
	{
	  $hostAndPort[$host][$port] = $foo['service'];
	}
    }
  $count++;
}

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Condensed NMAP scan results</title>

<style type="text/css">
table.result {
  border-width: 1px 1px 1px 1px;
  border-spacing: 0px;
  border-style: solid solid solid solid;
  border-color: black black black black;
  border-collapse: separate;
  background-color: white;
  margin-left: auto;
  margin-right: auto;
}
table.result th {
  border-width: 1px 1px 1px 1px;
 padding: 2px 2px 2px 2px;
  border-style: solid solid solid solid;
  border-color: black black black black;
  background-color: white;
  -moz-border-radius: 0px 0px 0px 0px;
}
table.result td {
  border-width: 1px 1px 1px 1px;
 padding: 2px 2px 2px 2px;
  border-style: solid solid solid solid;
  border-color: black black black black;
  background-color: white;
  -moz-border-radius: 0px 0px 0px 0px;
}
h2 { text-align: center;}
.lookhere { color: red;}
</style>
<script type="text/javascript" language="javascript">
function show_hide(show) {
<?php
$tableint = 0;
foreach($scanInfo as $num => $arr)
{
	$tableint++;

	echo "if (tbl = document.getElementById(\"td".$tableint."\")) {\n"; 
	echo "if (null == show) show = tbl.style.display == 'none';\n"; 
	echo "tbl.style.display = (show ? '' : 'none');\n"; 
	echo "}\n"; 
	
	echo "if (tbl = document.getElementById(\"th".$tableint."\")) {\n"; 
	echo "if (null == show) show = tbl.style.display == 'none';\n"; 
	echo "tbl.style.display = (show ? '' : 'none');\n"; 
	echo "}\n"; 	
}
?>
}
</script>
</head>
<body>
<h2>Nmap scan results (condensed)</h2>
<a href="javascript:void();" onclick="show_hide()">Show/Hide scanned services</a>
<?php

// output scan information
echo '<table class="result">'."\n";
echo '<tr><th colspan="7">Scans</th></tr>'."\n";
//echo '<tr><th>Num</th><th>proto</th><th>type</th><th>Services</th><th>num hosts</th><th>command</th><th>filename</th></tr>'."\n";
echo '<tr><th>Num</th><th>proto</th><th>type</th><th id="th'.$tableint.'" style="display:none;">Services</th><th>filename</th><th>Delete</th></tr>'."\n";

if(isset($_GET[delete])) {
	echo($_GET[delete]);
	
	
	exec("rm ".$_GET[delete]);
	unlink($_GET[delete]);
	
	
	echo "<script type=\"text/javascript\">\n"; 
	echo "<!--\n"; 
	echo "window.location = \"parse.php\"\n"; 
	echo "//-->\n"; 
	echo "<\/script>\n";	
	
}

$tableint = 0;
foreach($scanInfo as $num => $arr)
{
	$tableint++;
	//echo($tableint);
  //echo '<tr><td>'.$num.'</td><td>'.$arr['protocol'].'</td><td>'.$arr['type'].'</td><td>'.$arr['services'].'</td><td>'.$arr['numHosts'].'</td><td><pre>'.$arr['command'].'</pre></td><td>'.$arr['filename'].'</td></tr>'."\n";
  echo '<tr><td>'.$num.'</td><td>'.$arr['protocol'].'</td><td>'.$arr['type'].'</td><td id="td'.$tableint.'" style="display:none;">'.$arr['services'].'</td><td>'.$arr['filename'].'</td><td><a href=parse.php?delete='.$arr['filename'].'>Delete</a></td></tr>'."\n";
}
echo '</table>'."\n";

echo '<br />'."\n";

echo '<table class="result">'."\n";
echo '<tr><th colspan="'.(count($scanInfo)+1).'">Results</th></tr>'."\n";
echo '<tr><th>Port</th>';
for($i = 0; $i < count($scanInfo); $i++){ echo '<th>'.$i.' ('.$scanInfo[$i]['type'].')</th>';}
echo '</tr>'."\n";
foreach($hostAndPort as $host => $portArr)
{
  echo '<tr><th colspan="'.(count($scanInfo)+1).'">'.$host.'</th></tr>'."\n";

  foreach($portArr as $portName => $service)
    {
      echo '<tr><td>'.$portName.($service != "" ? " (".$service.")" : "").'</td>';
      foreach($scanInfo as $scanNum => $arr)
	{
	  if(isset($results[$scanNum][$host][$portName]))
	    {
	      echo '<td>'.(($results[$scanNum][$host][$portName]['state'] == "open" || $results[$scanNum][$host][$portName]['state'] == "closed" || $results[$scanNum][$host][$portName]['state'] == "unfiltered") ? '<span class="lookhere">' : '').$results[$scanNum][$host][$portName]['state'].' ('.$results[$scanNum][$host][$portName]['state_reason'].(isset($results[$scanNum][$host][$portName]['state_reason_ip']) ? ' '.$results[$scanNum][$host][$portName]['state_reason_ip'] : '').')'.(($results[$scanNum][$host][$portName]['state'] == "open" || $results[$scanNum][$host][$portName]['state'] == "closed" || $results[$scanNum][$host][$portName]['state'] == "unfiltered") ? '</span>' : '').'</td>';
	    }
	  else
	    {
	      echo '<td><em>n/a</em></td>';
	    }
	}
      echo '</tr>'."\n";
    }

}
echo '</table>'."\n";

/**
 * Parse meaningful information from a nmap XML output file and return it as an array
 *
 * @return array
 */
function handleError($errno, $errstr, $errfile, $errline, array $errcontext)
{
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler('handleError');

function getScanResults($file)
{
 try {
  $xml = simplexml_load_file($file);

  $result = array("scan" => array(), "hosts" => array());

  $command = $xml->attributes();
  $command = (string)$command['args'];
  $result['scan']['command'] = $command;

  $foo = $xml->scaninfo->attributes();
  $result['scan']['type'] = (string)$foo['type'];
  $result['scan']['protocol'] = (string)$foo['protocol'];
  $result['scan']['services'] = (string)$foo['services'];

  $count = 0;
  foreach($xml->host as $host)
    {
      $count++;

      $foo = $host->address->attributes();
      $addr = (string)$foo['addr'];

      $arr = array(); // array to hold ports and results

      // <port protocol="tcp" portid="445"><state state="filtered" reason="admin-prohibited" reason_ttl="241" reason_ip="67.83.255.41"/><service name="microsoft-ds" method="table" conf="3" /></port>
      foreach($host->ports->port as $port)
	{
	  $foo = $port->attributes();
	  $bar = array();
	  
	  $name = (string)($foo['protocol']." ".$foo['portid']);
	  $bar['protocol'] = (string)$foo['protocol'];
	  $bar['portid'] = (string)$foo['portid'];
	  $bar['name'] = $name;

	  $foo = $port->state->attributes();
	  $bar['state'] = (string)$foo['state'];
	  $bar['state_reason'] = (string)$foo['reason'];
	  $bar['state_reason_ttl'] = (string)$foo['reason_ttl'];
	  if(isset($foo['reason_ip'])){ $bar['state_reason_ip'] = (string)$foo['reason_ip'];}

	  if($port->service)
	    {
	      $foo = $port->service->attributes();
	      $bar['service'] = (string)$foo['name'];
	    }

	  $arr[$name] = $bar;
	}
      $result['hosts'][$addr] = $arr;
    }

  $result['scan']['numHosts'] = $count;
  return $result;

} catch (ErrorException $e) {
	echo ("fail");
}
}

?>
</body>
</html>