1616 * limitations under the License.
1717 * /
1818 */
19+
20+ /**
21+ * @typedef {{ id: string, name: string, description: string, osi_layer: string, reference: any, severity: string, attributes: { port: any, ip_address: any, mac_address: any, protocol: any, hostname: any, method: any, operating_system: any, service: any, scripts: [scriptname: string]: string }, hint: any, category: any, location: any } } Finding
22+ */
23+
1924const _ = require ( 'lodash' ) ;
2025const uuid = require ( 'uuid/v4' ) ;
2126
2227const portscan = require ( '../lib/portscan' ) ;
2328
29+ const resultsXmlParser = require ( './results-xml' ) ;
30+
2431function createFinding ( {
2532 id = uuid ( ) ,
2633 name,
@@ -56,6 +63,7 @@ function createFinding({
5663 method,
5764 operating_system,
5865 service,
66+ scripts : null ,
5967 } ,
6068 hint,
6169 category,
@@ -67,6 +75,7 @@ function createFinding({
6775 * Transforms the array of hosts into an array of open ports with host information included in each port entry.
6876 *
6977 * @param {array<host> } hosts An array of hosts
78+ * @returns {Finding[] }
7079 */
7180function transform ( hosts ) {
7281 return _ . flatMap ( hosts , ( { openPorts = [ ] , ...hostInfo } ) => {
@@ -89,6 +98,28 @@ function transform(hosts) {
8998 } ) ;
9099}
91100
101+ /**
102+ *
103+ * @param {{ ip: string, hostname: string, port: number, scriptOutputs: {[scriptName:string]:string} } } findingFromXml
104+ * @param {Finding[] } findings
105+ */
106+ function addScriptOutputsToFindings ( findingFromXml , findings ) {
107+ var res = findings . find (
108+ finding =>
109+ finding . attributes . port === findingFromXml . port &&
110+ finding . attributes . hostname === findingFromXml . hostname
111+ ) ;
112+ if ( res ) {
113+ if ( res . attributes . scripts === null ) {
114+ res . attributes . scripts = findingFromXml . scriptOutputs ;
115+ } else {
116+ Object . assign ( res . attributes . scripts , findingFromXml . scriptOutputs ) ;
117+ }
118+ } else {
119+ console . warn ( 'found script outputs for ports that are not in the findings' ) ;
120+ }
121+ }
122+
92123function joinResults ( results ) {
93124 const findings = _ . flatMap ( results , result => result . findings ) ;
94125 const rawFindings = _ . map ( results , result => result . raw ) ;
@@ -110,9 +141,20 @@ async function worker(targets) {
110141 const { hosts, raw } = await portscan ( location , parameter ) ;
111142 const result = transform ( hosts ) ;
112143
144+ if (
145+ typeof parameter === 'string' &&
146+ ( parameter . includes ( '--script=' ) || parameter . includes ( '-s' ) )
147+ ) {
148+ const findingsWithScriptOutput = await resultsXmlParser ( raw ) ;
149+ findingsWithScriptOutput . forEach ( xmlFinding =>
150+ addScriptOutputsToFindings ( xmlFinding , result )
151+ ) ;
152+ }
153+
113154 results . push ( { findings : result , raw } ) ;
114155 } catch ( err ) {
115- if ( err . startsWith ( `Failed to resolve "${ location } ".` ) || err === '\n' ) {
156+ var stringErr = extractErrorMessage ( err ) ;
157+ if ( stringErr . startsWith ( `Failed to resolve "${ location } ".` ) || stringErr === '\n' ) {
116158 console . warn ( err ) ;
117159 results . push ( {
118160 findings : [
@@ -127,7 +169,7 @@ async function worker(targets) {
127169 ] ,
128170 raw : '' ,
129171 } ) ;
130- } else if ( err . startsWith ( 'Error converting XML to JSON in xml2js' ) ) {
172+ } else if ( stringErr . startsWith ( 'Error converting XML to JSON in xml2js' ) ) {
131173 const error = new Error ( 'Failed to transform nmap xml to json.' ) ;
132174 error . name = 'TransformationError' ;
133175 throw error ;
@@ -141,5 +183,11 @@ async function worker(targets) {
141183 return joinResults ( results ) ;
142184}
143185
186+ function extractErrorMessage ( err ) {
187+ if ( err . message ) return err . message ;
188+ if ( err . toString ) return err . toString ( ) ;
189+ return '' + err ;
190+ }
191+
144192module . exports . transform = transform ;
145193module . exports . worker = worker ;
0 commit comments