#!/usr/bin/php <?php //error_reporting(0); include('config.php'); /*** * Main program - Don't edit below */ echo "_____ _____ _____ Gen\n||_// ||== ||_// \n|| \\ ||___ || \n\n"; foreach (glob("classes/*.php") as $filename) include $filename; $definitions = new \Clapp\CommandLineArgumentDefinition( array( "help|h" => "Shows help message", "path|p=s" => "/path/to/configs/", // should contain config.json and all vuln.json files ) ); $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("path") == false) die("[-] no path set\n"); echo "[!] path: ".$filter->getParam("path")."\n"; if(!is_dir($filter->getParam("path"))) die("[-] no such folder! \n"); //get config file $config = json_decode(file_get_contents($filter->getParam("path")."config.conf")); $riskRatings = array("Serious","High","Medium","Low"); //create owasp top 10 placeholders for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"A".$padNo} = 0; } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"M".$padNo} = 0; } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"API".$padNo} = 0; } //create owasp top 10 table placeholders for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"A".$padNo."_table"} = ""; } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"M".$padNo."_table"} = ""; } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); ${"API".$padNo."_table"} = ""; } // extract doc and get contents $rand = uniqid(); mkdir("/tmp/$rand"); if(unzipFolder($template, "/tmp/$rand/")) { $source = file_get_contents("/tmp/$rand/content.xml"); echo "[+] doc extracted\n"; } else { die("[-] unable to extract doc\n"); } $source = file_get_contents("/tmp/$rand/content.xml"); // add CHECK section into report if needed if(isset($config->checkRef) && trim($config->checkRef) <> ""){ $check_img = '<draw:frame draw:style-name="fr9" draw:name="FPCheckLogo" text:anchor-type="frame" svg:x="0cm" svg:y="5.879cm" svg:width="6.83cm" svg:height="2.628cm" draw:z-index="40"> <draw:image xlink:href="Pictures/10000000000004A3000001C98E2CC6AE1D6F811E.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" loext:mime-type="image/jpeg"/> </draw:frame>'; $check_section = '<text:p text:style-name="P26"/> <text:p text:style-name="P26"/> <text:p text:style-name="P26"/> <text:p text:style-name="P26"/> <text:p text:style-name="P26"> CHECK Ref: {checkRef} </text:p>'; $source = str_replace('{check_img}', $check_img, $source); $source = str_replace('{check_section}', $check_section, $source); echo "[+] Added CHECK section\n"; }else{ $check_section = '<text:p text:style-name="P26"> <text:bookmark-start text:name="__RefHeading___Toc72207_536000782"/> <text:bookmark-end text:name="__RefHeading___Toc72207_536000782"/> </text:p>'; $source = str_replace('{check_img}', "", $source); $source = str_replace('{check_section}', $check_section, $source); } // add config into template foreach ($config as $key => $value) { $source = str_replace('{'.$key.'}', $value, $source); } file_put_contents("/tmp/$rand/content.xml", $source); echo "[+] added config values\n"; // get all vulns $vuln = array(); $files = glob($filter->getParam("path")."*.json"); foreach($files as $finding){ $vuln[] = $found = json_decode(file_get_contents($finding), true); } echo "[+] sorting vulns by CVSS\n"; usort($vuln, 'order_by_cvss'); function order_by_cvss($a, $b) { return $b['cvss_score'] > $a['cvss_score'] ? 1 : -1; } if(empty($vuln)) echo "[-] no vulns found!\n"; // create vulns for odf $templateOrig = file_get_contents($vulnTemplate); $Serious = $High = $Medium = $Low = $Info = ""; $Count_Serious = $Count_High = $Count_Medium = $Count_Low = $Count_Info = 0; $Summary_Serious = $Summary_High = $Summary_Medium = $Summary_Low = $Summary_Info = array(); foreach ($vuln as $singlevuln) { $templateSource = $templateOrig; $togo = $singlevuln['risk']; foreach ($singlevuln as $key => $value){ $value = str_replace("<", "<", $value); $value = str_replace(">", ">", $value); $value = str_replace("\n", "</text:p><text:p text:style-name=\"Text_20_body\">", $value); $templateSource = str_replace('{'.$key.'}', $value, $templateSource); if($key == "risk"){ switch ($togo) { case 'Serious': $templateSource = str_replace('{risk_img}', '100000000000001C0000001C2B2344F988E3C014.png', $templateSource); break; case 'High': $templateSource = str_replace('{risk_img}', '100000000000001C0000001C478E326DAB1B0673.gif', $templateSource); break; case 'Medium': $templateSource = str_replace('{risk_img}', '100000000000001C0000001C08AD11DB0A5D02CD.png', $templateSource); break; case 'Low': $templateSource = str_replace('{risk_img}', '100000000000001C0000001C6CC3BB57AA64608B.gif', $templateSource); break; case 'Info': $templateSource = str_replace('{risk_img}', '100000000000001C0000001C7365C375D1750C0F.gif', $templateSource); break; } } } if(isset($singlevuln['hosts']) && $singlevuln['hosts'] <> ""){ $templateSource = str_replace('{hosts}', $singlevuln['hosts'], $templateSource); }else{ $templateSource = str_replace('{hosts}', "N/A", $templateSource); } $$togo .= $templateSource; ${"Count_$togo"} += 1; echo "[+] added $togo: ".$singlevuln['title']."\n"; // fixing summary tables $descExpl = explode(".", $singlevuln['description']); $fixExpl = explode(".", $singlevuln['solution']); $descFinal = $descExpl[0]."."; $fixFinal = $fixExpl[0]."."; // if small summaries exist use them! if(isset($singlevuln['summary_issue']) && $singlevuln['summary_issue'] <> ""){ // DEBUG: echo "[+] summary description found for: ".$singlevuln['title']."\n"; $descFinal = $singlevuln['summary_issue']; } if(isset($singlevuln['summary_solution']) && $singlevuln['summary_solution'] <> ""){ // DEBUG: echo "[+] summary solution found for: ".$singlevuln['title']."\n"; $fixFinal = $singlevuln['summary_solution']; } // set OWASP counts $issueOwasp = explode(":", $singlevuln['owasp']); if($issueOwasp[0] !== "N/A") ${$issueOwasp[0]}++; $hostSummary = (isset($singlevuln['hosts']) && $singlevuln['hosts'] <> "") ? $singlevuln['hosts'] : "N/A"; // populate arrays for small vuln tables // key = title, 0 = desc, 1 = fix, 2 = hosts, 3 = owasp, 4, page ref ${"Summary_$togo"}[$singlevuln['title']] = array($descFinal, $fixFinal, $hostSummary, $issueOwasp[0]); } // add page ref to each issue $placeA = 1; foreach ($riskRatings as $riskKey => $riskVal) { $placeB = 1; if(!empty( ${"Summary_$riskVal"} )){ foreach (${"Summary_$riskVal"} as $sumKey => $sumVal) { array_push(${"Summary_$riskVal"}[$sumKey], "5.".$placeA.".".$placeB); $placeB++; } $placeA++; } } // create sumaries tables $Summary_Serious_Final = $Summary_High_Final = $Summary_Medium_Final = $Summary_Low_Final = ""; $placeA = 1; foreach ($riskRatings as $riskKey => $riskVal) { $placeB = 1; if(empty( ${"Summary_$riskVal"} )){ ${"Summary_".$riskVal."_Final"} = ' <table:table-row table:style-name="Table11.1"> <table:table-cell table:style-name="Table11.A2" office:value-type="string"> <text:p text:style-name="P189">None Identified</text:p> </table:table-cell> <table:table-cell table:style-name="Table11.A2" office:value-type="string"> <text:p text:style-name="P170"/> </table:table-cell> <table:table-cell table:style-name="Table11.C2" office:value-type="string"> <text:p text:style-name="P171"/> </table:table-cell> <table:table-cell table:style-name="Table11.C2" office:value-type="string"> <text:p text:style-name="P172"/> </table:table-cell> </table:table-row> '; }else{ foreach (${"Summary_$riskVal"} as $sumKey => $sumVal) { // DEBUG: echo "[i] $sumKey:\n".$sumVal[0]."\n".$sumVal[1]."\n\n"; ${"Summary_".$riskVal."_Final"} .= ' <table:table-row table:style-name="Table11.1"> <table:table-cell table:style-name="Table11.A2" office:value-type="string"> <text:p text:style-name="P189">'.$sumKey.'</text:p> <text:p text:style-name="P170">'.$sumVal[0].'</text:p> </table:table-cell> <table:table-cell table:style-name="Table11.A2" office:value-type="string"> <text:p text:style-name="P170">'.$sumVal[1].'</text:p> </table:table-cell> <table:table-cell table:style-name="Table11.C2" office:value-type="string"> <text:p text:style-name="P171">'.$sumVal[4].'</text:p> </table:table-cell> <table:table-cell table:style-name="Table11.C2" office:value-type="string"> <text:p text:style-name="P172">'.$sumVal[2].'</text:p> </table:table-cell> </table:table-row> '; } } } //populate owasp findings tables foreach ($riskRatings as $riskKey => $riskVal) { if(!empty( ${"Summary_$riskVal"} )){ foreach (${"Summary_$riskVal"} as $sumKey => $sumVal) { if($sumVal[3] == "N/A") break; // no N/A owasp table! if( ${$sumVal[3]."_table"} == ""){ // if is first entry ${$sumVal[3]."_table"} = ' <table:table table:name="Table8" table:style-name="Table8"> <table:table-column table:style-name="Table8.C"/> <table:table-column table:style-name="Table8.D"/> <table:table-header-rows> <table:table-row table:style-name="Table8.1"> <table:table-cell table:style-name="Table8.A1" office:value-type="string"> <text:p text:style-name="P71">Vulnerabilities in This Category</text:p> </table:table-cell> <table:table-cell table:style-name="Table8.B1" office:value-type="string"> <text:p text:style-name="P72">Document Reference</text:p> </table:table-cell> </table:table-row> </table:table-header-rows> <table:table-row> <table:table-cell table:style-name="Table8.A10" office:value-type="string"> <text:p text:style-name="P40">'.$sumKey.'</text:p> </table:table-cell> <table:table-cell table:style-name="Table8.B2" office:value-type="string"> <text:p text:style-name="P44">'.$sumVal[4].'</text:p> </table:table-cell> </table:table-row> '; }else{ // not first entry, append new line ${$sumVal[3]."_table"} = str_replace("</table:table>", "", ${$sumVal[3]."_table"}); ${$sumVal[3]."_table"} .= ' <table:table-row> <table:table-cell table:style-name="Table8.A10" office:value-type="string"> <text:p text:style-name="P40">'.$sumKey.'</text:p> </table:table-cell> <table:table-cell table:style-name="Table8.B2" office:value-type="string"> <text:p text:style-name="P44">'.$sumVal[4].'</text:p> </table:table-cell> </table:table-row> '; } // close the table ${$sumVal[3]."_table"} .= '</table:table>'; } } } // squash vulns into one big xml $value = ""; if(!empty($Serious)){ $value .= '<text:list text:continue-numbering="true" text:style-name="Outline"> <text:list-item> <text:list> <text:list-item> <text:h text:outline-level="2">Serious Risk Vulnerabilities</text:h> </text:list-item> </text:list> </text:list-item> </text:list>'; $value .= $Serious; } if(!empty($High)){ $value .= '<text:list text:continue-numbering="true" text:style-name="Outline"> <text:list-item> <text:list> <text:list-item> <text:h text:outline-level="2">High Risk Vulnerabilities</text:h> </text:list-item> </text:list> </text:list-item> </text:list>'; $value .= $High; } if(!empty($Medium)){ $value .= '<text:list text:continue-numbering="true" text:style-name="Outline"> <text:list-item> <text:list> <text:list-item> <text:h text:outline-level="2">Medium Risk Vulnerabilities</text:h> </text:list-item> </text:list> </text:list-item> </text:list>'; $value .= $Medium; } if(!empty($Low)){ $value .= '<text:list text:continue-numbering="true" text:style-name="Outline"> <text:list-item> <text:list> <text:list-item> <text:h text:outline-level="2">Low Risk Vulnerabilities</text:h> </text:list-item> </text:list> </text:list-item> </text:list>'; $value .= $Low; } if(!empty($Info)){ $value .= '<text:list text:continue-numbering="true" text:style-name="Outline"> <text:list-item> <text:list> <text:list-item> <text:h text:outline-level="2">Informational Risk Vulnerabilities</text:h> </text:list-item> </text:list> </text:list-item> </text:list>'; $value .= $Info; } // add to template $source = file_get_contents("/tmp/$rand/content.xml"); $source = str_replace('{vuln}', $value, $source); //update total counts in exec summary table $source = str_replace('{count_serious}', $Count_Serious, $source); $source = str_replace('{count_high}', $Count_High, $source); $source = str_replace('{count_medium}', $Count_Medium, $source); $source = str_replace('{count_low}', $Count_Low, $source); echo "[+] added exec summary counts: $Count_Serious, $Count_High, $Count_Medium, $Count_Low\n"; //update issues summary tables $source = str_replace('{summary_table_serious}', $Summary_Serious_Final, $source); $source = str_replace('{summary_table_high}', $Summary_High_Final, $source); $source = str_replace('{summary_table_medium}', $Summary_Medium_Final, $source); $source = str_replace('{summary_table_low}', $Summary_Low_Final, $source); echo "[+] added findings summary tables\n"; //update owasp count tables for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{A'.$padNo.'}', ${"A".$padNo}, $source); } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{M'.$padNo.'}', ${"M".$padNo}, $source); } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{API'.$padNo.'}', ${"API".$padNo}, $source); } echo "[+] updated OWASP count tables\n"; //update owasp findings tables for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{A'.$padNo.'_table}', ${"A".$padNo."_table"}, $source); } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{M'.$padNo.'_table}', ${"M".$padNo."_table"}, $source); } for ($i=1; $i <= 10 ; $i++) { $padNo = sprintf("%02d", $i); $source = str_replace('{API'.$padNo.'_table}', ${"API".$padNo."_table"}, $source); } echo "[+] updated OWASP findings tables\n"; // save to file echo "[!] writing to /tmp content.xml\n"; file_put_contents("/tmp/$rand/content.xml", $source); // create report and tidying $repOutName = $config->ref.".3 ".$config->client ." ". $config->title1; zipFolder("/tmp/$rand", $filter->getParam("path").$repOutName.".odt"); echo "[=] generated report: ".$filter->getParam("path").$repOutName.".odt\n"; delTree("/tmp/$rand"); echo "[+] temp files removed\n"; 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 zipFolder($inputFolder, $zipOutputFile) { if (!extension_loaded('zip') || !file_exists($inputFolder)) { return false; } $zip = new ZipArchive(); if (!$zip->open($zipOutputFile, ZIPARCHIVE::CREATE)) { return false; } $inputFolder = str_replace('\\', "/", realpath($inputFolder)); if (is_dir($inputFolder) === true) { $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($inputFolder), RecursiveIteratorIterator::SELF_FIRST); foreach ($files as $file) { $file = str_replace('\\', "/", $file); if (in_array(substr($file, strrpos($file, '/')+1), array('.', '..'))) { continue; } $file = realpath($file); if (is_dir($file) === true) { $dirName = str_replace($inputFolder."/", '', $file."/"); $zip->addEmptyDir($dirName); } else if (is_file($file) === true) { $fileName = str_replace($inputFolder."/", '', $file); $zip->addFromString($fileName, file_get_contents($file)); } } } else if (is_file($inputFolder) === true) { $zip->addFromString(basename($inputFolder), file_get_contents($inputFolder)); } return $zip->close(); } ?>