{ "name": "Tenable IO Network & Range", "vendor_identifier": "Tenable IO", "comment": "TenableIO Network & Range management", "version": "5.0", "type": "REST_EVENT", "event_type": [ "NETWORK_IPV4", "RANGE_IPV4", "NETWORK_IPV6", "RANGE_IPV6" ], "content_type": "application/json", "quoting": "XMLA", "headers": { "X-apikeys": "accessKey=${S:A:accessKey};secretKey=${S:A:secretKey}", "vendor": "Infoblox", "product": "Infoblox_Outbound_Notification", "build": "1.0.2" }, "steps": [{ "name": "Debug0", "operation": "NOP", "body": "${XC:DEBUG:{H:}}${XC:DEBUG:{E:}}${XC:DEBUG:{I:}}${XC:DEBUG:{L:}}${XC:DEBUG:{S:}}${XC:DEBUG:{P:}}${XC:DEBUG:{R:}}${XC:DEBUG:{RH:}}${XC:DEBUG:{UT:}}" }, { "name": "CheckOperation", "comment": "Check for MODIFY operation. Currently not supported for NETWORK & RANGE events.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [ { "left": "${E:A:operation_type}", "op": "==", "right": "MODIFY" } ], "stop": true } }, { "name": "set_ref", "comment": "Set object reference for EA timestamp updating later.", "operation": "NOP", "body_list": [ "${XC:COPY:{L:Obj_ref}:{E:values{_ref}}}" ] }, { "name": "setLocals", "comment": "Set locals depening on RANGE or NETWORK event type.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "RANGE" }], "eval": "${XC:COPY:{L:TNBL_IO_Scan_Template}:{E:values{extattrs}{TNBL_IO_Scan_Template}{value}}}${XC:COPY:{L:TNBL_IO_Target_Group}:{E:values{extattrs}{TNBL_IO_Target_Group}{value}}}${XC:COPY:{L:RangeStart}:{E:values{start_addr}}}${XC:COPY:{L:RangeEnd}:{E:values{end_addr}}}${XC:COPY:{L:RangeEnd}:{E:values{end_addr}}}${XC:COPY:{L:RangeStart}:{E:values{start_addr}}}", "else_eval": "${XC:COPY:{L:TNBL_IO_Scan_Template}:{E:values{extattrs}{TNBL_IO_Scan_Template}{value}}}${XC:COPY:{L:TNBL_IO_Target_Group}:{E:values{extattrs}{TNBL_IO_Target_Group}{value}}}${XC:COPY:{L:Network}:{E:values{network}}}" } }, { "name": "checkOperationDelete", "comment": "Are we deleting?", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:operation_type}", "op": "=~", "right": "DELETE" }], "next": "checkEAsDelete", "else_next": "verifyAddToTargetGroupEAs" } }, { "name": "checkEAsDelete", "comment": "Verify EAs for deleting.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "==", "right": "true" }], "next": "checkDeleteNetwork", "else_stop": true } }, { "name": "checkDeleteNetwork", "comment": "Are we deleting a network?", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:operation_type}", "op": "=~", "right": "DELETE" }, { "left": "${E:A:event_type}", "op": "=~", "right": "NETWORK" }], "next": "deleteAssetNetwork" } }, { "name": "checkDeleteRange", "comment": "Are we deleting a range?", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:operation_type}", "op": "=~", "right": "DELETE" }, { "left": "${E:A:event_type}", "op": "=~", "right": "RANGE" }], "next": "deleteAssetRange" } }, { "name": "verifyAddToTargetGroupEAs", "comment": "Verify we want to add the network or range to the Target Group.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Sync}{value}}", "op": "==", "right": "true" }], "else_next": "verifyAssetSyncEAs" } }, { "name": "getTargetGroups", "comment": "Get all Target Groups.", "operation": "GET", "parse": "JSON", "transport": { "path": "target-groups" } }, { "name": "setLocalTargetGroupList", "comment": "Set list of target_groups to a local.", "operation": "NOP", "body": "${XC:COPY:{L:TargetGroups}:{P:target_groups}" }, { "name": "isEmptyTargetGroupList", "comment": "[START TARGET GROUP LOOP] Check if we are out of target_groups to check.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:L:TargetGroups}", "op": "==", "right": "0" }], "stop": true } }, { "name": "getNextTargetGroup", "comment": "[TARGET GROUP LOOP] Pop top of TargetGroups.", "operation": "VARIABLEOP", "variable_ops": [{ "operation": "POP", "type": "DICTIONARY", "destination": "L:ThisTargetGroup", "source": "L:TargetGroups" }] }, { "name": "verifyCorrectTargetGroup", "comment": "[TARGET GROUP LOOP] Verify the current Target Group matches the EA.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:TNBL_IO_Target_Group}", "op": "==", "right": "${L:A:ThisTargetGroup{name}}" }], "eval": "${XC:COPY:{L:TargetID}:{L:ThisTargetGroup{id}}", "next": "skipIfRangeCheckExistingTarget" } }, { "name": "loopBackForNextTargetGroup", "comment": "[END TARGET GROUP LOOP] Loop back to check if list is empty.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "0", "op": "==", "right": "0" }], "next": "isEmptyTargetGroupList" } }, { "name": "skipIfRangeCheckExistingTarget", "comment": "Skip check for NETWORK if this is a RANGE.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "RANGE" }], "next": "checkExistingTargetRange" } }, { "name": "checkExistingTargetNetwork", "comment": "Check if NETWORK already exists in Targets list.", "operation": "CONDITION", "condition": { "condition_type": "OR", "statements": [{ "left": "${L:A:ThisTargetGroup{members}}", "op": "=~", "right": "${L:A:Network}" }], "next": "verifyScanningEAs", "else_next": "updateTargetList" } }, { "name": "checkExistingTargetRange", "comment": "Check if RANGE already exists in Targets list. Needs separate check because RANGES have a start and end address.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:ThisTargetGroup{members}}", "op": "=~", "right": "${L:A:RangeStart}-${L:A:RangeEnd}" }], "next": "verifyScanningEAs", "else_next": "updateTargetListRange" } }, { "name": "updateTargetListRange", "comment": "Add RANGE to list of Targets.", "operation": "PUT", "parse": "JSON", "transport": { "path": "target-groups/${L:A:TargetID}" }, "body_list": [ "{", "\"members\": \"${L:A:ThisTargetGroup{members}} ,${L:A:RangeStart}-${L:A:RangeEnd}\"}" ], "result": [{ "codes": "200,201,202,203,204", "next": "verifyScanningEAs" }] }, { "name": "updateTargetList", "comment": "Add NETWORK to list of Targets.", "operation": "PUT", "parse": "JSON", "transport": { "path": "target-groups/${L:A:TargetID}" }, "body_list": [ "{", "\"members\": \"${L:A:ThisTargetGroup{members}} ,${L:A:Network}\"}" ] }, { "name": "verifyScanningEAs", "comment": "Verify correct EAs to scan item.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Scan_On_Add}{value}}", "op": "==", "right": "true" }, { "left": "${E:A:values{extattrs}{TNBL_IO_Scan_Template}{value}}", "op": "!=", "right": "" } ], "else_next": "verifyAssetSyncEAs" } }, { "name": "getScans", "comment": "Get list of all scans.", "operation": "GET", "parse": "JSON", "transport": { "path": "scans" } }, { "name": "setLocalScansList", "comment": "Set list of scans to a local.", "operation": "NOP", "body": "${XC:COPY:{L:Scans}:{P:scans}" }, { "name": "isEmptyScanList", "comment": "[START SCAN LOOP] Check if we are out of scans to check.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:L:Scans}", "op": "==", "right": "0" }], "stop": true } }, { "name": "getNextScan", "comment": "[SCAN LOOP] Pop top of Scans.", "operation": "VARIABLEOP", "variable_ops": [{ "operation": "POP", "type": "DICTIONARY", "destination": "L:ThisScan", "source": "L:Scans" }] }, { "name": "verifyCorrectScan", "comment": "[END SCAN LOOP] Verify the current Scan matches the EA.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${L:A:TNBL_IO_Scan_Template}", "op": "!=", "right": "${L:A:ThisScan{name}}" }], "next": "isEmptyScanList", "else_eval": "${XC:COPY:{L:Scan_ID}:{L:ThisScan{id}}" } }, { "name": "copyScan", "comment": "Create copy of scan.", "operation": "POST", "parse": "JSON", "transport": { "path": "scans/${L:A:Scan_ID}/copy" } }, { "name": "skipconfigureCopyScanifRange", "comment": "We want to include start and end addresses for RANGE, and the network for NETWORK.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "RANGE" }], "next": "configureCopyScanRange" } }, { "name": "configureCopyScanNetwork", "comment": "Add some data for scan for NETWORK.", "operation": "PUT", "parse": "JSON", "transport": { "path": "scans/${P:A:id}/" }, "body_list": [ "{", "\"scan_id\":\"${P:A:id}\",", "\"settings\":{", "\"name\":\"Infoblox Scan for ${L:A:Network} on ${UT:A:TIME}\",", "\"description\": \"Scan occured because of a ${E:A:event_type} event\",", "\"enabled\":\"false\",", "\"text_targets\":\"${L:A:Network}\"", "}", "}" ], "result": [{ "codes": "200,201,202,203,204", "next": "launchCopyScan" }] }, { "name": "configureCopyScanRange", "comment": "Add some data for scan for RANGE.", "operation": "PUT", "parse": "JSON", "transport": { "path": "scans/${P:A:id}/" }, "body_list": [ "{", "\"scan_id\":\"${P:A:id}\",", "\"settings\":{", "\"name\":\"Infoblox Scan for ${L:A:RangeStart}-${L:A:RangeEnd} on ${UT:A:TIME}\",", "\"description\": \"Scan occured because of a ${E:A:event_type} event\",", "\"enabled\":\"false\",", "\"text_targets\":\"${L:A:RangeStart}-${L:A:RangeEnd}\"", "}", "}" ] }, { "name": "launchCopyScan", "comment": "Launch scan.", "operation": "POST", "parse": "JSON", "transport": { "path": "scans/${P:A:id}/launch" } }, { "name": "updateLastScanTime", "comment": "Update TNBL_IO_Last_Scan of item with timestamp.", "operation": "PUT", "transport": { "path": "${L:A:Obj_ref}" }, "wapi": "v2.7", "wapi_quoting": "JSON", "body_list": [ "{\"extattrs+\":{\"TNBL_IO_Last_Scan\": { \"value\": \"${E:A:timestamp}\"}}}" ] }, { "name": "verifyAssetSyncEAs", "comment": "Verify EAs for adding asset.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:values{extattrs}{TNBL_IO_Asset_Sync}{value}}", "op": "==", "right": "true" }], "else_stop": true } }, { "name": "checkEventTypeforAddingAsset", "comment": "NETWORKS and RANGES have different formats.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "${E:A:event_type}", "op": "=~", "right": "RANGE" }], "next": "addAssetRange", "else_next": "addAssetNetwork" } }, { "name": "addAssetRange", "comment": "Add the range as an asset.", "operation": "POST", "parse": "JSON", "transport": { "path": "import/assets?accessKey=${S:A:accessKey}&secretKey=${S:A:secretKey}" }, "body_list": ["{", "\"assets\": [{ \"netbios_name\": \"${L:A:RangeStart} - ${L:A:RangeEnd}\"}], \"source\": \"NIOS\"", "}" ], "result": [{ "codes": "200,202", "next": "updateAddAssetTimestamp" }] }, { "name": "addAssetNetwork", "comment": "Add the network as an asset.", "operation": "POST", "parse": "JSON", "transport": { "path": "import/assets?accessKey=${S:A:accessKey}&secretKey=${S:A:secretKey}" }, "body_list": ["{", "\"assets\": [{ \"netbios_name\": \"${L:A:Network}\"}], \"source\": \"NIOS\"", "}" ], "result": [{ "codes": "200,202", "next": "updateAddAssetTimestamp" }] }, { "name": "updateAddAssetTimestamp", "comment": "Update TNBL_IO_Sync_Time of item with timestamp.", "operation": "PUT", "transport": { "path": "${L:A:Obj_ref}" }, "wapi": "v2.7", "wapi_quoting": "JSON", "body_list": [ "{\"extattrs+\":{\"TNBL_IO_Sync_Time\": { \"value\": \"${E:A:timestamp}\"}}}" ] }, { "name": "haltTemplate", "comment": "Halt template.", "operation": "CONDITION", "condition": { "condition_type": "AND", "statements": [{ "left": "1", "op": "==", "right": "1" }], "stop": true } }, { "name": "deleteAssetRange", "comment": "Delete range asset using its netbios_name. TenableIO will return code 202.", "operation": "POST", "parse": "JSON", "transport": { "path": "/api/v2/assets/bulk-jobs/delete" }, "result": [{ "codes": "200,202", "next": "haltTemplate" }], "body_list": [ "{", "\"query\": {", "\"field\": \"netbios_name\",", "\"operator\": \"eq\",", "\"value\": \"${L:A:RangeStart} - ${L:A:RangeEnd}\"", "},", "\"hard_delete\": true", "}" ] }, { "name": "deleteAssetNetwork", "comment": "Delete network asset using its netbios_name. TenableIO will return code 202.", "operation": "POST", "parse": "JSON", "transport": { "path": "/api/v2/assets/bulk-jobs/delete" }, "result": [{ "codes": "200,202", "next": "haltTemplate" }], "body_list": [ "{", "\"query\": {", "\"field\": \"netbios_name\",", "\"operator\": \"eq\",", "\"value\": \"${L:A:Network}\"", "},", "\"hard_delete\": true", "}" ] } ] }