#!/usr/bin/php <?php //error_reporting(0); /*** * Configuration options */ $sub1 = 5; // header no in doc e.g. "5 Discovered Vulnerabilities" /*** * Main program - Don't edit below */ echo "_____ _____ _____ 2\n||_// ||== ||_// \n|| \\ ||___ || \n\n"; foreach (glob("classes/*.php") as $filename) include $filename; $definitions = new \Clapp\CommandLineArgumentDefinition( array( "help|h" => "Shows help message", "doc|d=s" => "/path/to/doc.odt to use", ) ); $filter = new \Clapp\CommandArgumentFilter($definitions, $argv); if ($filter->getParam('h') === true || $argc < 2) { fwrite(STDERR, $definitions->getUsage()); exit(0); } // see if doc exists if ($filter->getParam("doc") == false) die("[-] no doc set\n"); echo "[!] doc: ".$filter->getParam("doc")."\n"; if(!file_exists($filter->getParam("doc"))) die("[-] no such file! \n"); // extract doc and get contents $rand = uniqid(); mkdir("/tmp/$rand"); if(unzipFolder($filter->getParam("doc"), "/tmp/$rand/")) { $source = file_get_contents("/tmp/$rand/content.xml"); echo "[+] doc extracted\n"; } else { die("[-] unable to extract doc\n"); } // Parse Doc's XML $line = array(); $reader = new XMLReader(); if (!$reader->open("/tmp/$rand/content.xml")) die("[-] Failed to open 'content.xml'\n"); // font checker /*** * FUTURE FEATURE PERHAPS */ $fonts = array(); while ($reader->read()){ //print_r($reader->name); if ($reader->nodeType == XMLREADER::ELEMENT && ($reader->name === 'style:font-face')) { //if(!empty($reader->name)){ //echo "here2\n"; //$line[] = $reader->expand()->textContent; // Put the text into array in correct order... $fonts[] = $reader->getAttribute("style:name"); //echo $font;echo "\n"; // DEBUG //} } } $reader->close(); //die(); echo "[=] fonts found: ".sizeof($fonts)."\n"; // get template version used $reader = new XMLReader(); if (!$reader->open("/tmp/$rand/meta.xml")) die("[-] Failed to open 'meta.xml'\n"); $templateVer = 0.0; while ($reader->read()) { if($reader->name == "dc:version"){ $reader->read(); $templateVer = number_format(floatval($reader->value), 2); break; } } // step through text:h and text:p elements to put them into an array $reader = new XMLReader(); if (!$reader->open("/tmp/$rand/content.xml")) die("[-] Failed to open 'content.xml'\n"); while ($reader->read()){ if ($reader->nodeType == XMLREADER::ELEMENT && ($reader->name === 'text:h' || $reader->name === 'text:p' || $reader->name === 'text:bookmark')) { if(!empty($reader->expand()->textContent)) $line[] = $reader->expand()->textContent; // Put the text into array in correct order... //echo $reader->expand()->textContent;echo "\n"; // DEBUG } } $reader->close(); // find the content we want $start = 0; $end = 0; foreach($line as $key => $val){ if(strpos($val, "Discovered Vulnerabilities") === 0){ $start = $key; } //if(strpos($val, "This section provides a quick guide to plan your remediation for the vulnerabilities discovered during the test.") === 0){ $end = $key-2; } if(strpos($val, "Observed Hosts and Services") === 0){ $end = $key-2; } $line[$key] = trim($val); } // add to sexy array's $vuln = array(); $vulnPlace = 0; $switch = 0; $sub2 = 0; $sub3 = 1; if(number_format($templateVer, 2) >= number_format(1.0, 2)){ echo "[=] Template $templateVer used\n"; for ($i=$start; $i <= $end ; $i++) { // change state (action to take) /*** * ~states~ * 0 = do nothing * 1 = next is title * 2 = next is description * 3 = next is solution * 4 = next is remediation * 5 = next is cvss no * 6 = next is risk level * 7 = next is hosts * 8 = next possibly title */ switch ($line[$i]) { case 'Discovered Vulnerabilities': $switch = 0; break; case 'Serious Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'High Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Medium Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Low Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Informational Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Description': $switch = 2; break; case 'Solution': $switch = 3; break; case 'Remediation': $switch = 4; break; case 'CVSS Base Score': $switch = 5; break; case 'Risk Analysis': $switch = 6; break; case 'Vulnerabilities Exist On': $switch = 7; break; case 'Potential Impact': $switch = 9; break; default: # code... break; } //take action switch ($switch) { case 1: $i++; $vuln[$vulnPlace]['title'] = $line[$i]; $vuln[$vulnPlace]['ref'] = "$sub1.$sub2.$sub3"; $sub3++; $switch = 0; break; case 2: @$vuln[$vulnPlace]['desc'] .= $line[$i]; break; case 3: @$vuln[$vulnPlace]['fix'] .= $line[$i]; break; case 4: $i++; //$vuln[$vulnPlace]['rem'] = trim(strtok($line[$i], " ")); $switch = 0; break; case 5: $i++; $vuln[$vulnPlace]['cvss'] = $line[$i]; $switch = 0; break; case 6: $i++; $line[$i+3] = str_replace("Vulnerability Img", "", $line[$i+3]); $vuln[$vulnPlace]['risk'] = strstr(trim($line[$i+3]), ":", true); $vuln[$vulnPlace]['owasp'] = trim(substr($line[$i+3], strpos($line[$i+3], ":") + 1)); $vuln[$vulnPlace]['impact'] = trim(strtok($line[$i+4], " ")); $vuln[$vulnPlace]['rem'] = trim(strtok($line[$i+5], " ")); $switch = 0; break; case 7: $i++; $vuln[$vulnPlace]['hosts'] = $line[$i]; $switch = 8; $vulnPlace++; break; case 8: $vuln[$vulnPlace]['title'] = trim($line[$i]); $vuln[$vulnPlace]['ref'] = "$sub1.$sub2.$sub3"; $sub3++; $switch = 0; break; case 9: @$vuln[$vulnPlace]['impact'] .= $line[$i]; break; default: # code... break; } echo $line[$i]."\n"; // DEBUG } $first_desc = explode("Description", $vuln[0]['desc']); $vuln[0]['desc'] = $first_desc[sizeof($first_desc)-1]; }else{ // old template or Dave's format for ($i=$start; $i <= $end ; $i++) { // change state (action to take) /*** * ~states~ * 0 = do nothing * 1 = next is title * 2 = next is description * 3 = next is solution * 4 = next is remediation * 5 = next is cvss no * 6 = next is risk level * 7 = next is hosts * 8 = next possibly title */ switch ($line[$i]) { case 'Discovered Vulnerabilities': $switch = 0; break; case 'Serious Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'High Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Medium Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Low Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Informational Risk Vulnerabilities': $sub2++; $sub3 = 1; $switch = 1; break; case 'Description': $switch = 2; break; case 'Solution': $switch = 3; break; case 'Remediation': $switch = 4; break; case 'CVSS Base Score': $switch = 5; break; case 'Risk Level': $switch = 6; break; case 'Vulnerabilities Exist On': $switch = 7; break; case 'Potential Impact': $switch = 9; break; default: # code... break; } //take action switch ($switch) { case 1: $i++; $vuln[$vulnPlace]['title'] = $line[$i]; $vuln[$vulnPlace]['ref'] = "$sub1.$sub2.$sub3"; $sub3++; $switch = 0; break; case 2: @$vuln[$vulnPlace]['desc'] .= $line[$i]; break; case 3: @$vuln[$vulnPlace]['fix'] .= $line[$i]; break; case 4: $i++; $vuln[$vulnPlace]['rem'] = trim(strtok($line[$i], " ")); $switch = 0; break; case 5: $i++; $vuln[$vulnPlace]['cvss'] = $line[$i]; $switch = 0; break; case 6: $i++; $vuln[$vulnPlace]['risk'] = trim(strtok($line[$i], " ")); $vuln[$vulnPlace]['owasp'] = trim(substr($line[$i], strpos($line[$i], ":") + 1)); $switch = 0; break; case 7: $i++; $vuln[$vulnPlace]['hosts'] = $line[$i]; $switch = 8; $vulnPlace++; break; case 8: $vuln[$vulnPlace]['title'] = trim($line[$i]); $vuln[$vulnPlace]['ref'] = "$sub1.$sub2.$sub3"; $sub3++; $switch = 0; break; case 9: @$vuln[$vulnPlace]['impact'] .= $line[$i]; break; default: # code... break; } //echo $line[$i]."\n"; // DEBUG } } // minor tidying of arrays for ($i=0; $i < sizeof($vuln) ; $i++) { if (strpos($vuln[$i]['desc'], "Description") === 0) $vuln[$i]['desc'] = substr($vuln[$i]['desc'], strlen("Description")); if (strpos($vuln[$i]['fix'], "Solution") === 0) $vuln[$i]['fix'] = substr($vuln[$i]['fix'], strlen("Solution")); $vuln[$i]['risk'] = rtrim($vuln[$i]['risk'], ":"); // remove html encoding foreach($vuln[$i] as $key => $val){ $vuln[$i][$key] = mb_convert_encoding($val, "UTF-8", 'UTF-8'); } } //print_r($vuln); // DEBUG echo "[+] vulnerabilities identified\n"; delTree("/tmp/$rand"); echo "[+] temp files removed\n"; $resultsFolder = substr($filter->getParam("doc"), 0, strrpos( $filter->getParam("doc"), '/') )."/rep2"; if(!file_exists($resultsFolder."/")){ mkdir($resultsFolder."/"); echo "[+] created directory $resultsFolder/\n"; }else{ $i = 1; while (file_exists($resultsFolder."_$i/")) $i++; mkdir($resultsFolder."_$i/"); $resultsFolder .= "_$i"; echo "[+] created directory $resultsFolder/\n"; } if(writeIssueTable($vuln, "Serious", $resultsFolder."/findings_serious.csv")) echo "[+] serious issues: $resultsFolder/findings_serious.csv\n"; if(writeIssueTable($vuln, "High", $resultsFolder."/findings_high.csv")) echo "[+] high issues: $resultsFolder/findings_high.csv\n"; if(writeIssueTable($vuln, "Medium", $resultsFolder."/findings_medium.csv")) echo "[+] medium issues: $resultsFolder/findings_medium.csv\n"; if(writeIssueTable($vuln, "Low", $resultsFolder."/findings_low.csv")) echo "[+] low issues: $resultsFolder/findings_low.csv\n"; if(writeIssueTable($vuln, "Info", $resultsFolder."/findings_info.csv")) echo "[+] info issues: $resultsFolder/findings_info.csv\n"; $order = array('title', 'ref', 'desc', 'fix','rem','cvss','risk','impact','owasp','hosts'); $orderedArray = array(); foreach($vuln as $vn_no =>$vn){ foreach ($order as $key) { //echo $key."\n"; $orderedArray[$vn_no][$key] = $vuln[$vn_no][$key]; } } if(writeAllTable($orderedArray, $resultsFolder."/findings_all.csv")) echo "[+] all issues: $resultsFolder/findings_all.csv\n"; if(writeRemediationTable($vuln, $resultsFolder."/remediation.csv")) echo "[+] remediation table: $resultsFolder/remediation.csv\n"; if(writeOWASPTable($vuln, $resultsFolder."/owasp.csv")) echo "[+] OWASP table: $resultsFolder/owasp.csv\n"; viewVulns($vuln); function unzipFolder($zipInputFile, $outputFolder) { $zip = new ZipArchive; $res = $zip->open($zipInputFile); if ($res === true) { $zip->extractTo($outputFolder); $zip->close(); return true; } else { return false; } } function XML2Array(SimpleXMLElement $parent){ $array = array(); foreach ($parent as $name => $element) { ($node = & $array[$name]) && (1 === count($node) ? $node = array($node) : 1) && $node = & $node[]; $node = $element->count() ? XML2Array($element) : trim($element); } return $array; } function delTree($dir){ $files = array_diff(scandir($dir), array('.', '..')); foreach ($files as $file) { (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); } return rmdir($dir); } function viewVulns($vuln){ $s = $h = $m = $l = 0; for ($i=0; $i < sizeof($vuln) ; $i++) { switch ($vuln[$i]['risk']) { case 'Serious': $s++; break; case 'High': $h++; break; case 'Medium': $m++; break; case 'Low': $l++; break; case 'Info': $i++; break; } } echo "[=] Serious = $s, High = $h, Medium = $m, Low = $l, Info = $i\n"; echo" Ref | Title | Risk | CVSS | Remediation | OWASP -------|-----------------------------------|--------|--------|---------------|------------------------------\n"; for ($i=0; $i < sizeof($vuln) ; $i++) { $ref = str_pad($vuln[$i]['ref'], 7); $title = str_pad($vuln[$i]['title'], 35); $risk = str_pad($vuln[$i]['risk'], 8); $cvss = str_pad($vuln[$i]['cvss'], 8); $rem = str_pad($vuln[$i]['rem'], 15); $owasp = str_pad($vuln[$i]['owasp'], 30); echo substr($ref, 0, 7); echo "|"; echo substr($title, 0, 35); echo "|"; echo substr($risk, 0, 8); echo "|"; echo substr($cvss, 0, 8); echo "|"; echo substr($rem, 0, 15); echo "|"; echo substr($owasp, 0, 30); echo "\n"; } } function writeIssueTable($vuln, $issue, $path){ $towrite = array(); for ($i=0; $i < sizeof($vuln) ; $i++) { if($vuln[$i]['risk'] == $issue){ $towrite[$i]['desc'] = $vuln[$i]['title']." - ".$vuln[$i]['desc']; $towrite[$i]['fix'] = $vuln[$i]['fix']; $towrite[$i]['ref'] = $vuln[$i]['ref']; $towrite[$i]['hosts'] = $vuln[$i]['hosts']; } } if(sizeof($towrite) > 0){ $fp = fopen($path, 'w'); fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF)); foreach ($towrite as $fields) { fputcsv($fp, $fields); } fclose($fp); return true; }else{ return false; } } function writeAllTable($vuln, $path){ if(sizeof($vuln) > 0){ $fp = fopen($path, 'w'); fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF)); fputcsv($fp, array("Title", "Ref", "Description", "Solution", "Remediation", "CVSS", "Risk","Impact", "OWASP", "Affected")); //print_r($orderedArray); foreach ($vuln as $fields) { fputcsv($fp, $fields); } fclose($fp); return true; }else{ return false; } } function writeRemediationTable($vuln, $path){ $towrite = array(); for ($i=0; $i < sizeof($vuln) ; $i++) { $towrite[$i]['hosts'] = $vuln[$i]['hosts']; $towrite[$i]['ref'] = $vuln[$i]['ref']; $towrite[$i]['p'] = " "; $towrite[$i]['c'] = " "; $towrite[$i]['d'] = " "; $towrite[$i]['u'] = " "; switch ($vuln[$i]['rem']) { case 'Patch': $towrite[$i]['p'] = $vuln[$i]['risk'][0]; break; case 'Configuration': $towrite[$i]['c'] = $vuln[$i]['risk'][0]; break; case 'Development': $towrite[$i]['d'] = $vuln[$i]['risk'][0]; break; case 'Upgrade': $towrite[$i]['u'] = $vuln[$i]['risk'][0]; break; } } if(sizeof($towrite) > 0){ $fp = fopen($path, 'w'); fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF)); fputcsv($fp, array("Host", "Ref", "P", "C", "D", "U")); foreach ($towrite as $fields) { fputcsv($fp, $fields); } fclose($fp); return true; }else{ return false; } } function writeOWASPTable($vuln, $path){ $towrite = array(); for ($i=0; $i < sizeof($vuln) ; $i++) { if(in_array($vuln[$i]['owasp'], array_column($towrite, 'owaspId'))){ $towrite[$vuln[$i]['owasp']]['no']++; }else{ $towrite[$vuln[$i]['owasp']]['owaspId'] = $vuln[$i]['owasp']; $towrite[$vuln[$i]['owasp']]['no'] = 1; } } if(sizeof($towrite) > 0){ $fp = fopen($path, 'w'); fprintf($fp, chr(0xEF).chr(0xBB).chr(0xBF)); foreach ($towrite as $fields) { fputcsv($fp, $fields); } fclose($fp); return true; }else{ return false; } } ?>