diff --git a/Playbooks/playbook-Phishing.yml b/Playbooks/playbook-Phishing.yml new file mode 100644 index 000000000000..88836ade2cf9 --- /dev/null +++ b/Playbooks/playbook-Phishing.yml @@ -0,0 +1,361 @@ +id: playbook2 +version: 1 +name: Phishing Playbook - Manual +description: Master playbook for phishing incidents. This playbook is a manual playbook. +tasks: +- id: "1" + taskid: f61f3880-e5f6-4a41-8af8-3349e3ebffff + type: title + task: + id: f61f3880-e5f6-4a41-8af8-3349e3ebffff + version: 4 + name: Engage + istitletask: true + issystemtask: true +- id: "2" + taskid: d69a6289-b692-404c-8f90-d37d72aa265c + type: regular + task: + id: d69a6289-b692-404c-8f90-d37d72aa265c + version: 3 + name: Notify management chain + description: 'Notify appropriate people inside the organization. ' + issystemtask: true +- id: "3" + taskid: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + type: regular + task: + id: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + version: 3 + name: Initial triage + description: 1. Make sure that there is relevant information in the incident - + system name, end user name and initial severity as reported. + issystemtask: true +- id: "4" + taskid: b7f2e51f-a39f-4cba-881d-e7efbef2553e + type: title + task: + id: b7f2e51f-a39f-4cba-881d-e7efbef2553e + version: 1 + name: 'Investigation Step 1: Initial Inspection' + istitletask: true + issystemtask: true + clonedfrom: ea731eb3-f592-42f3-892a-6a7d48c42e4d +- id: "5" + taskid: 30e833d0-8336-4ecd-8a36-a997ac1bb100 + type: regular + task: + id: 30e833d0-8336-4ecd-8a36-a997ac1bb100 + version: 1 + name: Inspect the email body for malicious URLs + description: Check the email body attached to the incident and see if it has malicious + URLs in it using threat feeds + issystemtask: true +- id: "6" + taskid: 0aba5f0e-c71f-4a1f-8f7a-993f727e3825 + type: regular + task: + id: 0aba5f0e-c71f-4a1f-8f7a-993f727e3825 + version: 1 + name: Inspect the email attachments + description: Check the attachments with threat services to see if any of them + is known bad + issystemtask: true +- id: "7" + taskid: fa90abdd-2ec1-490b-8a9e-2acc6f2f721d + type: regular + task: + id: fa90abdd-2ec1-490b-8a9e-2acc6f2f721d + version: 1 + name: Is the sender name or email address identified as bad by threat feeds? + description: Check the sender email and name against threat feed sources. + issystemtask: true +- id: "8" + taskid: d9fad845-7f5b-4c79-8835-2e8358c84e04 + type: regular + task: + id: d9fad845-7f5b-4c79-8835-2e8358c84e04 + version: 1 + name: Check if the hostname is being misrepresented? + description: |- + Check if domain of sender or any hostname in the URLs inside the email body are misrepresented. See if the URL text versus the hostname shown are different by comparing the link with the text. Also carefully inspected the URLs for spelling spoofing which + is typically a sign of phishing email. + issystemtask: true +- id: "9" + taskid: 5d36d65b-d63f-40b7-8167-2a341e9bed62 + type: condition + task: + id: 5d36d65b-d63f-40b7-8167-2a341e9bed62 + version: 1 + name: Is this a real phishing email? + description: Based on the steps above, is this really a phishing email? + issystemtask: true + clonedfrom: ef2034e6-1228-49a1-885a-01dce99cc963 + condition: + "no": + - id: "10" + taskid: b37377be-5c13-41f5-8635-69ea34571af7 + type: regular + task: + id: b37377be-5c13-41f5-8635-69ea34571af7 + version: 1 + name: Close the investigation as false positive + description: Close the investigation as false positive and reply to the user + sending the email that it is not malicious. + issystemtask: true + "yes": + - id: "11" + taskid: e76cfd73-35f3-4065-8e59-c37e365cd06c + type: regular + task: + id: e76cfd73-35f3-4065-8e59-c37e365cd06c + version: 2 + name: Assess severity + description: 'Based on the end user affected, and other information assess + and change the severity if needed. ' + issystemtask: true + - id: "12" + taskid: 5445acdd-df36-403e-8635-a0cbc3bd3f04 + type: regular + task: + id: 5445acdd-df36-403e-8635-a0cbc3bd3f04 + version: 2 + name: Assign and involve appropriate personnel + description: 'Invite the relevant users for investigation - malware expert + and network experts if needed. ' + issystemtask: true +- id: "13" + taskid: eb2b0d5a-cc72-4640-8116-85750701ae1d + type: title + task: + id: eb2b0d5a-cc72-4640-8116-85750701ae1d + version: 1 + name: 'Investigation Step 2: Deeper Analysis' + istitletask: true + issystemtask: true +- id: "14" + taskid: 92ae3779-12c5-4a24-827e-56e413088b80 + type: regular + task: + id: 92ae3779-12c5-4a24-827e-56e413088b80 + version: 1 + name: Get all the URLs from the email + issystemtask: true +- id: "15" + taskid: 13e0228e-ad6a-4148-8aa6-55e8143a4620 + type: regular + task: + id: 13e0228e-ad6a-4148-8aa6-55e8143a4620 + version: 1 + name: Get all the hostnames inside the email + issystemtask: true +- id: "16" + taskid: 05855c19-9221-478d-8c83-4145aa2cff16 + type: regular + task: + id: 05855c19-9221-478d-8c83-4145aa2cff16 + version: 1 + name: Fetch all the files from the URL + description: 'Use curl or similar tool to download all the files from the URLs + in the email. ' + issystemtask: true +- id: "17" + taskid: 010895a1-9f86-4106-8e56-8f6889d5e228 + type: condition + task: + id: 010895a1-9f86-4106-8e56-8f6889d5e228 + version: 1 + name: Are the files download malicious - hash inspection? + description: Check the files MD5 and SHA1 against the threat feed databases. + issystemtask: true + condition: + "no": + - id: "18" + taskid: 2580b31a-6c04-45b1-8752-959f66084ae3 + type: condition + task: + id: 2580b31a-6c04-45b1-8752-959f66084ae3 + version: 1 + name: Are the files download malicious - static and dynamic analysis? + description: Check the files in a sandbox solution to see if they are malicious. + issystemtask: true + condition: + "no": + - id: "20" + taskid: 24063b39-4c30-4ef2-8e7c-36081b45faaa + type: condition + task: + id: 24063b39-4c30-4ef2-8e7c-36081b45faaa + version: 1 + name: Is any URL malicious based on sandbox inspection? + description: 'Use Cuckoo or similar sandbox solutions for fetching the + content of the URL for deeper analysis. ' + issystemtask: true + condition: + "no": [] + "yes": + - id: "21" + taskid: 9c572188-54b5-4d56-8e62-95ee93e3a157 + type: regular + task: + id: 9c572188-54b5-4d56-8e62-95ee93e3a157 + version: 1 + name: Consider this email as phishing and move to "Response Section" + issystemtask: true + "yes": + - id: "19" + taskid: email_phishing + type: regular + task: + id: email_phishing + version: 1 + name: Consider this email as phishing and move to "Response Section" + issystemtask: true + "yes": + - id: "22" + taskid: ff551c65-6d74-460d-8e4d-4a5a84517e9b + type: regular + task: + id: ff551c65-6d74-460d-8e4d-4a5a84517e9b + version: 1 + name: Consider this email as phishing and move to "Response Section" + issystemtask: true +- id: "23" + taskid: 3b29ac0a-190d-46bf-80cf-dbc1197d2f80 + type: title + task: + id: 3b29ac0a-190d-46bf-80cf-dbc1197d2f80 + version: 1 + name: 'Investigation Step 3: Is it a Campaign?' + istitletask: true + issystemtask: true +- id: "24" + taskid: 78cc334d-fe36-4cb0-8e63-dbb571077edc + type: condition + task: + id: 78cc334d-fe36-4cb0-8e63-dbb571077edc + version: 1 + name: Did we have a similar phishing email earlier? + description: Search past phishing investigations for subject sender, email content + and URLs. + issystemtask: true + condition: + "no": [] + "yes": + - id: "25" + taskid: ec15c113-29a0-4ab5-85fc-3fc1fbe85a70 + type: regular + task: + id: ec15c113-29a0-4ab5-85fc-3fc1fbe85a70 + version: 1 + name: Mark this as a campaign rather than isolated incident. + issystemtask: true + - id: "26" + taskid: e3710c0f-861d-4a9a-8e89-3488f572d74e + type: regular + task: + id: e3710c0f-861d-4a9a-8e89-3488f572d74e + version: 1 + name: Link old and new incidents to this master incident. + description: Future emails with similar subject should be associated with + this incident + issystemtask: true +- id: "27" + taskid: 0386fa2c-a246-4dd9-8592-976b630148fc + type: title + task: + id: 0386fa2c-a246-4dd9-8592-976b630148fc + version: 1 + name: Respond + istitletask: true + issystemtask: true +- id: "28" + taskid: faf506e6-c1bd-49ee-8348-bdb258984785 + type: regular + task: + id: faf506e6-c1bd-49ee-8348-bdb258984785 + version: 1 + name: Notify internal PR team if this is a campaign + description: 'If we identified multiple emails with similar content, subject and + identified this as a campaign, we need to notify our users. Send an email to + internal communications team with the details - like sender, content etc. ' + issystemtask: true +- id: "29" + taskid: a0b42339-fa44-4215-8fdd-8dc900011dd8 + type: regular + task: + id: a0b42339-fa44-4215-8fdd-8dc900011dd8 + version: 1 + name: Block email on the server + description: |- + Identify the appropriate headers from the initial email beyond subject + and sender email to make sure we can effectively block this on server. This + task needs analysis of header to make sure we do not block other emails and + still be effective in blocking. + issystemtask: true +- id: "30" + taskid: e93a15aa-1c5d-46ff-813c-b1f6eed114f3 + type: regular + task: + id: e93a15aa-1c5d-46ff-813c-b1f6eed114f3 + version: 1 + name: Notify IT to update SPAM filters + description: 'Give IT the phishing email so that they can train the SPAM filter + with this email to avoid future attacks. ' + issystemtask: true +- id: "31" + taskid: f487ba1c-d67b-40f2-8cf8-85f646b0d768 + type: regular + task: + id: f487ba1c-d67b-40f2-8cf8-85f646b0d768 + version: 1 + name: Notify email security vendor + description: |- + Forward all the details to your security vendor for email security + solution. This will help them with the future updates. + issystemtask: true +- id: "32" + taskid: 1b6d8f94-452c-43b2-8606-da89d3f738c8 + type: regular + task: + id: 1b6d8f94-452c-43b2-8606-da89d3f738c8 + version: 1 + name: Remove email from inboxes + description: 'Work with IT to completely delete similar emails from all user inboxes. + Search through the SMTP logs to find all the recipients and delete the emails. ' + issystemtask: true +- id: "33" + taskid: c47f9b5a-cba2-4b2c-89ca-0c1003e9c295 + type: regular + task: + id: c47f9b5a-cba2-4b2c-89ca-0c1003e9c295 + version: 1 + name: Blackholing phishing domain on Domain Controller + description: |- + Work with IT to black hole the phishing domains (this particular + and related ones from other emails and incidents that were marked duplicate). + This should be blocked on the domain controller by resolving to 127.0.0.1 + issystemtask: true +- id: "34" + taskid: b3e805e2-2566-4f28-884d-dcc8a8fe3573 + type: regular + task: + id: b3e805e2-2566-4f28-884d-dcc8a8fe3573 + version: 1 + name: Blocking download URL + description: |2- + 1. Try to identify a pattern in the URL. For example if the URL is: http://hackedwebsite.com/dl.php?campaign=ra&id=12731342834923919 + 2. Create a reasonable regex like: ^.+/dl.php?.*campaign=ra.$ + 3. Contact the proxy team to block URLs based on the pattern + issystemtask: true +- id: "35" + taskid: ffa62d59-1b44-4305-8324-3cc29f4585ff + type: regular + task: + id: ffa62d59-1b44-4305-8324-3cc29f4585ff + version: 1 + name: Report malware sample to AV vendors + description: Report all the files that were downloaded from URL to AV vendor and + virustotal like services. + issystemtask: true +system: true \ No newline at end of file diff --git a/Playbooks/playbook-PhishingAutomated.yml b/Playbooks/playbook-PhishingAutomated.yml new file mode 100644 index 000000000000..db05843e2bd5 --- /dev/null +++ b/Playbooks/playbook-PhishingAutomated.yml @@ -0,0 +1,490 @@ +id: playbook5 +version: 1 +name: Phishing Playbook - Automated +description: This is an automated phishing playbook. +tags: +- Phishing +tasks: +- id: "1" + taskid: ea731eb3-f592-42f3-892a-6a7d48c42e4d + type: title + task: + id: ea731eb3-f592-42f3-892a-6a7d48c42e4d + version: 1 + name: Triage and Engage + istitletask: true + issystemtask: true +- id: "2" + taskid: d4a6e062-7700-4c04-80f1-cbb4571244fe + type: regular + task: + id: d4a6e062-7700-4c04-80f1-cbb4571244fe + version: 1 + name: IncidentToContext + script: IncidentToContext + issystemtask: true + results: + - Label/Application + - Label/Database + - Label/Directory + - Label/Email + - Label/Email/cc + - Label/Email/from + - Label/IP + - Label/System + - Label/URL + - Label/User + - id + - created + - modified + - occurred + - dueDate + - name + - owner + - type + - severity + - stage + - status + - details + - score +- id: "3" + taskid: 42aed86a-6e32-4ae9-8027-ee4c6280b9f5 + type: regular + task: + id: 42aed86a-6e32-4ae9-8027-ee4c6280b9f5 + version: 1 + name: Auto-respond to phishing email + description: Send an auto-response to the target telling them we are on it + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've received your email and are investigating. Please + do not touch the email until further notice. \nCordially,\n Your security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} +- id: "4" + taskid: 3ebc40e3-46db-4f25-8b45-31a46b4ad004 + type: condition + task: + id: 3ebc40e3-46db-4f25-8b45-31a46b4ad004 + version: 1 + name: Do we have known bad URLs + description: Check if we have known bad URLs + script: CheckURLs + issystemtask: true + condition: + "no": + - id: "9" + taskid: f6bfb9db-c44d-40ef-8f12-1cf328713344 + type: condition + task: + id: f6bfb9db-c44d-40ef-8f12-1cf328713344 + version: 1 + name: Check if we have known bad IPs + script: CheckIPs + issystemtask: true + condition: + "no": + - id: "10" + taskid: b62f132d-849b-490f-847a-15a6312a5b80 + type: condition + task: + id: b62f132d-849b-490f-847a-15a6312a5b80 + version: 1 + name: Check if we have known bad attachments + description: Iterate on all attachments and check reputation + script: BinaryReputationPy + issystemtask: true + condition: + "no": + - id: "11" + taskid: e6b6ace8-da53-4aee-8318-47614ecf874c + type: condition + task: + id: e6b6ace8-da53-4aee-8318-47614ecf874c + version: 1 + name: Check with wildfire if attachments are bad + description: First, this will check if files are known and if not, + upload them to Wildfire and wait for the report for 15 min. + script: CheckFilesWildfirePy + issystemtask: true + condition: + "no": [] + "yes": + - id: "12" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've received your email and are investigating. + Please do not touch the email until further notice. \nCordially,\n Your + security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "13" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "14" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "15" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true + "yes": + - id: "16" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've concluded that the email you forwarded + to us is malicious. We've taken steps to blacklist the sender and + quarantine the email. Good job on detecting and forwarding it to + us!\nAll the best, Your security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "17" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "18" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "19" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true + results: + - bad_hashes + "yes": + - id: "20" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've concluded that the email you forwarded to + us is malicious. We've taken steps to blacklist the sender and quarantine + the email. Good job on detecting and forwarding it to us!\nAll the best, + Your security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "21" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "22" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "23" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true + results: + - bad_ips + "yes": + - id: "5" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've concluded that the email you forwarded to us is + malicious. We've taken steps to blacklist the sender and quarantine the + email. Good job on detecting and forwarding it to us!\nAll the best, Your + security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "6" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "7" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "8" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true + results: + - bad_urls +- id: "24" + taskid: 7f1be339-fd7c-41f6-849f-55ccce5c4bbc + type: regular + task: + id: 7f1be339-fd7c-41f6-849f-55ccce5c4bbc + version: 1 + name: Check sender domain distance + description: Check if the sender is trying to confuse the user with a domain that + is very close to our domain + script: CheckSenderDomainDistance + issystemtask: true + scriptarguments: + domain: "" + sender: "" +- id: "25" + taskid: 5778ac35-8936-4170-8cf6-8cc09c98a300 + type: regular + task: + id: 5778ac35-8936-4170-8cf6-8cc09c98a300 + version: 1 + name: Manually inspect the email for anything suspicious + description: Since automatic triage did not find anything wrong, please inspect + it manually and see if something stands out + issystemtask: true +- id: "26" + taskid: 5445acdd-df36-403e-8635-a0cbc3bd3f04 + type: regular + task: + id: 5445acdd-df36-403e-8635-a0cbc3bd3f04 + version: 2 + name: Assign and involve appropriate personnel + description: 'Invite the relevant users for investigation - malware expert and + network experts if needed. ' + issystemtask: true +- id: "27" + taskid: e76cfd73-35f3-4065-8e59-c37e365cd06c + type: regular + task: + id: e76cfd73-35f3-4065-8e59-c37e365cd06c + version: 2 + name: Assess severity + description: 'Based on the end user affected, and other information assess and + change the severity if needed. ' + issystemtask: true +- id: "28" + taskid: 8577cc17-342c-4291-8918-611ca8adf6e5 + type: title + task: + id: 8577cc17-342c-4291-8918-611ca8adf6e5 + version: 1 + name: 'Investigation Step 1: Initial Inspection' + istitletask: true + issystemtask: true +- id: "29" + taskid: cceb5cd4-a661-434d-87d8-24b9988877c4 + type: condition + task: + id: cceb5cd4-a661-434d-87d8-24b9988877c4 + version: 1 + name: Check if the hostname in the url is being misrepresented? + description: |- + See if the URL text versus the hostname shown are different by hovering + over the link. Also carefully inspected the URL for spelling spoofing which + is typically a sign of phishing email. + issystemtask: true + condition: + "no": + - id: "34" + taskid: 8715668a-d08d-4270-8260-09298a3a01e6 + type: regular + task: + id: 8715668a-d08d-4270-8260-09298a3a01e6 + version: 1 + name: Check sender email address + script: CheckSenderPy + issystemtask: true + - id: "35" + taskid: 5ec6d252-8985-44f8-84d8-8c038d0b3b80 + type: condition + task: + id: 5ec6d252-8985-44f8-84d8-8c038d0b3b80 + version: 1 + name: Is the sender name or email address identified as bad by threat feeds? + description: 'Check the sender email and name against threat feed sources. ' + issystemtask: true + condition: + "no": [] + "yes": + - id: "36" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've concluded that the email you forwarded to + us is malicious. We've taken steps to blacklist the sender and quarantine + the email. Good job on detecting and forwarding it to us!\nAll the best, + Your security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "37" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "38" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "39" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true + "yes": + - id: "30" + taskid: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + type: regular + task: + id: de7bf577-4b5d-4ee3-83b9-e026a25fa53e + version: 6 + name: Send email to user notifying them it's a malicious email + script: SendEmail + issystemtask: true + scriptarguments: + attachIDs: "" + bcc: "" + body: Hi $recipient,\nWe've concluded that the email you forwarded to us is + malicious. We've taken steps to blacklist the sender and quarantine the + email. Good job on detecting and forwarding it to us!\nAll the best, Your + security team + cc: "" + subject: 'Re: Phishing Investigation - $name' + to: ${Label/Email/from} + - id: "31" + taskid: 9409a961-2ea3-4279-82af-ebf9740a5b5f + type: regular + task: + id: 9409a961-2ea3-4279-82af-ebf9740a5b5f + version: 6 + name: Find and delete malicious email + script: ExchangeFindAndDelete + issystemtask: true + - id: "32" + taskid: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + type: regular + task: + id: a898b05b-3a6e-4df8-832b-8917bf5fcae3 + version: 6 + name: Search attachment using Carbon Black + script: BinarySearchPy + issystemtask: true + - id: "33" + taskid: f5df9520-2247-49a4-882f-7ec3726a9d2a + type: regular + task: + id: f5df9520-2247-49a4-882f-7ec3726a9d2a + version: 6 + name: Close the phishing investigation + script: CloseInvestigation + issystemtask: true +system: true \ No newline at end of file diff --git a/Playbooks/playbook-default.yml b/Playbooks/playbook-default.yml new file mode 100644 index 000000000000..4d2045102564 --- /dev/null +++ b/Playbooks/playbook-default.yml @@ -0,0 +1,141 @@ +id: playbook0 +version: 1 +name: Default +description: Default playbook to help classify incoming incidents +tasks: +- id: "1" + taskid: ea9ee448-a157-44e5-8266-aba6173516e2 + type: regular + task: + id: ea9ee448-a157-44e5-8266-aba6173516e2 + version: 1 + name: ClassifyEmail + script: DefaultIncidentClassifier + scriptarguments: + defaultIncidentType: Phishing + splunkSender: please-specify +- id: "2" + taskid: f9de0883-2020-490e-85ed-fdfb66a2db87 + type: condition + task: + id: f9de0883-2020-490e-85ed-fdfb66a2db87 + version: 1 + name: Is this a malware incident + description: Did it involve a malicious binary running in your environment? + condition: + "no": [] + "yes": + - id: "3" + taskid: c5d0e4fe-72db-40e2-8016-b86b944f2c9f + type: regular + task: + id: c5d0e4fe-72db-40e2-8016-b86b944f2c9f + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: Malware +- id: "4" + taskid: 7b1823dd-b38e-4cd6-874d-87ede0be1f9e + type: condition + task: + id: 7b1823dd-b38e-4cd6-874d-87ede0be1f9e + version: 1 + name: Is this a phishing incident? + description: Was this incident created because a suspected email was received? + condition: + "no": [] + "yes": + - id: "5" + taskid: 66553f46-579a-42af-8c02-341af3445ba3 + type: regular + task: + id: 66553f46-579a-42af-8c02-341af3445ba3 + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: Phishing +- id: "6" + taskid: 93f3f626-0b08-4257-8559-c2d3838cea13 + type: condition + task: + id: 93f3f626-0b08-4257-8559-c2d3838cea13 + version: 1 + name: Is the incident a C2 communication incident? + description: Was the incident opened because communication to a known bad actor + was detected? + condition: + "no": [] + "yes": + - id: "7" + taskid: 070a2204-c59e-4c9c-88cf-95d5cd4a14ad + type: regular + task: + id: 070a2204-c59e-4c9c-88cf-95d5cd4a14ad + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: C2Communication +- id: "8" + taskid: bd100974-58ce-4b53-8e32-c3930e215184 + type: condition + task: + id: bd100974-58ce-4b53-8e32-c3930e215184 + version: 1 + name: Is the incident a ransomware incident? + condition: + "no": [] + "yes": + - id: "9" + taskid: 8a09e454-e0cc-4c4c-8b1b-77ccc402fabf + type: regular + task: + id: 8a09e454-e0cc-4c4c-8b1b-77ccc402fabf + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: Ransomware +- id: "10" + taskid: 6cab1990-09da-4e94-8d26-7a67571a6303 + type: condition + task: + id: 6cab1990-09da-4e94-8d26-7a67571a6303 + version: 1 + name: Is the incident an unknown binary incident? + condition: + "no": [] + "yes": + - id: "11" + taskid: bb222001-660e-418c-8849-25341bb74ddc + type: regular + task: + id: bb222001-660e-418c-8849-25341bb74ddc + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: UnknownBinary +- id: "12" + taskid: b4f728f9-7690-49ec-8214-216cf28d83e1 + type: condition + task: + id: b4f728f9-7690-49ec-8214-216cf28d83e1 + version: 1 + name: Does the incident involve a lost or stolen device? + condition: + "no": [] + "yes": + - id: "13" + taskid: 3e019db0-5b05-45e4-86ca-c5944a9fdd48 + type: regular + task: + id: 3e019db0-5b05-45e4-86ca-c5944a9fdd48 + version: 1 + name: SetIncidentType + script: IncidentSet + scriptarguments: + type: DeviceLost +system: true \ No newline at end of file diff --git a/Playbooks/playbook-malware.yml b/Playbooks/playbook-malware.yml new file mode 100644 index 000000000000..1ddcf3b1212f --- /dev/null +++ b/Playbooks/playbook-malware.yml @@ -0,0 +1,360 @@ +id: playbook1 +version: 1 +name: Malware Playbook - Manual +description: Master playbook for malware incidents. This playbook is a manual playbook. +tags: +- Virus +- Malware +tasks: +- id: "1" + taskid: f61f3880-e5f6-4a41-8af8-3349e3ebffff + type: title + task: + id: f61f3880-e5f6-4a41-8af8-3349e3ebffff + version: 4 + name: Engage + istitletask: true + issystemtask: true +- id: "2" + taskid: d69a6289-b692-404c-8f90-d37d72aa265c + type: regular + task: + id: d69a6289-b692-404c-8f90-d37d72aa265c + version: 3 + name: Notify management chain + description: 'Notify appropriate people inside the organization. ' + issystemtask: true +- id: "3" + taskid: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + type: regular + task: + id: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + version: 3 + name: Initial triage + description: 1. Make sure that there is relevant information in the incident - + system name, end user name and initial severity as reported. + issystemtask: true +- id: "4" + taskid: cd85115e-4379-4319-853b-f518e9aa98bc + type: regular + task: + id: cd85115e-4379-4319-853b-f518e9aa98bc + version: 3 + name: Assess severity + description: 'Based on the end user affected, and other information assess and + change the severity if needed. ' + issystemtask: true +- id: "5" + taskid: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + type: regular + task: + id: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + version: 3 + name: Assign and involve appropriate personnel + description: 'Invite the relevant users for investigation - malware expert and + network experts if needed. ' + issystemtask: true +- id: "6" + taskid: 6a8d2675-34a0-412b-8835-40e4f8a24849 + type: title + task: + id: 6a8d2675-34a0-412b-8835-40e4f8a24849 + version: 1 + name: 'Investigation Step 1: Initial Inspection' + istitletask: true + issystemtask: true +- id: "7" + taskid: 2820cd55-abce-480a-80db-484a2d4a817c + type: regular + task: + id: 2820cd55-abce-480a-80db-484a2d4a817c + version: 1 + name: Obtain phishing email from the user + description: 'Get the suspected email from end user and attach it to the investigation. + Document the subject, details of the email and other pieces in the investigation. ' + issystemtask: true +- id: "8" + taskid: c31637b7-02f1-4868-865c-ca5d5805c46a + type: regular + task: + id: c31637b7-02f1-4868-865c-ca5d5805c46a + version: 1 + name: Collect volatile system data + description: 'Collect system data like running processes, network connections + and files changed. ' + issystemtask: true +- id: "9" + taskid: 05339003-481a-4ba6-85cd-a4fc9a2d15a0 + type: regular + task: + id: 05339003-481a-4ba6-85cd-a4fc9a2d15a0 + version: 1 + name: Create memory dump of the system + description: 'In addition to a full backup create a memory dump of the system. ' + issystemtask: true +- id: "10" + taskid: 6754484c-6891-45be-80f3-8ca596286a8b + type: regular + task: + id: 6754484c-6891-45be-80f3-8ca596286a8b + version: 1 + name: Create backup of affected systems + description: Create complete backup of affected systems for recovery and forensics. + issystemtask: true +- id: "11" + taskid: 35d8737d-3dec-4a0b-86e1-9d421d3996b4 + type: regular + task: + id: 35d8737d-3dec-4a0b-86e1-9d421d3996b4 + version: 1 + name: Review antivirus logs for the affected systems + issystemtask: true +- id: "12" + taskid: 2327241b-ffc0-4a03-8af2-4654b53cbe2a + type: regular + task: + id: 2327241b-ffc0-4a03-8af2-4654b53cbe2a + version: 1 + name: Research other malware databases + description: "Review recently changed and created files on the system against + other malware databases (Virustotal, XFE). \n" + issystemtask: true +- id: "13" + taskid: b3510d6b-6202-4ee4-844f-c63f0f8a5789 + type: regular + task: + id: b3510d6b-6202-4ee4-844f-c63f0f8a5789 + version: 1 + name: Review registry for suspicious activity (windows) + description: 'Review the registry for suspicious activity in runonce etc. ' + issystemtask: true +- id: "14" + taskid: 43f9a58e-14e8-422b-83c4-38689773be3f + type: regular + task: + id: 43f9a58e-14e8-422b-83c4-38689773be3f + version: 1 + name: Run IOC database against the affected system + description: 'Run the recent IOC databases against the reported system. ' + issystemtask: true +- id: "15" + taskid: 3233684b-e31c-4ad8-86c4-274a6205208c + type: regular + task: + id: 3233684b-e31c-4ad8-86c4-274a6205208c + version: 1 + name: Analyze network traffic for signs of intrusion + description: Analyze the network traffic from/to this system for signs of intrusion. + issystemtask: true +- id: "16" + taskid: 5f142333-7e70-4884-8fd6-aadc40fdfa54 + type: regular + task: + id: 5f142333-7e70-4884-8fd6-aadc40fdfa54 + version: 1 + name: Analyze network traffic for malware activity + description: Analyze the network traffic from/to this system for malware activity + issystemtask: true +- id: "17" + taskid: ce404b7b-103c-46cb-8ee3-5ce318aee2bc + type: regular + task: + id: ce404b7b-103c-46cb-8ee3-5ce318aee2bc + version: 1 + name: Correlate network and file data against threat intelligence + description: | + Research current threat intelligence for network and file activity + issystemtask: true +- id: "18" + taskid: 7d3de1a4-dabf-485b-87d1-b4b42de754dd + type: regular + task: + id: 7d3de1a4-dabf-485b-87d1-b4b42de754dd + version: 1 + name: Look for traces of network sniffers + issystemtask: true +- id: "19" + taskid: fcef2636-23ce-4352-852e-13e7b513ceef + type: regular + task: + id: fcef2636-23ce-4352-852e-13e7b513ceef + version: 1 + name: Look for system file and registry (win) modification + description: "Look for modification made to system and configuration files. Document + recently modified system files. \n" + issystemtask: true +- id: "20" + taskid: 1aa0c9db-5d38-414c-802c-7605f0d380da + type: regular + task: + id: 1aa0c9db-5d38-414c-802c-7605f0d380da + version: 1 + name: Analyze file samples collected with a malware analysis sandbox + description: 'Run the analysis on file samples collected from affected system. ' + issystemtask: true +- id: "21" + taskid: e749b793-b7c2-4628-8101-2927e20796b9 + type: regular + task: + id: e749b793-b7c2-4628-8101-2927e20796b9 + version: 1 + name: Run memory analysis on the system memory + description: 'Use SIFT tools for memory analysis to look at running processes + and recently closed network connections. ' + issystemtask: true +- id: "22" + taskid: 303fc207-916d-4057-8717-3c5e38f945d5 + type: regular + task: + id: 303fc207-916d-4057-8717-3c5e38f945d5 + version: 1 + name: Research current intelligence against memory analysis + description: 'Research the current threat intelligence against findings in memory + analysis. ' + issystemtask: true +- id: "23" + taskid: 75065aaa-08b8-421c-82fb-ebb78296c3c8 + type: regular + task: + id: 75065aaa-08b8-421c-82fb-ebb78296c3c8 + version: 1 + name: Send status update + description: Update management team about status of incident + issystemtask: true +- id: "24" + taskid: 5e48a7f1-8c3d-4472-8edd-43ad2ef061ce + type: condition + task: + id: 5e48a7f1-8c3d-4472-8edd-43ad2ef061ce + version: 1 + name: Was malware found? + issystemtask: true + condition: + "no": + - id: "25" + taskid: 79732f56-83e8-428c-8a96-c9f0e853b45f + type: regular + task: + id: 79732f56-83e8-428c-8a96-c9f0e853b45f + version: 1 + name: Inform user that no malware was found + issystemtask: true + "yes": + - id: "26" + taskid: 9a73f01e-6096-4daf-80d3-0b671e74f619 + type: regular + task: + id: 9a73f01e-6096-4daf-80d3-0b671e74f619 + version: 1 + name: Report malware sample to AV vendor + issystemtask: true +- id: "27" + taskid: bc465242-756c-44ad-8546-b004ca98190c + type: title + task: + id: bc465242-756c-44ad-8546-b004ca98190c + version: 1 + name: Data Leak Assessment + istitletask: true + issystemtask: true +- id: "28" + taskid: 77134e96-d810-4fe9-8573-0dae9701905c + type: condition + task: + id: 77134e96-d810-4fe9-8573-0dae9701905c + version: 1 + name: Was any sensitive information leaked? + issystemtask: true + condition: + "no": [] + "yes": + - id: "29" + taskid: 79473708-5b11-44ae-86ad-1f05ec3ae75c + type: regular + task: + id: 79473708-5b11-44ae-86ad-1f05ec3ae75c + version: 1 + name: Notify Public Relations (PR) team + issystemtask: true +- id: "30" + taskid: 2b290909-b729-46a4-8c09-212bee8f6094 + type: title + task: + id: 2b290909-b729-46a4-8c09-212bee8f6094 + version: 1 + name: Respond + istitletask: true + issystemtask: true +- id: "31" + taskid: 5b96fdcb-14af-434b-8c89-ebbb3b344145 + type: regular + task: + id: 5b96fdcb-14af-434b-8c89-ebbb3b344145 + version: 2 + name: Notify affected user + description: Notify affected user about the outcome of investigation. + issystemtask: true +- id: "32" + taskid: b32992a7-f5e0-4b95-8dd2-5c70e938c715 + type: regular + task: + id: b32992a7-f5e0-4b95-8dd2-5c70e938c715 + version: 2 + name: Remove temporary containment measures + description: Remove the temporary containment measures that were placed. + issystemtask: true +- id: "33" + taskid: 35c0d3b2-d9cd-460c-88be-6d7a229e9906 + type: regular + task: + id: 35c0d3b2-d9cd-460c-88be-6d7a229e9906 + version: 2 + name: Provide end-user remediation guidance and link to training + issystemtask: true +- id: "34" + taskid: f68ec944-041d-4288-80fd-d4593bceb52b + type: condition + task: + id: f68ec944-041d-4288-80fd-d4593bceb52b + version: 2 + name: Is the identified malware known? (with automated remediation steps) + issystemtask: true + condition: + "no": + - id: "35" + taskid: f13d62e8-15a2-4240-8245-9537c0c7aa83 + type: regular + task: + id: f13d62e8-15a2-4240-8245-9537c0c7aa83 + version: 2 + name: Document manual remediation steps + issystemtask: true + "yes": + - id: "36" + taskid: 91223da8-3e5b-432e-85d6-b05a8e614f83 + type: regular + task: + id: 91223da8-3e5b-432e-85d6-b05a8e614f83 + version: 2 + name: Trigger remediation scripts + issystemtask: true +- id: "37" + taskid: 36ba1145-5eb5-4bc4-85f6-d5c9f4495cca + type: condition + task: + id: 36ba1145-5eb5-4bc4-85f6-d5c9f4495cca + version: 2 + name: Was remediation successful? + issystemtask: true + condition: + "no": + - id: "38" + taskid: c56d39eb-e583-4183-8b18-12e9d0547c17 + type: regular + task: + id: c56d39eb-e583-4183-8b18-12e9d0547c17 + version: 2 + name: Reimage the entire system and restore from backup + issystemtask: true + "yes": [] +system: true \ No newline at end of file diff --git a/Playbooks/playbook-ransomware.yml b/Playbooks/playbook-ransomware.yml new file mode 100644 index 000000000000..d451391c9e8f --- /dev/null +++ b/Playbooks/playbook-ransomware.yml @@ -0,0 +1,508 @@ +id: playbook3 +version: 1 +name: Ransomware Playbook - Manual +description: Master playbook for ransomware incidents. This playbook is a manual playbook. +tasks: +- id: "1" + taskid: f61f3880-e5f6-4a41-8af8-3349e3ebffff + type: title + task: + id: f61f3880-e5f6-4a41-8af8-3349e3ebffff + version: 4 + name: Engage + istitletask: true + issystemtask: true +- id: "2" + taskid: d69a6289-b692-404c-8f90-d37d72aa265c + type: regular + task: + id: d69a6289-b692-404c-8f90-d37d72aa265c + version: 3 + name: Notify management chain + description: 'Notify appropriate people inside the organization. ' + issystemtask: true +- id: "3" + taskid: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + type: regular + task: + id: 21cb9178-78a0-4610-801f-3bc5f808e4a2 + version: 3 + name: Initial triage + description: 1. Make sure that there is relevant information in the incident - + system name, end user name and initial severity as reported. + issystemtask: true +- id: "4" + taskid: cd85115e-4379-4319-853b-f518e9aa98bc + type: regular + task: + id: cd85115e-4379-4319-853b-f518e9aa98bc + version: 3 + name: Assess severity + description: 'Based on the end user affected, and other information assess and + change the severity if needed. ' + issystemtask: true +- id: "5" + taskid: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + type: regular + task: + id: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + version: 3 + name: Assign and involve appropriate personnel + description: 'Invite the relevant users for investigation - malware expert and + network experts if needed. ' + issystemtask: true +- id: "6" + taskid: 744fdee2-aae7-4a50-8197-9e871d0661da + type: title + task: + id: 744fdee2-aae7-4a50-8197-9e871d0661da + version: 1 + name: 'Investigation Step 1: Details for this incident' + istitletask: true + issystemtask: true +- id: "7" + taskid: e882cafd-1c86-4443-8ea8-e873d3552a0f + type: regular + task: + id: e882cafd-1c86-4443-8ea8-e873d3552a0f + version: 1 + name: Notify IT about the end user details for replacing device + description: "1. Notify IT with end user details to replace device. \n2. Hopefully + there is back for end user data to be restored." + issystemtask: true +- id: "8" + taskid: 9bdc27f9-07d9-4d9a-83f4-f1cebfd918c5 + type: condition + task: + id: 9bdc27f9-07d9-4d9a-83f4-f1cebfd918c5 + version: 1 + name: Is the incident reported by end user or an alert from SIEM (or another security + product)? + issystemtask: true + condition: + Alert from Security Product: + - id: "9" + taskid: 2438c513-4f3c-4c5a-8c2d-33fdee1b0ff0 + type: condition + task: + id: 2438c513-4f3c-4c5a-8c2d-33fdee1b0ff0 + version: 1 + name: Is the incident real or a false positive? + description: |- + 1. If a URL was flagged from the proxy logs or IDS or SIEM, check why: check for URL and IP reputation against threat feeds. + 2. If the alert came in from a file check (mail server or web server) - check file reputation (hash) against threat feeds like Virustotal + issystemtask: true + condition: + False positive: + - id: "10" + taskid: 1fe0d3b3-bd1e-415f-84a3-fd57071bf1cd + type: regular + task: + id: 1fe0d3b3-bd1e-415f-84a3-fd57071bf1cd + version: 1 + name: Mark the incident as false positive in SIEM + issystemtask: true + - id: "11" + taskid: f213bfb8-2e8d-462a-8430-ffa8afe8049c + type: regular + task: + id: f213bfb8-2e8d-462a-8430-ffa8afe8049c + version: 1 + name: Close the issue in the incident management system + description: Use /investigation_close command to close the investigation. + issystemtask: true + Real incident: + - id: "12" + taskid: 43ec8c44-5322-4cae-87f8-b4bbffb38fc0 + type: regular + task: + id: 43ec8c44-5322-4cae-87f8-b4bbffb38fc0 + version: 1 + name: Identify the affected endpoint and user + description: "1. Get the source IP address from the alert and add it to + investigation.\n2. Get the user associated with this system from domain + controller and AD " + issystemtask: true + - id: "13" + taskid: 732dad95-6ba7-4475-8fdb-4835137f7947 + type: regular + task: + id: 732dad95-6ba7-4475-8fdb-4835137f7947 + version: 1 + name: Inform user about Ransomeware + description: 'Call user and notify them about the incident details. ' + issystemtask: true + - id: "14" + taskid: 862a44d2-5599-4282-883f-de1d9e1d063c + type: regular + task: + id: 862a44d2-5599-4282-883f-de1d9e1d063c + version: 1 + name: Execute local containment + description: 'Ask the user to disconnect the system from network - turn + wifi off if needed. ' + issystemtask: true + User reported Incident: + - id: "15" + taskid: 794e5301-9904-4b42-8ad4-9f251c794781 + type: regular + task: + id: 794e5301-9904-4b42-8ad4-9f251c794781 + version: 1 + name: Document user details in investigation + description: |- + Take the following details from the end-user and register them into the ticket: + 1. Name of employee + 2. Contact details + 3. Computer name + 4. IP address + + Is the user aware he/she clicked on a suspicious link or attachment lately? + issystemtask: true + - id: "16" + taskid: e08042d0-b8a1-4220-8e6e-2d0a6895bd96 + type: regular + task: + id: e08042d0-b8a1-4220-8e6e-2d0a6895bd96 + version: 1 + name: Collect relevant details about incident + description: |- + 1. Did a window pop up with demanding a ransom? + 2. Has a text file with the instructions been placed on the Desktop? + 3. Have the file extensions been changed to .abc, .xxx or similar? + 4. Are the files unavailable? + 5. Is the user aware he/she clicked on a suspicious link or attachment lately? + issystemtask: true + - id: "17" + taskid: b47fff38-a785-41d6-8049-db1ae21226fa + type: regular + task: + id: b47fff38-a785-41d6-8049-db1ae21226fa + version: 1 + name: Execute initial containment + description: Ask the user to disconnect the device from the network. If the + user connects to the network with a wifi, he/she must turn it off. + issystemtask: true +- id: "18" + taskid: efecb59f-31c6-4416-8e3a-a00e9deafc0f + type: title + task: + id: efecb59f-31c6-4416-8e3a-a00e9deafc0f + version: 1 + name: 'Investigation Step 2: Identify Source of Infection' + istitletask: true + issystemtask: true +- id: "19" + taskid: 478d2a8f-2138-4b64-8555-54b3d1acfd75 + type: regular + task: + id: 478d2a8f-2138-4b64-8555-54b3d1acfd75 + version: 1 + name: 'Option 1: Investigate whether the ransomeware has been delivered by email' + issystemtask: true +- id: "20" + taskid: 9a551e7e-0816-499f-8cfa-86d6584ea7f1 + type: regular + task: + id: 9a551e7e-0816-499f-8cfa-86d6584ea7f1 + version: 1 + name: Analyze email logs to narrow down suspicious emails + description: 1. Go to the SIEM 2. Filter on the email logs associated with the + user from the last 3 days 3. Filter again on emails where the recipient was + the victim 4. Remove email logs where the sender was from within your company. + 5. Export the list of emails into a CSV file. It should only contain emails + sent to the victim from the Internet within the last 3 days. + issystemtask: true +- id: "21" + taskid: cef1ed6a-c8e3-4b06-8ca4-4fcd15bbf067 + type: regular + task: + id: cef1ed6a-c8e3-4b06-8ca4-4fcd15bbf067 + version: 1 + name: Collect and analyze suspicious emails + description: "1. Send the CSV file to IT Team and ask them to retrieve the full + emails from the user’s inbox. Attach the cvs to the investigation as evidence.\n2. + Once you get the emails in a zip file, go through them to identify suspicious + links or attachments.\n3. Look for links that does not point to the same URL + displayed on the screen (e.g. http://www.bbc.co.uk)\n4. + Check the domain in the ‘From:’ field correspond to the topic of the email (e.g. + package delivery notification emails from UPS will not come from john@mypersonalblog.com)\n5. + Scan suspicious URLs as necessary with threat feeds like Virustotal, http://www.phishtank.com. + If you identify suspicious URL analyze in depth in next steps. \n" + issystemtask: true +- id: "22" + taskid: 170848e4-7295-4ebf-8e7a-0c02403a710f + type: regular + task: + id: 170848e4-7295-4ebf-8e7a-0c02403a710f + version: 1 + name: Analyze suspicious URLs and files collected from emails (malware playbook) + description: "1. If you identify a suspicious URL, Download the malicious file + with ‘curl’\n2. Check reputation of file using virustotal and other threat feeds. + \n3. Do a static and dynamic analysis of files using sandbox or SIFT workstation. + \n4. If you find suspicious file, then upload to VT or other AV vendors.\n" + issystemtask: true +- id: "23" + taskid: 71148252-7dfa-442c-8d28-20cb54927a29 + type: regular + task: + id: 71148252-7dfa-442c-8d28-20cb54927a29 + version: 1 + name: 'Option 2: Investigate whether the victim’s PC has been infected by an exploit + kit/drive-by download' + issystemtask: true +- id: "24" + taskid: a4bc2ab7-98b8-493a-8bc2-b06430cf849e + type: regular + task: + id: a4bc2ab7-98b8-493a-8bc2-b06430cf849e + version: 1 + name: Analyze web proxy (or web gateway) logs to find suspicious URL + description: |- + 1. Go to the SIEM + 2. Filter on the proxy logs from the last 3 days + 3. Filter on the username of the affected user (all users should be authenticated to the proxy) + 4. Filter out URLs that has been categorised, you should only have uncategorized URLs on your list. + 5. Export list to CSV + 6. Sort the list by URLs, remove duplicates + 7. Make sure this is attached as artifact to the investigation + issystemtask: true +- id: "25" + taskid: 7c9242cc-71a0-4e72-821d-226ffd2c8921 + type: regular + task: + id: 7c9242cc-71a0-4e72-821d-226ffd2c8921 + version: 1 + name: Analyze the URLs from previous task for malicious URL + description: |- + 1. Check Reputation of all the collected URL against threat feeds like virustotal + 2.. Search for suspicious URLs, such as: + IP address in the URL + Random characters in the hostname of the URL (e.g. http://asdheguhadaasd.com) + URL contains lots of random letters and/or numbers + WordPress sites are involved (wp-content …) + 3. Search for requests to Tor2Web (e.g. https://3fdzgtam4qk625n6.fi/) + 4. Weird User-Agent strings, such as + IE6 (e.g. Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1)) + Programmatic libraries (e.g. python-requests/1.2.0) + dJava (e.g. Java/1.6.0_13) + issystemtask: true +- id: "26" + taskid: e37b3eef-ac20-4ee6-8d71-5edb5a62ee29 + type: regular + task: + id: e37b3eef-ac20-4ee6-8d71-5edb5a62ee29 + version: 1 + name: Analyze the URL in a sandbox + description: "Consider deeper analysis of the URL using sandbox like Cuckoo. \nBased + on the analysis here and the previous step, create the final list of malicious + URL.\n\n" + issystemtask: true +- id: "27" + taskid: b770133f-1b8d-4b29-8fc2-32ac77a2b1a0 + type: regular + task: + id: b770133f-1b8d-4b29-8fc2-32ac77a2b1a0 + version: 1 + name: Get file details from web logs for downloaded files + description: "1. Get the hash for downloaded files. \n2. Check the reputation + of files against threat feeds. \n\n" + issystemtask: true +- id: "28" + taskid: 9fd3ac5d-71d7-4d85-8715-0a0b489ea248 + type: regular + task: + id: 9fd3ac5d-71d7-4d85-8715-0a0b489ea248 + version: 1 + name: 'Go to : Generating IoCs from URLs and Hashes' + description: 'Take the malicious URL and files from this section and generate + IOC using steps in Section: Generating IoCs from URLs and Hashes' + issystemtask: true +- id: "29" + taskid: 207c8a2d-2ec5-418c-86cf-22fa818c8cb9 + type: title + task: + id: 207c8a2d-2ec5-418c-86cf-22fa818c8cb9 + version: 1 + name: Generating IoCs for URLs and Hashes + istitletask: true + issystemtask: true +- id: "30" + taskid: 9ac4e924-5559-455c-852c-d3a67a0a27a0 + type: regular + task: + id: 9ac4e924-5559-455c-852c-d3a67a0a27a0 + version: 1 + name: Generate IOC for malicious URL from SIEM Threat Feed + description: "1. Get the list of flagged URLs/hashes from the Investigation Step\n2. + Check the URL against threat feed (virustotal, IBM Xforce).\n3. Check your SIEM + for threat feeds and see if there are IOC related to the URLs. \n4. Subscribe + to the feed in SIEM. This will install the relevant IoCs into our SIEM automatically.\n5. + If none of the IoCs are on the TI feed, you need to generate IoCs manually in + next step\n" + issystemtask: true +- id: "31" + taskid: cf6fe0f5-fe53-4ba7-80c7-4d6eaf896d2a + type: regular + task: + id: cf6fe0f5-fe53-4ba7-80c7-4d6eaf896d2a + version: 1 + name: Generate IOC for malicious URL manually + description: "1. Go to the proxy logs again\n2. Find 2-3 properties associated + with the flagged URL, such as:\n The request is POST\n The User-Agent + field is dodgy (Java, Python, IE6 etc.)\n URL contains more than 128 random + characters\n URL contains .php\n URL contains lots of slashes (/)\n + \ URL contains WordPress related things (wp-content)\n URL contains dodgy + TLDs (for instance .tk, .ru)\n\n3. Test your assumption on the proxy logs in + the SIEM. Use your pattern and check how many false positives and true positives + it produces.\n4. If the pattern is good enough, append your results to the investigation. + \n\n\n" + issystemtask: true +- id: "32" + taskid: c24a436e-71bb-48e7-89cd-8058fec1d2fb + type: regular + task: + id: c24a436e-71bb-48e7-89cd-8058fec1d2fb + version: 1 + name: Generate IOC from phishing emails + description: "If you find in previous steps that source was phishing email - \n\n1. + Find all the URLs in the email and go through the URL IOC generation steps. + \n2. Find all the attachments for the email and analyze the file using file + IOC generation steps. \n3. If these steps identify files or URL as malicious + - \n extract sender, sending domain and other properties to find emails. + \n use this data to block future emails." + issystemtask: true +- id: "33" + taskid: a91c4be9-cf1b-40b6-861e-5cd4a620cf96 + type: regular + task: + id: a91c4be9-cf1b-40b6-861e-5cd4a620cf96 + version: 1 + name: Deploy the IoCs collected + description: |- + 1. Deploy a new rule to the SIEM, this will alert new infection attempts in the future + 2. Mark the hashes collected as malicious in the SIEM and import this into IOC databases for your enterprise. + 2. Send the patterns to IT and ask IT to block these URLs on the proxy and web gateway + issystemtask: true +- id: "34" + taskid: dcccd78c-a7c6-4a21-8024-24ec6870c979 + type: title + task: + id: dcccd78c-a7c6-4a21-8024-24ec6870c979 + version: 1 + name: Identify other affected devices + istitletask: true + issystemtask: true +- id: "35" + taskid: fe9439ce-8a68-45dc-8a4e-71a97d98072f + type: regular + task: + id: fe9439ce-8a68-45dc-8a4e-71a97d98072f + version: 1 + name: Identify other systems based on URL and hashes + description: "1. Go to SIEM and search for the URL pattern from Generating IOC + step in the proxy logs in order to identify other computers already affected. + \n2. Search for hashes identified in all logs and identify systems associated.\n2. + If you identify other affected PCs with above two steps, create new incident.\n\n" + issystemtask: true +- id: "36" + taskid: e8e246cf-bf4c-47e8-89f5-4f0d1fbf0edb + type: regular + task: + id: e8e246cf-bf4c-47e8-89f5-4f0d1fbf0edb + version: 1 + name: Create new incident with the affected systems + description: 'Create new incidents based on above steps. ' + issystemtask: true +- id: "37" + taskid: 08e01fbf-47af-4926-8cd1-c359cfc94410 + type: title + task: + id: 08e01fbf-47af-4926-8cd1-c359cfc94410 + version: 1 + name: Respond + istitletask: true + issystemtask: true +- id: "38" + taskid: 5b96fdcb-14af-434b-8c89-ebbb3b344145 + type: regular + task: + id: 5b96fdcb-14af-434b-8c89-ebbb3b344145 + version: 2 + name: Notify affected user + description: Notify affected user about the outcome of investigation. + issystemtask: true +- id: "39" + taskid: bcc506a2-1413-43d8-8012-8c1d63f35ecc + type: regular + task: + id: bcc506a2-1413-43d8-8012-8c1d63f35ecc + version: 1 + name: IOC deployment verification + description: 'Make sure that IOC deployment is in place. These are the IOC identified + from previous steps. ' + issystemtask: true +- id: "40" + taskid: b32992a7-f5e0-4b95-8dd2-5c70e938c715 + type: regular + task: + id: b32992a7-f5e0-4b95-8dd2-5c70e938c715 + version: 2 + name: Remove temporary containment measures + description: Remove the temporary containment measures that were placed. + issystemtask: true +- id: "41" + taskid: 35c0d3b2-d9cd-460c-88be-6d7a229e9906 + type: regular + task: + id: 35c0d3b2-d9cd-460c-88be-6d7a229e9906 + version: 2 + name: Provide end-user remediation guidance and link to training + issystemtask: true +- id: "42" + taskid: f68ec944-041d-4288-80fd-d4593bceb52b + type: condition + task: + id: f68ec944-041d-4288-80fd-d4593bceb52b + version: 2 + name: Is the identified malware known? (with automated remediation steps) + issystemtask: true + condition: + "no": + - id: "43" + taskid: f13d62e8-15a2-4240-8245-9537c0c7aa83 + type: regular + task: + id: f13d62e8-15a2-4240-8245-9537c0c7aa83 + version: 2 + name: Document manual remediation steps + issystemtask: true + "yes": + - id: "44" + taskid: 91223da8-3e5b-432e-85d6-b05a8e614f83 + type: regular + task: + id: 91223da8-3e5b-432e-85d6-b05a8e614f83 + version: 2 + name: Trigger remediation scripts + issystemtask: true +- id: "45" + taskid: 36ba1145-5eb5-4bc4-85f6-d5c9f4495cca + type: condition + task: + id: 36ba1145-5eb5-4bc4-85f6-d5c9f4495cca + version: 2 + name: Was remediation successful? + issystemtask: true + condition: + "no": + - id: "46" + taskid: c56d39eb-e583-4183-8b18-12e9d0547c17 + type: regular + task: + id: c56d39eb-e583-4183-8b18-12e9d0547c17 + version: 2 + name: Reimage the entire system and restore from backup + issystemtask: true + "yes": [] +system: true diff --git a/Playbooks/playbook-unknown-binary-analysis.yml b/Playbooks/playbook-unknown-binary-analysis.yml new file mode 100644 index 000000000000..3cf399cc0b04 --- /dev/null +++ b/Playbooks/playbook-unknown-binary-analysis.yml @@ -0,0 +1,104 @@ +id: playbook4 +version: 1 +name: Unknown Binary Analysis playbook +description: This playbook provides tools for analyzing an unknown binary file discovered + on our network. +tasks: +- id: "1" + taskid: f61f3880-e5f6-4a41-8af8-3349e3ebffff + type: title + task: + id: f61f3880-e5f6-4a41-8af8-3349e3ebffff + version: 4 + name: Engage + istitletask: true + issystemtask: true +- id: "2" + taskid: c125cda9-bd9d-4e8c-8b25-b7d0171254f2 + type: regular + task: + id: c125cda9-bd9d-4e8c-8b25-b7d0171254f2 + version: 1 + name: Initial triage + description: 1. Make sure that there is relevant information in the incident - + either there is a file attached to the incident or there is a hash in the incident + issystemtask: true +- id: "3" + taskid: cd85115e-4379-4319-853b-f518e9aa98bc + type: regular + task: + id: cd85115e-4379-4319-853b-f518e9aa98bc + version: 3 + name: Assess severity + description: 'Based on the end user affected, and other information assess and + change the severity if needed. ' + issystemtask: true +- id: "4" + taskid: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + type: regular + task: + id: 8135a8aa-6d2c-4cf1-80c4-c5cf4bf136a8 + version: 3 + name: Assign and involve appropriate personnel + description: 'Invite the relevant users for investigation - malware expert and + network experts if needed. ' + issystemtask: true +- id: "5" + taskid: 69b90798-0528-4dd8-8305-bc94bde2e380 + type: title + task: + id: 69b90798-0528-4dd8-8305-bc94bde2e380 + version: 1 + name: Investigation for the unknown binary + istitletask: true + issystemtask: true +- id: "6" + taskid: f054078c-7ba9-4d6d-8920-41cba166e996 + type: regular + task: + id: f054078c-7ba9-4d6d-8920-41cba166e996 + version: 1 + name: Check Reputation of the binary + description: 'Perform various file reputation lookups (e.g. virustotal) for the + hash. ' + script: FileReputation + issystemtask: true +- id: "7" + taskid: 16908eeb-ded8-4c67-8b00-109b06fce2cf + type: regular + task: + id: 16908eeb-ded8-4c67-8b00-109b06fce2cf + version: 1 + name: Search the hash of file across infrastructure + description: | + Perform search across the fleet using CB API. + script: CBSearch + issystemtask: true +- id: "8" + taskid: b1ce179a-cafb-42e0-8322-fa91379b6825 + type: regular + task: + id: b1ce179a-cafb-42e0-8322-fa91379b6825 + version: 1 + name: Detonate the file in a sandbox + description: "Integrate with wildfire to allow for executable detonation. \n" + script: WildfireReport + issystemtask: true +- id: "9" + taskid: ba6946cc-e633-4fc0-8455-5454f668e080 + type: regular + task: + id: ba6946cc-e633-4fc0-8455-5454f668e080 + version: 1 + name: Generate IOC/Yara for binary + description: 'Generate signatures (e.g. yara, IOC, etc) ' + issystemtask: true +- id: "10" + taskid: 780b78e3-687e-44ea-83c5-95a138e30cad + type: regular + task: + id: 780b78e3-687e-44ea-83c5-95a138e30cad + version: 1 + name: Block the binary across systems + issystemtask: true +system: true \ No newline at end of file diff --git a/Reports/report-criticalAndHighIncidentsReport.json b/Reports/report-criticalAndHighIncidentsReport.json new file mode 100644 index 000000000000..15cd54bfbade --- /dev/null +++ b/Reports/report-criticalAndHighIncidentsReport.json @@ -0,0 +1,362 @@ +{ + "id": "criticalAndHighIncidentsReport", + "name": "Critical and High incidents", + "description": "All critical and high severity incidents that may need the analyst attention.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Critical and High incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true, + "totalOnly": true + } + }, + "data": "Total open incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Critical and High Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "level": [3, 4], + "andOp": true + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-dailyIncidentReport.json b/Reports/report-dailyIncidentReport.json new file mode 100644 index 000000000000..a1daeae01f6f --- /dev/null +++ b/Reports/report-dailyIncidentReport.json @@ -0,0 +1,383 @@ +{ + "id": "dailyIncidentReport", + "name": "Daily incidents", + "description": "Daily summary of incidents statistics, followed by a list of all current open incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Daily Incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "totalOnly": true + } + }, + "data": "Total incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "sectionStyle": { + "width": 200 + }, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Last day incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last24HoursClosedIncidentsReport.json b/Reports/report-last24HoursClosedIncidentsReport.json new file mode 100644 index 000000000000..85fe5a156392 --- /dev/null +++ b/Reports/report-last24HoursClosedIncidentsReport.json @@ -0,0 +1,392 @@ +{ + "id": "last24HoursClosedIncidentsReport", + "name": "Last 24 hours closed incidents", + "description": "All closed incidents in the last 24 hours. Counts of types, severity, SLAs and analysts work, and a list of all closed incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 24 hours closed incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "status": [2], + "andOp": true, + "totalOnly": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "data": "Last 24 hours closed incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Closed incidents in the last 24 hours", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "status": [2], + "andOp": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "closed" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last24HoursIncidentReport.json b/Reports/report-last24HoursIncidentReport.json new file mode 100644 index 000000000000..b5d52b887ea9 --- /dev/null +++ b/Reports/report-last24HoursIncidentReport.json @@ -0,0 +1,419 @@ +{ + "id": "last24HoursIncidentReport", + "name": "Last 24 hours incidents", + "description": "Last 24 hours summary of incidents statistics, followed by a list of all current open incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 24 hours incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "totalOnly": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Total incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "sectionStyle": { + "width": 200 + }, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Last 24 hours incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "period": { + "by": "hour", + "fromValue": 24, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last30DaysClosedIncidentsReport.json b/Reports/report-last30DaysClosedIncidentsReport.json new file mode 100644 index 000000000000..6660546289d8 --- /dev/null +++ b/Reports/report-last30DaysClosedIncidentsReport.json @@ -0,0 +1,392 @@ +{ + "id": "last30DaysClosedIncidentsReport", + "name": "Last 30 days closed incidents", + "description": "All closed incidents in the last 30 days. Counts of types, severity, SLAs and analysts work, and a list of all closed incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 30 days closed incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "status": [3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "data": "Last 30 days closed incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "status": [3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "status": [3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "status": [3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Closed incidents in the last 30 days", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "status": [3], + "andOp": true, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "closed" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last30DaysIncidentReport.json b/Reports/report-last30DaysIncidentReport.json new file mode 100644 index 000000000000..0fedf69b3aea --- /dev/null +++ b/Reports/report-last30DaysIncidentReport.json @@ -0,0 +1,419 @@ +{ + "id": "last30DaysIncidentReport", + "name": "Last 30 days incidents", + "description": "Last 30 days summary of incidents statistics, followed by a list of all current open incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 30 days incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Total incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "sectionStyle": { + "width": 200 + }, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Last 30 days incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "period": { + "by": "day", + "fromValue": 30, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last7DaysClosedIncidentsReport.json b/Reports/report-last7DaysClosedIncidentsReport.json new file mode 100644 index 000000000000..9a1fe679d809 --- /dev/null +++ b/Reports/report-last7DaysClosedIncidentsReport.json @@ -0,0 +1,390 @@ +{ + "id": "last7DaysClosedIncidentsReport", + "name": "Last 7 days closed incidents", + "description": "All closed incidents in the last 7 days. Counts of types, severity, SLAs and analysts work, and a list of all closed incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 7 days closed incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "status": [2], + "andOp": true, + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "closed" + } + } + }, + "data": "Last 7 days closed incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "status": [2], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Closed incidents in the last 7 days", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "status": [2], + "andOp": true, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "closed" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "closed" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-last7DaysIncidentReport.json b/Reports/report-last7DaysIncidentReport.json new file mode 100644 index 000000000000..666cc9b08c6f --- /dev/null +++ b/Reports/report-last7DaysIncidentReport.json @@ -0,0 +1,419 @@ +{ + "id": "last7DaysIncidentReport", + "name": "Last 7 days incidents", + "description": "Last 7 days summary of incidents statistics, followed by a list of all current open incidents.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Last 7 days incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Total incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "sectionStyle": { + "width": 200 + }, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "data": "Last 7 days incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "period": { + "by": "day", + "fromValue": 7, + "toValue": 0, + "field": "created" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-lateIncidentsReport.json b/Reports/report-lateIncidentsReport.json new file mode 100644 index 000000000000..8d255aa873c5 --- /dev/null +++ b/Reports/report-lateIncidentsReport.json @@ -0,0 +1,386 @@ +{ + "id": "lateIncidentsReport", + "name": "Late Incidents", + "description": "All the incidents that passed their SLA due date and the incidents that are at risk to soon pass their SLA.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Late Incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "data": "Total late incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Late incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "period": { + "by": "day", + "toValue": 0, + "field": "dueDate" + } + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-openIncidentsReport.json b/Reports/report-openIncidentsReport.json new file mode 100644 index 000000000000..485ed6ba31ae --- /dev/null +++ b/Reports/report-openIncidentsReport.json @@ -0,0 +1,356 @@ +{ + "id": "openIncidentsReport", + "name": "Open Incidents", + "description": "List and statistics of the current open incidents including type and severity distribution and SLA compliance.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": true + } + }, + "data": "Total open incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Open Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "andOp": true + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Reports/report-unknownIncidentsReport.json b/Reports/report-unknownIncidentsReport.json new file mode 100644 index 000000000000..21b35c74d83b --- /dev/null +++ b/Reports/report-unknownIncidentsReport.json @@ -0,0 +1,362 @@ +{ + "id": "unknownIncidentsReport", + "name": "Unknown severity incidents", + "description": "Report about all unknown severity incidents that may need the analyst attention.", + "tags": [], + "createdBy": "Demisto", + "type": "pdf", + "orientation": "portrait", + "recipients": [], + "system": true, + "decoder": { + "incident.status.0": { "type": "string", "value": "Not Assigned" }, + "incident.status.1": { "type": "string", "value": "Assigned" }, + "incident.status.2": { "type": "string", "value": "Done" }, + "incident.status.3": { "type": "string", "value": "Closed" }, + "incident.status.4": { "type": "string", "value": "On Hold" }, + "incident.severity.0": { "type": "string", "value": "Unknown" }, + "incident.severity.1": { "type": "string", "value": "Low" }, + "incident.severity.2": { "type": "string", "value": "Medium" }, + "incident.severity.3": { "type": "string", "value": "High" }, + "incident.severity.4": { "type": "string", "value": "Critical" }, + "incident.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.occurred": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.activated": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.dueDate": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "incident.reminder": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.status.0": { "type": "string", "value": "Active" }, + "investigation.status.1": { "type": "string", "value": "Done" }, + "investigation.type.0": { "type": "string", "value": "Standard" }, + "investigation.type.1": { "type": "string", "value": "Restricted" }, + "investigation.type.9": { "type": "string", "value": "Playground" }, + "investigation.created": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.closed": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" }, + "investigation.openDuration": { "type": "date", "value": "Mon, 02 Jan 2006 15:04:05 MST" } + }, + "sections": [ + { + "type": "header", + "data": "Unknown severity incidents", + "layout": { + "rowPos": 1, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 28 + } + } + }, + { + "type": "date", + "layout": { + "rowPos": 2, + "columnPos": 1, + "style": { + "textAlign": "left", + "color": "gray", + "fontSize": 13, + "fontStyle": "italic", + "marginBottom:": 12 + }, + "format": "MMMM Do YYYY, h:mm:ss a" + } + }, + { + "type": "placeholder", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true, + "totalOnly": true + } + }, + "data": "Total open incidents: {0}", + "layout": { + "rowPos": 3, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "divider", + "layout": { + "rowPos": 4, + "style": { + } + } + }, + { + "type": "text", + "data": "Severity", + "layout": { + "rowPos": 5, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Type", + "layout": { + "rowPos": 5, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["severity"], + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12, + "marginTop": -10 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "Critical", "fill": "#8d070a" }, + { "name": "High", "fill": "#D00a00" }, + { "name": "Medium", "fill": "#cb4a00" }, + { "name": "Low", "fill": "#267634" }, + { "name": "Unknown", "fill": "#999999" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["type"], + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 6, + "columnPos": 2, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 220 + }, + "chartProperties" : { + "cy": 75, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "sortBy": { + "values": ["value", "name"], + "orders": ["desc", "asc"] + }, + "legend": [ + { "name": "C2Communication", "fill": "#853732" }, + { "name": "Default", "fill": "#3aabe8" }, + { "name": "DeviceLost", "fill": "#5fa54a" }, + { "name": "Malware", "fill": "#4f8aab" }, + { "name": "Phishing", "fill": "#4f854a" }, + { "name": "Ransomware", "fill": "#5b4185" }, + { "name": "UnknownBinary", "fill": "#4faa5b" } + ] + } + }, + { + "type": "text", + "data": "SLA", + "layout": { + "rowPos": 7, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "text", + "data": "Analyst", + "layout": { + "rowPos": 7, + "columnPos": 2, + "style": { + "textAlign": "left", + "fontSize": 16, + "fontWeight": "bold" + } + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["dueDate"], + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 1, + "chartType": "pie", + "style": { + "textAlign": "left", + "fontSize": 12 + }, + "dimensions": { + "width": 300, + "height": 180 + }, + "chartProperties" : { + "cy": 75, + "cx": 155, + "startAngle": 90, + "endAngle": -270, + "outerRadius": 60, + "innerRadius": 40, + "labelLine": false, + "label": { "offsetRadius": 10 } + }, + "legendStyle": { + "align": "left", + "layout": "vertical", + "verticalAlign": "top", + "iconSize": 10 + }, + "legend": [ + { "name": "late", "fill": "red" }, + { "name": "risk", "fill": "orange" }, + { "name": "within", "fill": "green" } + ] + } + }, + { + "type": "chart", + "query": { + "type": "incident", + "groupBy": ["owner"], + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true, + "totalOnly": false + } + }, + "layout": { + "rowPos": 8, + "columnPos": 2, + "chartType": "bar", + "style": { + "textAlign": "left", + "fontSize": 10, + "marginLeft": -15 + }, + "chartProperties" : { + "layout": "vertical", + "strokeDasharray": "3 300", + "barSize": 13 + }, + "dimensions": { + "width": 300, + "height": 200 + }, + "legend": [ + { "name": "Busy Analyst", "fill": "#2884d1", "bar": 1 } + ] + } + }, + { + "type": "header", + "data": "Unknown Incidents", + "layout": { + "rowPos": 9, + "columnPos": 1, + "style": { + "textAlign": "left", + "fontSize": 18 + } + } + }, + { + "type": "table", + "query": { + "type": "incident", + "filter": { + "notStatus": [2, 3], + "level": [0], + "andOp": true + } + }, + "layout": { + "rowPos": 10, + "columnPos": 1, + "tableColumns": ["name", "occurred", "type", "owner", "severity", "status", "dueDate" ], + "classes": "striped stackable small very compact" + } + } + ] +} diff --git a/Scripts/ADGetComputerGroups.py b/Scripts/ADGetComputerGroups.py new file mode 100644 index 000000000000..2174a29be7ac --- /dev/null +++ b/Scripts/ADGetComputerGroups.py @@ -0,0 +1,24 @@ +# Optional arguments and default values +attrs = 'name' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] + +memberDN = '' +if demisto.get(demisto.args(), 'dn'): + memberDN = demisto.args()['dn'] +elif demisto.get(demisto.args(), 'name'): + resp = demisto.executeCommand('ad-search', {'filter':"(&(objectCategory=Computer)(name=" + demisto.args()['name']+"))"}) + if type(resp)==list and len(resp)==1 and type(resp[0])==dict and 'Contents' in resp[0] and type(resp[0]['Contents'])==list and len(resp[0]['Contents'])==1 and type(resp[0]['Contents'][0])==dict and 'dn' in resp[0]['Contents'][0]: + memberDN = resp[0]['Contents'][0]['dn'] + else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from ad command.' } ) + sys.exit(0) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'You must provide either dn or name as argument!' } ) + sys.exit(0) + +if memberDN: + filterstr = r"(&(member=" + memberDN + ")(objectcategory=group))" + demisto.results( demisto.executeCommand( 'ad-search' , { 'filter' : filterstr, 'attributes' : attrs } ) ) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Computer not found.' } ) diff --git a/Scripts/ADGetEmailForUser.py b/Scripts/ADGetEmailForUser.py new file mode 100644 index 000000000000..f21336fba87a --- /dev/null +++ b/Scripts/ADGetEmailForUser.py @@ -0,0 +1,24 @@ +# Optional arguments and default values +attrs = 'name,displayname,mail' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] + +memberDN = '' +if demisto.get(demisto.args(), 'dn'): + memberDN = demisto.args()['dn'] +elif demisto.get(demisto.args(), 'name'): + resp = demisto.executeCommand( 'ad-search', { 'filter' : "(&(objectClass=User)(name=" + demisto.args()['name'] + "))" } ) + if type(resp)==list and len(resp)==1 and type(resp[0])==dict and 'Contents' in resp[0] and type(resp[0]['Contents'])==list and len(resp[0]['Contents'])==1 and type(resp[0]['Contents'][0])==dict and 'dn' in resp[0]['Contents'][0]: + memberDN = resp[0]['Contents'][0]['dn'] + else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from ad command.' } ) + sys.exit(0) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'You must provide either dn or name as argument!' } ) + sys.exit(0) + +if memberDN: + filterstr = r"(&(objectClass=User)(distinguishedName=" + memberDN + "))" + demisto.results( demisto.executeCommand( 'ad-search' , { 'filter' : filterstr, 'attributes' : attrs } ) ) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'User not found.' } ) diff --git a/Scripts/ADGetGroupComputers.py b/Scripts/ADGetGroupComputers.py new file mode 100644 index 000000000000..2127dab99b35 --- /dev/null +++ b/Scripts/ADGetGroupComputers.py @@ -0,0 +1,7 @@ +# Optional arguments and default values +attrs = 'name' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] + +filterstr = r"(&(objectCategory=Computer)(memberof=" + demisto.args()['groupdn'] + "))" +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : filterstr, 'attributes' : attrs } ) ) diff --git a/Scripts/ADGetGroupUsers.py b/Scripts/ADGetGroupUsers.py new file mode 100644 index 000000000000..7193f1e3486a --- /dev/null +++ b/Scripts/ADGetGroupUsers.py @@ -0,0 +1,7 @@ +# Optional arguments and default values +attrs = 'name,displayname' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] + +filterstr = r"(&(objectCategory=User)(memberof=" + demisto.args()['groupdn'] + "))" +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : filterstr, 'attributes' : attrs } ) ) diff --git a/Scripts/ADGetUserGroups.py b/Scripts/ADGetUserGroups.py new file mode 100644 index 000000000000..f18de50471df --- /dev/null +++ b/Scripts/ADGetUserGroups.py @@ -0,0 +1,35 @@ +# Optional arguments and default values +attrs = 'name' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] +resp = '' +memberDN = '' +if demisto.get(demisto.args(), 'dn'): + memberDN = demisto.args()['dn'] +elif demisto.get(demisto.args(), 'name'): + resp = demisto.executeCommand( 'ad-search', { 'filter' : "(&(objectCategory=User)(name=" + demisto.args()['name'] + "))" } ) +elif demisto.get(demisto.args(), 'email'): + resp = demisto.executeCommand( 'ADGetUsersByEmail', { 'email' : demisto.args()['email'] } ) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'You must provide either dn, name or email as argument!' } ) + sys.exit(0) + +if type(resp)==list and len( [ r for r in resp if isError(r) ] ) > 0 : + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Error returned by ad command: ' + r['Contents'] } ) + sys.exit(0) + +if not memberDN: + if type(resp)==list and len(resp)==1 and type(resp[0])==dict and 'Contents' in resp[0] and type(resp[0]['Contents'])==list and len(resp[0]['Contents'])==1 and type(resp[0]['Contents'][0])==dict and 'dn' in resp[0]['Contents'][0]: + memberDN = resp[0]['Contents'][0]['dn'] + else: + if resp[0]['Contents'] == 'No results': + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'User not found.' } ) + else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from ad command.' } ) + sys.exit(0) + +if memberDN: + filterstr = r"(&(member=" + memberDN + ")(objectcategory=group))" + demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : filterstr, 'attributes' : attrs } ) ) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Received empty DN or cannot locate DN for the specified arguments.' } ) diff --git a/Scripts/ADGetUsersByEmail.py b/Scripts/ADGetUsersByEmail.py new file mode 100644 index 000000000000..b829ccd9471a --- /dev/null +++ b/Scripts/ADGetUsersByEmail.py @@ -0,0 +1,8 @@ +# Optional arguments and default values +attrs = 'name,displayname,mail' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] + +email = demisto.args()['email'] +filterstr = r"(&(objectClass=user)(mail=" + email + "))" +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : filterstr, 'attributes' : attrs } ) ) diff --git a/Scripts/ADIsUserMember.py b/Scripts/ADIsUserMember.py new file mode 100644 index 000000000000..cf082c0550c4 --- /dev/null +++ b/Scripts/ADIsUserMember.py @@ -0,0 +1,13 @@ +resp = demisto.executeCommand( 'ADGetUserGroups', demisto.args() ) +try: + if not isError(resp[0]): + for d in resp[0]['Contents']: + if demisto.args()['groupname'] == d['name']: + demisto.results("yes") + sys.exit(0) + demisto.results("no") + else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Error returned from ADGetUserGroups:\n' + resp[0]['Contents'] } ) +except Exception, ex: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Error occurred while parsing output from ADGetUserGroups. Exception info:\n' + str(ex) + '\n\nInvalid output:\n' + str( resp ) } ) + diff --git a/Scripts/ADListComputers.py b/Scripts/ADListComputers.py new file mode 100644 index 000000000000..fa09974512a8 --- /dev/null +++ b/Scripts/ADListComputers.py @@ -0,0 +1,5 @@ +# Optional arguments and default values +attrs = 'name' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : "(objectCategory=Computer)", 'attributes' : attrs } ) ) diff --git a/Scripts/ADListUsers.py b/Scripts/ADListUsers.py new file mode 100644 index 000000000000..078aae3d4789 --- /dev/null +++ b/Scripts/ADListUsers.py @@ -0,0 +1,5 @@ +# Optional arguments and default values +attrs = 'name,displayname' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : "(objectClass=User)", 'attributes' : attrs } ) ) diff --git a/Scripts/ADListUsersEx.py b/Scripts/ADListUsersEx.py new file mode 100644 index 000000000000..e926da9d1111 --- /dev/null +++ b/Scripts/ADListUsersEx.py @@ -0,0 +1,5 @@ +# Optional arguments and default values +attrs = 'name,displayname,memberOf,lastlogon,lastlogoff,logoncount,badPasswordTime,badPwdCount,lastLogonTimestamp,pwdLastSet,whenCreated,whenChanged' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] +demisto.results( demisto.executeCommand( 'ad-search', { 'filter' : "(objectClass=User)", 'attributes' : attrs } ) ) diff --git a/Scripts/ADUserLogonInfo.py b/Scripts/ADUserLogonInfo.py new file mode 100644 index 000000000000..57cbe0e03d8e --- /dev/null +++ b/Scripts/ADUserLogonInfo.py @@ -0,0 +1,46 @@ +# Optional arguments and default values +attrs = 'name,displayname,lastlogon,lastlogoff,logoncount,badPasswordTime,badPwdCount,lastLogonTimestamp,pwdLastSet,whenCreated,whenChanged,memberOf' +if demisto.get(demisto.args(), 'attributes'): + attrs += "," + demisto.args()['attributes'] +userDN = '' +resp = '' +if demisto.get(demisto.args(), 'dn'): + userDN = demisto.args()['dn'] +elif demisto.get(demisto.args(), 'name'): + resp = demisto.executeCommand( 'ad-search', { 'filter' : "(&(objectCategory=User)(name=" + demisto.args()['name'] + "))" } ) +elif demisto.get(demisto.args(), 'email'): + resp = demisto.executeCommand( 'ADGetUsersByEmail', { 'email' : demisto.args()['email'] } ) +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'You must provide either dn, name or email as argument!' } ) + sys.exit(0) + +if type(resp)==list and len( [ r for r in resp if isError(r) ] ) > 0 : + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Error returned by ad command: ' + r['Contents'] } ) + sys.exit(0) + +if type(resp)==list and len(resp)==1 and type(resp[0])==dict and 'Contents' in resp[0] and type(resp[0]['Contents'])==list and len(resp[0]['Contents'])==1 and type(resp[0]['Contents'][0])==dict and 'dn' in resp[0]['Contents'][0]: + userDN = resp[0]['Contents'][0]['dn'] +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from ad command.' } ) + sys.exit(0) + +if userDN: + filterstr = r"(&(objectClass=User)(distinguishedName=" + userDN + "))" + resAD = demisto.executeCommand( 'ad-search', { 'filter' : filterstr, 'attributes' : attrs } ) + try: + for m in resAD: + if isError(m): + continue + for f in [ 'lastlogon' , 'lastlogoff' , 'pwdLastSet' , 'badPasswordTime' , 'lastLogonTimestamp' ]: + if m['Contents'][0][f] == "0": + m['Contents'][0][f] = "N/A" + else: + m['Contents'][0][f] = FormatADTimestamp( m['Contents'][0][f] ) + for f in [ 'whenChanged' , 'whenCreated' ]: + m['Contents'][0][f] = PrettifyCompactedTimestamp( m['Contents'][0][f] ) + demisto.results ( resAD ) + except: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Error occurred while parsing output from ad command. Invalid output:\n' + str( resAD ) } + +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'User not found.' } ) diff --git a/Scripts/CBAlerts.py b/Scripts/CBAlerts.py new file mode 100644 index 000000000000..a29717b704d4 --- /dev/null +++ b/Scripts/CBAlerts.py @@ -0,0 +1,14 @@ +# args: same as cb-alert +res = [] +resCmd1 = demisto.executeCommand("cb-alert", demisto.args()) +for entry in resCmd1: + if isError(entry): + res.append(entry) + else: + matches = entry["Contents"]["results"] + if matches: + formattedMatches = [{ k: json.dumps(m[k]) if type(m[k])==dict else m[k] for k in m } for m in matches] + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["table"], "Contents" : formattedMatches } ) + else: + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["text"], "Contents" : "No matches." } ) +demisto.results(res) diff --git a/Scripts/CBPApproveHash.py b/Scripts/CBPApproveHash.py new file mode 100644 index 000000000000..beb77997a891 --- /dev/null +++ b/Scripts/CBPApproveHash.py @@ -0,0 +1,2 @@ +CBP_HASH_APPROVED = '2' +demisto.results(demisto.executeCommand("cbp-fileRule-update", {"fileState": CBP_HASH_APPROVED,"hash": demisto.args()["hash"]})) diff --git a/Scripts/CBPBanHash.py b/Scripts/CBPBanHash.py new file mode 100644 index 000000000000..628d12526359 --- /dev/null +++ b/Scripts/CBPBanHash.py @@ -0,0 +1,2 @@ +CBP_HASH_BANNED = '3' +demisto.results(demisto.executeCommand("cbp-fileRule-update", {"fileState": CBP_HASH_BANNED, "hash": demisto.args()["hash"]})) diff --git a/Scripts/CBPFindComputer.py b/Scripts/CBPFindComputer.py new file mode 100644 index 000000000000..68ad1aabae61 --- /dev/null +++ b/Scripts/CBPFindComputer.py @@ -0,0 +1,16 @@ +# query syntax is according to Carbon Black Enterprise Protection query language documented in https://developer.carbonblack.com/reference/enterprise-protection/7.2/rest-api/#query-condition - e.g. "name:*srv*" +res = [] +dArgs = demisto.args() +if not "limit" in demisto.args(): + dArgs["limit"] = "10" +resCmd1 = demisto.executeCommand("cbp-computer-search", dArgs) +for entry in resCmd1: + if isError(entry): + res.append(entry) + else: + matches = entry["Contents"] + if matches: + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["table"], "Contents" : matches } ) + else: + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["text"], "Contents" : "No matches." } ) +demisto.results(res) diff --git a/Scripts/CBPFindRule.py b/Scripts/CBPFindRule.py new file mode 100644 index 000000000000..579c461a483e --- /dev/null +++ b/Scripts/CBPFindRule.py @@ -0,0 +1,11 @@ +STATES = { 1: "Unapproved", 2: "Approved", 3: "Banned" } +res = [] +limit = demisto.args()["limit"] if "limit" in demisto.args() else "10" +resSearch = demisto.executeCommand("cbp-fileRule-search", { "query": "hash:" + demisto.args()["hash"] }) +for entry in resSearch: + if isError(entry): + res.append(entry) + else: + for rule in entry["Contents"]: + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["markdown"], "Contents" : "Hash " + rule["hash"] + " is in state **" + STATES[rule["fileState"]] + "**" } ) +demisto.results(res) diff --git a/Scripts/CBWatchlists.py b/Scripts/CBWatchlists.py new file mode 100644 index 000000000000..afae8bbfd649 --- /dev/null +++ b/Scripts/CBWatchlists.py @@ -0,0 +1,18 @@ +# args: id - Optional - only show the watchlist with this specific ID +cols = ['name','search_query','id','enabled','search_timestamp','last_hit','last_hit_count','total_hits'] +fullcols = ['alliance_id', 'date_added', 'enabled', 'from_alliance', 'group_id', 'id', 'index_type', 'last_hit', 'last_hit_count', 'name', 'readonly', 'search_query', 'search_timestamp', 'total_hits', 'total_tags'] +res = [] +resCmd1 = demisto.executeCommand("cb-watchlist-get", {"watchlist-id" : demisto.args()["id"]} if "id" in demisto.args() else {}) +for entry in resCmd1: + if isError(entry): + res.append(entry) + else: + matches = entry["Contents"] + if matches: + if type(matches)==dict: + matches = [matches] + filtered_matches = [{ k: m[k] for k in cols if k in m } for m in matches] + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["table"], "Contents" : filtered_matches } ) + else: + res.append( { "Type" : entryTypes["note"], "ContentsFormat" : formats["text"], "Contents" : "No matches." } ) +demisto.results(res) diff --git a/Scripts/CloseInvestigation.py b/Scripts/CloseInvestigation.py new file mode 100644 index 000000000000..0b8e8547721c --- /dev/null +++ b/Scripts/CloseInvestigation.py @@ -0,0 +1,4 @@ +dArgs = {} +if demisto.get(demisto.args(), 'reason'): + dArgs['reason_What-happened'] = demisto.args()['reason'] +demisto.results(demisto.executeCommand('closeInvestigation', dArgs)) diff --git a/Scripts/ConferIncidentDetails.py b/Scripts/ConferIncidentDetails.py new file mode 100644 index 000000000000..704bc059f168 --- /dev/null +++ b/Scripts/ConferIncidentDetails.py @@ -0,0 +1,38 @@ +import time + +def formatDate(t): + if t: + return time.ctime(t / 1000) + return '' + +incDetails = demisto.incidents()[0]['details'] +if incDetails: + try: + inc = json.loads(incDetails) + res = '## Confer Incident Details' + res += '\n\nID: **' + demisto.gets(inc, 'threatInfo.incidentId') + '**' + res += '\nTime: **' + formatDate(demisto.get(inc, 'eventTime')) + '**' + res += '\nType: **' + demisto.gets(inc, 'type') + '**' + res += '\nEvent ID: **' + demisto.gets(inc, 'eventId') + '**' + res += '\nScore: **' + demisto.gets(inc, 'threatInfo.score') + '**' + res += '\nURL: **' + demisto.gets(inc, 'url') + '**' + res += '\n### Indicators' + ind = demisto.get(inc, 'threatInfo.indicators') + if ind: + res += '\nIndicator Name | Application Name | SHA256' + res += '\n-------------- | ---------------- | ------' + for i in ind: + res += '\n ' + demisto.gets(i, 'indicatorName') + ' | ' + demisto.gets(i, 'applicationName') + ' | ' + demisto.gets(i, 'sha256Hash') + dev = demisto.get(inc, 'deviceInfo') + if dev: + res += '\n### Device Info' + res += '\nID | Type | Name | Version | Email | Priority | Group Name | External IP' + res += '\n-- | ---- | ---- | ------- | ----- | -------- | ---------- | -----------' + res += '\n' + demisto.gets(dev, 'deviceId') + ' | ' + demisto.gets(dev, 'deviceType') + ' | ' + demisto.gets(dev, 'deviceName') + ' | ' + \ + demisto.gets(dev, 'deviceVersion') + ' | ' + demisto.gets(dev, 'email') + ' | ' + demisto.gets(dev, 'targetPriorityType') + ' | ' + \ + demisto.gets(dev, 'groupName') + ' | ' + demisto.gets(dev, 'externalIpAddress') + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) + except: + demisto.results('Incident details are not JSON') +else: + demisto.results('No details were found for the incident') diff --git a/Scripts/ConferSetSeverity.py b/Scripts/ConferSetSeverity.py new file mode 100644 index 000000000000..018f66640180 --- /dev/null +++ b/Scripts/ConferSetSeverity.py @@ -0,0 +1,29 @@ +# Severity levels are 4 - Critical, 3 - High, 2 - Medium, 1 - Low, 0 - Unknown +levelDict = {'DETECTED_MALWARE_APP': 3, 'FILELESS': 3, 'KNOWN_APT': 3, 'KNOWN_BACKDOOR': 3, 'KNOWN_DOWNLOADER': 3, 'KNOWN_DROPPER': 3, 'KNOWN_KEYLOGGER': 3, 'KNOWN_PASSWORD_STEALER': 3, \ + 'KNOWN_RANSOMWARE': 3, 'KNOWN_ROGUE': 3, 'KNOWN_ROOTKIT': 3, 'KNOWN_WORM': 3, 'MALWARE_APP': 3, 'RUN_MALWARE_APP': 3, 'MALWARE_DROP': 3, 'COMPANY_BLACKLIST': 3, \ + 'PHONE_HOME': 2, 'INJECT_CODE': 2, 'GET_CONTACTS': 2, 'FILE_TRANSFER': 2, 'CODE_DROP': 2, 'RUN_CMD_SHELL': 2, 'COMPROMISED_PROCESS': 2, 'BUFFER_OVERFLOW_CALL': 2, \ + 'ENUMERATE_PROCESSES': 2, 'FIXED_PORT_LISTEN': 2, 'HAS_PUP_CODE': 2, 'RUN_BROWSER': 2, 'BEACON': 2, 'REVERSE_SHELL': 2, 'MODIFY_KERNEL': 2, 'HAS_PACKED_CODE': 2, \ + 'PACKED_CALL': 2, 'MODIFY_SERVICE': 2, 'RUN_SYSTEM_APP': 2, 'RUN_ANOTHER_APP': 2, 'MODIFY_OWN_PROCESS': 2, 'INJECT_INPUT': 2, 'RAM_SCRAPING': 2, 'READ_SECURITY_DATA': 2, \ + 'HAS_BUFFER_OVERFLOW': 2, 'MODIFY_PROCESS': 2, 'HAS_SCRIPT_DLL': 2, 'ACTIVE_SERVER': 2, 'PERSIST': 2, 'SET_APP_LAUNCH': 2, 'RUN_PUP_APP': 2, 'INTERNATIONAL_SITE': 1, \ + 'SUSPICIOUS_SITE': 1, 'DETECTED_SUSPECT_APP': 1, 'LOW_REPUTATION_SITE': 1, 'IRC': 1, 'UNKNOWN_APP': 1, 'SUSPICIOUS_DOMAIN': 1, 'SUSPICIOUS_BEHAVIOR': 1, 'HAS_SUSPECT_CODE': 1, \ + 'ACCESS_EMAIL_DATA': 1, 'NETWORK_ACCESS': 1} +levelTranslate = {4: 'Critical', 3: 'High', 2: 'Medium', 1: 'Low', 0: 'Unknown'} +incDetails = demisto.incidents()[0]['details'] +if incDetails: + try: + inc = json.loads(incDetails) + ind = demisto.get(inc, 'threatInfo.indicators') + maxLevel = 0 + if ind: + for i in ind: + level = levelDict[demisto.gets(i, 'indicatorName')] + if level and level > maxLevel: + maxLevel = level + demisto.executeCommand('setSeverity', {'id': demisto.incidents()[0]['id'], 'severity': levelTranslate[maxLevel]}) + demisto.results('Changed incident level to: ' + levelTranslate[maxLevel]) + else: + demisto.results('Could not find indicators') + except: + demisto.results('Incident details are not JSON') +else: + demisto.results('No details were found for the incident') diff --git a/Scripts/CopyFileD2.js b/Scripts/CopyFileD2.js new file mode 100644 index 000000000000..ed81585921f1 --- /dev/null +++ b/Scripts/CopyFileD2.js @@ -0,0 +1,14 @@ +var e = executeCommand( 'getEntry', { 'id' : args.entryid } ); +if ( e.length === 0 ) + return "Entry " + args.entryid + " not found."; +if ( e.length>1 ) + return "More than one entry with that ID found. Assertion error."; +e = e[0]; + +if ( e.File ) { + var fileName = fileNameFromEntry( args.entryid ); + var rep = executeCommand( 'D2Drop', { destpath : args.destpath , files : fileName, using : args.system } ); + return rep; +} else + return "Entry " + args.entryid + " does not include a file."; + diff --git a/Scripts/CuckooDetonateFile.py b/Scripts/CuckooDetonateFile.py new file mode 100644 index 000000000000..068d561569af --- /dev/null +++ b/Scripts/CuckooDetonateFile.py @@ -0,0 +1 @@ +demisto.results( demisto.executeCommand("ck-file", { "entryID": demisto.args()["entryID"] }) ) diff --git a/Scripts/CuckooGetReport.py b/Scripts/CuckooGetReport.py new file mode 100644 index 000000000000..9841d59b0df0 --- /dev/null +++ b/Scripts/CuckooGetReport.py @@ -0,0 +1 @@ +demisto.results( demisto.executeCommand("ck-report", { "id": demisto.args()["taskID"] }) ) diff --git a/Scripts/CuckooTaskStatus.py b/Scripts/CuckooTaskStatus.py new file mode 100644 index 000000000000..2dffffb6d9d6 --- /dev/null +++ b/Scripts/CuckooTaskStatus.py @@ -0,0 +1 @@ +demisto.results( demisto.executeCommand("ck-view", {"id": demisto.args()["taskID"]})) diff --git a/Scripts/D2Drop.js b/Scripts/D2Drop.js new file mode 100644 index 000000000000..422d59bb4d2e --- /dev/null +++ b/Scripts/D2Drop.js @@ -0,0 +1,8 @@ +var files = files( '/tmp', true, false, args.files ); +if ( files && files.length > 0 ) { + if ( 1 != copy( files[0].Path, args.destpath ) ) + throw "Error copying file " + files[0].Path + " to " + files[0].destpath + "."; + else + pack("File copied successfully."); +} + diff --git a/Scripts/D2GetSystemLog.js b/Scripts/D2GetSystemLog.js new file mode 100644 index 000000000000..6920bfb76058 --- /dev/null +++ b/Scripts/D2GetSystemLog.js @@ -0,0 +1,26 @@ +function copyLogUnix() { + pack_file('/var/log/' + args.logName, args.logName); +} + +function copyLogWindows() { + var fileName = 'c:\\' + args.logName + '.log'; + var output = execute('wevtutil epl ' + args.logName + ' ' + fileName); + + if (!output.Success) { + pack(output); + throw output.Error + ': '; + } + + pack_file(fileName, args.logName); + del(fileName); +} + +try { + if (env.OS === 'windows') { + copyLogWindows(); + } else { + copyLogUnix(); + } +} catch (ex) { + pack('Error: ' + ex); +} diff --git a/Scripts/D2RegQuery.js b/Scripts/D2RegQuery.js new file mode 100644 index 000000000000..4f572281ee47 --- /dev/null +++ b/Scripts/D2RegQuery.js @@ -0,0 +1 @@ +pack(registry(args.regpath)); \ No newline at end of file diff --git a/Scripts/D2exec.js b/Scripts/D2exec.js new file mode 100644 index 000000000000..92748c4e59c1 --- /dev/null +++ b/Scripts/D2exec.js @@ -0,0 +1 @@ +packOutput(args.cmd); diff --git a/Scripts/D2hardware.js b/Scripts/D2hardware.js new file mode 100644 index 000000000000..ddc38d23db75 --- /dev/null +++ b/Scripts/D2hardware.js @@ -0,0 +1,26 @@ + +function hardwareLinux() { + packOutput('lshw'); +} + +function hardwareDarwin(){ + packOutput('system_profiler'); +} +function hardwareWindows() { + pack(wmi_query('select Name,FileSystem, FreeSpace,Size,VolumeName,VolumeSerialNumber from Win32_LogicalDisk'),'table'); + pack(wmi_query('select Description, Manufacturer, Name, SMBIOSBIOSVersion,Version from Win32_Bios'),'table'); + pack(wmi_query('select Version, SerialNumber,SocketDesignation, Name, Description, Manufacturer, AddressWidth from Win32_Processor'),'table'); + pack(wmi_query('select Manufacturer, Model, SystemType, UserName from Win32_ComputerSystem'),'table'); +} + +try { + if (env.OS=== "windows") { + hardwareWindows(); + } else if (env.OS==="linux") { + hardwareLinux(); + } else { + hardwareDarwin(); + } +} catch (ex) { + pack("Error: " + ex); +} diff --git a/Scripts/D2pedump.js b/Scripts/D2pedump.js new file mode 100644 index 000000000000..6226b8605105 --- /dev/null +++ b/Scripts/D2pedump.js @@ -0,0 +1,5 @@ +var files = files('/tmp', true, false, args.file); + +if (files && files.length > 0) { + packOutput('pedump ' + files[0].Path); +} diff --git a/Scripts/D2processes.js b/Scripts/D2processes.js new file mode 100644 index 000000000000..f73b9bd0b009 --- /dev/null +++ b/Scripts/D2processes.js @@ -0,0 +1,23 @@ +function processesUnix() { + var output = execute('ps ax'); + if (output.Success) { + pack(output.Stdout); + } else { + throw output.Error; + } +} + +function processesWindows() { + var ps = wmi_query('select ProcessId, CommandLine, ThreadCount, WorkingSetSize, Description From Win32_Process'); + pack(ps, 'table'); +} + +try { + if (env.OS === 'windows') { + processesWindows(); + } else { + processesUnix(); + } +} catch (ex) { + pack('Error: ' + ex); +} diff --git a/Scripts/D2services.js b/Scripts/D2services.js new file mode 100644 index 000000000000..d60814f2c49d --- /dev/null +++ b/Scripts/D2services.js @@ -0,0 +1,23 @@ +function servicesLinux() { + packOutput('service --status-all'); +} + +function servicesDarwin() { + packOutput('launchctl list'); +} + +function servicesWindows() { + pack(wmi_query('select Name,Description,PathName,StartMode,ProcessId,State,StartName from Win32_Service'), 'table'); +} + +try { + if (env.OS === 'windows') { + servicesWindows(); + } else if (env.OS === 'linux') { + servicesLinux(); + } else { + servicesDarwin(); + } +} catch (ex) { + pack('Error: ' + ex); +} diff --git a/Scripts/D2users.js b/Scripts/D2users.js new file mode 100644 index 000000000000..0a579c8a0ed3 --- /dev/null +++ b/Scripts/D2users.js @@ -0,0 +1,17 @@ +function usersUnix() { + packOutput('cat /etc/passwd'); +} + +function usersWindows() { + pack(wmi_query('select * from Win32_Account'), 'table'); +} + +try { + if (env.OS === 'windows') { + usersWindows(); + } else { + usersUnix(); + } +} catch (ex) { + pack('Error: ' + ex); +} diff --git a/Scripts/DefaultIncidentClassifier.js b/Scripts/DefaultIncidentClassifier.js new file mode 100644 index 000000000000..61a3511676e5 --- /dev/null +++ b/Scripts/DefaultIncidentClassifier.js @@ -0,0 +1,18 @@ +for (var i =0; incidents[0].labels && i < incidents[0].labels.length; i++) { + if (incidents[0].labels[i].type === 'Email/from') { + var sender = incidents[0].labels[i].value; + if (sender === args.splunkSender) { + executeCommand('SplunkEmailParser', {}); + return setPlaybookAccordingToType(incidents[0].type); + } else if (sender === args.nexposeSender) { + return executeCommand('NexposeEmailParser', {minRiskScore: args.minRiskScore, minVulnCount: args.minVulnCount}); + } else if (sender === args.sentinelOneSender) { + return setIncident({type: args.sentinelOneIncidentType}); + } else { + return [setPlaybookAccordingToType(args.defaultIncidentType), + setIncident({type: args.defaultIncidentType})]; + } + } +} + +return 'incident is not an email, not classifying'; \ No newline at end of file diff --git a/Scripts/ESMNitroExample.js b/Scripts/ESMNitroExample.js new file mode 100644 index 000000000000..5a3a3b72e7b1 --- /dev/null +++ b/Scripts/ESMNitroExample.js @@ -0,0 +1,10 @@ +var queryLimit = '100'; +if (args.limit) { + queryLimit = args.limit; +} + +var ip = args.ip; + +var filters = '[{ "type": "EsmFieldFilter", "field": {"name": "SrcIP"}, "operator": "EQUALS", "values": [{ "type": "EsmBasicValue", "value": "'+ip+'" }] }]'; + +return executeCommand('search', {'using-brand': 'esm', limit: queryLimit, filters: filters, 'time_range': 'CURRENT_YEAR', fields: 'Alert.ID,Alert.LastTime'}); diff --git a/Scripts/EmailToContext.py b/Scripts/EmailToContext.py new file mode 100644 index 000000000000..5b0c2372e298 --- /dev/null +++ b/Scripts/EmailToContext.py @@ -0,0 +1,25 @@ +import re +strSenderRegex = r".*From\w*:.*\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})\b" +strTargetRegex = r".*To\w*:.*\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})\b" + +body = demisto.incidents()[0]['details'] +demisto.setContext('emailBody', body) + +fromLines = re.match(strSenderRegex, body, re.I) +if fromLines: + # Use the last "From" line found + sender = fromLines[-1].group(1) + demisto.setContext('emailOriginalSender', sender) + +toLines = re.match(strSenderRegex, body, re.I) +if toLines: + # Use the last "From" line found + sender = fromLines[-1].group(1) + demisto.setContext('emailOriginalSender', sender) +var toRE = /To:.*href="mailto:(.*)"/ig; +var to = toRE.exec(body); +var sentRE = /Sent:<\/b> (.*)
/ig; +var sent = sentRE.exec(body); +var subjectRE = /Subject:<\/b> (.*)/ig; +var subject = subjectRE.exec(body); +return {Contents: {From: from[1], To: to[1], Sent: sent[1], Subject: subject[1]}, ContentsFormat: formats.table, Type: entryTypes.note}; diff --git a/Scripts/ExchangeFindAndDelete.py b/Scripts/ExchangeFindAndDelete.py new file mode 100644 index 000000000000..fabf5290b792 --- /dev/null +++ b/Scripts/ExchangeFindAndDelete.py @@ -0,0 +1,148 @@ +import re +resultText = '' +strSubjectLineRegex = r'.*Subject\w*:(.*)' +# example to match: Subject: Cloud Services Invoice' + +strFromLineRegex = r'.*From\w*:(.*)' +# example to match:

From: john.doe@gmail.com + +strTagRegex = r'<[^>]*>' +strEmailRegex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b' + +entries = demisto.executeCommand('getEntries', {}) +mailbody = demisto.incidents()[0]['details'] +mailbody = mailbody.replace('
','\n') +# defaults +mailbox='' +sender='' +attachmentname='' +subject='' + +query ='' + + +# Get the mailbox +if demisto.args().has_key('mailbox'): + mailbox = demisto.args()['mailbox'] +else: + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email/from': + mailbox = t['value'] + break + if mailbox == '': + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email': + mailbox = t['value'] + break + +if not mailbox: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'No mailbox specified. Cannot continue.' } ) + sys.exit(0) + + +# Get the mail's subject +if demisto.args().has_key('subject'): + subject = demisto.args()['subject'] +else: + matches = re.findall(strSubjectLineRegex, mailbody, re.I) + if len(matches) > 0: + subject = re.sub(strTagRegex,'',matches[0]) + +qsubject = 'subject:"' + subject.strip() +'"' if subject else '' + + +# Get the attachment file name +if demisto.get(demisto.args(), 'attachmentName'): + attachmentname = demisto.args()['attachmentName'] +else: + for entry in entries: + if entry['File'] and demisto.get(entry, 'File'): + attachmentname = entry['File'] + +qattach = 'attachment:"'+attachmentname+'"' if attachmentname else '' + + +# Get the sender +if demisto.args().has_key('sender'): + sender = demisto.args()['sender'] +else: + matches = re.findall(strFromLineRegex, mailbody, re.I) + if len(matches) > 0: + emails = re.findall(strEmailRegex, matches[0], re.I) + if len(emails) > 0: + sender = emails[0] + +qsender = 'from:"'+sender+'"' if sender else '' + +folder = 'inbox' +parts = [qsubject, qsender,qattach] +query = ' AND '.join([x for x in parts if not x=='']) + + +resultText +='Searching for emails using query:\n**' + query + '**\n' + +FoundIDs = [] +def AddID(id): + resultText += 'Found Item ID:\t' + id + '\n' + FoundIDs.append(id) + +respSearch = demisto.executeCommand('ews-search-mailbox', {'target-mailbox': mailbox, 'folders-ids': folder, 'query': query }) + +if isError(respSearch[0]) or not respSearch[0]['ContentsFormat'] == formats['json']: + err = [{ 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected response from ews-search-mailbox.' }] + demisto.results( [err] + respSearch) + sys.exit(0) + + +c = respSearch[0]['Contents'] +#demisto.log(json.dumps(c)+'\n') +fault = demisto.get(c, 'Envelope.Body.Fault') +if fault: + if 'ErrorNonExistentMailbox' == demisto.gets(fault, 'detail.ResponseCode.#text'): + resultText += 'No mails found.\n' + finished=True + else: + msgXmlName = demisto.gets(fault, 'detail.MessageXml.Value.-Name') + msgXmlText = demisto.gets(fault, 'detail.MessageXml.Value.#text') + mdErr = '### Received error from Exchange Web Services :\n' + mdErr += 'faultcode|faultstring|Message|ResponseCode' + ('|' + msgXmlName if type(msgXmlName)==str else '') + '\n' + mdErr += '-|-|-|-|-\n' + mdErr += '|'.join( [str(demisto.gets(fault, loc)) for loc in 'faultcode.#text', 'faultstring.#text', 'detail.Message.#text', 'detail.ResponseCode.#text' ] + ([msgXmlText] if msgXmlText else [])) + '\n' + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['markdown'], 'Contents' : mdErr} ) + sys.exit(0) +else: + resp = demisto.get(c, 'Envelope.Body.FindItemResponse.ResponseMessages.FindItemResponseMessage') + if resp and demisto.get(resp, '-ResponseClass') == 'Success': + itemcount = int(resp['RootFolder']['-TotalItemsInView']) # todo handle parsing error for ints + if itemcount==0: + resultText += 'No mails found.\n' + finished=True + elif itemcount>1: + items = resp['RootFolder']['Items']['Message'] + for item in items: + AddID(item['ItemId']['-Id']) + else: + AddID(resp['RootFolder']['Items']['Message']['ItemId']['-Id']) + else: + resultText += "Received empty or unsuccessful response with error:" + str(resp) +'\n' + finished = True + +if not finished: + resultText += 'Deleting all founds emails...\n' + itemids = ','.join(FoundIDs) + delres = demisto.executeCommand('ews-delete-items', {'target-mailbox': mailbox, 'item-ids' :itemids }) + + delres = delres[0] + if delres['Type'] != 4 and delres['ContentsFormat'] == 'json': + delresp = demisto.get(delres, 'Contents.Envelope.Body.DeleteItemResponse.ResponseMessages.DeleteItemResponseMessage') + if delresp: + if delresp['-ResponseClass'] == 'Success': + resultText += 'Delete successful.\n' + else: + resultText += "Delete failed: " + delresp['MessageText'] + "\nResponse Code:" + delresp['-ResponseCode']+'\n' + else: + resultText += "Delete failed with missing response\n" + else: + demisto.results(delres) + +demisto.results( { 'Type' : entryTypes['note'], 'ContentsFormat' : formats['markdown'], 'Contents': resultText } ) diff --git a/Scripts/FPDeleteRule.py b/Scripts/FPDeleteRule.py new file mode 100644 index 000000000000..d7d46874a509 --- /dev/null +++ b/Scripts/FPDeleteRule.py @@ -0,0 +1,30 @@ +from re import escape +FILTER_CONFIG_PATH = "/opt/WCG/config/filter.config" +CMD_DEL_RULE_FORMAT = "sed -i '/^{0}={1} action=[A-Za-z]*$/d' {2}" +CMD_TRITON_RELOAD_CONFIG = "/opt/WCG/bin/content_line -x" # && /opt/WCG/WCGAdmin runds" +ruleType = demisto.args()["type"] +if not ruleType in ["dest_domain", "dest_ip", "dest_host", "url_regex"]: + demisto.results( { "Type" : entryTypes["error"], "ContentsFormat" : formats["text"], "Contents" : 'Type argument must be "dest_domain", "dest_ip", "dest_host" or "url_regex". Invalid value: ' + ruleType } ) +else: + valueFormat = escape(demisto.args()["value"]) + if ruleType in ["dest_domain", "url_regex"]: + valueFormat = r'\"' + valueFormat + r'\"' + # sed command that deletes the rule + cmdDelRule = CMD_DEL_RULE_FORMAT.format(ruleType, valueFormat, FILTER_CONFIG_PATH) + sshArgs = {"cmd": cmdDelRule + " && " + CMD_TRITON_RELOAD_CONFIG} + if "tritonsystem" in demisto.args(): + if "remoteaccessname" in demisto.args(): + demisto.results({ "Type" : entryTypes["error"], "ContentsFormat": formats["markdown"], "Contents": "You cannot uses both **tritonsystem** and **remoteaccessname**. Please choose one." }) + sys.exit(0) + sshArgs["system"] = demisto.args()["tritonsystem"] + elif "remoteaccessname" in demisto.args(): + sshArgs["using"] = demisto.args()["remoteaccessname"] + else: + demisto.results({ "Type" : entryTypes["error"], "ContentsFormat": formats["markdown"], "Contents": "You must provide either **tritonsystem** or **remoteaccessname** as arguments." }) + sys.exit(0) + if "using" in sshArgs or "system" in sshArgs: + resSSH = demisto.executeCommand("ssh", sshArgs) + if not isError(resSSH[0]) and demisto.gets(resSSH[0], "Contents.success"): + demisto.results("Command executed successfully.") + else: + demisto.results(resSSH) diff --git a/Scripts/FPSetRule.py b/Scripts/FPSetRule.py new file mode 100644 index 000000000000..458cc62845f5 --- /dev/null +++ b/Scripts/FPSetRule.py @@ -0,0 +1,33 @@ +from re import escape +FILTER_CONFIG_PATH = "/opt/WCG/config/filter.config" +CMD_SET_RULE_FORMAT = "sed -i '/^{0}={1} action=/{{h;s/{0}={1} action=[A-Za-z]*$/{0}={1} action={2}/}};${{x;/^$/{{s//{0}={1} action={2}/;H}};x}}' {3}" +CMD_TRITON_RELOAD_CONFIG = "/opt/WCG/bin/content_line -x" # && /opt/WCG/WCGAdmin runds" +policy = demisto.args()["policy"] +ruleType = demisto.args()["type"] +if not policy in ["allow", "deny"]: + demisto.results({"Type": entryTypes["error"], "ContentsFormat": formats["text"], "Contents": 'Policy argument must be "allow" or "deny". Invalid value: ' + policy } ) +if not ruleType in ["dest_domain", "dest_ip", "dest_host", "url_regex"]: + demisto.results({"Type": entryTypes["error"], "ContentsFormat": formats["text"], "Contents": 'Type argument must be "dest_domain", "dest_ip", "dest_host" or "url_regex". Invalid value: ' + ruleType } ) +else: + valueFormat = escape(demisto.args()["value"]) + if ruleType in ["dest_domain", "url_regex"]: + valueFormat = r'\"' + valueFormat + r'\"' + # sed command that modifies the action of the rule if found, otherwise it adds it in a new line + cmdSetRule = CMD_SET_RULE_FORMAT.format(ruleType, valueFormat, policy, FILTER_CONFIG_PATH) + sshArgs = {"cmd": cmdSetRule + " && " + CMD_TRITON_RELOAD_CONFIG} + if "tritonsystem" in demisto.args(): + if "remoteaccessname" in demisto.args(): + demisto.results({ "Type" : entryTypes["error"], "ContentsFormat": formats["markdown"], "Contents": "You cannot uses both **tritonsystem** and **remoteaccessname**. Please choose one." }) + sys.exit(0) + sshArgs["system"] = demisto.args()["tritonsystem"] + elif "remoteaccessname" in demisto.args(): + sshArgs["using"] = demisto.args()["remoteaccessname"] + else: + demisto.results({ "Type" : entryTypes["error"], "ContentsFormat": formats["markdown"], "Contents": "You must provide either **tritonsystem** or **remoteaccessname** as arguments." }) + sys.exit(0) + if "using" in sshArgs or "system" in sshArgs: + resSSH = demisto.executeCommand("ssh", sshArgs) + if not isError(resSSH[0]) and demisto.gets(resSSH[0], "Contents.success"): + demisto.results("Command executed successfully.") + else: + demisto.results(resSSH) diff --git a/Scripts/IPExtract.py b/Scripts/IPExtract.py new file mode 100644 index 000000000000..76e7640e8d21 --- /dev/null +++ b/Scripts/IPExtract.py @@ -0,0 +1,39 @@ +import re +import socket + +def is_valid_ipv4_address(address): + try: + socket.inet_pton(socket.AF_INET, address) + except AttributeError: # no inet_pton here, sorry + try: + socket.inet_aton(address) + except socket.error: + return False + return address.count('.') == 3 + except socket.error: # not a valid address + return False + return True + +res = [] +ips = [] + +data = demisto.args()['text'] + +for m in re.finditer(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', data, re.I): + ip = m.group(0) + if ip in ips: + continue + if not is_valid_ipv4_address(ip): + continue + ips.append(ip) + +res.append('IPs found:\n' + '\n'.join(ips)) +currIPs = demisto.get(demisto.context(), 'ips') +if currIPs and isinstance(currIPs, list): + for i in ips: + if i not in currIPs: + currIPs.append(i) +else: + currIPs = ips +demisto.setContext('ips', currIPs) +demisto.results(res) diff --git a/Scripts/IncidentSet.py b/Scripts/IncidentSet.py new file mode 100644 index 000000000000..4931ceec9448 --- /dev/null +++ b/Scripts/IncidentSet.py @@ -0,0 +1,26 @@ +res = [] +dArgs = {} +inArgs= demisto.args() +if demisto.get(inArgs, 'owner'): + res += demisto.executeCommand("setOwner", {'owner': inArgs['owner']}) +if demisto.get(inArgs, 'playbook'): + res += demisto.executeCommand("setPlaybook", {'name': inArgs['playbook']}) +if demisto.get(inArgs, 'stage'): + res += demisto.executeCommand("setStage", {'stage': inArgs['stage']}) +if demisto.get(inArgs, 'name'): + dArgs['incName'] = inArgs['name'] +if demisto.get(inArgs, 'details'): + dArgs['details'] = inArgs['details'] +if demisto.get(inArgs, 'severity'): + dArgs['severity'] = inArgs['severity'] +if demisto.get(inArgs, 'labels'): + dArgs['labels'] = inArgs['labels'] +if demisto.get(inArgs, 'addLabels'): + dArgs['addLabels'] = inArgs['addLabels'] +if demisto.get(inArgs, 'type'): + dArgs['type'] = inArgs['type'] + if (not demisto.get(inArgs, 'updatePlaybookForType') or demisto.get(inArgs, 'updatePlaybookForType') == 'yes') and not demisto.get(inArgs, 'playbook'): + demisto.executeCommand("setPlaybookAccordingToType", {'type': inArgs['type']}) +if dArgs: + res += demisto.executeCommand("setIncident", dArgs) +demisto.results(res) diff --git a/Scripts/IncidentToContext.py b/Scripts/IncidentToContext.py new file mode 100644 index 000000000000..d2c9a1aa4636 --- /dev/null +++ b/Scripts/IncidentToContext.py @@ -0,0 +1,42 @@ +# These comments are required to make sure that all pre-defined labels are selectable in the playbook +# demisto.setContext('Label/Application', '') +# demisto.setContext('Label/Database', '') +# demisto.setContext('Label/Directory', '') +# demisto.setContext('Label/Email', '') +# demisto.setContext('Label/Email/cc', '') +# demisto.setContext('Label/Email/from', '') +# demisto.setContext('Label/IP', '') +# demisto.setContext('Label/System', '') +# demisto.setContext('Label/URL', '') +# demisto.setContext('Label/User', '') + +i = demisto.incidents()[0] +demisto.setContext('id', i['id']) +demisto.setContext('created', i['created']) +demisto.setContext('modified', i['modified']) +demisto.setContext('occurred', i['occurred']) +demisto.setContext('dueDate', i['dueDate']) +demisto.setContext('name', i['name']) +demisto.setContext('owner', i['owner']) +demisto.setContext('type', i['type']) +demisto.setContext('severity', i['severity']) +demisto.setContext('stage', i['stage']) +demisto.setContext('status', i['status']) +demisto.setContext('details', i['details']) + +# Setting initial score based on severity. Severity "Unknown" yields score 0. +score = i['severity'] * 25 +demisto.setContext('score', score) + +labels = {} +for l in i['labels']: + name = 'Label/' + l['type'] + if demisto.get(labels, name): + labels[name] = labels[name].append(l['value']) + else: + labels[name] = [l['value']] + +for k, v in labels.iteritems(): + demisto.setContext(k, v if len(v) > 1 else v[0]) + +demisto.results('Incident context set') diff --git a/Scripts/MD5Extract.py b/Scripts/MD5Extract.py new file mode 100644 index 000000000000..575c99c34b29 --- /dev/null +++ b/Scripts/MD5Extract.py @@ -0,0 +1,24 @@ +import re + +md5Regex = r'\b[a-fA-F\d]{32}\b' + +res = [] +hashes = [] + +data = demisto.args()['text'] + +for m in re.finditer(md5Regex, data, re.I): + h = m.group(0) + if h not in hashes: + hashes.append(h) + +res.append('MD5s found:\n' + '\n'.join(hashes)) +currHashes = demisto.get(demisto.context(), 'md5s') +if currHashes and isinstance(currHashes, list): + for h in hashes: + if h not in currHashes: + currHashes.append(h) +else: + currHashes = hashes +demisto.setContext('md5s', currHashes) +demisto.results(res) diff --git a/Scripts/NexposeEmailParser.js b/Scripts/NexposeEmailParser.js new file mode 100644 index 000000000000..535adc76991f --- /dev/null +++ b/Scripts/NexposeEmailParser.js @@ -0,0 +1,62 @@ +var entries = executeCommand('getEntries', {}); +var report = 0; +if (!args.entryID) { + for (var i = 0; i < entries.length; i++) { + if (entries[i].File) { + var entryIDFromInv = entries[i].ID; + report = getFileByEntryID(entryIDFromInv); + if (/$/); +for (var i=0; i < nodes.length; i++) { + var nodeRegexp = //g; + var match = nodeRegexp.exec(nodes[i]); + if (nodes[i] && match) { + var testRegexp = //g ; + var vulnCount = nodes[i].match(testRegexp) ? nodes[i].match(testRegexp).length : '0'; + var data = { + Address: match[1], + Name: match[4], + Risk: match[6], + Status: match[2], + Importance: match[5], + Vulnerabilities: vulnCount + }; + if ((args.minRiskScore && args.minRiskScore <= data.Risk) || !args.minRiskScore) { + if ((args.minVulnCount && args.minVulnCount <= data.Vulnerabilities) || !args.minVulnCount) { + contents.push(data); + + var sev = "low"; + if (data.Risk > 3000) { + sev = "critical"; + } else if (data.Risk > 2500) { + sev = "high"; + } else if (data.Risk > 2000) { + sev = "medium"; + } + + createNewIncident({ + type: 'Nexpose alert', + details: nodes[i], + severity: sev, + incName: data.Address + ' vulnerability count ' + data.Vulnerabilities + ' risk score ' + data.Risk, + systems: data.Address + }); + + } + } + } +} + +return [{Contents: contents, + ContentsFormat: formats.table, + Type: entryTypes.note}, + closeInvestigation({Reason: 'Spawned ' + contents.length + ' child incidents'})]; \ No newline at end of file diff --git a/Scripts/NexposeEmailParserForVuln.js b/Scripts/NexposeEmailParserForVuln.js new file mode 100644 index 000000000000..e5626b976fc8 --- /dev/null +++ b/Scripts/NexposeEmailParserForVuln.js @@ -0,0 +1,51 @@ +var report = args.report ? args.report : incidents[0].details; +var contents = {}; +var nodes = report.split(/<\/node>/); +for (var i=0; i < nodes.length; i++) { + var nodeRegexp = //g; + var vulnRegexp = /()/g; + var res = nodes[i].match(/()/g); + var match = nodeRegexp.exec(nodes[i]); + if (nodes[i] && match) { + var vulnCount = nodes[i].match(vulnRegexp) ? nodes[i].match(vulnRegexp).length : '0'; + var data = { + Address: match[1], + Name: match[4], + Risk: match[6], + Status: match[2], + Importance: match[5], + Vulnerabilities: vulnCount + }; + for (var j = 0; res && j < res.length; j++) { + var current = vulnRegexp.exec(res[j]); + if (current) { + if (contents[current[2]]) { + contents[current[2]].labels.push(data); + } else { + contents[current[2]] = {labels: [], Name: current[2]}; + } + } + } + } +} + +var k = 0; +for (var key in contents) { + var element = contents[key]; + var labels = ''; + for (var j = 0; j < element.labels.length; j++) { + labels += element.labels[j].Address + ','; + } + labels = labels.slice(0, -1); + if (labels.length > 0) { + createNewIncident({ + type: 'Nexpose alert', + details: JSON.stringify(element.labels), + severity: args.defaultNexposeSeverity, + incName: key, + systems: labels + }); + } +} + +return closeInvestigation({Reason: 'Spawned ' + k + ' child incidents'}); \ No newline at end of file diff --git a/Scripts/NexposeVulnExtractor.js b/Scripts/NexposeVulnExtractor.js new file mode 100644 index 000000000000..ef9b820450ed --- /dev/null +++ b/Scripts/NexposeVulnExtractor.js @@ -0,0 +1,11 @@ +var report = args.report ? args.report : incidents[0].details; +var res = report.match(/()/g); +var contents = []; +for (var i =0; i < res.length; i++) { + var current = /()/g.exec(res[i]); + contents.push({Name: current[2], Status: current[4], Since: current[6], Compliance: current[7]}); +} + +return {Contents: contents, + ContentsFormat: formats.table, + Type: entryTypes.note}; \ No newline at end of file diff --git a/Scripts/PrintContext.py b/Scripts/PrintContext.py new file mode 100644 index 000000000000..c1f03c61e3d0 --- /dev/null +++ b/Scripts/PrintContext.py @@ -0,0 +1,6 @@ +res = demisto.executeCommand('getContext', {}) +if isError(res[0]): + demisto.results(res) +else: + md = "**Context data**:\n" + json.dumps(res[0]['Contents'], indent=4) + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': md}) diff --git a/Scripts/RegCollectValues.py b/Scripts/RegCollectValues.py new file mode 100644 index 000000000000..aed3adf144d7 --- /dev/null +++ b/Scripts/RegCollectValues.py @@ -0,0 +1,31 @@ +def Reg2Markdown(baseKey,regResp): + res, mdRows = [], '' + if isError(regResp[0]): + res += regResp + elif len(regResp) > 1 : + res.append( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from D2RegQuery - more than one entry returned:\n'+'\n'.join( [ str(x) for x in regResp ] ) } ) + else: + subkeys = regResp[0]['Contents'] + for sk in subkeys: + if type(subkeys[sk]) == dict: + for ssk in subkeys[sk]: + mdRows += '\n|' + str(baseKey) + '\\' + str(sk) + '|' + str(ssk) + '|' + str( subkeys[sk][ssk] ) + '|' + else: + mdRows += '\n|' + str(baseKey) + '|' + str(sk) + '|' + str( subkeys[sk] ) + '|' + return ( res, mdRows ) + + +# Note: Don't use !d2_status as that only shows systems with generated agents - the correct way is below: +res = [] +regPath = NormalizeRegistryPath( demisto.args()['regpath'] ) +for system in demisto.investigation()['systems']: + if system['os'] == 'windows': + mdTable = '### Values retrieved from system *' + system['name'] + '*' + mdTable += '\n|Key|SubKey|Value|' + mdTable += '\n|-----|------|-----|' + cmdResp = demisto.executeCommand( 'D2RegQuery', { 'using' : system['name'], 'path' : regPath } ) + moreEntries, moreRows = Reg2Markdown( regPath , cmdResp ) + mdTable += moreRows + res += moreEntries + res.append( { 'Type' : entryTypes['note'], 'ContentsFormat' : formats['markdown'], 'Contents' : mdTable } ) +demisto.results(res) diff --git a/Scripts/RegPathReputationBasicLists.py b/Scripts/RegPathReputationBasicLists.py new file mode 100644 index 000000000000..89f2ebc8f54c --- /dev/null +++ b/Scripts/RegPathReputationBasicLists.py @@ -0,0 +1,112 @@ +whitelist = [ r'HKEY_LOCAL_MACHINE\Software\wow6432node\Microsoft\Windows\CurrentVersion\Run\vmware-tray.exe' ] + +blacklist = [ r'HKEY_CURRENT_USER\Software\Locky', +r'HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\Locky' ] + +suspicious = [ r"HKCU\Software\Microsoft\Internet Explorer\UrlSearchHooks", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\Run", +r"HKLM\SOFTWARE\Classes\Htmlfile\Shell\Open\Command", +r"HKLM\SOFTWARE\Classes\Htmlfile\Shell\Open\Command\(Default)", +r"HKLM\SOFTWARE\Classes\Protocols\Filter", +r"HKLM\SOFTWARE\Classes\Protocols\Handler", +r"HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\VmApplet", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\PLAP Providers", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", +r"HKLM\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components", +r"HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls", +r"HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects", +r"HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run", +r"HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Authentication Packages", +r"HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages", +r"HKLM\SYSTEM\CurrentControlSet\Control\Lsa\OSConfig\Security Packages", +r"HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Security Packages", +r"HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order", +r"HKLM\SYSTEM\CurrentControlSet\Control\Print\Monitors", +r"HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot", +r"HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\AlternateShell", +r"HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders", +r"HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SecurityProviders", +r"HKLM\Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Classes\AllFileSystemObjects\ShellEx\PropertySheetHandlers", +r"HKLM\Software\Classes\CLSID\{083863F1-70DE-11d0-BD40-00A0C911CE86}\Instance", +r"HKLM\Software\Classes\CLSID\{7ED96837-96F0-4812-B211-F13C24117ED3}\Instance", +r"HKLM\Software\Classes\Directory\Background\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Classes\Directory\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Classes\Directory\Shellex\CopyHookHandlers", +r"HKLM\Software\Classes\Directory\Shellex\DragDropHandlers", +r"HKLM\Software\Classes\Directory\Shellex\PropertySheetHandlers", +r"HKLM\Software\Classes\Drive\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Classes\Folder\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Classes\Folder\ShellEx\DragDropHandlers", +r"HKLM\Software\Classes\Folder\ShellEx\PropertySheetHandlers", +r"HKLM\Software\Classes\Folder\Shellex\ColumnHandlers", +r"HKLM\Software\Microsoft\Windows NT\CurrentVersion\Drivers32", +r"HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows", +r"HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\IconServiceLib", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce", +r"HKLM\Software\Wow6432Node\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Wow6432Node\Classes\AllFileSystemObjects\ShellEx\PropertySheetHandlers", +r"HKLM\Software\Wow6432Node\Classes\CLSID\{083863F1-70DE-11d0-BD40-00A0C911CE86}\Instance", +r"HKLM\Software\Wow6432Node\Classes\CLSID\{7ED96837-96F0-4812-B211-F13C24117ED3}\Instance", +r"HKLM\Software\Wow6432Node\Classes\Directory\Background\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Wow6432Node\Classes\Directory\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Wow6432Node\Classes\Directory\Shellex\CopyHookHandlers", +r"HKLM\Software\Wow6432Node\Classes\Directory\Shellex\DragDropHandlers", +r"HKLM\Software\Wow6432Node\Classes\Directory\Shellex\PropertySheetHandlers", +r"HKLM\Software\Wow6432Node\Classes\Drive\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Wow6432Node\Classes\Folder\ShellEx\ContextMenuHandlers", +r"HKLM\Software\Wow6432Node\Classes\Folder\ShellEx\DragDropHandlers", +r"HKLM\Software\Wow6432Node\Classes\Folder\ShellEx\PropertySheetHandlers", +r"HKLM\Software\Wow6432Node\Classes\Folder\Shellex\ColumnHandlers", +r"HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32", +r"HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects", +r"HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", +r"HKLM\System\CurrentControlSet\Control", +r"HKLM\System\CurrentControlSet\Control\ServiceControlManagerExtension", +r"HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute", +r"HKLM\System\CurrentControlSet\Control\Session Manager\KnownDlls", +r"HKLM\System\CurrentControlSet\Control\Terminal Server\Wds\rdpwd", +r"HKLM\System\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\StartupPrograms", +r"HKLM\System\CurrentControlSet\Services", +r"HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\NameSpace_Catalog5\Catalog_Entries", +r"HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\NameSpace_Catalog5\Catalog_Entries64", +r"HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries", +r"HKLM\System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries64", +r"HKLM\software\microsoft\windows\currentversion\policies\explorer\run", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\RunServices", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices", +r"HKLM\software\microsoft\wbem\ess\//./root/cimv2\win32clockprovider", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce", +r"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify", +r"HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad", +r"HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnceEx", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\Run", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce", +r"HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run", +r"HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\load", +r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler" ] + +regPath = NormalizeRegistryPath( demisto.args()['input'] ) +regPath = regPath.upper() +if regPath in (key.upper() for key in whitelist): + score = 1 +elif regPath in (key.upper() for key in blacklist): + score = 3 +elif regPath in (key.upper() for key in suspicious): + score = 2 +else: + score = 0 +demisto.results(score) + diff --git a/Scripts/RegProbeBasic.py b/Scripts/RegProbeBasic.py new file mode 100644 index 000000000000..54d84e362e5a --- /dev/null +++ b/Scripts/RegProbeBasic.py @@ -0,0 +1,45 @@ +keys = [ r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", +r"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run", +r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components", +r"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components", +r"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run", +r"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce" ] + + +def Reg2Markdown(baseKey,regResp): + res, mdRows = [], '' + if isError(regResp[0]): + res += regResp + elif len(regResp) > 1 : + res.append( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'Unexpected output from D2RegQuery - more than one entry returned:\n'+'\n'.join( [ str(x) for x in regResp ] ) } ) + else: + subkeys = regResp[0]['Contents'] + for sk in subkeys: + if type(subkeys[sk]) == dict: + for ssk in subkeys[sk]: + mdRows += '\n|' + str(baseKey) + '\\' + str(sk) + '|' + str(ssk) + '|' + str( subkeys[sk][ssk] ) + '|' + else: + mdRows += '\n|' + str(baseKey) + '|' + str(sk) + '|' + str( subkeys[sk] ) + '|' + return ( res, mdRows ) + + +res = [] +if 'system' in demisto.args(): + system = demisto.args()['system'] +elif 'using' in demisto.args(): + system = demisto.args()['using'] +else: + demisto.results( { 'Type' : entryTypes['error'], 'ContentsFormat' : formats['text'], 'Contents' : 'You must provide "system" or "using" as arguments.'} ) + sys.exit(0) + +mdTable = '### Results for short registry probe of system *' + system + '*' +mdTable += '\n|Key|SubKey|Value|' +mdTable += '\n|-----|------|-----|' +for k in keys: + regPath = NormalizeRegistryPath( k ) + cmdResp = demisto.executeCommand( 'D2RegQuery', { 'using' : system, 'regpath' : regPath } ) + moreEntries , moreRows = Reg2Markdown( regPath, cmdResp ) + mdTable += moreRows + res += moreEntries +res.append ( { 'Type' : entryTypes['note'], 'ContentsFormat' : formats['markdown'], 'Contents' : mdTable } ) +demisto.results(res) diff --git a/Scripts/RemoteExec.js b/Scripts/RemoteExec.js new file mode 100644 index 000000000000..af66d4a4a24f --- /dev/null +++ b/Scripts/RemoteExec.js @@ -0,0 +1,16 @@ +//Execute a command on a remote machine +var output = []; +var entries = executeCommand("ssh", {system: args.system, cmd: args.cmd}); +var ret = entries[0]; +if (ret === null) { + output.push({ContentsFormat: formats.text, Type: entryTypes.error, Contents: "Failed to execute remote command."}); +} else { + result = ret.Contents; + if (!result.success) { + output.push({ContentsFormat: formats.text, Type: entryTypes.error, Contents: result.error}); + } else { + output.push({ContentsFormat: formats.text, Type: entryTypes.note, Contents: result.output}); + } +} +return output; + \ No newline at end of file diff --git a/Scripts/SendEmail.py b/Scripts/SendEmail.py new file mode 100644 index 000000000000..bd59f66eb33b --- /dev/null +++ b/Scripts/SendEmail.py @@ -0,0 +1,7 @@ +from string import Template +body = Template(demisto.args()['body'].replace('\\n', '\n')) +subject = Template(demisto.args()['subject']) +to = demisto.args()['to'] +subject = subject.safe_substitute(name=demisto.incidents()[0]['name']) +body = body.safe_substitute(recipient=to) +demisto.results(demisto.executeCommand('send-mail', {'to': to, 'subject': subject , 'body': body})) diff --git a/Scripts/SeverityByReputationsScore.py b/Scripts/SeverityByReputationsScore.py new file mode 100644 index 000000000000..6ae2bb75999c --- /dev/null +++ b/Scripts/SeverityByReputationsScore.py @@ -0,0 +1,34 @@ +for k in demisto.args(): + if demisto.args()[k] == '': + demisto.results({'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Please provide non-empty value for arg ' + k}) + sys.exit(0) + +badWeights = {"bad_urls": demisto.args()['bad_url_weight'], + "bad_ips": demisto.args()['bad_ip_weight'], + "bad_hashes": demisto.args()['bad_hash_weight']} +tCritical = demisto.args()['threshold_critical'] +tHigh = demisto.args()['threshold_high'] +tMed = demisto.args()['threshold_medium'] + +score = demisto.get(demisto.context(), 'score') +# Must explicitly compare to None since 0 is a valid score +if score is None: + # Setting initial score based on severity. Severity "Unknown" yields score 0. + score = i['severity'] * 25 + +for badKey in badWeights: + v = demisto.get(demisto.context(), badKey) + v = [v] if isinstance(v, list) else v + score += len(v) * badWeights[badKey] + +demisto.setContext('score', score) +if score >= tMed: + if score >= tHigh: + if score >= tCritical: + demisto.executeCommand('IncidentSet', {'severity': 4}) + else: + demisto.executeCommand('IncidentSet', {'severity': 3}) + else: + demisto.executeCommand('IncidentSet', {'severity': 2}) +else: + demisto.executeCommand('IncidentSet', {'severity': 1}) diff --git a/Scripts/SlackSend.py b/Scripts/SlackSend.py new file mode 100644 index 000000000000..5413a582ddf7 --- /dev/null +++ b/Scripts/SlackSend.py @@ -0,0 +1,6 @@ +dArgs = {} +for argName in ['message', 'to', 'channel', 'group', 'entry']: + if demisto.get(demisto.args(), argName): + dArgs[argName] = demisto.args()[argName] + +demisto.results( demisto.executeCommand( 'slack-send', dArgs ) ) diff --git a/Scripts/SplunkEmailParser.js b/Scripts/SplunkEmailParser.js new file mode 100644 index 000000000000..d0639366f476 --- /dev/null +++ b/Scripts/SplunkEmailParser.js @@ -0,0 +1,65 @@ +var body = args.body ? args.body : incidents[0].details; +var subject = args.subject ? args.subject : incidents[0].name; + +function parseBody() { + var lines = body.split(/\r*\n/); + var header=""; + var content = ""; + for (var i =0; i < lines.length; i++) { + var line = lines[i]; + if (line.toLowerCase().indexOf("view results") >=0&& lines.length > i+3) { + header = lines[i+1]; + content = lines[i+3]; + break; + } + } + return {header: header,content: content}; +} + +function headerIndex(header, column) { + lowerHeader = header.toLowerCase(); + lowerColumn = column.toLowerCase(); + columns = lowerHeader.split(/\s+/); + for (var i = 0; i < columns.length; i++){ + if (columns[i]===lowerColumn) { + var start = lowerHeader.indexOf(lowerColumn); + var end = -1; + if (columns.length > i+1 && columns[i + 1]!=="") { + end = lowerHeader.indexOf(columns[i + 1], start); + } + return {start:start,end:end}; + } + } + return {start:-1,end:-1}; +} + +function getContent(content,start,end) { + lastIndex = end ; + if (lastIndex===-1) { + lastIndex = content.length + } + if (start === -1) { + return ""; + } + return content.substring(start,lastIndex).trim(); +} + +function getField(field) { + mail = parseBody(); + dataBounderies = headerIndex(mail.header,field); + return getContent(mail.content,dataBounderies.start,dataBounderies.end); +} + +var type = getField('sourcetype'); +var details = getField('_raw'); +var severity = getField('level'); +var systems = getField('host'); +var incName = subject; + +return setIncident({ + type: type, + details: details, + severity: severity, + incName: incName, + systems: systems + }); \ No newline at end of file diff --git a/Scripts/SplunkSearchJson.py b/Scripts/SplunkSearchJson.py new file mode 100644 index 000000000000..03c11823049a --- /dev/null +++ b/Scripts/SplunkSearchJson.py @@ -0,0 +1,31 @@ +rows = 30 +if 'rows' in demisto.args(): + rows = demisto.args()['rows'] + +query = demisto.args()['query'] +if '|' not in query: + query = query + ' | head ' + str(rows) + +res = demisto.executeCommand('search', {'query': query}) +md = { + 'Type': entryTypes['note'], + 'ContentsFormat': formats['markdown'], + 'Contents': '# Splunk search result' +} + +for result in res: + if result['Brand'] == 'splunk': + for r in res[0]['Contents']: + data = demisto.get(r, 'result._raw') + if data: + md['Contents'] += '\n|Time|Host|Source|\n|-|-|-|' + md['Contents'] += '\n|' + str(demisto.get(r, 'result._time')) + '|' + str(demisto.get(r, 'result.host')) + '|' + str(demisto.get(r, 'result.source')) + '|\n' + try: + j = json.loads(data) + for f in j: + md['Contents'] += '\n- ' + f + ': ' + str(j[f]) + except: + md['Contents'] += '\n- Raw data: ' + str(data) + md['Contents'] += '\n' + +demisto.results(md) diff --git a/Scripts/TextFromHTML.py b/Scripts/TextFromHTML.py new file mode 100644 index 000000000000..8c6acd9f99df --- /dev/null +++ b/Scripts/TextFromHTML.py @@ -0,0 +1,10 @@ +import re +body = re.search(r'', demisto.args()['html'], re.M + re.S + re.I) +if body and body.group(0): + data = re.sub(r'<.*?>', '', body.group(0)) + entities = {'quot': '"', 'amp': '&', 'apos': "'", 'lt': '<', 'gt': '>', 'nbsp': ' ', 'copy': '(C)', 'reg': '(R)', 'tilde': '~', 'ldquo': '"', 'rdquo': '"', 'hellip': '...'} + for e in entities: + data = data.replace('&' + e + ';', entities[e]) + demisto.results(data) +else: + demisto.results('Could not extract text') diff --git a/Scripts/URLExtract.py b/Scripts/URLExtract.py new file mode 100644 index 000000000000..c3fbdbc2fece --- /dev/null +++ b/Scripts/URLExtract.py @@ -0,0 +1,30 @@ +import re + +strURLRegex = r'(?i)(?:(?:https?|ftp):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])' + +res = [] +urls = [] +filtered = ['http://schemas.microsoft.com/office/2004/12/omml', 'http://www.w3.org/TR/REC-html40'] + +data = demisto.args()['text'] + +for m in re.finditer(strURLRegex, data, re.I): + u = m.group(0) + if u in filtered: + continue + if u in urls: + continue + if 'mailto:' in u: + continue + urls.append(u) + +res.append('URLs found:\n' + '\n'.join(urls)) +currUrls = demisto.get(demisto.context(), 'urls') +if currUrls and isinstance(currUrls, list): + for u in urls: + if u not in currUrls: + currUrls.append(u) +else: + currUrls = urls +demisto.setContext('urls', currUrls) +demisto.results(res) diff --git a/Scripts/analyzememimage.js b/Scripts/analyzememimage.js new file mode 100644 index 000000000000..49e97e874ee3 --- /dev/null +++ b/Scripts/analyzememimage.js @@ -0,0 +1,17 @@ +var imginfo = executeCommand('Vol', {file:args.memdump, system: args.system, cmd:'imageinfo'}); +if (imginfo) { + imginfo[0].Contents = '================ Image Info for ' + args.memdump + '==============\n' + imginfo[0].Contents; +} +var pstree = executeCommand('Vol', {file:args.memdump, system: args.system, cmd:'pstree'}); +if (pstree) { + pstree[0].Contents = '================ Process Tree for ' + args.memdump + '==============\n' + pstree[0].Contents; +} +var connscan = executeCommand('Vol', {file:args.memdump, system: args.system, cmd:'connscan'}); +if (connscan) { + connscan[0].Contents = '================ Past Network Connections for ' + args.memdump + '==============\n' + connscan[0].Contents; +} +var res = []; +res.push(imginfo); +res.push(pstree); +res.push(connscan); +return res; diff --git a/Scripts/analyzeosx.js b/Scripts/analyzeosx.js new file mode 100644 index 000000000000..7e0fe1f65264 --- /dev/null +++ b/Scripts/analyzeosx.js @@ -0,0 +1,40 @@ +var osx_report = executeCommand('Osxcollector', {section: args.section, system: args.system, timeout: args.timeout}); +var res = []; +var maxchecks = 10; +if (args.maxchecks) { + maxchecks = args.maxchecks; +} +for (var i=0; i 0) { + return res; +} +return 'No infected files or malicious urls detected on OSX machine: '+args.system; diff --git a/Scripts/binaryreputation.py b/Scripts/binaryreputation.py new file mode 100644 index 000000000000..5298991ee2b2 --- /dev/null +++ b/Scripts/binaryreputation.py @@ -0,0 +1,49 @@ +# Look for various hashes in the incident +# Inspect labels and attachments for hashes and check the hash reputation +import re + +strHashRegex = r'\b[a-fA-F\d]{32}\b' + +# Iterate on all the labels and find hashes +hashRe = re.compile(strHashRegex, re.I) +hashes = set() +for t in demisto.incidents()[0]['labels']: + for h in hashRe.finditer(t['value']): + hashes.add(h.group(0)) + +# Find hashes in the details +for h in hashRe.finditer(demisto.incidents()[0]['details']): + hashes.add(h.group(0)) + + +fileNames = [] +if 'fileNames' in demisto.args(): + fileNames = demisto.args()['fileNames'].split(',') + +# Also get hashes of files in war room entries +entries = demisto.executeCommand('getEntries', {}) +for entry in entries: + if entry['File'] and demisto.get(entry, 'FileMetadata.md5') and (len(fileNames) == 0 or entry['File'] in fileNames): + hashes.add(demisto.get(entry, 'FileMetadata.md5')) + +badHashes = [] +res = [] +for h in hashes: + rep = demisto.executeCommand('file', {'file': h}) + for r in rep: + if positiveFile(r): + badHashes.append(h) + res.append(shortFile(r)) + +if len(res) > 0: + res.extend(['yes', 'Found malicious hashes!']) + currHashes = demisto.get(demisto.context(), 'bad_hashes') + if currHashes and isinstance(currHashes, list): + currHashes += [h for h in badHashes if h not in currHashes] + else: + currHashes = badHashes + demisto.setContext('bad_hashes', currHashes) +else: + res.extend(['No suspicious files found', 'no']) + +demisto.results(res) diff --git a/Scripts/binarysearch.py b/Scripts/binarysearch.py new file mode 100644 index 000000000000..a73b9d8fc463 --- /dev/null +++ b/Scripts/binarysearch.py @@ -0,0 +1,40 @@ +# Look for various hashes in the incident +# Inspect labels and attachments for hashes and check if we have this process running anywhere using Carbon Black +import re + +# Iterate on all the labels and see which one has hashes +hashRe = re.compile(r'\b[a-fA-F\d]{32}\b', re.I) +hashes = set() +for t in demisto.incidents()[0]['labels']: + for h in hashRe.finditer(t['value']): + hashes.add(h.group(0)) + +# Find hashes in the details +for h in hashRe.finditer(demisto.incidents()[0]['details']): + hashes.add(h.group(0)) + +# Get also hashes from files in entries +entries = demisto.executeCommand('getEntries', {}) +for entry in entries: + if entry['File'] and demisto.get(entry, 'FileMetadata.md5'): + hashes.add(demisto.get(entry, 'FileMetadata.md5')) + +res = [] + +for h in hashes: + processes = demisto.executeCommand('process', {'query': 'md5:' + h}) + if len(processes) > 0 and processes[0]['Type'] == entryTypes['note'] and processes[0]['ContentsFormat'] == formats['json']: + process = demisto.get(processes[0], 'Contents.results') + if process: + res.append({ + '1. MD5': h, + '2. Name': demisto.get(process, 'process_name'), + '3. Hostname': demisto.get(process, 'hostname'), + '4. Path': demisto.get(process, 'path'), + '5. Updated': demisto.get(process, 'last_update'), + '6. Terminated': demisto.get(process, 'terminated')}) + +if len(res) > 0: + demisto.results(['yes', {'Type': entryTypes['note'], 'ContentsFormat': formats['table'], 'Contents': res}]) +else: + demisto.results(['no', {'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': 'No process hashes found'}]) diff --git a/Scripts/cbevents.js b/Scripts/cbevents.js new file mode 100644 index 000000000000..1bb506b23463 --- /dev/null +++ b/Scripts/cbevents.js @@ -0,0 +1,48 @@ +//Searches for all processes with a given query - and lists events associated with processes. +//Args - process search query + +var output = []; + +function formatEvents(header, pname, pid, segid, arr) { + var entry = []; + if (typeof (arr) !== 'undefined') { + + for (var i = 0; i < arr.length; i++) { + var items = arr[i].split("|"); + var row = {}; + row["name"]=pname; + row["pid"]=pid; + row["segid"]=segid; + for (var k = 0; k < items.length; k++){ + row[header[k]]=items[k]; + } + entry.push(row); + } + output.push({ContentsFormat: formats.table, Type: entryTypes.note, Contents: entry}); + } +} + +var res = executeCommand("cb-process", {session: args.sessionid, query: args.query}); +if (res.length > 0) { + var list = res[0].Contents.results; + if (typeof (list) !== 'undefined') { + if (list.length === 0) { + output.push({ContentsFormat: formats.text, Type: entryTypes.note, Contents: "No results"}); + } + for (var i = 0; i < list.length; i++) { + var process = list[i]; + var res1 = executeCommand("process-events", {pid: process.id.toString(), segid: process.segment_id.toString()}); + var pevent = res1[0].Contents; + formatEvents(["time","md5","path"],pevent.process.process_name,process.id, process.segment_id, pevent.process.modload_complete); + formatEvents(["type","time","reg path"],pevent.process.process_name,process.id, process.segment_id, pevent.process.regmod_complete); + formatEvents(["type","time","file path","last md5","file type","tamper"],pevent.process.process_name,process.id, process.segment_id, pevent.process.filemod_complete); + formatEvents(["time","remote ip","remote port","proto","dns name","outbound"],pevent.process.process_name,process.id, process.segment_id, pevent.process.netconn_complete); + formatEvents(["time","uid","md5","path","pid","started","tamper"],pevent.process.process_name,process.id, process.segment_id, pevent.process.childproc_complete); + formatEvents(["type","time","uid","md5","path","sub-type","access","tamper"],pevent.process.process_name,process.id, process.segment_id, pevent.process.crossproc_complete); + } + } else { + output.push(res); + } +} + +return output; diff --git a/Scripts/cbliveprocesslist.js b/Scripts/cbliveprocesslist.js new file mode 100644 index 000000000000..d976af2f86b2 --- /dev/null +++ b/Scripts/cbliveprocesslist.js @@ -0,0 +1,9 @@ +//Execute 'process list' command on a sensor +//Args - sensor ID, session ID +var output = []; + +var cmd = executeCommand("cb-command-create",{session: args.sessionid, wait: "true", name: "process list"}); +var id = cmd[0].Contents.id; +var result = executeCommand("cb-command-info",{session: args.sessionid, command: id.toString()}); +output.push({ContentsFormat: formats.table, Type: entryTypes.note, Contents: result[0].Contents.processes}); +return output; \ No newline at end of file diff --git a/Scripts/cbsearch.js b/Scripts/cbsearch.js new file mode 100644 index 000000000000..b270b5474f15 --- /dev/null +++ b/Scripts/cbsearch.js @@ -0,0 +1,53 @@ +//Script to query carbon black servers: +//type must be either 'process' or 'binary' +//can provide query & number of rows to return + +function formatresults(rows, columns) { + var table = []; + for (var index in rows) { + var row = rows[index]; + if (typeof (row) === "object") { + tablerow = {}; + for (var name in row) { + var value = row[name]; + if (typeof (value) === "object") { + value = JSON.stringify(value); + } + var columnIndex = columns.indexOf(name); + var columnName; + if (columnIndex !== -1) { + columnName = columnIndex.toString() + ". " + name; + } else { + columnName = name; + } + tablerow[columnName] = value; + } + table.push(tablerow); + } + } + return table; +} + +var output = []; +var searchType = args.type ? args.type : 'process'; +if ((searchType !== 'process') && (searchType !== 'binary')) { + output.push({ContentsFormat: formats.text, Type: entryTypes.error, Contents: "Error! type must be 'process' or 'binary"}); +} else { + var res = []; + var columns = []; + if (searchType === 'process') { + columns = ["hostname", "username", "process_pid", "path", "process_md5", "start", "os_type", "parent_pid", "sensor_id"]; + } else { + columns = ["md5", "observed_filename", "original_filename", "is_executable_image", "endpoint", "signed", "os_type"]; + } + myArgs = { + start: args.start ? args.start : '0', + rows: args.rows ? args.rows : '20' + }; + if(args.query) + myArgs.query = args.query; + res = executeCommand('cb-' + searchType, myArgs); + var table = formatresults(res[0].Contents.results, columns); + output.push({ContentsFormat: formats.table, Type: entryTypes.note, Contents: table}); +} +return output; diff --git a/Scripts/cbsensors.js b/Scripts/cbsensors.js new file mode 100644 index 000000000000..0f5fa84dfeeb --- /dev/null +++ b/Scripts/cbsensors.js @@ -0,0 +1,5 @@ +//Show a list of carbon black sensors. +var sensors = executeCommand("cb-list-sensors",{}) +var output = sensors[0]; +output.ContentsFormat = formats.table; +return output; \ No newline at end of file diff --git a/Scripts/cbsessions.js b/Scripts/cbsessions.js new file mode 100644 index 000000000000..66eb093eb0ad --- /dev/null +++ b/Scripts/cbsessions.js @@ -0,0 +1,26 @@ +//Show a list of carbon black sessions. +//Argument: Verbose = true, to show all properties. +var output = []; +var entries = executeCommand("cb-list-sessions", {}); +var array = entries[0].Contents; +var outTable = []; +for (var index in array) { + var item = array[index]; + var outItem = {}; + if (args.verbose === "true") { + for (var name in item) { + var value = item[name]; + if (typeof (value) !== "object") { + outItem[name] = value; + } + } + } else { + outItem["status"] = item["status"]; + outItem["id"] = item["id"]; + outItem["sensor"]=item["sensor_id"]; + } + outTable.push(outItem); +} +output.push({ContentsFormat: formats.table, Type: entryTypes.note, Contents: outTable}); + +return output; \ No newline at end of file diff --git a/Scripts/checkfiles.js b/Scripts/checkfiles.js new file mode 100644 index 000000000000..407c9db5b5eb --- /dev/null +++ b/Scripts/checkfiles.js @@ -0,0 +1,23 @@ +var fileNames = []; +if (args.fileNames) { + fileNames = args.fileNames.split(','); +} +var entries = executeCommand('getEntries', {}); +var res = []; +for (var i=0; i= 0)) { + var rep = executeCommand('file', {file: entries[i].FileMetadata.MD5}); + if (rep && Array.isArray(rep)) { + for (var r = 0; r < rep.length; r++) { + if (positiveFile(rep[r])) { + res.push(shortFile(rep[r])); + } + } + } + } +} +if (res.length > 0) { + res.push('yes'); + return res; +} +return ['No suspicious files found', 'no']; diff --git a/Scripts/checkfileswildfire.py b/Scripts/checkfileswildfire.py new file mode 100644 index 000000000000..d701a3d1708f --- /dev/null +++ b/Scripts/checkfileswildfire.py @@ -0,0 +1,37 @@ +import time + +fileNames = [] +if 'fileNames' in demisto.args(): + fileNames = demisto.args()['fileNames'].split(',') + +res = [] +uploaded = [] +entries = demisto.executeCommand('getEntries', {}) +for entry in entries: + if entry['File'] and demisto.get(entry, 'FileMetadata.md5') and (len(fileNames) == 0 or entry['File'] in fileNames): + demisto.log('Checking - ' + demisto.get(entry, 'FileMetadata.md5')) + rep = demisto.executeCommand('wildfire-report', {'md5': demisto.get(entry, 'FileMetadata.md5')}) + for r in rep: + if positiveFile(r): + res.append(shortFile(r)) + elif r['Type'] == entryTypes['error'] and '404' in r['Contents']: + upReply = demisto.executeCommand('wildfire-upload', {'upload': entry['ID']}) + if upReply[0]['Type'] != entryTypes['error']: + uploaded.append(demisto.get(entry, 'FileMetadata.md5')) + +# Wait for the uploaded files to be processed - 15 min +if len(uploaded) > 0: + time.sleep(15 * 60) + +for u in uploaded: + rep = demisto.executeCommand('wildfire-report', {'md5': u}) + notFound = False + for r in rep: + if positiveFile(r): + res.append(shortFile(r)) + +if len(res) > 0: + res.append('yes') +else: + res.extend(['No suspicious files found', 'no']) +demisto.results(res) diff --git a/Scripts/checkips.py b/Scripts/checkips.py new file mode 100644 index 000000000000..46fe387adce0 --- /dev/null +++ b/Scripts/checkips.py @@ -0,0 +1,54 @@ +import re +import socket + +strIpRegex = r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b' + +def is_valid_ipv4_address(address): + try: + socket.inet_pton(socket.AF_INET, address) + except AttributeError: # no inet_pton here, sorry + try: + socket.inet_aton(address) + except socket.error: + return False + return address.count('.') == 3 + except socket.error: # not a valid address + return False + return True + +res = [] +ips = [] +badIps = [] + +data = demisto.args()['data'] if demisto.get(demisto.args(), 'data') else demisto.incidents()[0]['details'] + +if isinstance(data, list): + ips = data[:] +else: + for m in re.finditer(strIpRegex, data, re.I): + ip = m.group(0) + if ip in ips: + continue + if not is_valid_ipv4_address(ip): + continue + ips.append(ip) +for ip in ips: + rep = demisto.executeCommand('ip', {'ip': ip}) + for r in rep: + if positiveIp(r): + badIps.append(ip) + res.append(shortIp(r)) + +if len(res) > 0: + res.extend(['yes', 'Found malicious IPs!']) + currIps = demisto.get(demisto.context(), 'bad_ips') + if currIps and isinstance(currIps, list): + currIps += [i for i in badIps if i not in currIps] + else: + currIps = badIps + demisto.setContext('bad_ips', currIps) +else: + res.append('no') + res.append('Only clean IPs found: \n' + '\n'.join(ips)) + +demisto.results(res) diff --git a/Scripts/checksender.js b/Scripts/checksender.js new file mode 100644 index 000000000000..d173a767d480 --- /dev/null +++ b/Scripts/checksender.js @@ -0,0 +1,7 @@ +var fromRE = /From:.*href="mailto:(.*)"/ig; +var from = fromRE.exec(incidents[0].details); +var res = []; +var rep = executeCommand('pipl-search', {email: from[1]}); +Array.prototype.push.apply(res, rep); +res.push({Contents: 'no', Type: entryTypes.note, ContentsFormat: formats.text}); +return res; diff --git a/Scripts/checksender.py b/Scripts/checksender.py new file mode 100644 index 000000000000..57d84439cf55 --- /dev/null +++ b/Scripts/checksender.py @@ -0,0 +1,13 @@ +import re + +email = '' +if 'email' in demisto.args(): + email = demisto.args()['email'] +else: + sender = re.search('From:.*href="mailto:(.*)"', demisto.incidents()[0]['details'], re.I) + if sender: + email = sender.group(1) +if email: + demisto.results(demisto.executeCommand('pipl-search', {'email': email})) +else: + demisto.results('Could not find the sender data') diff --git a/Scripts/checksenderdomaindistance.py b/Scripts/checksenderdomaindistance.py new file mode 100644 index 000000000000..760bd0316223 --- /dev/null +++ b/Scripts/checksenderdomaindistance.py @@ -0,0 +1,44 @@ +import re + +domain = 'demisto.com' +if 'domain' in demisto.args(): + domain = demisto.args()['domain'] + +def levenshtein(s1, s2): + l1 = len(s1) + l2 = len(s2) + + matrix = [range(l1 + 1)] * (l2 + 1) + for zz in range(l2 + 1): + matrix[zz] = range(zz,zz + l1 + 1) + for zz in range(0,l2): + for sz in range(0,l1): + if s1[sz] == s2[zz]: + matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz]) + else: + matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz] + 1) + return matrix[l2][l1] + +res = [] +found = False +sender = demisto.get(demisto.args(), 'sender') +if not sender: + sender = re.search(r".*From\w*:.*\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})\b", demisto.incidents()[0]['details'], re.I) +if sender: + parts = sender.group(1).split('@') + if len(parts) == 2: + distance = levenshtein(domain, parts[1]) + if distance > 0 and distance < 3: + res.append({'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': 'Domain ' + parts[1] + ' is suspicioiusly close to ' + domain}) + found = True + else: + res.append({'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Unable to extract domain from sender - ' + sender.group(1)}) +else: + res.append({'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Unable to find sender in email'}) + +if found: + res.append('yes') +else: + res.append('no') + +demisto.results(res) diff --git a/Scripts/checkurls.py b/Scripts/checkurls.py new file mode 100644 index 000000000000..211f95d25f18 --- /dev/null +++ b/Scripts/checkurls.py @@ -0,0 +1,44 @@ +import re + +strURLRegex = r'(?i)(?:(?:https?|ftp):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])' + +res = [] +urls = [] +badUrls = [] +filtered = ['http://schemas.microsoft.com/office/2004/12/omml', 'http://www.w3.org/TR/REC-html40'] + +data = demisto.args()['data'] if demisto.get(demisto.args(), 'data') else demisto.incidents()[0]['details'] + +if isinstance(data, list): + urls = data[:] +else: + for m in re.finditer(strURLRegex, data, re.I): + u = m.group(0) + if u in filtered: + continue + if u in urls: + continue + if 'mailto:' in u: + continue + urls.append(u) + +for u in urls: + rep = demisto.executeCommand('url', {'url': u}) + for r in rep: + if positiveUrl(r): + badUrls.append(u) + res.append(shortUrl(r)) + +if len(res) > 0: + res.extend(['yes', 'Found malicious URLs!']) + currUrls = demisto.get(demisto.context(), 'bad_urls') + if currUrls and isinstance(currUrls, list): + currUrls += [u for u in badUrls if u not in currUrls] + else: + currUrls = badUrls + demisto.setContext('bad_urls', currUrls) +else: + res.append('no') + res.append('Only clean URLs found: \n' + '\n'.join(urls)) + +demisto.results(res) diff --git a/Scripts/common-d2.js b/Scripts/common-d2.js new file mode 100644 index 000000000000..a04474810d2e --- /dev/null +++ b/Scripts/common-d2.js @@ -0,0 +1,36 @@ +// Common functions script +// ======================= +// This script will be appended to each d2 agent script before being executed. +// Place here all common functions you'd like to share between d2 agent scripts. + +/** + * Checks if the given string represents a valid IPv4 address + * @param {String} ip - the string to check + * @returns {Boolean} true if valid IPv4 address + */ +function isIp(ip) { + var d = ip.split('.'), i = d.length; + if (i !== 4) { + return false; + } + var ok = true; + while (i-- && ok) { + ok = d[i].length !== 0 && !isNaN(parseInt(d[i])) && d[i] > -1 && d[i] < 256; + } + return ok; +} + +/** + * Execute a command and pack the standard output or throw the error + * @param {String} command - the command to execute on the OS + * @returns {Void} + */ +function packOutput(command){ + var output = execute(command); + if (output.Success) { + pack(output.Stdout); + } else { + throw 'Errcode:' + output.Error + '\nStderr:' + output.Stderr + '\nStdout: ' + output.Stdout; + + } +} diff --git a/Scripts/common.js b/Scripts/common.js new file mode 100644 index 000000000000..296d2c009dfe --- /dev/null +++ b/Scripts/common.js @@ -0,0 +1,373 @@ +// Common functions script +// ======================= +// This script will be appended to each server script before being executed. +// Place here all common functions you'd like to share between server scripts. + +/** + * Checks if the given string represents a valid IPv4 address + * @param {String} ip - the string to check + * @returns {Boolean} true if valid IPv4 address + */ +function isIp(ip) { + var d = ip.split('.'), i = d.length; + if (i !== 4) { + return false; + } + var ok = true; + while (i-- && ok) { + ok = d[i].length !== 0 && !isNaN(parseInt(d[i])) && d[i] > -1 && d[i] < 256; + } + return ok; +} + +var entryTypes = {note: 1, downloadAgent: 2, file: 3, error: 4, pinned: 5, userManagement: 6, image: 7, plagroundError: 8}; +var formats = {table: 'table', json: 'json', text: 'text', dbotResponse: 'dbotCommandResponse', markdown: 'markdown'}; +var brands = {xfe: 'xfe', vt: 'virustotal', cy: 'cylance', wf: 'wildfire', cs: 'crowdstrike-intel'}; +var providers = {xfe: 'IBM X-Force Exchange', vt: 'VirusTotal', cy: 'Cylance', wf: 'WildFire', cs: 'CrowdStrike'}; + +/** + * Returns the name of the file as stored in our investigation artifacts on disk. + * This should be used when sending files to d2 scripts as you can see in StaticAnalyze. + * @param {String} entryId - the entry ID containing the file + * @returns {String} the name of the file in our artifact repository + */ +function fileNameFromEntry(entryId) { + var parts = entryId.split('@'); + if (parts.length !== 2) { + return null; + } + var res = executeCommand('getEntry', {id: entryId}); + if (res && Array.isArray(res) && res.length === 1) { + return parts[1] + '_' + res[0].FileID; + } + return null; +} + +/** + * Closes the current investigation + * @param {Object} args - arguments for the close (what happened, damange, etc.) + * @returns {Array} an array with error entry if there is an error or empty array + */ +function closeInvestigation(args) { + return executeCommand('closeInvestigation', args); +} + +// Thresholds for the various reputation services to mark something as positive +var thresholds = {xfeScore: 3, vtPositives: 10, vtPositiveUrlsForIP: 10}; + +/** + * Checks if the given entry from a URL reputation query is positive (known bad) + * @param {Object} entry - reputation entry + * @returns {Boolean} true if positive, false otherwise + */ +function positiveUrl(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && c && c.url.result.score && c.url.result.score > thresholds.xfeScore) { + return true; + } else if (entry.Brand === brands.vt && c && c.positives && c.positives > thresholds.vtPositives) { + return true; + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator && (c[0].malicious_confidence === 'high' || c[0].malicious_confidence === 'medium')) { + return true; + } + } + return false; +} + +/** + * Checks if the given entry from a file reputation query is positive (known bad) + * @param {Object} entry - reputation entry + * @returns {Boolean} true if positive, false otherwise + */ +function positiveFile(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && c && c.malware.family) { + return true; + } else if (entry.Brand === brands.vt && c && c.positives && c.positives > thresholds.vtPositives) { + return true; + } else if (entry.Brand === brands.wf && c && c.wildfire && c.wildfire.file_info) { + return c.wildfire.file_info.malware === 'yes'; + } else if (entry.Brand === brands.cy && c) { + var k = Object.keys(c); + if (k && k.length > 0) { + var v = c[k[0]]; + if (v && v.generalscore) { + return v.generalscore < -0.5; + } + } + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator && (c[0].malicious_confidence === 'high' || c[0].malicious_confidence === 'medium')) { + return true; + } + } + return false; +} + +/** + * Checks if the given entry from an IP reputation query is positive (known bad) + * @param {Object} entry - reputation entry + * @returns {Boolean} true if positive, false otherwise + */ +function positiveIP(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && c && c.reputation.score && c.reputation.score > thresholds.xfeScore) { + return true; + } else if (entry.Brand === brands.vt && c && c.detected_urls) { + var positives = 0; + for (var i = 0; i < c.detected_urls.length; i++) { + if (c.detected_urls[i].positives > thresholds.vtPositives) { + positives++; + } + } + return positives > thresholds.vtPositiveUrlsForIP; + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator && (c[0].malicious_confidence === 'high' || c[0].malicious_confidence === 'medium')) { + return true; + } + } + return false; +} + +/** + * Display CrowdStrike Intel results in Markdown + * @param {Object} entry - reputation entry + * @returns {Object} the markdown entry + */ +function shortCrowdStrike(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.cs && c && c.length && c[0].indicator) { + var csRes = '## CrowdStrike Falcon Intelligence'; + csRes += '\n\n### Indicator - ' + c[0].indicator; + if (c[0].labels && c[0].labels.length) { + csRes += '\n### Labels'; + csRes += '\nName|Created|Last Valid'; + csRes += '\n----|-------|----------'; + for (var l = 0; l < c[0].labels.length; l++) { + csRes += '\n' + c[0].labels[l].name + '|' + new Date(c[0].labels[l].created_on * 1000) + '|' + new Date(c[0].labels[l].last_valid_on * 1000); + } + } + if (c[0].relations && c[0].relations.length) { + csRes += '\n### Relations'; + csRes += '\nIndicator|Type|Created|Last Valid'; + csRes += '\n---------|----|-------|----------'; + for (var r = 0; r < c[0].relations.length; r++) { + csRes += '\n' + c[0].relations[r].indicator + '|' + c[0].relations[r].type + '|' + new Date(c[0].relations[r].created_date * 1000) + '|' + new Date(c[0].relations[r].last_valid_date * 1000); + } + } + return {ContentsFormat: formats.markdown, Type: entryTypes.note, Contents: csRes}; + } + } + return entry; +} + +/** + * Formats a URL reputation entry into a short table + * @param {Object} entry - reputation entry + * @returns {Object} the table entry + */ +function shortUrl(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && c) { + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + Country: c.country, MalwareCount: c.malware.count, A: c.resolution.A ? c.resolution.A.join(',') : '', + AAAA: c.resolution.AAAA ? c.resolution.AAAA.join(',') : '', Score: c.url.result.score, + Categories: c.url.result.cats ? Object.keys(c.url.result.cats).join(',') : '', + URL: c.url.result.url, Provider: providers.xfe, ProviderLink: 'https://exchange.xforce.ibmcloud.com/url/' + c.url.result.url + }}; + } else if (entry.Brand === brands.vt && c) { + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + ScanDate: c.scan_date, Positives: c.positives, Total: c.total, URL: c.url, Provider: providers.vt, ProviderLink: c.permalink + }}; + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator) { + return shortCrowdStrike(entry); + } + } + return entry; +} + +/** + * Formats a file reputation entry into a short table + * @param {Object} entry - reputation entry + * @returns {Object} the table entry + */ +function shortFile(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && entry.Contents) { + var cm = c.malware; + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + Family: cm.family, MIMEType: cm.mimetype, MD5: cm.md5 ? cm.md5.substring(2) : '', + CnCServers: cm.origins.CnCServers.count, DownloadServers: cm.origins.downloadServers.count, + Emails: cm.origins.emails.count, ExternalFamily: cm.origins.external && cm.origins.external.family ? cm.origins.external.family.join(',') : '', + ExternalCoverage: cm.origins.external.detectionCoverage, Provider: providers.xfe, + ProviderLink: 'https://exchange.xforce.ibmcloud.com/malware/' + cm.md5.replace(/^(0x)/,"") + }}; + } else if (entry.Brand === brands.vt && entry.Contents) { + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + Resource: c.resource, ScanDate: c.scan_date, Positives: c.positives, Total: c.total, SHA1: c.sha1, SHA256: c.sha256, Provider: providers.vt, ProviderLink: c.permalink + }}; + } else if (entry.Brand === brands.cy && entry.Contents) { + var k = Object.keys(entry.Contents); + if (k && k.length > 0) { + var v = entry.Contents[k[0]]; + if (v) { + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + Status: v.status, Code: v.statuscode, Score: v.generalscore, Classifiers: JSON.stringify(v.classifiers), ConfirmCode: v.confirmcode, Error: v.error, Provider: providers.cy + }}; + } + } + } else if (entry.Brand === brands.wf && entry.Contents && entry.Contents.wildfire && entry.Contents.wildfire.file_info) { + var c = entry.Contents.wildfire.file_info; + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + Type: c.filetype, Malware: c.malware, MD5: c.md5, SHA256: c.sha256, Size: c.size, Provider: providers.wf + }}; + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator) { + return shortCrowdStrike(entry); + } + } + return entry; +} + +/** + * Formats an ip reputation entry into a short table + * @param {Object} entry - reputation entry + * @returns {Object} the table entry + */ +function shortIP(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + var c = entry.Contents; + if (entry.Brand === brands.xfe && entry.Contents) { + var cr = c.reputation; + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + IP: cr.ip, Score: cr.score, Geo: cr.geo && cr.geo['country'] ? cr.geo['country'] : '', + Categories: cr.cats ? JSON.stringify(cr.cats) : '', Provider: providers.xfe + }}; + } else if (entry.Brand === brands.vt && entry.Contents) { + var positives = 0; + for (var i = 0; i < entry.Contents.detected_urls.length; i++) { + if (entry.Contents.detected_urls[i].positives > thresholds.vtPositives) { + positives++; + } + } + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + DetectedURLs: positives, Provider: providers.vt + }}; + } else if (entry.Brand === brands.cs && c && c.length && c[0].indicator) { + return shortCrowdStrike(entry); + } + } + return entry; +} + +/** + * Formats a domain reputation entry into a short table + * @param {Object} entry - reputation entry + * @returns {Object} the table entry + */ +function shortDomain(entry) { + if (entry.Type !== entryTypes.error && entry.ContentsFormat === formats.json) { + if (entry.Brand === brands.vt && entry.Contents) { + var c = entry.Contents; + var positives = 0; + for (var i = 0; i < entry.Contents.detected_urls.length; i++) { + if (entry.Contents.detected_urls[i].positives > 20) { + positives++; + } + } + return {ContentsFormat: formats.table, Type: entryTypes.note, Contents: { + DetectedURLs: positives, Provider: providers.vt + }}; + } + } + return entry; +} + +/** + * Sets severity an incident. The incident must be related to current investigation. + * @param {Object} arg - has 2 keys, 'id' - the incident id, 'severity' - the new severity value (Critical, High, Medium etc.). + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setSeverity(arg) { + return executeCommand('setSeverity', arg); +} + +/** + * Sets fields of the incident. The incident must be related to current investigation and be the only incident in it. + * @param {Object} args - has 5 optional keys: type, severity, details, incName and systems of the incident. + * systems should follow this string template: '1.1.1.1,10.10.10.10' + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setIncident(args) { + return executeCommand('setIncident', args); +} + +/** + * Create a new incident with the fields specified, only if an incident with the same name does not exist as an active incident. + * If an active incident with the same name exists, ignore the request. + * @param {Object} args - has 5 optional keys: type, severity, details, incName and system of the incident. + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function createNewIncident(args) { + return executeCommand('createNewIncident', args); +} + +/** + * Sets playbook according to type. + * @param {String} type - the incident type, which the playbook is set accordingly. + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setPlaybookAccordingToType(type) { + return executeCommand('setPlaybookAccordingToType', {type: type}); +} + +/** + * Sets Owner to an incident. The incident must be related to current investigation. + * @param {Object} name - the owner user name. + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setOwner(name) { + return executeCommand('setOwner', { owner: name }); +} + +/** + * Assigns a playbook task to a user. + * @param {Object} arg - has 2 keys, 'id' - the task id, 'assignee' - assignee user name. + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function taskAssign(arg) { + return executeCommand('taskAssign', arg); +} + +/** + * Sets task due date. + * @param {Object} arg - has 2 keys, 'id' - the task id, 'dueDate' - time string in UTC format (To get current time use: 'new Date().toUTCString()'). + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setTaskDueDate(arg) { + return executeCommand('setTaskDueDate', arg); +} + +/** + * Sets investigation playbook + * @param {String} name - the playbook name. + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function setPlaybook(name) { + return executeCommand('setPlaybook', { name: name }); +} + +/** + * Adds task to Workplan + * @param {Object} arg - has 5 keys: + * 'name' - (mandatory) The new task's name. + * 'description' - (optional) The new task's description. + * 'script' - (optional) Name of script to be run by task. + * 'addBefore' - (optional, refers to task id) Insert new task before specified task (when using this argument do not use afterTask) + * 'addAfter' - (optional, refers to task id) Insert new task after specified task (when using this argument do not use beforeTask) + * @returns {Array} in case of error will contain the error entry. In Case of success will return an empty array. + */ +function addTask(arg) { + return executeCommand('addTask', arg); +} diff --git a/Scripts/common.py b/Scripts/common.py new file mode 100644 index 000000000000..3e302c385d5d --- /dev/null +++ b/Scripts/common.py @@ -0,0 +1,185 @@ +# Common functions script +# ======================= +# This script will be appended to each server script before being executed. +# Please notice that to add custom common code, add it to the CommonServerUserPython script +from datetime import datetime, timedelta +import time + +entryTypes = {'note': 1, 'downloadAgent': 2, 'file': 3, 'error': 4, 'pinned': 5, 'userManagement': 6, 'image': 7, 'plagroundError': 8} +formats = {'table': 'table', 'json': 'json', 'text': 'text', 'dbotResponse': 'dbotCommandResponse', 'markdown': 'markdown'} +brands = {'xfe': 'xfe', 'vt': 'virustotal', 'wf': 'wildfire', 'cy': 'cylance', 'cs': 'crowdstrike-intel'} +providers = {'xfe': 'IBM X-Force Exchange', 'vt': 'VirusTotal', 'wf': 'Wildfire', 'cy': 'Cylance', 'cs': 'CrowdStrike'} +thresholds = {'xfeScore': 4, 'vtPositives': 10, 'vtPositiveUrlsForIP': 30} + +# Checks if the given entry from a URL reputation query is positive (known bad) +def positiveUrl(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + if entry['Brand'] == brands['xfe']: + return demisto.get(entry, 'Contents.url.result.score') > thresholds['xfeScore'] + if entry['Brand'] == brands['vt']: + return demisto.get(entry, 'Contents.positives') > thresholds['vtPositives'] + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + c = demisto.get(entry, 'Contents')[0] + return demisto.get(c, 'indicator') and demisto.get(c, 'malicious_confidence') in ['high', 'medium'] + return False + +def positiveFile(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + if entry['Brand'] == brands['xfe'] and (demisto.get(entry, 'Contents.malware.family') or demisto.gets(entry, 'Contents.malware.origins.external.family')): + return True + if entry['Brand'] == brands['vt']: + return demisto.get(entry, 'Contents.positives') > thresholds['vtPositives'] + if entry['Brand'] == brands['wf']: + return demisto.get(entry, 'Contents.wildfire.file_info.malware') == 'yes' + if entry['Brand'] == brands['cy'] and demisto.get(entry, 'Contents'): + contents = demisto.get(entry, 'Contents') + k = contents.keys() + if k and len(k) > 0: + v = contents[k[0]] + if v and demisto.get(v, 'generalscore'): + return v['generalscore'] < -0.5 + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + c = demisto.get(entry, 'Contents')[0] + return demisto.get(c, 'indicator') and demisto.get(c, 'malicious_confidence') in ['high', 'medium'] + return False + +def vtCountPositives(entry): + positives = 0 + if demisto.get(entry, 'Contents.detected_urls'): + for detected in demisto.get(entry, 'Contents.detected_urls'): + if demisto.get(detected, 'positives') > thresholds['vtPositives']: + positives += 1 + return positives + +def positiveIp(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + if entry['Brand'] == brands['xfe']: + return demisto.get(entry, 'Contents.reputation.score') > thresholds['xfeScore'] + if entry['Brand'] == brands['vt'] and demisto.get(entry, 'Contents.detected_urls'): + return vtCountPositives(entry) > thresholds['vtPositiveUrlsForIP'] + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + c = demisto.get(entry, 'Contents')[0] + return demisto.get(c, 'indicator') and demisto.get(c, 'malicious_confidence') in ['high', 'medium'] + return False + +def formatEpochDate(t): + if t: + return time.ctime(t) + return '' + +def shortCrowdStrike(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + c = demisto.get(entry, 'Contents')[0] + csRes = '## CrowdStrike Falcon Intelligence' + csRes += '\n\n### Indicator - ' + demisto.gets(c, 'indicator') + labels = demisto.get(c, 'labels') + if labels: + csRes += '\n### Labels' + csRes += '\nName|Created|Last Valid' + csRes += '\n----|-------|----------' + for label in labels: + csRes += '\n' + demisto.gets(label, 'name') + '|' + formatEpochDate(demisto.get(label, 'created_on')) + '|' + formatEpochDate(demisto.get(label, 'last_valid_on')) + relations = demisto.get(c, 'relations') + if relations: + csRes += '\n### Relations' + csRes += '\nIndicator|Type|Created|Last Valid' + csRes += '\n---------|----|-------|----------' + for r in relations: + csRes += '\n' + demisto.gets(r, 'indicator') + '|' + demisto.gets(r, 'type') + '|' + formatEpochDate(demisto.get(label, 'created_date')) + '|' + formatEpochDate(demisto.get(label, 'last_valid_date')) + return {'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': csRes} + return entry + +def shortUrl(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + c = entry['Contents'] + if entry['Brand'] == brands['xfe']: + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': { + 'Country': c['country'], 'MalwareCount': demisto.get(c, 'malware.count'), + 'A': demisto.gets(c, 'resolution.A'), 'AAAA': demisto.gets(c, 'resolution.AAAA'), + 'Score': demisto.get(c, 'url.result.score'), 'Categories': demisto.gets(c, 'url.result.cats'), + 'URL': demisto.get(c, 'url.result.url'), 'Provider': providers['xfe'], 'ProviderLink': 'https://exchange.xforce.ibmcloud.com/url/' + demisto.get(c, 'url.result.url')}} + if entry['Brand'] == brands['vt']: + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': { + 'ScanDate': c['scan_date'], 'Positives': c['positives'], 'Total': c['total'], + 'URL': c['url'], 'Provider': providers['vt'], 'ProviderLink': c['permalink']}} + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + return shortCrowdStrike(entry) + return {'ContentsFormat': 'text', 'Type': 4, 'Contents': 'Unknown provider for result: ' + entry['Brand']} + +def shortFile(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + c = entry['Contents'] + if entry['Brand'] == brands['xfe']: + cm = c['malware'] + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': { + 'Family': cm['family'], 'MIMEType': cm['mimetype'], 'MD5': cm['md5'][2:] if 'md5' in cm else '', + 'CnCServers': demisto.get(cm, 'origins.CncServers.count'), 'DownloadServers': demisto.get(cm, 'origins.downloadServers.count'), + 'Emails': demisto.get(cm, 'origins.emails.count'), 'ExternalFamily': demisto.gets(cm, 'origins.external.family'), + 'ExternalCoverage': demisto.get(cm, 'origins.external.detectionCoverage'), 'Provider': providers['xfe'], + 'ProviderLink': 'https://exchange.xforce.ibmcloud.com/malware/' + cm['md5'].replace('0x', '')}} + if entry['Brand'] == brands['vt']: + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': { + 'Resource': c['resource'], 'ScanDate': c['scan_date'], 'Positives': c['positives'], + 'Total': c['total'], 'SHA1': c['sha1'], 'SHA256': c['sha256'], 'Provider': providers['vt'], 'ProviderLink': c['permalink']}} + if entry['Brand'] == brands['wf']: + c = demisto.get(entry, 'Contents.wildfire.file_info') + if c: + return {'Contents': {'Type': c['filetype'], 'Malware': c['malware'], 'MD5': c['md5'], 'SHA256': c['sha256'], 'Size': c['size'], 'Provider': providers['wf']}, + 'ContentsFormat': formats['table'], 'Type': entryTypes['note']} + if entry['Brand'] == brands['cy'] and demisto.get(entry, 'Contents'): + contents = demisto.get(entry, 'Contents') + k = contents.keys() + if k and len(k) > 0: + v = contents[k[0]] + if v and demisto.get(v, 'generalscore'): + return {'Contents': {'Status': v['status'], 'Code': v['statuscode'], 'Score': v['generalscore'], 'Classifiers': str(v['classifiers']), 'ConfirmCode': v['confirmcode'], 'Error': v['error'], 'Provider': providers['cy']}, + 'ContentsFormat': formats['table'], 'Type': entryTypes['note']} + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + return shortCrowdStrike(entry) + return {'ContentsFormat': formats['text'], 'Type': entryTypes['error'], 'Contents': 'Unknown provider for result: ' + entry['Brand']} + +def shortIp(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + c = entry['Contents'] + if entry['Brand'] == brands['xfe']: + cr = c['reputation'] + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': { + 'IP': cr['ip'], 'Score': cr['score'], 'Geo': str(cr['geo']), 'Categories': str(cr['cats']), + 'Provider': providers['xfe']}} + if entry['Brand'] == brands['vt']: + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': {'Positive URLs': vtCountPositives(entry), 'Provider': providers['vt']}} + if entry['Brand'] == brands['cs'] and demisto.get(entry, 'Contents'): + return shortCrowdStrike(entry) + return {'ContentsFormat': formats['text'], 'Type': entryTypes['error'], 'Contents': 'Unknown provider for result: ' + entry['Brand']} + +def shortDomain(entry): + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + if entry['Brand'] == brands['vt']: + return {'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': {'Positive URLs': vtCountPositives(entry), 'Provider': providers['vt']}} + return {'ContentsFormat': formats['text'], 'Type': entryTypes['error'], 'Contents': 'Unknown provider for result: ' + entry['Brand']} + +def isError(entry): + return type(entry)==dict and entry['Type']==entryTypes['error'] + + +def FormatADTimestamp(ts): + return ( datetime(year=1601, month=1, day=1) + timedelta(seconds = int(ts)/10**7) ).ctime() + +def PrettifyCompactedTimestamp(x): + return '%s-%s-%sT%s:%s:%s' % (x[:4], x[4:6], x[6:8], x[8:10], x[10:12], x[12:]) + +def NormalizeRegistryPath(strRegistryPath): + dSub = { + 'HKCR' : 'HKEY_CLASSES_ROOT', + 'HKCU' : 'HKEY_CURRENT_USER', + 'HKLM' : 'HKEY_LOCAL_MACHINE', + 'HKU' : 'HKEY_USERS', + 'HKCC' : 'HKEY_CURRENT_CONFIG', + 'HKPD' : 'HKEY_PERFORMANCE_DATA' + } + for k in dSub: + if strRegistryPath[:len(k)] == k: + return dSub[k] + strRegistryPath[len(k):] + return strRegistryPath + diff --git a/Scripts/csactors.py b/Scripts/csactors.py new file mode 100644 index 000000000000..b7f4ad0ce606 --- /dev/null +++ b/Scripts/csactors.py @@ -0,0 +1,41 @@ +import time + +def formatDate(t): + if t: + return time.ctime(t) + return '' + +def formatSlugs(slugs): + res = '' + first = True + if slugs: + for s in slugs: + if first: + first = False + else: + res += ', ' + res += demisto.gets(s, 'value') + return res + +res = '## CrowdStrike Falcon Intelligence' +entry = demisto.executeCommand('cs-actors', demisto.args())[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + meta = demisto.get(entry, 'Contents.meta') + if meta: + res += '\n\n### Metadata' + res += '\n|Total|Offset|Limit|Time|' + res += '\n|-----|------|-----|----|' + res += '\n| ' + demisto.gets(meta, 'paging.total') + ' | ' + demisto.gets(meta, 'paging.offset') + ' | ' + demisto.gets(meta, 'paging.limit') + ' | ' + demisto.gets(meta, 'query_time') + ' |' + resources = demisto.get(entry, 'Contents.resources') + if resources: + res += '\n\n### Actors' + res += '\n|ID|Name|Short Description|URL|Known As|Create Date|First Date|Last Date|Origins|Target Countries|Target Industries|Motivations|' + res += '\n|--|----|-----------------|---|--------|-----------|----------|---------|-------|----------------|-----------------|-----------|' + for r in resources: + res += '\n| ' + demisto.gets(r, 'id') + ' | ' + demisto.gets(r, 'name') + ' | ' + demisto.gets(r, 'short_description') + ' | ' + demisto.gets(r, 'url') + ' | ' + \ + demisto.gets(r, 'known_as') + ' | ' + formatDate(demisto.get(r, 'created_date')) + ' | ' + formatDate(demisto.get(r, 'first_activity_date')) + ' | ' + \ + formatDate(demisto.get(r, 'last_activity_date')) + ' | ' + formatSlugs(demisto.get(r, 'origins')) + ' | ' + formatSlugs(demisto.get(r, 'target_countries')) + ' | ' + \ + formatSlugs(demisto.get(r, 'target_industries')) + ' | ' + formatSlugs(demisto.get(r, 'motivations')) + ' |' + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) \ No newline at end of file diff --git a/Scripts/csindicators.py b/Scripts/csindicators.py new file mode 100644 index 000000000000..0a5a01a5fb81 --- /dev/null +++ b/Scripts/csindicators.py @@ -0,0 +1,35 @@ +import time + +def formatDate(t): + if t: + return time.ctime(t) + return '' + +def formatLabels(labels): + res = '' + first = True + if labels: + for l in labels: + if first: + first = False + else: + res += ', ' + res += demisto.gets(l, 'name') + return res + +res = '## CrowdStrike Falcon Intelligence' +entry = demisto.executeCommand('cs-indicators', demisto.args())[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + indicators = demisto.get(entry, 'Contents') + if indicators: + res += '\n\n### Indicators' + res += '\n|Indicator|Type|Published|Updated|Confidence|Reports|Actors|Malware Families|Kill Chains|Domain Types|IP Address Types|Labels|' + res += '\n|---------|----|---------|-------|----------|-------|------|----------------|-----------|------------|----------------|------|' + for i in indicators: + res += '\n| ' + demisto.gets(i, 'indicator') + ' | ' + demisto.gets(i, 'type') + ' | ' + formatDate(demisto.get(i, 'published_date')) + ' | ' + \ + formatDate(demisto.get(i, 'last_updated')) + ' | ' + demisto.gets(i, 'malicious_confidence') + ' | ' + ','.join(demisto.get(i, 'reports')) + ' | ' + \ + ','.join(demisto.get(i, 'actors')) + ' | ' + ','.join(demisto.get(i, 'malware_families')) + ' | ' + ','.join(demisto.get(i, 'kill_chains')) + ' | ' + \ + ','.join(demisto.get(i, 'domain_types')) + ' | ' + ','.join(demisto.get(i, 'ip_address_types')) + ' | ' + formatLabels(demisto.get(i, 'labels')) + ' |' + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) \ No newline at end of file diff --git a/Scripts/cyfilerep.py b/Scripts/cyfilerep.py new file mode 100644 index 000000000000..229eb1dcab19 --- /dev/null +++ b/Scripts/cyfilerep.py @@ -0,0 +1,41 @@ +# Retrieve file entry reputation using Cylance +# First, get the file entry, check with Cylance if the file is known and if not, upload the file, wait 5 seconds and check again +import time + +e = demisto.args()['entry'] +fileEntry = demisto.executeCommand('getEntry', {'id': e}) +if fileEntry and len(fileEntry) == 1 and fileEntry[0]['Type'] != entryTypes['error']: + fe = fileEntry[0] + if fe['File'] and demisto.get(fe, 'FileMetadata.md5'): + rep = demisto.executeCommand('file', {'file': demisto.get(fe, 'FileMetadata.md5'), 'using-brand': brands['cy']}) + if rep and len(rep) == 1 and rep[0]['Type'] != entryTypes['error']: + contents = demisto.get(rep[0], 'Contents') + k = contents.keys() + if k and len(k) > 0: + v = contents[k[0]] + if demisto.get(v, 'status') == 'NEEDFILE' and demisto.get(v, 'confirmcode'): + upload = demisto.executeCommand('cy-upload', {'entry': e, 'confirmCode': demisto.get(v, 'confirmcode')}) + if upload and len(upload) == 1 and upload[0]['Type'] != entryTypes['error']: + contents = demisto.get(upload[0], 'Contents') + k = contents.keys() + if k and len(k) > 0: + v1 = contents[k[0]] + if demisto.get(v1, 'status') == 'ACCEPTED': + time.sleep(10) + rep = demisto.executeCommand('file', {'file': demisto.get(fe, 'FileMetadata.md5'), 'using-brand': brands['cy']}) + if rep and len(rep) == 1 and rep[0]['Type'] != entryTypes['error']: + demisto.results(shortFile(rep[0])) + else: + demisto.results(rep) + else: + demisto.results(upload) + else: + demisto.results(upload) + else: + demisto.results(shortFile(rep[0])) + else: + demisto.results(rep) + else: + demisto.results('Entry is not a file') +else: + demisto.results('Unable to retrieve entry') diff --git a/Scripts/datahashrep.js b/Scripts/datahashrep.js new file mode 100644 index 000000000000..80395927fab4 --- /dev/null +++ b/Scripts/datahashrep.js @@ -0,0 +1,48 @@ +var xfeScore = -1; +var vtScore = -1; +var cyScore = -1; +var wfScore = -1; +var csScore = -1; +var rep = executeCommand('file', {file: args.input}); +if (rep) { + for (var r = 0; r < rep.length; r++) { + if (rep[r].Type !== entryTypes.error && rep[r].ContentsFormat === formats.json) { + if (rep[r].Brand === brands.xfe && rep[r].Contents && rep[r].Contents.malware.family) { + xfeScore = 3; + } else if (rep[r].Brand === brands.vt && rep[r].Contents && rep[r].Contents.positives) { + var detected = rep[r].Contents.positives; + if (detected > 15) { + vtScore = 3; + } else if (detected > 4) { + vtScore = 2; + } else { + vtScore = 1; + } + } else if (rep[r].Brand === brands.cy && rep[r].Contents) { + var k = Object.keys(rep[r].Contents); + if (k && k.length > 0) { + var v = rep[r].Contents[k[0]]; + if (v && v.generalscore) { + var score = v.generalscore; + if (score < -0.7) { + cyScore = 3; + } else if (score < -0.1) { + cyScore = 2; + } else { + cyScore = 1; + } + } + } + } else if (rep[r].Brand === brands.wf && rep[r].Contents) { + if (positiveFile(rep[r])) { + wfScore = 3; + } + } else if (rep[r].Brand === brands.cs && rep[r].Contents && rep[r].Contents.length) { + csScore = rep[r].Contents[0].malicious_confidence === 'high' ? 3 : rep[r].Contents[0].malicious_confidence === 'medium' ? 2 : 1; + } + } + } +} + +var score = Math.max(xfeScore, vtScore, cyScore, wfScore, csScore); +return score < 0 ? 0 : score; diff --git a/Scripts/dataiprep.js b/Scripts/dataiprep.js new file mode 100644 index 000000000000..8acc3921b4b7 --- /dev/null +++ b/Scripts/dataiprep.js @@ -0,0 +1,42 @@ +var xfeScore = -1; +var vtScore = -1; +var csScore = -1; +var rep = executeCommand('ip', {ip: args.input}); +if (rep) { + for (var r = 0; r < rep.length; r++) { + if (rep[r].Type !== entryTypes.error && rep[r].ContentsFormat === formats.json) { + if (rep[r].Brand === brands.xfe && rep[r].Contents && rep[r].Contents.reputation.score) { + var s = rep[r].Contents.reputation.score; + if (s >= 6) { + xfeScore = 3; + } else if (s >= 3) { + xfeScore = 2; + } else { + xfeScore = 1; + } + } else if (rep[r].Brand === brands.vt && rep[r].Contents && rep[r].Contents.detected_urls) { + var positives = 0; + var suspect = 0; + for (var i = 0; i < rep[r].Contents.detected_urls.length; i++) { + if (rep[r].Contents.detected_urls[i].positives > 20) { + positives++; + } else if (rep[r].Contents.detected_urls[i].positives > 10) { + suspect++; + } + } + if (positives > 20) { + vtScore = 3; + } else if (positives > 10 || suspect > 20) { + vtScore = 2; + } else { + vtScore = 1; + } + } else if (rep[r].Brand === brands.cs && rep[r].Contents && rep[r].Contents.length) { + csScore = rep[r].Contents[0].malicious_confidence === 'high' ? 3 : rep[r].Contents[0].malicious_confidence === 'medium' ? 2 : 1; + } + } + } +} + +var score = Math.max(xfeScore, vtScore, csScore); +return score < 0 ? 0 : score; diff --git a/Scripts/dataurlrep.js b/Scripts/dataurlrep.js new file mode 100644 index 000000000000..6905d1577bf7 --- /dev/null +++ b/Scripts/dataurlrep.js @@ -0,0 +1,34 @@ +var xfeScore = -1; +var vtScore = -1; +var csScore = -1; +var rep = executeCommand('url', {url: args.input}); +if (rep) { + for (var r = 0; r < rep.length; r++) { + if (rep[r].Type !== entryTypes.error && rep[r].ContentsFormat === formats.json) { + if (rep[r].Brand === brands.xfe && rep[r].Contents && rep[r].Contents.url.result.score) { + var s = rep[r].Contents.url.result.score; + if (s >= 6) { + xfeScore = 3; + } else if (s >= 3) { + xfeScore = 2; + } else { + xfeScore = 1; + } + } else if (rep[r].Brand === brands.vt && rep[r].Contents && rep[r].Contents.positives) { + var detected = rep[r].Contents.positives; + if (detected > 20) { + vtScore = 3; + } else if (detected > 8) { + vtScore = 2; + } else { + vtScore = 1; + } + } else if (rep[r].Brand === brands.cs && rep[r].Contents && rep[r].Contents.length) { + csScore = rep[r].Contents[0].malicious_confidence === 'high' ? 3 : rep[r].Contents[0].malicious_confidence === 'medium' ? 2 : 1; + } + } + } +} + +var score = Math.max(xfeScore, vtScore, csScore); +return score < 0 ? 0 : score; diff --git a/Scripts/emailrep.js b/Scripts/emailrep.js new file mode 100644 index 000000000000..370c58c24ac4 --- /dev/null +++ b/Scripts/emailrep.js @@ -0,0 +1 @@ +return executeCommand('pipl-search', {email: args.email}); diff --git a/Scripts/example.js b/Scripts/example.js new file mode 100644 index 000000000000..ddab9de60b45 --- /dev/null +++ b/Scripts/example.js @@ -0,0 +1,78 @@ +// This is an Example server-side script that shows how to use and create JavaScript scripts in the Demisto server +// The log function allows you to print data during script execution +log('Hello World'); + +// You can use arguments (that are added via the CLI) inside scripts in the following ways, (in our example, +// the argument name is : 'ArgumentExample') +// e.g. run this script !ExampleJSScript ArgumentExample=MD5 +log('Your argument value = ' + args.ArgumentExample); + +// You can view (but not change directly) incidents and investigation properties relevant to your current investigation +log('Investigation name is: ' + investigation.name); + +// Please note incidents can be empty (e.g. if you run the from playground) the following returns the incident +// details only if the incidents are not empty +if (incidents && typeof incidents === 'object' && incidents !== null) { + log('First incident details: ' + incidents[0].details); +} + +// You can run specific integrations if they are already configured. The following is an example of a script +// running on a particular splunk instance called "Splunk1". +// The first example brings back the first event offset. +// log('Splunk query result: ' + executeCommand('search', {'using': 'Splunk1', 'query':' * | head 2 '})[0]['offset']); + +// executeCommand is used to run a command without specifying the entity that will execute it. +// For example, if you want to run a single command that runs on every integration that supports the search command: +// log('Search query result: ' + executeCommand('search', {'query':' * | head 2 '})); + +// Another example for executeCommand enables running an internal command that will get all entries of this investigation +log('First Entry content: ' + executeCommand('getEntries', {})[0]); + +// You can check for all supported commands using the getAllSupportedCommands function. +// The following will return all supported commands and the entities supported +var cmds = getAllSupportedCommands(); +for (var key in cmds) { + if (cmds.hasOwnProperty(key)) { + log('supporting integration: ' + key); + } +} + +// Util function isIp +log(isIp('8.8.8.8')); + +// Util function http +var res = http('http://www.demisto.com'); +log('Http GET call result StatusCode = ' +res.StatusCode); + +// You can perform operations on current investigation and incidents, see follow example, +// Methods descriptions available in CommonServer script. +/* +var user = 'David'; +var time = new Date(); +var taskId = '3'; + +setOwner(user); + +setPlaybook('Phishing Playbook'); + +setSeverity({id: incidents[0].id, severity: 'Critical'}); + +setTaskDueDate({id: taskId, dueDate: time.toUTCString()}); + +taskAssign({id: taskId, assignee: user}); + +You can change incident type, name, severity, details and systems for an investigation with a single incident. +This can be done by sending an object to setIncident with the details. +setIncident({type: 'Phishing', details: 'Phishing on my computer', severity: 'Critical', incName: 'Phishing incident', + systems: '2.2.2.2,10.10.10.10'}); + +You can also spawn a new incident from the current one, in the same manner as changing the details of the incident: +createNewIncident({type: 'Phishing', details: 'Phishing on your computer', severity: 'Critical', incName: 'Phishing incident', + systems: '2.2.2.2,10.10.10.10'}); + + +return; +*/ + +// You can also return either string or JSON objects to be printed to the screen as script results +return 'Script success! GO and write new scripts :)'; diff --git a/Scripts/exassignrole.js b/Scripts/exassignrole.js new file mode 100644 index 000000000000..aca67265f559 --- /dev/null +++ b/Scripts/exassignrole.js @@ -0,0 +1,33 @@ +//+ exchange/assign.ps1 + +//Params: +//See here: https://technet.microsoft.com/en-us/library/dd298173(v=exchg.160).aspx +//query is the string provided to the -SearchQuery parameter +//to-mailbox is the string provided to -TargetMailbox parameter +//to-folder is the string provided to -TargetFolder parameter +//if server is provided, it'll be used as -ServerFQDN parameter to Connect-ExchangeServer cmdlet + +if ((env.ARCH !== "amd64") && (env.OS !== "windows")) { + throw("Script can run only in 64bit Windows Agents"); +} + +var command = []; +command.push("powershell.exe"); +command.push("-version 2.0"); +command.push("-NonInteractive"); +command.push("-NoLogo"); +command.push(which("assign.ps1")); +if (typeof (args.role) !== "undefined") { + command.push("-role"); + command.push(args.role); +} +if (typeof (args.username) !== "undefined") { + command.push("-username"); + command.push(args.username); +} +if (typeof (args.server) !== "undefined") { + command.push("-server"); + command.push(args.server); +} + +pack(execute(command.join(" ")), 'table'); diff --git a/Scripts/exchange/assign.ps1 b/Scripts/exchange/assign.ps1 new file mode 100644 index 000000000000..ff5b25a4c120 --- /dev/null +++ b/Scripts/exchange/assign.ps1 @@ -0,0 +1,27 @@ +param ( + [string]$server = $null, + [string]$username = $env:USERNAME, + [string]$role = "Mailbox Import Export" + ) + +. RemoteExchange.ps1 + +if (!$server){ + Connect-ExchangeServer -auto +} +else { + Connect-ExchangeServer -ServerFqdn $server +} + +if (!$username){ + $username=whoami +} + +$assignment = New-ManagementRoleAssignment -Role $role -User:$username + +if (!$assignment){ + $msg ="Failed to assign '$username' to role: '$role'" + throw $msg +} + +Remove-PSSession $remoteSession diff --git a/Scripts/exchange/search.ps1 b/Scripts/exchange/search.ps1 new file mode 100644 index 000000000000..19a8bcd6fce2 --- /dev/null +++ b/Scripts/exchange/search.ps1 @@ -0,0 +1,36 @@ +param ( + [string]$server = $null, + [string]$username = $env:USERNAME, + [string]$query = $null, + [string]$targetmbx = $null, + [string]$targetFolder = $null, + [switch]$delete = $false + ) + +. RemoteExchange.ps1 + +if (!$query){ + throw "Missing parameter: -query" +} + +if (!$server){ + Connect-ExchangeServer -auto +} +else { + Connect-ExchangeServer -ServerFqdn $server +} + +if ($delete){ + Get-Mailbox -ResultSize Unlimited | Search-Mailbox -SearchQuery '$query' -Force:$true -DeleteContent +} +else { + if (!$targetmbx){ + throw "Missing parameter: -targetmbx" + } + if (!$targetFolder){ + throw "Missing parameter: -targetFolder" + } + Get-Mailbox -ResultSize Unlimited | Search-Mailbox -SearchQuery '$query' -TargetMailbox $targetmbx -TargetFolder $targetFolder +} + +Remove-PSSession $remoteSession diff --git a/Scripts/exdeletemail.js b/Scripts/exdeletemail.js new file mode 100644 index 000000000000..5f410a569ffa --- /dev/null +++ b/Scripts/exdeletemail.js @@ -0,0 +1,27 @@ +//+ exchange/search.ps1 + +//Params: +//See here: https://technet.microsoft.com/en-us/library/dd298173(v=exchg.160).aspx +//query is the string provided to the -SearchQuery parameter + +if ((env.ARCH !== "amd64") && (env.OS !== "windows")) { + throw("Script can ran only in 64bit Windows Agents"); +} + +var command = []; +command.push("powershell.exe"); +command.push("-version 2.0"); +command.push("-NonInteractive"); +command.push("-NoLogo"); +command.push(which("search.ps1")); +command.push("-query"); +command.push(args.query); +command.push("-delete"); + +if (typeof (args.server) !== "undefined") { + command.push("-server"); + command.push(args.server); +} + +pack(execute(command.join(" ")), 'table'); + diff --git a/Scripts/exsearchmailbox.js b/Scripts/exsearchmailbox.js new file mode 100644 index 000000000000..63fdd22bb29f --- /dev/null +++ b/Scripts/exsearchmailbox.js @@ -0,0 +1,33 @@ +//+ exchange/search.ps1 + +//Params: +//See here: https://technet.microsoft.com/en-us/library/dd298173(v=exchg.160).aspx +//query is the string provided to the -SearchQuery parameter +//to-mailbox is the string provided to -TargetMailbox parameter +//to-folder is the string provided to -TargetFolder parameter +//if server is provided, it'll be used as -ServerFQDN parameter to Connect-ExchangeServer cmdlet + +if ((env.ARCH !== "amd64") && (env.OS !== "windows")) { + throw("Script can ran only in 64bit Windows Agents"); +} + +var command = []; +command.push("powershell.exe"); +command.push("-version 2.0"); +command.push("-NonInteractive"); +command.push("-NoLogo"); +command.push(which("search.ps1")); +command.push("-query"); +command.push(args.query); +command.push("-targetmbx"); +command.push(args["to-mailbox"]); +command.push("-targetFolder"); +command.push(args["to-folder"]); + +if (typeof (args.server) !== "undefined") { + command.push("-server"); + command.push(args.server); +} + +pack(execute(command.join(" ")), 'table'); + diff --git a/Scripts/filerep.js b/Scripts/filerep.js new file mode 100644 index 000000000000..ca8dace0cd8b --- /dev/null +++ b/Scripts/filerep.js @@ -0,0 +1,8 @@ +var res = []; +var rep = executeCommand('file', {file: args.file}); +if (rep && Array.isArray(rep)) { + for (var i = 0; i < rep.length; i++) { + res.push(shortFile(rep[i])); + } +} +return res; diff --git a/Scripts/iprep.js b/Scripts/iprep.js new file mode 100644 index 000000000000..b806ce7fbd7e --- /dev/null +++ b/Scripts/iprep.js @@ -0,0 +1,8 @@ +var res = []; +var rep = executeCommand('ip', {ip: args.ip}); +if (rep && Array.isArray(rep)) { + for (var i = 0; i < rep.length; i++) { + res.push(shortIP(rep[i])); + } +} +return res; diff --git a/Scripts/lcfinddomain.js b/Scripts/lcfinddomain.js new file mode 100644 index 000000000000..b2bcbba6127c --- /dev/null +++ b/Scripts/lcfinddomain.js @@ -0,0 +1,16 @@ +// Demisto script for LimaCharlie +var r = executeCommand('objectloc', {obj_name: args.domain, obj_type: 'DOMAIN_NAME'}); + +if (r && Array.isArray(r) && r.length === 1 && r[0].ContentsFormat === formats.json && r[0].Contents && r[0].Contents && Array.isArray(r[0].Contents)) { + var res = {Contents: [], ContentsFormat: formats.table, Type: entryTypes.note}; + for (var i=0; i 0) { + return res; + } +} +return r; diff --git a/Scripts/lcfindprocess.js b/Scripts/lcfindprocess.js new file mode 100644 index 000000000000..896ad776c235 --- /dev/null +++ b/Scripts/lcfindprocess.js @@ -0,0 +1,17 @@ +// Demisto script for LimaCharlie +var r = executeCommand('objectloc', {obj_name: args.name, obj_type: 'PROCESS_NAME'}); + +if (r && Array.isArray(r) && r.length === 1 && r[0].ContentsFormat === formats.json && r[0].Contents && r[0].Contents && Array.isArray(r[0].Contents)) { + var res = {Contents: [], ContentsFormat: formats.table, Type: entryTypes.note}; + for (var i=0; i 0) { + return res; + } +} + +return r; diff --git a/Scripts/lcnewprocess.js b/Scripts/lcnewprocess.js new file mode 100644 index 000000000000..8800b74f03bf --- /dev/null +++ b/Scripts/lcnewprocess.js @@ -0,0 +1,37 @@ +// Demisto script for LimaCharlie +var before = Math.round((new Date()).getTime() / 1000).toString(); +var days = (args.days) ? args.days : 1; +var after = (before - days * 24 * 60 * 60).toString(); +var size = (args.size) ? args.size : '4096'; + +var r = executeCommand('timeline', {before: before, after: after, sensor_id: args.sensor, max_size: size}); + +if (r && Array.isArray(r) && r.length === 1 && r[0].ContentsFormat === formats.json && r[0].Contents && r[0].Contents.events) { + var res = {Contents: [], ContentsFormat: formats.table, Type: entryTypes.note}; + for (var i=0; i 0) { + return res; + } +} + +return r; diff --git a/Scripts/osxcollector.js b/Scripts/osxcollector.js new file mode 100644 index 000000000000..4ebb016624e5 --- /dev/null +++ b/Scripts/osxcollector.js @@ -0,0 +1,32 @@ +var res = http('https://raw.githubusercontent.com/Yelp/osxcollector/master/osxcollector/osxcollector.py', {SaveToFile: true}); + +execute('chmod +x '+res.Path); + +var cmd = res.Path ; +if (args.section) { + cmd = cmd + " -s " + args.section ; +} +var timeout = 600 ; +if (args.timeout) { + timeout = args.timeout ; +} +pack(cmd); + +var output = execute(cmd,timeout); +pack(output); + +var result = output.Stderr; +var fileNameStartIndex = result.lastIndexOf("osxcollect"); +var fileName = result.substring(fileNameStartIndex, result.length-1); + +pack_file(String(fileName)); + +fileNameWithoutExtension = fileName.substring(0, fileName.length-7); + +execute('tar -zxvf '+fileName+' ./'+fileNameWithoutExtension+'/'+fileNameWithoutExtension+'.json'); + +var jsonResultStr = read_file(fileNameWithoutExtension+'/'+fileNameWithoutExtension+'.json'); +var arr = jsonResultStr.split('\n'); +str = arr.join(','); +var result = '{"osxcollector_result":['+str.substring(0, str.length-1)+']}'; +pack(JSON.parse(result)); \ No newline at end of file diff --git a/Scripts/pagerdutyalert.js b/Scripts/pagerdutyalert.js new file mode 100644 index 000000000000..5143429b2cce --- /dev/null +++ b/Scripts/pagerdutyalert.js @@ -0,0 +1,4 @@ +if (incidents[0].severity == 4) { + return executeCommand('pagerDutySubmitEvent', {description: incidents[0].name,details: '{"incidentDetails":"'+incidents[0].details+'"}'}); +} +return 'Incident severity not high enough to wake up user' ; \ No newline at end of file diff --git a/Scripts/pagerdutyassign.js b/Scripts/pagerdutyassign.js new file mode 100644 index 000000000000..8ca96718f976 --- /dev/null +++ b/Scripts/pagerdutyassign.js @@ -0,0 +1,25 @@ +var query = '' ; +if (args.query) { + query = args.query ; +} +var res = executeCommand('PagerDutyGetUsersOnCallNow', {query: query}); +if (res[0].Type == entryTypes.error) { + return res[0] +} + +var usersOnCall = res[0].Contents; + +var selectedUser = usersOnCall[0]; + + +if (selectedUser === null) { + return 'error : could not find user from PagerDuty OnCall now!'; +} +res = executeCommand('getUserByEmail', {userEmail: selectedUser.email}); +if (res[0].Type == entryTypes.error) { + return res[0]; +} +var userId = res[0].Contents.id; + +setOwner(userId); +return 'User ' + userId + ' was set as owner to incidents of this investigation'; diff --git a/Scripts/panoramacommit.js b/Scripts/panoramacommit.js new file mode 100644 index 000000000000..4fae2cdb325d --- /dev/null +++ b/Scripts/panoramacommit.js @@ -0,0 +1,5 @@ +var reqArgs = { + type: 'commit', + cmd: '' + }; +return executeCommand('panorama', reqArgs)[0].Contents.response['-status']; \ No newline at end of file diff --git a/Scripts/panoramaconfig.js b/Scripts/panoramaconfig.js new file mode 100644 index 000000000000..c6c6d9a1a890 --- /dev/null +++ b/Scripts/panoramaconfig.js @@ -0,0 +1,38 @@ +function AddArgumentOpen(arg, fieldName, member) { + if (arg) { + if (member) { + return '<'+fieldName+'>' + arg+ ''; + } else { + return '<'+fieldName+'>' + arg + ''; + } + } + return ''; +} + +function AddArgumentYesNo(arg, fieldName) { + if (arg !== undefined) { + return '<'+fieldName+'>' + (arg ? 'yes' : 'no') + ''; + } + return ''; +} +var req = { + type: 'config', + action: 'set', + key: 'keyvalue', + xpath: args.xpath || '/config/devices/entry/vsys/entry/rulebase/security/rules/entry[@name=\'' + args.ruleName +'\']', + element: AddArgumentOpen(args.action, 'action') + + AddArgumentOpen(args.description, 'description') + + AddArgumentOpen(args.srcIP, 'source', true) + + AddArgumentOpen(args.dstIP, 'destination', true) + + AddArgumentOpen(args.application, 'application', true) + + AddArgumentOpen(args.srcUser, 'source-user', true) + + AddArgumentOpen(args.from, 'from', true) + + AddArgumentOpen(args.to, 'to', true) + + AddArgumentOpen(args.service, 'service', true) + + AddArgumentYesNo(args.negateSrc, 'negate-source') + + AddArgumentYesNo(args.negateDst, 'negate-destination') + + AddArgumentYesNo(args.disable, 'disabled') + + AddArgumentYesNo(args.disableServerResponseInspection, 'disable-server-response-inspection') + }; +var raw = executeCommand('panorama', req); +return raw[0].Contents.response['-status']; \ No newline at end of file diff --git a/Scripts/panoramamove.js b/Scripts/panoramamove.js new file mode 100644 index 000000000000..54d50868c0db --- /dev/null +++ b/Scripts/panoramamove.js @@ -0,0 +1,12 @@ +var req = { + type: 'config', + action: 'move', + key: 'keyvalue', + xpath: args.xpath || '/config/devices/entry/vsys/entry/rulebase/security/rules/entry[@name=\'' + args.src +'\']', + where: args.where, + }; +if (args.dst) { + req.dst = args.dst +} +var raw = executeCommand('panorama', req); +return raw[0].Contents.response['-status']; \ No newline at end of file diff --git a/Scripts/panoramapcaps.js b/Scripts/panoramapcaps.js new file mode 100644 index 000000000000..d1bfadd87825 --- /dev/null +++ b/Scripts/panoramapcaps.js @@ -0,0 +1,34 @@ +function AddArgument(arg, argName,req) { + if (arg) { + req[argName] = arg; + } + return req; +} + +var reqArgs = { + type: 'export', + category: args.pcapType, + }; +if (args.password) { + reqArgs['dlp-password'] = args.password; +} else if (args.pcapType === 'dlp-pcap') { + return 'can not provide dlp-pcap without password'; +} + +AddArgument(args.from, 'from', reqArgs); +AddArgument(args.to, 'to', reqArgs); +AddArgument(args.serialNo, 'serialno', reqArgs); +AddArgument(args.searchTime, 'search-time', reqArgs); +AddArgument(args.pcapID, 'pcap-id', reqArgs); + +raw = executeCommand('panorama', reqArgs); +if (raw[0].ContentsFormat === 'json') { + var content = raw[0].Contents.response; + if (content['-status'] === 'success') { + return content.result; + } else { + return content['-status']; + } +} else { + return raw; +} \ No newline at end of file diff --git a/Scripts/scripts.json b/Scripts/scripts.json new file mode 100644 index 000000000000..1bdddbd149bf --- /dev/null +++ b/Scripts/scripts.json @@ -0,0 +1,3325 @@ +{ + "server": [ + { + "name": "ExampleJSScript", + "script": "example.js", + "type": "javascript", + "visualScript": "", + "tags": ["example"], + "comment": "This is only an example script, to showcase how to use and write JavaScript scripts", + "system": true, + "arguments": [ + { + "name": "ArgumentExample", + "description": "An example argument that will be passed into and used by the script", + "required": true, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "WhoisSummary", + "script": "whoissummary.js", + "type": "javascript", + "visualScript": "", + "tags": ["threat-intel", "whois", "server"], + "comment": "A simple script that outputs a shorter summary of the !whois command output", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Input for the WHOIS query", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["whois"] } + }, + { + "name": "Whois", + "script": "whois.js", + "type": "javascript", + "visualScript": "", + "tags": ["threat-intel", "whois", "server"], + "comment": "A simple script that returns WHOIS info for a domain", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Input for the WHOIS query", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["whois"] } + }, + { + "name": "VolLDRModules", + "script": "volldrmodules.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command ldrmodules", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolPSList", + "script": "volpslist.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command pslist", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolGetProcWithMalNetConn", + "script": "volgetprocwithmalnetconn.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for getting the list of processes that have connections to ip address with bad reputation.", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": true, + "default": false + }, + { + "name": "repthreshold", + "description": "Reputation threshold - any IP addresses up to and including this score are considered malicious", + "required": false, + "default": false + }, + { + "name": "repscript", + "description": "Reputation script to use for checking IP addresses", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolConnscan", + "script": "volconnscan.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command connscan", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolNetworkConnections", + "script": "volnetworkconnections.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for finding all the network connections. This script runs through different commands based on the profile provided.", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": true, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolImageinfo", + "script": "volimageinfo.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command imageinfo", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolMalfind", + "script": "volmalfind.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command ldrmodules", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "pid", + "description": "Process ID to pass to volatility as a parameter of the ldrmodules command", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolApihooks", + "script": "volapihooks.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command apihooks", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "pid", + "description": "Process ID to pass to volatility as a parameter of the apihooks command", + "required": false, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolDlllist", + "script": "voldlllist.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Volatility script for command ldrmodules", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "pid", + "description": "Process ID to pass to volatility as a parameter of the dlllist command", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "CommonServer", + "script": "common.js", + "type": "javascript", + "visualScript": "", + "tags": ["infra", "server"], + "comment": "Common code that will be merged into each server script when it runs", + "system": true, + "scriptTarget": 0 + }, + { + "name": "CommonUserServer", + "script": "", + "type": "javascript", + "visualScript": "", + "tags": ["infra", "server"], + "comment": "Common user defined code that will be merged into each server script when it runs", + "system": false, + "scriptTarget": 0 + }, + { + "name": "CommonServerPython", + "script": "common.py", + "type": "python", + "visualScript": "", + "tags": ["infra", "server"], + "comment": "Common code that will be merged into each server script when it runs", + "system": true, + "scriptTarget": 0 + }, + { + "name": "CommonServerUserPython", + "script": "", + "type": "python", + "visualScript": "", + "tags": ["infra", "server"], + "comment": "Common user defined code that will be merged into each server script when it runs", + "system": false, + "scriptTarget": 0 + }, + { + "name": "Volatility", + "script": "volatilitygeneric.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Execute volatility with command and return tabular output. Incase where proper json output is not supported, scripts returns error. User should use raw command.", + "system": true, + "arguments": [ + { + "name": "cmd", + "description": "The volatility command/module you want to use", + "required": true, + "default": false + }, + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "SplunkEmailParser", + "script": "SplunkEmailParser.js", + "type": "javascript", + "visualScript": "", + "tags": ["splunk","ingestion"], + "comment": "Classify an incident created from an email originating from Splunk.\nThe mail type should be in plain text, and inline: table should be selected.\nParsing is done in the following manner -\ntype is the header sourcetype, severity is the mail importance level, \nthe incident name is the mail subject and the systems are taken from host.", + "system": true, + "arguments": [ + { + "name": "body", + "description": "Contents (body) of the email", + "required": false, + "default": false + }, + { + "name": "subject", + "description": "Subject of the email", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "DefaultIncidentClassifier", + "script": "DefaultIncidentClassifier.js", + "type": "javascript", + "visualScript": "", + "tags": ["ingestion"], + "comment": "Classify an incident from mail.", + "system": true, + "arguments": [ + { + "name": "splunkSender", + "description": "Email address from which Splunk sends emails to our mail listener", + "required": false, + "default": false + }, + { + "name": "nexposeSender", + "description": "Email address from which Nexpose sends emails to our mail listener", + "required": false, + "default": false + }, + { + "name": "defaultIncidentType", + "description": "The incident type to be set in case the email is neither from Splunk nor Nexpose", + "required": true, + "default": false + }, + { + "name": "minRiskScore", + "description": "Argument passed as-is to NexposeEmailParser. See its documentation for details.", + "required": false, + "default": false + }, + { + "name": "minVulnCount", + "description": "Argument passed as-is to NexposeEmailParser. See its documentation for details.", + "required": false, + "default": false + }, + { + "name": "sentinelOneSender", + "description": "Email address from which sentinel one sends emails to our mail listener", + "required": false, + "default": false + }, + { + "name": "sentinelOneIncidentType", + "description": "Incident type to classify sentinel one events to", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "NexposeEmailParser", + "script": "NexposeEmailParser.js", + "type": "javascript", + "visualScript": "", + "tags": ["nexpose","ingestion"], + "comment": "Parses nexpose report into a clear table that contain risk score and vulnerability count for each server,\nAnd creates a new incident for each server.", + "system": true, + "arguments": [ + { + "name": "entryID", + "description": "ID of the entry containing the Nexpose report. If none is provided, the script will iterate and find a relevant entry.", + "required": false, + "default": false + }, + { + "name": "minRiskScore", + "description": "Minimal Risk Score an item in the report needs to reach in order to trigger an incident. Leave empty to trigger for any risk score.", + "required": false, + "default": false + }, + { + "name": "minVulnCount", + "description": "Minimal Vulnerability Count an item in the report needs to reach in order to trigger an incident. Leave empty to trigger for any count.", + "required": false, + "default": false + }, + { + "name": "defaultNexposeSeverity", + "description": "Severity to be set on triggered incidents", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "NexposeEmailParserForVuln", + "script": "NexposeEmailParserForVuln.js", + "type": "javascript", + "visualScript": "", + "tags": ["nexpose","ingestion"], + "comment": "Parses nexpose report into a clear table that contain risk score and vulnerability count for each server,\nAnd creates a new incident for each server.", + "system": true, + "arguments": [ + { + "name": "report", + "description": "Full XML contents of the Nexpose report. If not provided, it will be taken from the Incident Details.", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "NexposeVulnExtractor", + "script": "NexposeVulnExtractor.js", + "type": "javascript", + "visualScript": "", + "tags": ["nexpose"], + "comment": "Parse a specific server nexpose response in to a table of vulnerabilities.", + "system": true, + "arguments": [ + { + "name": "report", + "description": "Full XML contents of the Nexpose report. If not provided, it will be taken from the Incident Details.", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "VolRunCmds", + "script": "volruncmds.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Execute volatility with command and return tabular output. Incase where proper json output is not supported, scripts returns error. User should use raw command.", + "system": true, + "arguments": [ + { + "name": "cmds", + "description": "Comma-separated list of volatility commands/modules to run", + "required": true, + "default": false + }, + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + }, + { + "name": "profile", + "description": "Volatility profile to use", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "CheckFiles", + "script": "checkfiles.js", + "type": "javascript", + "visualScript": "", + "tags": ["server", "threat-intel"], + "comment": "Iterate on all file artifacts in the investigation and return details of positives", + "system": true, + "arguments": [ + { + "name": "fileNames", + "description": "If provided, checks only files whose names are in the list. The names should be comma-separated.", + "required": false, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["file"] } + }, + { + "name": "CheckSender", + "script": "checksender.js", + "type": "javascript", + "visualScript": "", + "tags": ["phishing"], + "comment": "For phishing incidents, check the sender of the email via Pipl search", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["pipl-search"] } + }, + { + "name": "StaticAnalyze", + "script": "staticanalyze.js", + "type": "javascript", + "visualScript": "", + "tags": ["phishing"], + "comment": "For phishing incidents, iterate on all attachments and run PE dump on each", + "system": true, + "scriptTarget": 0 + }, + { + "name": "AnalyzeOSX", + "script": "analyzeosx.js", + "type": "javascript", + "visualScript": "", + "tags": ["osx"], + "comment": "Get file and url reputation for osxcollector result.\n will use VirusTotal for Url checks, and IBM XForce for MD5 checks.\n maxchecks : for \n system : system name to run agent on.\n section : the type check that OSXCollector should run.", + "system": true, + "arguments": [ + { + "name": "section", + "description": "Ask OSXCollector for a specific section", + "required": false, + "default": true + }, + { + "name": "timeout", + "description": "Timeout to be passed to OSXCollector script", + "required": false, + "default": false + }, + { + "name": "maxchecks", + "description": "Maximum amount of files/urls to verify", + "required": false, + "default": false + }, + { + "name": "system", + "description": "OSX System to be used", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["file", "url"] } + }, + { + "name": "LCNewProcess", + "script": "lcnewprocess.js", + "type": "javascript", + "visualScript": "", + "tags": ["lima charlie"], + "comment": "Using Lima Charlie, find all new process launches for a given sensor", + "system": true, + "arguments": [ + { + "name": "sensor", + "description": "Sensor to query", + "required": true, + "default": true + }, + { + "name": "size", + "description": "Size for the response", + "required": false, + "default": false + }, + { + "name": "days", + "description": "Size of time window, in days", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["timeline"] } + }, + { + "name": "LCFindProcess", + "script": "lcfindprocess.js", + "type": "javascript", + "visualScript": "", + "tags": ["lima charlie"], + "comment": "Using Lima Charlie, find a given process name across all sensors", + "system": true, + "arguments": [ + { + "name": "name", + "description": "Process name to find", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["objectloc"] } + }, + { + "name": "LCFindDomain", + "script": "lcfinddomain.js", + "type": "javascript", + "visualScript": "", + "tags": ["lima charlie"], + "comment": "Using Lima Charlie, find which sensor saw access to given domain", + "system": true, + "arguments": [ + { + "name": "domain", + "description": "Domain to be found", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["objectloc"] } + }, + { + "name": "SplunkSearch", + "script": "splunksearch.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement","splunk"], + "comment": "Run a query through Splunk and format the results as a table", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Splunk query to execute", + "required": true, + "default": true + }, + { + "name": "rows", + "description": "Return up to X first rows. If omitted, defaults to 30.", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["search"] } + }, + { + "name": "SplunkSearchJsonPy", + "script": "SplunkSearchJson.py", + "type": "python", + "visualScript": "", + "tags": ["enhancement"], + "comment": "Run a query through Splunk and format the results as a markdown with raw data parsed as JSON", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Splunk query to execute", + "required": true, + "default": true + }, + { + "name": "rows", + "description": "Return up to X first rows. If omitted, defaults to 30.", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["search"] } + }, + { + "name": "TriagePhishing", + "script": "triagephishing.js", + "type": "javascript", + "visualScript": "", + "tags": ["phishing"], + "comment": "Process a suspected email and check URLs, attachments and sender via reputation services", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": [], "should": ["url", "pipl-search", "file"] } + }, + { + "name": "DataIPReputation", + "script": "dataiprep.js", + "type": "javascript", + "visualScript": "", + "tags": ["reputation"], + "comment": "Evaluate reputation of an IP address and return a score between 1 to 5", + "system": true, + "arguments": [ + { + "name": "input", + "description": "IP address to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["ip"] } + }, + { + "name": "DataURLReputation", + "script": "dataurlrep.js", + "type": "javascript", + "visualScript": "", + "tags": ["reputation"], + "comment": "Evaluate reputation of a URL and return a score between 1 to 5", + "system": true, + "arguments": [ + { + "name": "input", + "description": "URL to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["url"] } + }, + { + "name": "DataHashReputation", + "script": "datahashrep.js", + "type": "javascript", + "visualScript": "", + "tags": ["reputation"], + "comment": "Evaluate reputation of the given hash and return a score between 1 to 5", + "system": true, + "arguments": [ + { + "name": "input", + "description": "Hash value to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["file"] } + }, + { + "name": "IPReputation", + "script": "iprep.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement"], + "comment": "A context script for IP entities", + "system": true, + "arguments": [ + { + "name": "ip", + "description": "IP address to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["ip"] } + }, + { + "name": "FileReputation", + "script": "filerep.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement"], + "comment": "A context script for MD5 entities", + "system": true, + "arguments": [ + { + "name": "file", + "description": "File MD5 hash to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["file"] } + }, + { + "name": "EmailReputation", + "script": "emailrep.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement"], + "comment": "A context script for Email entities", + "system": true, + "arguments": [ + { + "name": "email", + "description": "Email address to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["pipl-search"] } + }, + { + "name": "URLReputation", + "script": "urlrep.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement"], + "comment": "A context script for URL entities", + "system": true, + "arguments": [ + { + "name": "url", + "description": "URL to look up", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["url"] } + }, + { + "name": "CBSearch", + "script": "cbsearch.js", + "type": "javascript", + "visualScript": "", + "tags": ["carbon-black", "endpoint", "enhancement"], + "comment": "Search Carbon Black for process & binary information", + "system": true, + "arguments": [ + { + "name": "type", + "description": "\"process\" or \"binary\" according to the type of search you want to run", + "required": false, + "default": false + }, { + "name": "query", + "description": "Query to be run - in Carbon Black syntax", + "required": false, + "default": true + }, + { + "name": "rows", + "description": "Number of rows to return. If omitted, default is as stated in the Carbon Black API documentation, currently 10.", + "required": false, + "default": false + }, + { + "name": "start", + "description": "Start at this row #. Allows pagination through large response. If omitted, default is as stated in the Carbon Black API documentation, currently 0. ", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": [], "should": ["cb-process", "cb-binary"] } + }, + { + "name": "CBSensors", + "script": "cbsensors.js", + "type": "javascript", + "visualScript": "", + "tags": ["carbon-black", "endpoint"], + "comment": "List Carbon Black sensors", + "system": true, + "arguments": [], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-list-sensors"] } + }, + { + "name": "CBSessions", + "script": "cbsessions.js", + "type": "javascript", + "visualScript": "", + "tags": ["carbon-black", "endpoint"], + "comment": "List Carbon Black sessions", + "system": true, + "arguments": [ + { + "name": "verbose", + "description": "Show more detailed output", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-list-sessions"] } + }, + { + "name": "CBLiveProcessList", + "script": "cbliveprocesslist.js", + "type": "javascript", + "visualScript": "", + "tags": ["carbon-black", "endpoint"], + "comment": "Runs 'process list' command on a remote Carbon Black sensor", + "system": true, + "arguments": [ + { + "name": "sessionid", + "description": "ID of an active Carbon Black session", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-command-create", "cb-command-info"] } + }, + { + "name": "CBEvents", + "script": "cbevents.js", + "type": "javascript", + "visualScript": "", + "tags": ["carbon-black", "endpoint", "enhancement"], + "comment": "Returns all events associated with a process query", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Query to match against events", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-process", "process-events"] } + }, + { + "name": "AnalyzeMemImage", + "script": "analyzememimage.js", + "type": "javascript", + "visualScript": "", + "tags": ["memory", "forensics", "volatility", "server"], + "comment": "Use Volatility to run common memory image analysis commands", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": true + }, + { + "name": "system", + "description": "System with Volatility installed to be used for the analysis", + "required": true, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "EsmExample", + "script": "ESMNitroExample.js", + "type": "javascript", + "visualScript": "", + "tags": ["esm", "nitro", "siem", "example"], + "comment": "Example of using McAfee ESM (Nitro) with advanced filters", + "system": true, + "arguments": [ + { + "name": "ip", + "description": "IP Address to find", + "required": true, + "default": true + }, + { + "name": "limit", + "description": "Query limit. If omitted, defaults to 100.", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "PagerDutyAssignOnCallUser", + "script": "pagerdutyassign.js", + "type": "javascript", + "visualScript": "", + "tags": ["pagerduty", "communication"], + "comment": "By default assigns the first on-call user to an investigation (all incidents in the investigation will be owned by the on call user)", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Filter user. E.g. query=dan will find the first on call user with the string \"dan\" in their name", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["PagerDutyGetUsersOnCallNow"] } + }, + { + "name": "PagerDutyAlertOnIncident", + "script": "pagerdutyalert.js", + "type": "javascript", + "visualScript": "", + "tags": ["pagerduty", "communication"], + "comment": "Send incident details to pagerduty (useful to include in playbooks)", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["pagerDutySubmitEvent"] } + }, + { + "name": "WildfireReport", + "script": "wildfirereport.js", + "type": "javascript", + "visualScript": "", + "tags": ["enhancement", "wildfire", "sandbox"], + "comment": "Use wildfire file analysis and parse result", + "system": true, + "arguments": [ + { + "name": "md5", + "description": "MD5 Hash to look up", + "required": false, + "default": true + }, + { + "name": "hash", + "description": "Hash to look up", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["wildfire-report"] } + }, + { + "name": "WildfireUpload", + "script": "wildfireupload.js", + "type": "javascript", + "visualScript": "", + "tags": ["wildfire", "sandbox"], + "comment": "Upload file to wildfire for analysis.\nExample usage: !WildfireUpload upload=2@3", + "system": true, + "arguments": [ + { + "name": "upload", + "description": "ID of a war room entry containing a file to be uploaded to the WildFire service", + "required": true, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["wildfire-upload"] } + }, + { + "name": "PanoramaConfig", + "script": "panoramaconfig.js", + "type": "javascript", + "visualScript": "", + "tags": ["panorama", "firewall"], + "comment": "Set panorama configuration", + "system": true, + "arguments": [ + { + "name": "ruleName", + "description": "Name for the rule to be configured", + "required": false, + "default": false + }, + { + "name": "xpath", + "description": "Usually not required as ruleName is sufficient. Direct XPath to the rule entry to be modified.", + "required": false, + "default": false + }, + { + "name": "srcIP", + "description": "Source IP address", + "required": false, + "default": false + }, + { + "name": "dstIP", + "description": "Destination IP address", + "required": false, + "default": false + }, + { + "name": "negateSrc", + "description": "Yes/No - whether to negate the source IP address (match all except the specified address)", + "required": false, + "default": false + }, + { + "name": "negateDst", + "description": "Yes/No - whether to negate the destination IP address (match all except the specified address)", + "required": false, + "default": false + }, + { + "name": "action", + "description": "Action for the rule", + "required": false, + "default": false + }, + { + "name": "service", + "description": "Service for the rule", + "required": false, + "default": false + }, + { + "name": "disable", + "description": "Yes/No - whether to disable the rule", + "required": false, + "default": false + }, + { + "name": "application", + "description": "Application for the rule", + "required": false, + "default": false + }, + { + "name": "srcUser", + "description": "Source user for the rule", + "required": false, + "default": false + }, + { + "name": "from", + "description": "\"From\" value for the rule", + "required": false, + "default": false + }, + { + "name": "to", + "description": "\"To\" value for the rule", + "required": false, + "default": false + }, + { + "name": "disableServerResponseInspection", + "description": "Value for the \"disable-server-response-inspection\" option", + "required": false, + "default": false + }, + { + "name": "description", + "description": "Rule description", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["panorama"] } + }, + { + "name": "PanoramaPcaps", + "script": "panoramapcaps.js", + "type": "javascript", + "visualScript": "", + "tags": ["panorama", "firewall"], + "comment": "Get panorama pcaps", + "system": true, + "arguments": [ + { + "name": "pcapType", + "description": "Type of Packet Capture", + "required": true, + "default": false + }, + { + "name": "from", + "description": "\"From\" value for the rule", + "required": false, + "default": false + }, + { + "name": "to", + "description": "\"To\" value for the rule", + "required": false, + "default": false + }, + { + "name": "serialNo", + "description": "Serial number for the request. For further information, see the Panorama XML API Documentation.", + "required": false, + "default": false + }, + { + "name": "searchTime", + "description": "Search time for the request. For further information, see the Panorama XML API Documentation.", + "required": false, + "default": false + }, + { + "name": "pcapID", + "description": "ID of the Pcap for the request. For further information, see the Panorama XML API Documentation.", + "required": false, + "default": false + }, + { + "name": "password", + "description": "Password for Panorama.", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["panorama"] } + }, + { + "name": "PanoramaMove", + "script": "panoramamove.js", + "type": "javascript", + "visualScript": "", + "tags": ["panorama", "firewall"], + "comment": "Move panorama rules", + "system": true, + "arguments": [ + { + "name": "xpath", + "description": "Usually not required as \"src\" is sufficient. Full XPath to the source rule to be moved.", + "required": false, + "default": false + }, + { + "name": "src", + "description": "Source value for the request. For further information, see the Panorama XML API Documentation.", + "required": false, + "default": false + }, + { + "name": "where", + "description": "Values for the \"where\" parameter include \"before\", \"after\", \"top\" or \"bottom\". For further information, see the Panorama XML API Documentation.", + "required": true, + "default": false + }, + { + "name": "dst", + "description": "Destination xpath to move the rule. For further information, see the Panorama XML API Documentation.", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["panorama"] } + }, + { + "name": "PanoramaCommit", + "script": "panoramacommit.js", + "type": "javascript", + "visualScript": "", + "tags": ["panorama", "firewall"], + "comment": "Commit configuration to panorama", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["panorama"] } + }, + { + "name": "RemoteExec", + "script": "RemoteExec.js", + "type": "javascript", + "visualScript": "", + "tags": ["endpoint"], + "arguments": [ + { + "name": "system", + "description": "Name of system on which to run the command", + "required": true, + "default": false + }, + { + "name": "cmd", + "description": "Command to run", + "required": true, + "default": false + } + ], + "comment": "Execute a command on a remote machine (without installing a D2 agent)", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ssh"] } + }, + { + "name": "BinaryReputationPy", + "script": "binaryreputation.py", + "type": "python", + "visualScript": "", + "tags": ["hash", "server", "threat-intel", "virustotal", "xfe", "wildfire"], + "arguments": [ + { + "name": "fileNames", + "description": "If provided, checks only files whose names are in the list. The names should be comma-separated.", + "required": false, + "default": true + } + ], + "comment": "Get reputation for any hash or file in the incident details", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["file"] } + }, + { + "name": "BinarySearchPy", + "script": "binarysearch.py", + "type": "python", + "visualScript": "", + "tags": ["hash", "server", "endpoint", "carbon-black"], + "arguments": [], + "comment": "Search for a binary on an endpoint using Carbon Black", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["process"] } + }, + { + "name": "CheckFilesWildfirePy", + "script": "checkfileswildfire.py", + "type": "python", + "visualScript": "", + "tags": ["hash", "server", "threat-intel", "wildfire"], + "arguments": [ + { + "name": "fileNames", + "description": "If provided, checks only files whose names are in the list. The names should be comma-separated.", + "required": false, + "default": true + } + ], + "comment": "Get reputation for attachments using wildfire and if the file is not known upload it to wildfire, wait 15 min and get reputation again", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["wildfire-upload", "wildfire-report"]} + }, + { + "name": "CheckIPs", + "script": "checkips.py", + "type": "python", + "visualScript": "", + "tags": ["server", "threat-intel", "virustotal", "xfe"], + "arguments": [ + { + "name": "data", + "description": "Raw text from which to extract IP addresses using the appropriate regular expression. If omitted, will scan Incident Details instead.", + "required": false, + "default": true + } + ], + "comment": "Get reputation for IPs in the incident or given raw text", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ips"] } + }, + { + "name": "CheckSenderDomainDistance", + "script": "checksenderdomaindistance.py", + "type": "python", + "visualScript": "", + "tags": ["server", "phishing"], + "arguments": [ + { + "name": "domain", + "description": "The domain to be measured against the domain in the sender's email address.\nUsually the domain used by the company for email, e.g. acme.com when users are assigned jane@acme.com", + "required": false, + "default": true + } + ], + "comment": "Get the string distance for the sender from our domain", + "system": true, + "scriptTarget": 0 + }, + { + "name": "CheckSenderPy", + "script": "checksender.py", + "type": "python", + "visualScript": "", + "tags": ["server", "phishing"], + "arguments": [ + { + "name": "email", + "description": "Email address to look up. If omitted, will instead extract with regular expression from Incident Details, where the phishing email should be provided.", + "required": false, + "default": true + } + ], + "comment": "For phishing incidents, check the sender of the email via Pipl search", + "system": true, + "scriptTarget": 0 + }, + { + "name": "CheckURLs", + "script": "checkurls.py", + "type": "python", + "visualScript": "", + "tags": ["server", "threat-intel", "xfe", "virustotal"], + "arguments": [ + { + "name": "data", + "description": "Raw text from which to extract URLs using the appropriate regular expression. If omitted, will scan Incident Details instead.", + "required": false, + "default": true + } + ], + "comment": "Check the URLs in the incident, or raw text provided as argument, for malicious URLs", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["url"] } + }, + { + "name": "ExchangeFindAndDelete", + "script": "ExchangeFindAndDelete.py", + "type": "python", + "visualScript": "", + "tags": ["server", "response", "ews","exchange","email"], + "arguments": [ + { + "name": "mailbox", + "description": "Mailbox to be searched, e.g. dave@acme.com", + "required": false, + "default": true + }, + { + "name": "subject", + "description": "Only match mails containing this Subject", + "required": false, + "default": false + }, + { + "name": "attachmentName", + "description": "Only match mails containing an attachment with this name", + "required": false, + "default": false + }, + { + "name": "sender", + "description": "Only match mails from this sender (Email address)", + "required": false, + "default": false + } + ], + "comment": "Search for the given mail details and in the given mailbox delete found emails", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ews-delete-items", "ews-search-mailbox"] } + }, + { + "name": "CloseInvestigation", + "script": "CloseInvestigation.py", + "type": "python", + "visualScript": "", + "tags": ["server", "management"], + "arguments": [ + { + "name": "reason", + "description": "Reason for closing the investigation", + "required": false, + "default": true + } + ], + "comment": "Close an investigation", + "system": true, + "scriptTarget": 0 + }, + { + "name": "XBInfo", + "script": "xbinfo.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [], + "comment": "Retrieve global Exabeam info about number of users, assets and events", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": [], "should": ["xb-users", "xb-assets", "xb-events"] } + }, + { + "name": "XBNotable", + "script": "xbnotable.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [ + { + "name": "rows", + "description": "Maximum number of result rows to return", + "required": false, + "default": false + }, + { + "name": "days", + "description": "Number of days back to include in results", + "required": false, + "default": false + } + ], + "comment": "Retrieve notable Exabeam users", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["xb-notable"] } + }, + { + "name": "XBLockouts", + "script": "xblockouts.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [ + { + "name": "rows", + "description": "Maximum number of result rows to return", + "required": false, + "default": false + }, + { + "name": "days", + "description": "Number of days back to include in results", + "required": false, + "default": false + } + ], + "comment": "Retrieve lockouts from Exabeam", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["xb-lockouts"] } + }, + { + "name": "XBUser", + "script": "xbuser.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [ + { + "name": "username", + "description": "Username for query", + "required": true, + "default": true + } + ], + "comment": "Retrieve user info from Exabeam", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["xb-user"] } + }, + { + "name": "XBTimeline", + "script": "xbtimeline.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [ + { + "name": "username", + "description": "Username for query", + "required": true, + "default": true + } + ], + "comment": "Retrieve timeline of a user", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["xb-timeline"] } + }, + { + "name": "XBTriggeredRules", + "script": "xbtriggeredrules.py", + "type": "python", + "visualScript": "", + "tags": ["server", "analytics", "exabeam"], + "arguments": [ + { + "name": "session", + "description": "Session to query", + "required": true, + "default": true + } + ], + "comment": "Retrieve the triggered rules for a session", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["xb-triggered-rules"] } + }, + { + "name": "CYFileRep", + "script": "cyfilerep.py", + "type": "python", + "visualScript": "", + "tags": ["server", "threat-intel", "cylance", "file"], + "arguments": [ + { + "name": "entry", + "description": "The ID of a file entry to upload", + "required": true, + "default": true + } + ], + "comment": "Retrieve file reputation and upload the file if required for analysis", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["file", "cy-upload"] } + }, + { + "name": "CSActors", + "script": "csactors.py", + "type": "python", + "visualScript": "", + "tags": ["server", "threat-intel", "crowdstrike"], + "arguments": [ + { + "name": "q", + "description": "Search all fields for the given data", + "required": false, + "default": true + }, + { + "name": "name", + "description": "Search based on actor name", + "required": false, + "default": false + }, + { + "name": "description", + "description": "Search based on description", + "required": false, + "default": false + }, + { + "name": "minLastModifiedDate", + "description": "Search range from modified date. Dates are formatted as YYYY-MM-DD.", + "required": false, + "default": false + }, + { + "name": "maxLastModifiedDate", + "description": "Search range to modified date. Dates are formatted as YYYY-MM-DD.", + "required": false, + "default": false + }, + { + "name": "minLastActivityDate", + "description": "Search range from activity date. Dates are formatted as YYYY-MM-DD.", + "required": false, + "default": false + }, + { + "name": "maxLastActivityDate", + "description": "Search range to activity date. Dates are formatted as YYYY-MM-DD.", + "required": false, + "default": false + }, + { + "name": "origins", + "description": "Search by origins - takes a comma-separated list", + "required": false, + "default": false + }, + { + "name": "targetCountries", + "description": "Search by target countries - takes a comma-separated list", + "required": false, + "default": false + }, + { + "name": "targetIndustries", + "description": "Search by target industries - takes a comma-separated list", + "required": false, + "default": false + }, + { + "name": "motivations", + "description": "Search by motivations - takes a comma-separated list", + "required": false, + "default": false + }, + { + "name": "sort", + "description": "Sort is field_name.order, field_name.order where order is either asc or desc.", + "required": false, + "default": false + }, + { + "name": "offset", + "description": "Which page of the results to retrieve. It is 0 based.", + "required": false, + "default": false + }, + { + "name": "limit", + "description": "Number of results for the page", + "required": false, + "default": false + } + ], + "comment": "Query CrowdStrike actors based on given parameters. For fields like countries and industries, multiple values can be passed separated by ','.", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cs-actors"] } + }, + { + "name": "CSIndicators", + "script": "csindicators.py", + "type": "python", + "visualScript": "", + "tags": ["server", "threat-intel", "crowdstrike"], + "arguments": [ + { + "name": "parameter", + "description": "Based on what parameter to search.\nSee CrowdStrike documentation for details.\nCan be one of indicator, type, report, actor, malicious_confidence, published_date, last_updated, malware_family, kill_chain, labels, DomainType, EmailAddressType, IntelNews, IPAddressType, Malware, Status, Target, ThreatType, Vulnerability", + "required": true, + "default": true + }, + { + "name": "filter", + "description": "Can be either match, equal, gt(e), lt(e)", + "required": true, + "default": false + }, + { + "name": "value", + "description": "The value for the given parameter", + "required": true, + "default": false + }, + { + "name": "sort", + "description": "Sort by a field. Should be field_name.order where order is either asc or desc. Fields are indicator, type, report, actor, malicious_confidence, published_date, last_updated.", + "required": false, + "default": false + }, + { + "name": "page", + "description": "The page to retrieve - 1 based", + "required": false, + "default": false + }, + { + "name": "pageSize", + "description": "The size of the page to retrieve", + "required": false, + "default": false + } + ], + "comment": "Query CrowdStrike indicators based on given parameters.", + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cs-indicators"] } + }, + { + "name": "SendEmail", + "script": "SendEmail.py", + "type": "python", + "visualScript": "", + "tags": ["response", "email", "server"], + "comment": "Send an email with the specified parameters.\nAttachments are provided as a comma-separated list of entry IDs.\nExample usage: !SendEmail subject=\"File from war room\" body=\"Please see the attached file. --DBot\" to=jane@acme.com cc=john@acme.com attachIDs=89@3,46@3", + "arguments": [ + { + "name": "to", + "description": "Email addresses for the 'to' field", + "required": true, + "default": false + }, + { + "name": "cc", + "description": "Email addresses for the 'cc' field", + "required": false, + "default": false + }, + { + "name": "bcc", + "description": "Email addresses for the 'bcc' field", + "required": false, + "default": false + }, + { + "name": "subject", + "description": "Subject for the email to be sent", + "required": false, + "default": false + }, + { + "name": "body", + "description": "The contents (body) of the email to be sent", + "required": false, + "default": false + }, + { + "name": "attachIDs", + "description": "A comma-separated list of IDs of war room entries that contain files. Used to attach files to the outgoing email. Example: attachIDs=15@8,19@8", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["send-mail"] } + }, + { + "name": "CopyFileD2", + "script": "CopyFileD2.js", + "type": "javascript", + "visualScript": "", + "tags": ["util", "server"], + "comment": "Copy a file from an entry to the destination path on the specified system. This uses the dissolvable agent's HTTPS communication channel rather than scp or other out-of-band methods.\nExample usage: !CopyFileD2 destpath=/home/sansforensics/collectedbinaries/inv8_suspiciousPE1.exe.evil entryid=21@8 system=Analyst1", + "arguments": [ + { + "name": "system", + "description": "System to which we want to copy the file", + "required": true, + "default": false + }, + { + "name": "destpath", + "description": "Full filesystem path and filename under which to save the file", + "required": true, + "default": false + }, + { + "name": "entryid", + "description": "ID of the war room entry containing the file to copy", + "required": true, + "default": false + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "ADGetUserGroups", + "script": "ADGetUserGroups.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the groups in which the specified user is a member. The user can be specified by name, email or as an Active Directory Distinguished Name (DN).", + "arguments": [ + { + "name": "dn", + "description": "Active Directory Distinguished Name of the desired user", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Name of the desired user", + "required": false, + "default": false + }, + { + "name": "email", + "description": "Email address of the desired user", + "required": false, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADGetUsersByEmail", + "script": "ADGetUsersByEmail.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the user associated with the specified email address.", + "arguments": [ + { + "name": "email", + "description": "Email address by which to search", + "required": true, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADGetEmailForUser", + "script": "ADGetEmailForUser.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the email address associated with the specified user. The user can be specified by name, email or as an Active Directory Distinguished Name (DN).", + "arguments": [ + { + "name": "dn", + "description": "Active Directory Distinguished Name of the desired user", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Name of the desired user", + "required": false, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADGetComputerGroups", + "script": "ADGetComputerGroups.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the groups in which the specified computer is a member. The member computer can be specified by name or by DN.", + "arguments": [ + { + "name": "dn", + "description": "Active Directory Distinguished Name for the desired computer", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Name of the desired computer", + "required": false, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADUserLogonInfo", + "script": "ADUserLogonInfo.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve detailed information about a user account. The user can be specified by name, email or as an Active Directory Distinguished Name (DN).", + "arguments": [ + { + "name": "dn", + "description": "Active Directory Distinguished Name for the desired user", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Name of the desired user", + "required": false, + "default": false + }, + { + "name": "email", + "description": "Email address of the desired user", + "required": false, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADGetGroupComputers", + "script": "ADGetGroupComputers.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the list of computers that are members of the specified group. Group must be given by its AD Distinguished Name. The \"attributes\" argument receives a comma-separated list of additional attributes you wish to be displayed in the results.\nExample usage: !ADGetGroupComputers groupdn=\"CN=ImportantComputers,DC=demisto,DC=com\" attributes=operatingsystem ", + "arguments": [ + { + "name": "groupdn", + "description": "Active Directory Distinguished Name for the desired group", + "required": true, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADGetGroupUsers", + "script": "ADGetGroupUsers.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to retrieve the list of users who are members of the specified group. Group must be given by its AD Distinguished Name. The \"attributes\" argument receives a comma-separated list of additional attributes you wish to be displayed in the results.\nExample usage: !ADGetGroupUsers groupdn=\"CN=Domain Admins,CN=Users,DC=demisto,DC=com\" attributes=badPwdCount,memberOf ", + "arguments": [ + { + "name": "groupdn", + "description": "Active Directory Distinguished Name for the desired group", + "required": true, + "default": false + }, + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADListComputers", + "script": "ADListComputers.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Retrieve the list of Computer objects stored in Active Directory. Use the \"attributes\" argument to include specific attributes in the results. ", + "arguments": [ + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADListUsers", + "script": "ADListUsers.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Retrieve the list of User objects stored in Active Directory. Use the \"attributes\" argument to include specific attributes in the results. ", + "arguments": [ + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ADListUsersEx", + "script": "ADListUsersEx.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Retrieve the list of User objects stored in Active Directory and include an extended list of attributes and information about each user. Use the \"attributes\" argument to include additional specific attributes in the results.", + "arguments": [ + { + "name": "attributes", + "description": "Include these AD attributes of the resulting objects in addition to the default ones", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "Strings", + "script": "strings.py", + "type": "python", + "visualScript": "", + "tags": ["server", "file"], + "comment": "Extract strings from a file with optional filter - similar to binutils strings command", + "arguments": [ + { + "name": "entry", + "required": true, + "default": true, + "description": "Entry ID of a file entry to retrieve strings from" + }, + { + "name": "chars", + "required": false, + "default": false, + "description": "Number of consecutive characters to be considered a string - default is 4" + }, + { + "name": "size", + "required": false, + "default": false, + "description": "Display first 'size' results - default is 1024" + }, + { + "name": "filter", + "required": false, + "default": false, + "description": "Regex to filter the strings - compiled with ignore case" + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "RegProbeBasic", + "script": "RegProbeBasic.py", + "type": "python", + "visualScript": "", + "tags": ["registry"], + "comment": "Perform a short probe of the specified system's registry - retrieve and display the values of a list of interesting keys ", + "arguments": [ + { + "name": "system", + "required": true, + "default": true, + "description": "Name of the system to be queried" + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "RegCollectValues", + "script": "RegCollectValues.py", + "type": "python", + "visualScript": "", + "tags": ["registry","enhancement"], + "comment": "Collect values for the given registry path from all Windows systems in this investigation.", + "arguments": [ + { + "name": "regpath", + "required": true, + "default": true, + "description": "The registry path of the key to query" + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "RegPathReputationBasicLists", + "script": "RegPathReputationBasicLists.py", + "type": "python", + "visualScript": "", + "tags": ["registry","reputation"], + "comment": "Check the given registry path against a small blacklist and whitelist. If the key matches neither, returns an answer of 2 meaning \"Unknown\".", + "arguments": [ + { + "name": "input", + "required": true, + "default": true, + "description": "Registry path to be checked" + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "TaniumDeployAction", + "script": "taniumDeployAction.js", + "type": "javascript", + "visualScript": "", + "comment": "Execute an action, optionally with parameters, and filtering - based on an existing package. See https://kb.tanium.com/SOAP for more information", + "system": true, + "tags": ["tanium"], + "arguments": [ + { + "name": "packageName", + "description": "Specify the package name. e.g. !TaniumDeployAction packageName=\"Clean Stale Tanium Client Data\"", + "required": false, + "default": false + }, + { + "name": "packageID", + "description": "Use the package ID instead of its name", + "required": false, + "default": false + }, + { + "name": "parameters", + "description": "Use parameters with the package. See https://kb.tanium.com/SOAP for more details", + "required": false, + "default": false + }, + { + "name": "comment", + "description": "Comment to be added to the action history in the Tanium server", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["tn-deploy-package"] } + }, + { + "name": "TaniumAskQuestion", + "script": "taniumAskQuestion.js", + "type": "javascript", + "visualScript": "", + "comment": "Send a request for a formatted result of a saved question. To receive the most up to date data, run the same command twice. See https://kb.tanium.com/SOAP for more information", + "system": true, + "tags": ["tanium"], + "arguments": [ + { + "name": "name", + "description": "Retrieve the question by its name. E.g. !TaniumAskQuestion name=\"Running Services\"", + "required": false, + "default": false + }, + { + "name": "id", + "description": "Retrieve the question by its ID. To view ID in the Tanium console go to: Authoring -> Saved Questions tab. This shows you a list of Saved Questions. Click the edit button on a Saved Question and the ID will be shown in the lower left corner", + "required": false, + "default": false + }, + { + "name": "timeout", + "description": "Force Tanium to respond after x seconds (even if data was not collected fully by Tanium)", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["tn-result-data", "tn-result-info"] } + }, + { + "name": "TaniumAskQuestionComplex", + "script": "taniumAskQuestionComplex.js", + "type": "javascript", + "visualScript": "", + "comment": "TaniumAskQuestionComplex - same as the AskQuestion command with additional filtering prepared by the script (an XML subsection added to the request).", + "system": true, + "tags": ["tanium"], + "arguments": [ + { + "name": "timeout", + "description": "Force Tanium to respond after x seconds (even if data was not collected fully by Tanium)", + "required": false, + "default": false + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["tn-result-data", "tn-result-info", "tn-add-question-complex"] } + }, + { + "name": "ADIsUserMember", + "script": "ADIsUserMember.py", + "type": "python", + "visualScript": "", + "tags": ["active directory"], + "comment": "Use Active Directory to check if the specified user is a member of the specified group. Returns simply yes/no. The user can be specified by name, email or as an Active Directory Distinguished Name (DN).", + "system": true, + "arguments": [ + { + "name": "dn", + "description": "Active Directory Distinguished Name of the desired user", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Name of the desired user", + "required": false, + "default": false + }, + { + "name": "email", + "description": "Email address of the desired user", + "required": false, + "default": false + }, + { + "name": "groupname", + "description": "Name of the AD group to check", + "required": true, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["ad-search"] } + }, + { + "name": "ConferIncidentDetails", + "script": "ConferIncidentDetails.py", + "type": "python", + "visualScript": "", + "tags": ["confer"], + "comment": "Display the incident details retrieved from Confer in a readable format", + "arguments": [], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["confer"] } + }, + { + "name": "ConferSetSeverity", + "script": "ConferSetSeverity.py", + "type": "python", + "visualScript": "", + "tags": ["confer"], + "comment": "Set incident severity according to indicators found in an confer alert", + "arguments": [], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["confer"] } + }, + { + "name": "CuckooDetonateFile", + "script": "CuckooDetonateFile.py", + "type": "python", + "visualScript": "", + "tags": ["cuckoo"], + "comment": "Detonate the file in Cuckoo sandbox.", + "arguments": [ + { + "name": "entryID", + "description": "ID of the entry containing the file to detonate.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ck-file"] } + }, + { + "name": "CuckooGetReport", + "script": "CuckooGetReport.py", + "type": "python", + "visualScript": "", + "tags": ["cuckoo"], + "comment": "Get the report for a completed analysis.", + "arguments": [ + { + "name": "taskID", + "description": "ID of the task in Cuckoo.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ck-report"] } + }, + { + "name": "CuckooTaskStatus", + "script": "CuckooTaskStatus.py", + "type": "python", + "visualScript": "", + "tags": ["cuckoo"], + "comment": "Check the current status of a task in Cuckoo sandbox.", + "arguments": [ + { + "name": "taskID", + "description": "ID of the task to check.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["ck-view"] } + }, + { + "name": "FPSetRule", + "script": "FPSetRule.py", + "type": "python", + "visualScript": "", + "tags": ["forcepoint","triton"], + "comment": "Adds (or updates existing) rule in Forcepoint Triton. Preserves order of rules and modifies policy in-place if a rule exists with the exact type and value.", + "arguments": [ + { + "name": "policy", + "description": "Policy/action assigned to the rule - \"allow\" or \"deny\" only.", + "required": true, + "default": true + }, + { + "name": "type", + "description": "The Triton rule type - \"dest_domain\", \"dest_ip\", \"dest_host\" or \"url_regex\"", + "required": true, + "default": false + }, + { + "name": "value", + "description": "The value to match for this rule (domain, regex, etc. depending on the type)", + "required": true, + "default": false + }, + { + "name": "remoteaccessname", + "description": "If the Forcepoint Triton instance is configured as a RemoteAccess integration instance ‐ insert its name here. Replaces argument \"tritonsystem\".", + "required": false, + "default": false + }, + { + "name": "tritonsystem", + "description": "System name of the linux host on which Forcepoint Triton is installed. Only use if not working with Triton as a RemoteAccess integration instance ‐ if so, use the \"remoteaccessname\" argument instead.", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "FPDeleteRule", + "script": "FPDeleteRule.py", + "type": "python", + "visualScript": "", + "tags": ["forcepoint","triton"], + "comment": "Deletes a rule in Forcepoint Triton.", + "arguments": [ + { + "name": "type", + "description": "The Triton rule type - \"dest_domain\", \"dest_ip\", \"dest_host\" or \"url_regex\"", + "required": true, + "default": false + }, + { + "name": "value", + "description": "The value to match for this rule (domain, regex, etc. depending on the type)", + "required": true, + "default": false + }, + { + "name": "remoteaccessname", + "description": "If the Forcepoint Triton instance is configured as a RemoteAccess integration instance ‐ insert its name here. Replaces argument \"tritonsystem\".", + "required": false, + "default": false + }, + { + "name": "tritonsystem", + "description": "System name of the linux host on which Forcepoint Triton is installed. Only use if not working with Triton as a RemoteAccess integration instance ‐ if so, use the \"remoteaccessname\" argument instead.", + "required": false, + "default": false + } + ], + "system": true, + "scriptTarget": 0 + }, + { + "name": "CBPApproveHash", + "script": "CBPApproveHash.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black-protection","bit9"], + "comment": "Approve/whitelist a hash in CBEP/Bit9.", + "arguments": [ + { + "name": "hash", + "description": "The hash value to approve.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cbp-fileRule-update"] } + }, + { + "name": "CBPBanHash", + "script": "CBPBanHash.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black-protection","bit9"], + "comment": "Ban/blacklist a hash in CBEP/Bit9.", + "arguments": [ + { + "name": "hash", + "description": "The hash value to ban.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cbp-fileRule-update"] } + }, + { + "name": "CBPFindComputer", + "script": "CBPFindComputer.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black-protection","bit9"], + "comment": "Find a computer in CBEP/Bit9.", + "arguments": [ + { + "name": "query", + "description": "Only show computers matching this query. If omitted, displays all computers. Query is in CBEP/Bit9 syntax documented in https://developer.carbonblack.com/reference/enterprise-protection/7.2/rest-api/#query-condition - e.g. \"name:*srv*\"", + "required": false, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cbp-computer-search"] } + }, + { + "name": "CBPFindRule", + "script": "CBPFindRule.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black-protection","bit9"], + "comment": "Find the rule state for a hash value in CBEP/Bit9.", + "arguments": [ + { + "name": "hash", + "description": "The hash value to check.", + "required": true, + "default": true + } + ], + "system": true, + "scriptTarget": 0, + "dependsOn": { "must": ["cbp-fileRule-search"] } + }, + { + "name": "CBAlerts", + "script": "CBAlerts.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black"], + "comment": "Get the list of Alerts from Carbon Black Enterprise Response. Supports the same arguments as the cb-alerts command.", + "system": true, + "arguments": [], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-alerts"] } + }, + { + "name": "CBWatchlists", + "script": "CBWatchlists.py", + "type": "python", + "visualScript": "", + "tags": ["carbon-black"], + "comment": "Display all watchlists and their details, queries, etc.", + "system": true, + "arguments": [ + { + "name": "id", + "description": "Display a specific watchlist by watchlist ID (numeric)", + "required": false, + "default": true + } + ], + "scriptTarget": 0, + "dependsOn": { "must": ["cb-watchlist-get"] } + }, + { + "name": "IncidentSet", + "script": "IncidentSet.py", + "type": "python", + "visualScript": "", + "tags": ["management"], + "comment": "Modify incident info such as name, owner, type, etc.", + "system": true, + "arguments": [ + { + "name": "owner", + "description": "Incident owner - must be an existing user in the platform", + "required": false, + "default": false + }, + { + "name": "playbook", + "description": "Assigned new playbook name", + "required": false, + "default": false + }, + { + "name": "stage", + "description": "Incident stage - must be from a predefined list of stages", + "required": false, + "default": false + }, + { + "name": "details", + "description": "Incident details", + "required": false, + "default": false + }, + { + "name": "severity", + "description": "The severity to set. Can be \"low\",\"medium\",\"high\" or \"critical\".", + "required": false, + "default": false + }, + { + "name": "type", + "description": "Incident type", + "required": false, + "default": false + }, + { + "name": "name", + "description": "Incident name", + "required": false, + "default": true + }, + { + "name": "updatePlaybookForType", + "description": "Should we also update the playbook according to the new given type. Can be yes or no. Default is yes.", + "required": false, + "default": false + }, + { + "name": "labels", + "description": "Set and override the labels for the incident. Labels expected format is [{\"labelName\": \"labelValue\"}, {\"labelName1\": \"labelValue1\"}] (JSON).", + "required": false, + "default": false + }, + { + "name": "addLabels", + "description": "Add to the list of labels for the incident. Labels expected format is [{\"labelName\": \"labelValue\"}, {\"labelName1\": \"labelValue1\"}] (JSON).", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "SendURLDetailsByEmail", + "script": "sendurldetails.py", + "type": "python", + "visualScript": "", + "tags": ["threat-intel"], + "comment": "Get all details about URL (reputation, number of ads, etc.) and send them via email", + "system": true, + "arguments": [ + { + "name": "url", + "description": "The URL to get details for. If not provided, will be taken from incident details.", + "required": false, + "default": false + }, + { + "name": "subject", + "description": "The subject of the email. If not provided will be the incident name.", + "required": false, + "default": false + }, + { + "name": "recipient", + "description": "The recipient of the email", + "required": true, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "SendEmailToManager", + "script": "sendemailtomanager.py", + "type": "python", + "visualScript": "", + "tags": ["communication"], + "comment": "Send an approval email to the manager of the employee with the given email allowing the manager to reply directly into the incident", + "system": true, + "arguments": [ + { + "name": "email", + "description": "The employee email. We will send an email to his manager. If not provided will be taken from incident label 'Email/from'", + "required": false, + "default": false + }, + { + "name": "manager", + "description": "The manager attribute in Active Directory. Default is 'manager'.", + "required": false, + "default": false + }, + { + "name": "entitlement", + "description": "If provided (any value), we will add an entitlement to the subject allowing manager to reply to war room", + "required": false, + "default": false + }, + { + "name": "body", + "description": "The contents of the email body. It's a template that can include $empName and $managerName which will be replaced with actual values.", + "required": false, + "default": false + }, + { + "name": "request", + "description": "The contents of the request from the manager. Will be added below the body. If none is provided, incident details will be taken.", + "required": false, + "default": false + } + ], + "scriptTarget": 0 + }, + { + "name": "URLExtract", + "script": "URLExtract.py", + "type": "python", + "visualScript": "", + "tags": ["url", "infra"], + "comment": "Extract URLs from the given text and place them both as output and in the context of a playbook", + "system": true, + "arguments": [ + { + "name": "text", + "description": "The text to extract URLs from", + "required": true, + "default": true + } + ], + "scriptTarget": 0 + }, + { + "name": "IPExtract", + "script": "IPExtract.py", + "type": "python", + "visualScript": "", + "tags": ["ip", "infra"], + "comment": "Extract IPs from the given text and place them both as output and in the context of a playbook", + "system": true, + "arguments": [ + { + "name": "text", + "description": "The text to extract ip from", + "required": true, + "default": true + } + ], + "scriptTarget": 0 + }, + { + "name": "MD5Extract", + "script": "MD5Extract.py", + "type": "python", + "visualScript": "", + "tags": ["hash", "infra"], + "comment": "Extract md5s from the given text and place them both as output and in the context of a playbook", + "system": true, + "arguments": [ + { + "name": "text", + "description": "The text to extract md5 from", + "required": true, + "default": true + } + ], + "scriptTarget": 0 + }, + { + "name": "TextFromHTML", + "script": "TextFromHTML.py", + "type": "python", + "visualScript": "", + "tags": ["infra"], + "comment": "Extract regular text from the given HTML", + "system": true, + "arguments": [ + { + "name": "html", + "description": "The HTML to strip tags from", + "required": true, + "default": true + } + ], + "scriptTarget": 0 + }, + { + "name": "PrintContext", + "script": "PrintContext.py", + "type": "python", + "visualScript": "", + "tags": ["infra"], + "comment": "Pretty-print the contents of the playbook context", + "system": true, + "arguments": [], + "scriptTarget": 0 + }, + { + "name": "IncidentToContext", + "script": "IncidentToContext.py", + "type": "python", + "visualScript": "", + "tags": ["infra"], + "comment": "Inserts incident info and labels into context for use inside playbooks.", + "system": true, + "arguments": [], + "scriptTarget": 0 + }, + { + "name": "SlackSend", + "script": "SlackSend.py", + "type": "python", + "visualScript": "", + "tags": ["slack"], + "comment": "Send messages to Slack teams", + "system": true, + "arguments": [ + { + "name": "to", + "description": "Send a Direct message by specifying a Slack user name", + "required": false, + "default": false + }, + { + "name": "channel", + "description": "Specify a Slack channel where the message will appear.", + "required": false, + "default": false + }, + { + "name": "entry", + "description": "Send a link to this entry in the War Room", + "required": false, + "default": false + }, + { + "name": "group", + "description": "Specify a private channel", + "required": false, + "default": false + }, + { + "name": "message", + "description": "Message contents to send.", + "required": false, + "default": true + } + ], + "scriptTarget": 0 + } + ], + "agent": [ + { + "name": "VolMalfindDumpAgent", + "script": "volmalfinddumpagent.js", + "type": "javascript", + "visualScript": "", + "tags": ["volatility"], + "comment": "Volatility script for command ldrmodules", + "system": true, + "arguments": [ + { + "name": "memdump", + "description": "Path to memory dump file on the system being used", + "required": true, + "default": false + }, + { + "name": "pid", + "description": "Process ID to pass to volatility malfind command", + "required": true, + "default": false + }, + { + "name": "dumpdir", + "description": "Path to directory in which to save dumped memory sections", + "required": true, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "D2Processes", + "script": "D2processes.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Show running processes", + "system": true, + "scriptTarget": 1 + }, + { + "name": "D2Hardware", + "script": "D2hardware.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Show system information", + "system": true, + "scriptTarget": 1 + }, + { + "name": "D2Users", + "script": "D2users.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Show local accounts", + "system": true, + "scriptTarget": 1 + }, + { + "name": "D2GetSystemLog", + "script": "D2GetSystemLog.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Copy a log file. Works on Windows and Unix (differently - take a peek at the script itself to see how).", + "system": true, + "arguments": [ + { + "name": "logName", + "description": "Name of the log to retrieve", + "required": true, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "D2Services", + "script": "D2services.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Show system services", + "system": true, + "scriptTarget": 1 + }, + { + "name": "CommonD2", + "script": "common-d2.js", + "type": "javascript", + "visualScript": "", + "tags": ["infra","agent"], + "comment": "Common code that will be merged into each D2 agent script when it runs", + "system": false, + "scriptTarget": 1 + }, + { + "name": "D2Exec", + "script": "D2exec.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","endpoint"], + "comment": "Execute the command and pack the output back to server", + "system": true, + "arguments": [ + { + "name": "cmd", + "description": "System command to execute", + "required": true, + "default": true + } + ], + "scriptTarget": 1 + }, + { + "name": "VolRaw", + "script": "vol.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","volatility"], + "comment": "Execute volatility with command and file as parameters and returns raw output from stdout.", + "system": true, + "arguments": [ + { + "name": "cmd", + "description": "Volatility command to run", + "required": true, + "default": false + }, + { + "name": "file", + "description": "Path of file to pass as argument to Volatility", + "required": true, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "VolJson", + "script": "voljson.js", + "type": "javascript", + "visualScript": "", + "tags": ["volatility","agent"], + "comment": "Execute volatility with command and file as parameters and return output as json.", + "system": true, + "arguments": [ + { + "name": "cmd", + "description": "Volatility command to run", + "required": true, + "default": false + }, + { + "name": "file", + "description": "Path of file to pass as argument to Volatility", + "required": true, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "D2PEDump", + "script": "D2pedump.js", + "type": "javascript", + "visualScript": "", + "tags": ["executable","agent"], + "comment": "Execute PE Dump on a file that is under /tmp somewhere. Used internally by StaticAnalyze", + "system": true, + "arguments": [ + { + "name": "file", + "description": "Path to the PE file to analyze, relative to /tmp", + "required": true, + "default": true + } + ], + "scriptTarget": 1 + }, + { + "name": "Osxcollector", + "script": "osxcollector.js", + "type": "javascript", + "visualScript": "", + "tags": ["osx","agent"], + "comment": "Execute osxcollector on machine, can run ONLY on OSX", + "system": true, + "arguments": [ + { + "name": "section", + "description": "Ask OSXCollector for a specific section", + "required": false, + "default": true + }, + { + "name": "timeout", + "description": "Timeout for the OSXCollector execution to complete. If omitted, defaults to 10 minutes.", + "required": false, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "ExchangeSearchMailbox", + "script": "exsearchmailbox.js", + "type": "javascript", + "tags": ["exchange","email"], + "visualScript": "", + "comment": "Search all mailboxes on an Exchange server and copy the results to a specified target mailbox. This script runs through the agent on a Windows machine, pulls and executes a PowerShell script - which talks to the Exchange server.", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Exchange query to match against emails", + "required": true, + "default": false + }, + { + "name": "toMailbox", + "description": "Destination mailbox", + "required": true, + "default": false + }, + { + "name": "toFolder", + "description": "Folder within destination mailbox in which to place matched emails", + "required": true, + "default": false + }, + { + "name": "server", + "description": "Hostname of the Exchange server", + "required": false, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "ExchangeDeleteMail", + "script": "exdeletemail.js", + "type": "javascript", + "tags": ["exchange","email"], + "visualScript": "", + "comment": "Search all mailboxes on an Exchange server for a query and deletes all messages in which query is satisfied. This script runs through the agent on a Windows machine, pulls and executes a PowerShell script - which talks to the Exchange server.", + "system": true, + "arguments": [ + { + "name": "query", + "description": "Exchange query to match against emails", + "required": true, + "default": false + }, + { + "name": "server", + "description": "Hostname of the Exchange server", + "required": false, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "ExchangeAssignRole", + "script": "exassignrole.js", + "type": "javascript", + "tags": ["exchange","email"], + "visualScript": "", + "comment": "Assign a 'Mailbox Import Export' management role to a user. This script runs through the agent on a Windows machine, pulls and executes a PowerShell script - which talks to the Exchange server.", + "system": true, + "arguments": [ + { + "name": "username", + "description": "Username to whom to assign the role", + "required": false, + "default": false + }, + { + "name": "role", + "description": "Choose a different role to assign to the user. Default is 'Mailbox Import Export'.", + "required": false, + "default": false + }, + { + "name": "server", + "description": "Hostname of the Exchange server", + "required": false, + "default": false + } + ], + "scriptTarget": 1 + }, + { + "name": "D2Drop", + "script": "D2Drop.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","util"], + "comment": "Drop a file to a target system by providing its path on the server. Use CopyFileD2 instead in most cases.\nThis is a utility agent script to be used inside server scripts. See CopyFileD2 for an example.", + "arguments": [ + { + "name": "destpath", + "description": "Full filesystem path and filename under which to save the file", + "required": true, + "default": false + } + ], + "system": true, + "scriptTarget": 1 + }, + { + "name": "D2RegQuery", + "script": "D2RegQuery.js", + "type": "javascript", + "visualScript": "", + "tags": ["agent","registry"], + "comment": "Use the D2 agent to retrieve the value of the given registry key.", + "arguments": [ + { + "name": "regpath", + "required": true, + "default": true, + "description": "The registry path of the key to be queried" + } + ], + "system": true, + "scriptTarget": 1 + } + + ] +} diff --git a/Scripts/searchmailbox.js b/Scripts/searchmailbox.js new file mode 100644 index 000000000000..63fdd22bb29f --- /dev/null +++ b/Scripts/searchmailbox.js @@ -0,0 +1,33 @@ +//+ exchange/search.ps1 + +//Params: +//See here: https://technet.microsoft.com/en-us/library/dd298173(v=exchg.160).aspx +//query is the string provided to the -SearchQuery parameter +//to-mailbox is the string provided to -TargetMailbox parameter +//to-folder is the string provided to -TargetFolder parameter +//if server is provided, it'll be used as -ServerFQDN parameter to Connect-ExchangeServer cmdlet + +if ((env.ARCH !== "amd64") && (env.OS !== "windows")) { + throw("Script can ran only in 64bit Windows Agents"); +} + +var command = []; +command.push("powershell.exe"); +command.push("-version 2.0"); +command.push("-NonInteractive"); +command.push("-NoLogo"); +command.push(which("search.ps1")); +command.push("-query"); +command.push(args.query); +command.push("-targetmbx"); +command.push(args["to-mailbox"]); +command.push("-targetFolder"); +command.push(args["to-folder"]); + +if (typeof (args.server) !== "undefined") { + command.push("-server"); + command.push(args.server); +} + +pack(execute(command.join(" ")), 'table'); + diff --git a/Scripts/sendemailtomanager.py b/Scripts/sendemailtomanager.py new file mode 100644 index 000000000000..10ba6c4f1830 --- /dev/null +++ b/Scripts/sendemailtomanager.py @@ -0,0 +1,71 @@ +email = demisto.get(demisto.args(), 'email') +if not email: + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email/from': + email = t['value'].lower() + +if not email: + demisto.results('Could not find employee email. Quiting.') + sys.exit(0) + +managerAttrubute = demisto.get(demisto.args(), 'manager') +if not managerAttrubute: + managerAttrubute = 'manager' + +res = demisto.executeCommand('ad-search', {'filter': r'(&(objectClass=user)(mail=' + email + '))', 'attributes': 'displayname,' + managerAttrubute}) +if isError(res[0]): + demisto.results(res) + sys.exit(0) + +managerDN = demisto.get(res[0]['Contents'][0], managerAttrubute) +empName = demisto.get(res[0]['Contents'][0], 'displayname') + +if not managerDN: + demisto.results('Unable to get manager email') + sys.exit(0) + +filterstr = r'(&(objectClass=User)(distinguishedName=' + managerDN + '))' +res = demisto.executeCommand('ad-search', {'filter': filterstr, 'attributes': 'displayname,mail'}) +if isError(res[0]): + demisto.results(res) + sys.exit(0) + +managerEmail = demisto.get(res[0]['Contents'][0], 'mail') +managerName = demisto.get(res[0]['Contents'][0], 'displayname') +if not managerDN: + demisto.results('Unable to get manager email from DN - ' + managerDN) + sys.exit(0) + +entitlement = demisto.get(demisto.args(), 'entitlement') +if entitlement: + res = demisto.executeCommand('addOneTimeEntitlement', {}) + if isError(res[0]): + demisto.results(res) + sys.exit(0) + entitlement = demisto.get(res[0], 'Contents') + if not entitlement: + demisto.results('Unable to get entitlement') + sys.exit(0) + subject = demisto.gets(demisto.incidents()[0], 'name') + ' - #' + demisto.investigation()['id'] + ' ' + entitlement +else: + subject = demisto.gets(demisto.incidents()[0], 'name') + ' - #' + demisto.investigation()['id'] + +from string import Template +import textwrap + +body = demisto.get(demisto.args(), 'body') +if not body: + body = """\ + Hi $managerName, + We've received the following request below from $empName. Please reply to this email with either "approve" or "deny". + + Cheers, + Your friendly security team""" + +actualBody = Template(body) + +empRequest = demisto.get(demisto.args(), 'request') +if not empRequest: + empRequest = demisto.incidents()[0]['details'] + +demisto.results(demisto.executeCommand('send-mail', {'to': managerEmail, 'subject': subject, 'body': textwrap.dedent(actualBody.safe_substitute(managerName=managerName, empName=empName)) + '\n----------' + empRequest})) diff --git a/Scripts/sendgotitemailtotarget.py b/Scripts/sendgotitemailtotarget.py new file mode 100644 index 000000000000..e5ca85623d19 --- /dev/null +++ b/Scripts/sendgotitemailtotarget.py @@ -0,0 +1,28 @@ +# Find the recipient of the email - should be the target +target = '' +for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email/from': + target = t['value'] + break + +if target == '': + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email': + target = t['value'] + break + +if target == '': + demisto.results({'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Could not find the target email'}) +else: + from string import Template + import textwrap + defaultBody = """\ + Hi $target, + We've received your email and are investigating. Please do not touch the email until further notice. + + Cheers, + Your friendly security team""" + body = demisto.args()['body'] if demisto.get(demisto.args(), 'body') else defaultBody + actualBody = Template(body) + subject = demisto.args()['subject'] if demisto.get(demisto.args(), 'subject') else 'Security Email Re: ' + demisto.incidents()[0]['name'] + demisto.results(demisto.executeCommand('send-mail', {'to': target, 'subject': subject, 'body': textwrap.dedent(actualBody.safe_substitute(target=target))})) diff --git a/Scripts/senditsbademailtotarget.py b/Scripts/senditsbademailtotarget.py new file mode 100644 index 000000000000..9c8d74179d57 --- /dev/null +++ b/Scripts/senditsbademailtotarget.py @@ -0,0 +1,29 @@ +# Find the recipient of the email - should be the target +target = '' +for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email/from': + target = t['value'] + break + +if target == '': + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email': + target = t['value'] + break + +if target == '': + demisto.results({'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Could not find the target email'}) +else: + from string import Template + import textwrap + defaultBody = """\ + Hi $target, + We've concluded that the email you forwarded to us is malicious. We've taken steps to blacklist the sender and quarantine the email. + Good job on detecting and forwarding it to us! + + Cheers, + Your friendly security team""" + body = demisto.args()['body'] if demisto.get(demisto.args(), 'body') else defaultBody + actualBody = Template(body) + subject = demisto.args()['subject'] if demisto.get(demisto.args(), 'subject') else 'Security Email Re Malicious: ' + demisto.incidents()[0]['name'] + demisto.results(demisto.executeCommand('send-mail', {'to': target, 'subject': subject, 'body': textwrap.dedent(actualBody.safe_substitute(target=target))})) diff --git a/Scripts/senditsgoodemailtotarget.py b/Scripts/senditsgoodemailtotarget.py new file mode 100644 index 000000000000..40fa47ede4b9 --- /dev/null +++ b/Scripts/senditsgoodemailtotarget.py @@ -0,0 +1,29 @@ +# Find the recipient of the email - should be the target +target = '' +for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email/from': + target = t['value'] + break + +if target == '': + for t in demisto.incidents()[0]['labels']: + if t['type'] == 'Email': + target = t['value'] + break + +if target == '': + demisto.results({'Type': entryTypes['note'], 'ContentsFormat': formats['text'], 'Contents': 'Could not find the target email'}) +else: + from string import Template + import textwrap + defaultBody = """\ + Hi $target, + We've concluded that the email you forwarded to us is benign. + Good job on being alert and forwarding it to us! + + Cheers, + Your friendly security team""" + body = demisto.args()['body'] if demisto.get(demisto.args(), 'body') else defaultBody + actualBody = Template(body) + subject = demisto.args()['subject'] if demisto.get(demisto.args(), 'subject') else 'Security Email Re Malicious: ' + demisto.incidents()[0]['name'] + demisto.results(demisto.executeCommand('send-mail', {'to': target, 'subject': subject, 'body': textwrap.dedent(actualBody.safe_substitute(target=target))})) diff --git a/Scripts/sendurldetails.py b/Scripts/sendurldetails.py new file mode 100644 index 000000000000..38770a441451 --- /dev/null +++ b/Scripts/sendurldetails.py @@ -0,0 +1,97 @@ +import re +import urllib2 +import ssl +#import os + +strURLRegex = r'(?i)(?:(?:https?|ftp):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])' + +filtered = ['http://schemas.microsoft.com/office/2004/12/omml', 'http://www.w3.org/TR/REC-html40'] +res = [] +cleanUrls = [] + +url = demisto.get(demisto.args(), 'url') +if not url: + url = demisto.incidents()[0]['details'] + +subject = demisto.get(demisto.args(), 'subject') +if not subject: + subject = demisto.incidents()[0]['name'] + +body = """\ +Hi whitelisting team, +We've received the following request to whitelist the below. Here are the details we have about the URL.""" + +suffix = """\ + + +Cheers, +Your friendly security team""" + +def ads(html,termlist): + results = {} + tags = re.findall("<[^/][^>]*>",html) + for item in termlist.split('\n'): + if not item.strip(): + continue + if item.startswith('!') or item.startswith('[Adbl') or item.startswith('@@'): + continue + if item.startswith('###'): + item = item[3:] + if item.startswith('||'): + item = item[2:item.find("^$")] + for t in tags: + if item in t: + results[item] = (results[item] + 1) if item in results else 1 + return results + +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +#os.environ["http_proxy"] = "" +#os.environ["https_proxy"] = "" + +easylist = urllib2.urlopen('https://easylist.github.io/easylist/easylist.txt', context=ctx).read() + +for m in re.finditer(strURLRegex, url, re.I): + u = m.group(0) + if u in filtered: + continue + if u in cleanUrls: + continue + if 'mailto:' in u: + continue + cleanUrls.append(u) + rep = demisto.executeCommand('url', {'url': u}) + for entry in rep: + if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + c = entry['Contents'] + if entry['Brand'] == brands['xfe']: + body += \ + '\n\nURL: ' + demisto.gets(c, 'url.result.url') + \ + '\nA: ' + demisto.gets(c, 'resolution.A') + \ + '\nAAAA: ' + demisto.gets(c, 'resolution.AAAA') + \ + '\nContry: ' + demisto.gets(c, 'country') + \ + '\nCategories: ' + demisto.gets(c, 'url.result.cats') + \ + '\nScore: ' + demisto.gets(c, 'url.result.score') + \ + '\nMalwareCount: ' + demisto.gets(c, 'malware.count') + \ + '\nProvider: ' + providers['xfe'] + \ + '\nProviderLink: ' + 'https://exchange.xforce.ibmcloud.com/url/' + demisto.gets(c, 'url.result.url') + if entry['Brand'] == brands['vt']: + body += \ + '\n\nURL: ' + demisto.gets(c, 'url') + \ + '\nScanDate: ' + demisto.gets(c, 'scan_date') + \ + '\nPositives: ' + demisto.gets(c, 'positives') + \ + '\nTotal: ' + demisto.gets(c, 'total') + \ + '\nProvider: ' + providers['vt'] + \ + '\nProviderLink ' + demisto.gets(c, 'permalink') + + # Now, get the number of ads and external links + html = urllib2.urlopen(u, context=ctx).read() + hits = ads(html, easylist) + score = sum(hits.values()) + body += '\n\nTotal ads score is: ' + str(score) + body += '\nTotal number of links is: ' + str(len(re.findall(strURLRegex, html, re.I))) + +body += suffix +demisto.results(demisto.executeCommand('send-mail', {'to': demisto.args()['recipient'], 'subject': subject, 'body': body + '\n\n--------------------\n\n' + url})) diff --git a/Scripts/splunksearch.js b/Scripts/splunksearch.js new file mode 100644 index 000000000000..830c25a87645 --- /dev/null +++ b/Scripts/splunksearch.js @@ -0,0 +1,15 @@ +var rows = args.rows ? args.rows : 30; +var query = (args.query.indexOf('|') > 0) ? args.query : args.query + ' | head ' + rows; + +var res = executeCommand('search', {'using-brand': 'splunk', query: query}); +var table = { + Type: 1, + ContentsFormat: 'table', + Contents: [] +}; + +for (var i=0; i 0) { + return res; +} +return 'No files found'; diff --git a/Scripts/strings.py b/Scripts/strings.py new file mode 100644 index 000000000000..199e3bd05f0a --- /dev/null +++ b/Scripts/strings.py @@ -0,0 +1,45 @@ +import re +import string + +# Optional arguments and default values +chars = 4 +if 'chars' in demisto.args(): + chars = int(demisto.args()['chars']) + +size = 1024 +if 'size' in demisto.args(): + size = int(demisto.args()['size']) + +regex = None +if 'filter' in demisto.args(): + regex = re.compile(demisto.args()['filter'], re.I) + +fEntry = demisto.executeCommand('getFilePath', {'id': demisto.args()['entry']})[0] +if not isError(fEntry): + matches = [] + with open(demisto.get(fEntry, 'Contents.path'), 'rb', 1024 * 1024) as f: + buff = '' + c = f.read(1) + while c != '': + if c in string.printable: + buff += c + if len(buff) >= 32 * 1024: + matches.append('File is a regular text file') + break + else: + if len(buff) >= chars: + if regex: + if regex.match(buff): + matches.append(buff) + else: + matches.append(buff) + if len(matches) >= size: + break + buff = '' + c = f.read(1) + if matches: + demisto.results('\n'.join(matches)) + else: + demisto.results('No strings were found.') +else: + demisto.results(fEntry) diff --git a/Scripts/taniumAskQuestion.js b/Scripts/taniumAskQuestion.js new file mode 100644 index 000000000000..fbab2126664a --- /dev/null +++ b/Scripts/taniumAskQuestion.js @@ -0,0 +1,95 @@ +// An example script for asking Tanium a question + +/* name - The name of the Saved-Question in Tanium server (mandatory if no 'id' was specified) +For example: + Computer Name + User Information + Adobe Acrobat Versions + BIOS Information + CPU Utilization Over 75% + Installed Applications + ... +*/ +// id - The ID of the Saved-Question in Tanium server (mandatory if no 'name' was specified) +// timeout - seconds to wait on each iteration while waiting for the question's result +var taniumArgs = { + 'name': args.name, + 'id': args.id, + 'timeout': args.timeout + }; + +var table = { + Type: 1, + ContentsFormat: 'table', + Contents: [] +}; + +var res = executeCommand('tn-result-info', taniumArgs); +if (res[0].Type !== entryTypes.error) { + if (!res[0].Contents.result_infos) { + return res[0].Contents.Envelope.Body.return.command; + } + + // Need to compare 'mr_passed' and 'estimated_total' values, + // to confirm that all machines have answered + var answers = res[0].Contents.result_infos.result_info.mr_passed; + var expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total; + + // Check the status 10 times, and wait 'timeout' seconds between each iteration + var iterToWait = 10; + var sec = 1; + if (taniumArgs.timeout) { + sec = parseInt(taniumArgs.timeout) || 1; + } + while (answers !== expectedAnswers && iterToWait-- > 0) { + wait(sec); + res = executeCommand('tn-result-info', taniumArgs); + if (res[0].Type === entryTypes.error) { + return res[0]; + } + answers = res[0].Contents.result_infos.result_info.mr_passed; + expectedAnswers = res[0].Contents.result_infos.result_info.estimated_total; + } + + // Get question data (i.e. question result) + var qDataRes = executeCommand('tn-result-data', taniumArgs); + if (!qDataRes[0].Contents.result_sets) { + return qDataRes[0].Contents.Envelope.Body.return.command; + } + + // Extract the relevant fields from the data + itemCount = parseInt(qDataRes[0].Contents.result_sets.result_set.item_count); + if (itemCount === 0) { + return 'No results'; + } + + var output = ""; + var cs = qDataRes[0].Contents.result_sets.result_set.cs; + var rs = qDataRes[0].Contents.result_sets.result_set.rs; + + // When a single item is returned, rs.r is a single object. Otherwise, it is an array... + if (itemCount === 1) { + var row = {}; + for (var i=0; i < cs.c.length; i++) { + //output += cs.c[i].dn + ': ' + rs.r.c[i].v + '\n'; + row[cs.c[i].dn] = rs.r.c[i].v; + } + table.Contents.push(row); + } else { + for (var item=0; item < itemCount; item++) { + var row = {}; + for (var j=0; j < cs.c.length; j++) { + // output += cs.c[j].dn + ': ' + rs.r[item].c[j].v + '\n'; + row[cs.c[j].dn] = rs.r[item].c[j].v; + } + table.Contents.push(row); + } + } + + if (table.Contents.length === 0) { + return 'No Results'; + } + return table; +} + +return res; diff --git a/Scripts/taniumAskQuestionComplex.js b/Scripts/taniumAskQuestionComplex.js new file mode 100644 index 000000000000..e5ddb59edcb4 --- /dev/null +++ b/Scripts/taniumAskQuestionComplex.js @@ -0,0 +1,159 @@ +// An example script for asking a complex question with filter and select-filter + +/* This script represents the following question: + "Get Computer Name and IP Address starts with 172 from machines where Operating System contains 2012" + Explanation: + There are two selects in this question: Computer Name and IP Address, but IP Address has what is called a select filter on it. + When a Tanium Client evaluates these selects, it will provide its computer name in response to the Computer Name select, + and it will respond with any IP Addresses that it has that start with the substring "172". + So, if a machine doesn't have any IP addresses that start with "172", it will actually return its computer name and "[no results]". + If it did have a valid IP address, it would return its computer name and the valid IP address(es). + + The latter half of the question, "where Operating System contains 2012", is called a filter, which limits which machines respond. + For instance, when Tanium Clients see this Question, they will only evaluate the selects of the Question if their calculated Operating System value contains the substring "2012". + If you have no 2012 machines, then no machines will respond to your Question. This filter is similar to the select filter described in the previous paragraph, + but the is a very important distinction: + If a Tanium Client doesn't meet a filter, it doesn't respond. + If a Tanium Client doesn't meet a select filter, it will respond with the string "[no results]". +*/ + +var table = { + Type: 1, + ContentsFormat: 'table', + Contents: [] +}; + +// "Get Computer Name and IP Address starts with 172" +var selects = '\ +\ + \ + \ +'; + +// "where Operating System contains 2012" +var group = '\ +\ + 1\ + 0\ + \ + \ + 1\ + 0\ + \ + \ + \ + Operating System\ + \ + RegexMatch\ + String\ + .*2012.*\ + 0\ + 1\ + \ + \ + \ + 0\ + \ + \ +'; + +var taniumArgs = { + 'selects': selects, + 'group': group, + 'timeout': args.timeout + }; + +var res = executeCommand('tn-add-question-complex', taniumArgs); +if (res[0].Type !== entryTypes.error) { + var result = res[0].Contents.Envelope.Body.return; + if (result.command !== 'AddObject') { + return result.command; + } + if (result.result_object.question.id) { + var qid = result.result_object.question.id; + + // check the status of the new question, based on the returned ID + var infoRes = executeCommand('tn-result-info', {'id': qid, 'question-type': 'question'}); + if (infoRes[0].Type !== entryTypes.error) { + if (!infoRes[0].Contents.result_infos) { + return infoRes[0].Contents.Envelope.Body.return.command; + } + + // Need to compare 'mr_passed' and 'estimated_total' values, + // to confirm that all machines have answered + var answers = infoRes[0].Contents.result_infos.result_info.mr_passed; + var expectedAnswers = infoRes[0].Contents.result_infos.result_info.estimated_total; + + // Check the status 10 times, and wait 'timeout' seconds between each iteration + var iterToWait = 10; + var sec = 1; + if (taniumArgs.timeout) { + sec = parseInt(taniumArgs.timeout) || 1; + } + while (answers !== expectedAnswers && iterToWait-- > 0) { + wait(sec); + infoRes = executeCommand('tn-result-info', {'id': qid, 'question-type': 'question'}); + if (infoRes[0].Type === entryTypes.error) { + return infoRes[0]; + } + answers = infoRes[0].Contents.result_infos.result_info.mr_passed; + expectedAnswers = infoRes[0].Contents.result_infos.result_info.estimated_total; + } + + // Get question data (i.e. question result) + var qDataRes = executeCommand('tn-result-data', {'id': qid, 'question-type': 'question'}); + if (!qDataRes[0].Contents.result_sets) { + return qDataRes[0].Contents.Envelope.Body.return.command; + } + + // Extract the relevant fields from the data + itemCount = parseInt(qDataRes[0].Contents.result_sets.result_set.item_count); + if (itemCount === 0) { + return 'No results'; + } + + var output = ""; + var cs = qDataRes[0].Contents.result_sets.result_set.cs; + var rs = qDataRes[0].Contents.result_sets.result_set.rs; + + // When a single item is returned, rs.r is a single object. Otherwise, it is an array... + if (itemCount === 1) { + var row = {}; + for (var i=0; i < cs.c.length; i++) { + //output += cs.c[i].dn + ': ' + rs.r.c[i].v + '\n'; + row[cs.c[i].dn] = rs.r.c[i].v; + } + table.Contents.push(row); + } else { + for (var item=0; item < itemCount; item++) { + var row = {}; + for (var j=0; j < cs.c.length; j++) { + // output += cs.c[j].dn + ': ' + rs.r[item].c[j].v + '\n'; + row[cs.c[j].dn] = rs.r[item].c[j].v; + } + table.Contents.push(row); + } + } + + if (table.Contents.length === 0) { + return 'No Results'; + } + return table; + } + } +} +return res diff --git a/Scripts/taniumDeployAction.js b/Scripts/taniumDeployAction.js new file mode 100644 index 000000000000..a822b4df240a --- /dev/null +++ b/Scripts/taniumDeployAction.js @@ -0,0 +1,44 @@ +// An example script for deploying Tanium action with filter + +if (!args.packageName && !args.packageID) { + return 'Missing parameter: packageName or packageID'; +} + +var packageName = args.packageName || ''; +var packageID = args.packageID || ''; +var packageParams = args.parameters || ''; +var comment = args.comment || ''; + +// targetGroup is the properties of the systems on which the requested package should run +var targetGroup = '\ +\ + 1\ + 0\ + \ + \ + \ + IP Address\ + \ + 0\ + 1\ + 0\ + RegexMatch\ + 172.*\ + String\ + \ + \ + 0\ + \ + Online is \"True\"\ +'; + +var taniumArgs = { + 'package-name': packageName, + 'package-id': packageID, + 'parameters': packageParams, + 'comment': comment, + 'target-group': targetGroup, + }; + +var res = executeCommand('tn-deploy-package', taniumArgs); +return res diff --git a/Scripts/triagephishing.js b/Scripts/triagephishing.js new file mode 100644 index 000000000000..a625db0a745a --- /dev/null +++ b/Scripts/triagephishing.js @@ -0,0 +1,85 @@ +var results = []; // Collect all the results +var malicious = false; + +var body = incidents[0].details; +var fromRE = /From:.*href="mailto:(.*?)"/ig; +var from = fromRE.exec(body); +var toRE = /To:.*href="mailto:(.*?)"/ig; +var to = toRE.exec(body); +var sentRE = /Sent:<\/b> (.*?)
/ig; +var sent = sentRE.exec(body); +var subjectRE = /Subject:<\/b> (.*?)/ig; +var subject = subjectRE.exec(body); + +var fromStr = ''; +var toStr = ''; +var subjectStr = ''; +var sentStr = ''; +if (from && from.length > 1) { + fromStr = from[1]; +} +if (to && to.length > 1) { + toStr = to[1]; +} +if (sent && sent.length > 1) { + sentStr = sent[1]; +} +if (subject && subject.length > 1) { + subjectStr = subject[1]; +} +results.push({Contents: {From: fromStr, To: toStr, Sent: sentStr, Subject: subjectStr}, ContentsFormat: formats.table, Type: entryTypes.note}); // Add the raw email details + +// Check the URLs via reputation services +var urlPattern = /href=".*"/ig; +var urls = body.match(urlPattern); +var cleanUrls = []; +if (urls) { + for (var i=0; i= 0) continue; + cleanUrls.push(u); + var rep = executeCommand('url', {url: u}); + if (rep && Array.isArray(rep)) { + for (var r = 0; r < rep.length; r++) { + if (positiveUrl(rep[r])) { + results.push(shortUrl(rep[r])); + malicious = true; + } + } + } + } +} +if (!malicious) { + results.push({Contents: 'Only clean URLs found: ' + cleanUrls.join(', '), Type: entryTypes.note, ContentsFormat: formats.text}); +} + +// Check the attachments via reputation services +var entries = executeCommand('getEntries', {}); +for (var i=0; i -1) && (pidindex > -1)) { + for (var j = 0; j < jsonout.rows.length; j++) { + var obj = {'ip':jsonout.rows[j][ipindex].split(':')[0], 'port':jsonout.rows[j][ipindex].split(':')[1], 'pid':jsonout.rows[j][pidindex]} + ipaddrarr.push(obj); + } + } + } + } + } +} + +for (var i = 0; i < ipaddrarr.length; i++) { + var repscript = 'DataIPReputation'; + if (args.repscript){ + repscript = args.repscript; + } + var iprep = executeCommand(repscript, {input: ipaddrarr[i].ip}); + if (iprep[0].Type !== entryTypes.error) { + if (iprep[0].Contents <= reputationthreshold) { + var result = {}; + result['PID'] = ipaddrarr[i].pid; + result['IP'] = ipaddrarr[i].ip; + result['PORT'] = ipaddrarr[i].port; + result['REPUTATION'] = iprep[0].Contents; + resultarr.push(result); + } + } + +} +var result = {}; +result.Contents = resultarr; +result.ContentsFormat = formats.table; +result.Type = entryTypes.note; + +return result; diff --git a/Scripts/volimageinfo.js b/Scripts/volimageinfo.js new file mode 100644 index 000000000000..60fd1ac2d824 --- /dev/null +++ b/Scripts/volimageinfo.js @@ -0,0 +1,3 @@ +var cmdline = 'imageinfo'; +var out = executeCommand('Volatility', {memdump:args.memdump, profile:args.profile, system: args.system, cmd:cmdline}); +return out; diff --git a/Scripts/voljson.js b/Scripts/voljson.js new file mode 100644 index 000000000000..42fb07f462e7 --- /dev/null +++ b/Scripts/voljson.js @@ -0,0 +1 @@ +packOutput('vol.py --output=json -f ' + args.file + ' ' + args.cmd); diff --git a/Scripts/volldrmodules.js b/Scripts/volldrmodules.js new file mode 100644 index 000000000000..abeef6444477 --- /dev/null +++ b/Scripts/volldrmodules.js @@ -0,0 +1,3 @@ +var cmdline = 'ldrmodules'; +var out = executeCommand('Volatility', {memdump:args.memdump, profile:args.profile, system: args.system, cmd:cmdline}); +return out; diff --git a/Scripts/volmalfind.js b/Scripts/volmalfind.js new file mode 100644 index 000000000000..5dedc0505301 --- /dev/null +++ b/Scripts/volmalfind.js @@ -0,0 +1,3 @@ +var cmdline = 'malfind -p ' + args.pid; +var out = executeCommand('Volatility', {memdump:args.memdump, profile:args.profile, system: args.system, cmd:cmdline}); +return out; diff --git a/Scripts/volmalfinddumpagent.js b/Scripts/volmalfinddumpagent.js new file mode 100644 index 000000000000..eadcd24d4d5b --- /dev/null +++ b/Scripts/volmalfinddumpagent.js @@ -0,0 +1,27 @@ +var cmdline = 'vol.py -f ' + args.memdump + ' ' + 'malfind'; +if (args.pid) { + cmdline = cmdline + ' -p ' + args.pid; +} +var dumpdir = args.dumpdir; + +cmdline = cmdline + ' -D ' + dumpdir; +var timeout = 600 ; +if (args.timeout) { + timeout = args.timeout ; +} + +mkdir(dumpdir); +var output = execute(cmdline,timeout); +if (output.Success) { + // we need to take all the files and move them over. + pack(output); + var results = files(dumpdir); + for (var i = 0; i < results.length; i++) { + if (results[i].Type !== "Folder") { + var fileName = results[i].Path; + pack_file(fileName); + del(fileName); + } + } +} +rmdir(dumpdir); \ No newline at end of file diff --git a/Scripts/volnetworkconnections.js b/Scripts/volnetworkconnections.js new file mode 100644 index 000000000000..132a6955d7f3 --- /dev/null +++ b/Scripts/volnetworkconnections.js @@ -0,0 +1,90 @@ +var cmds = []; + +switch (args.profile) { + case 'VistaSP0x64' : + case 'VistaSP0x86' : + case 'VistaSP1x64' : + case 'VistaSP1x86' : + case 'VistaSP2x64' : + case 'VistaSP2x86' : + case 'Win2008R2SP0x64' : + case 'Win2008R2SP1x64' : + case 'Win2008SP1x64' : + case 'Win2008SP1x86' : + case 'Win2008SP2x64' : + case 'Win2008SP2x86' : + case 'Win7SP0x64' : + case 'Win7SP0x86' : + case 'Win7SP1x64' : + case 'Win7SP1x86' : + case 'Win81U1x64' : + case 'Win81U1x86' : + case 'Win8SP0x64' : + case 'Win8SP0x86' : + case 'Win8SP1x64' : + case 'Win8SP1x86' : + case 'Win10x64' : + case 'Win10x86' : + case 'Win2012R2x64' : + case 'Win2012x64' : + cmds.push('netscan'); + break; + case 'Win2003SP0x86' : + case 'Win2003SP1x64' : + case 'Win2003SP1x86' : + case 'Win2003SP2x64' : + case 'Win2003SP2x86' : + case 'WinXPSP1x64' : + case 'WinXPSP2x64' : + case 'WinXPSP2x86' : + case 'WinXPSP3x86' : + cmds.push('connections'); + cmds.push('connscan'); + cmds.push('sockets'); + cmds.push('sockscan'); + break; + default: + break; +} + +var resultarr = []; + +for (var i = 0; i < cmds.length; i++) { + var cmdline = cmds[i]; + if (args.profile) { + cmdline = cmdline + ' --profile=' + args.profile; + } + var out = executeCommand('VolJson', {file:args.memdump, system: args.system, cmd:cmdline}); + if (out) { + var mapper = function(columns) { + return function(val) { + return val.reduce(function(prev, curr, i) { + prev[columns[i]] = '' + curr; + return prev; + }, {}); + }; + }; + for (var r = 0; r < out.length; r++) { + if (out[r].Type !== entryTypes.error) { + var jsonout = JSON.parse(out[r].Contents); + result = {}; + result.Contents = jsonout.rows.map(mapper(jsonout.columns)); + result.ContentsFormat = formats.table; + result.Type = entryTypes.note; + resultarr.push(result); + } + else + { + result = {}; + var errstring = out[r].Contents; + result.Contents = errstring.split('Stderr:')[1]; + result.ContentsFormat = formats.text; + result.Type = entryTypes.error; + resultarr.push(result); + } + } + } + +} + +return resultarr; diff --git a/Scripts/volpslist.js b/Scripts/volpslist.js new file mode 100644 index 000000000000..240cd177b5c7 --- /dev/null +++ b/Scripts/volpslist.js @@ -0,0 +1,3 @@ +var cmdline = 'pslist'; +var out = executeCommand('Volatility', {memdump:args.memdump, profile:args.profile, system: args.system, cmd:cmdline}); +return out; diff --git a/Scripts/volruncmds.js b/Scripts/volruncmds.js new file mode 100644 index 000000000000..9923445acf38 --- /dev/null +++ b/Scripts/volruncmds.js @@ -0,0 +1,43 @@ +var cmds = args.cmds.split(','); + +var resultarr = []; + +for (var i = 0; i < cmds.length; i++) { + var cmdline = cmds[i]; + if (args.profile) { + cmdline = cmdline + ' --profile=' + args.profile; + } + var out = executeCommand('VolJson', {file:args.memdump, system: args.system, cmd:cmdline}); + if (out) { + var mapper = function(columns) { + return function(val) { + return val.reduce(function(prev, curr, i) { + prev[columns[i]] = '' + curr; + return prev; + }, {}); + }; + }; + for (var r = 0; r < out.length; r++) { + if (out[r].Type !== entryTypes.error) { + var jsonout = JSON.parse(out[r].Contents); + result = {}; + result.Contents = jsonout.rows.map(mapper(jsonout.columns)); + result.ContentsFormat = formats.table; + result.Type = entryTypes.note; + resultarr.push(result); + } + else + { + result = {}; + var errstring = out[r].Contents; + result.Contents = errstring.split('Stderr:')[1]; + result.ContentsFormat = formats.text; + result.Type = entryTypes.error; + resultarr.push(result); + } + } + } + +} + +return resultarr; diff --git a/Scripts/whois.js b/Scripts/whois.js new file mode 100644 index 000000000000..5b69af9b9706 --- /dev/null +++ b/Scripts/whois.js @@ -0,0 +1 @@ +return executeCommand('whois', {'query':args.query}); diff --git a/Scripts/whoissummary.js b/Scripts/whoissummary.js new file mode 100644 index 000000000000..cff20646a49a --- /dev/null +++ b/Scripts/whoissummary.js @@ -0,0 +1,37 @@ +// A simple example script for parsing WHOIS data + +// Regexp for matching ": " pattern +var re = /^([a-zA-Z\s]+):\s(.+)$/; + +function stringStartsWith (string, prefix) { + return string.slice(0, prefix.length) == prefix; +} + +var res = executeCommand('whois', {'using-brand': 'whois', 'query':args.query}); +var lines = res[0].Contents.split('\n'); + +var out = ''; +for (var i=0; i < lines.length; ++i) { + var str = lines[i]; + str.trim(); + if (str.length === 0) { + continue; + } + + // Skip '%' lines + if (stringStartsWith(str, '%')) { + continue; + } + + // Stop when reaching the "last update" line + if (stringStartsWith(str, '>>> Last update')) { + break; + } + + // See if the line matches the regex + if (re.test(str)) { + out += str + '\n'; + } +} + +return out; diff --git a/Scripts/wildfirereport.js b/Scripts/wildfirereport.js new file mode 100644 index 000000000000..e7be44deb67a --- /dev/null +++ b/Scripts/wildfirereport.js @@ -0,0 +1,22 @@ +var raw +if (args.md5) { + raw = executeCommand('wildfire-report', {md5: args.md5}); +} else if (args.hash) { + raw = executeCommand('wildfire-report', {hash: args.hash}); +} else { + return 'no'; +} + +if (!raw[0] || !raw[0].Contents || !raw[0].Contents.wildfire || !raw[0].Contents.wildfire.file_info) { + return "failed"; +} + +var item = raw[0].Contents.wildfire.file_info; +return {Contents: { + Type: item.filetype, + Malware: item.malware, + MD5: item.md5, + SHA256: item.sha256, + Size: item.size}, + ContentsFormat: formats.table, + Type: entryTypes.note}; \ No newline at end of file diff --git a/Scripts/wildfireupload.js b/Scripts/wildfireupload.js new file mode 100644 index 000000000000..9bee2ee843d3 --- /dev/null +++ b/Scripts/wildfireupload.js @@ -0,0 +1,15 @@ +var raw = executeCommand('wildfire-upload', {upload: args.upload}); + +if (!raw[0] || !raw[0].Contents || !raw[0].Contents.wildfire || !raw[0].Contents.wildfire['upload-file-info']) { + return "failed"; +} + +var item = raw[0].Contents.wildfire['upload-file-info']; +return {Contents: { + Type: item.filetype, + MD5: item.md5, + SHA256: item.sha256, + Size: item.size, + URL: item.url}, + ContentsFormat: formats.table, + Type: entryTypes.note}; \ No newline at end of file diff --git a/Scripts/xbinfo.py b/Scripts/xbinfo.py new file mode 100644 index 000000000000..be43926a418f --- /dev/null +++ b/Scripts/xbinfo.py @@ -0,0 +1,19 @@ +res = '## Exabeam global info' +entry = demisto.executeCommand('xb-users', {})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + res += '\n### Users:' + res += '\n- High Risk: ' + str(demisto.get(entry, 'Contents.highRisk')) + res += '\n- Recent: ' + str(demisto.get(entry, 'Contents.recent')) + res += '\n- Total: ' + str(demisto.get(entry, 'Contents.total')) +entry = demisto.executeCommand('xb-assets', {})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + res += '\n### Assets:' + res += '\n- High Risk: ' + str(demisto.get(entry, 'Contents.highRisk')) + res += '\n- Recent: ' + str(demisto.get(entry, 'Contents.recent')) + res += '\n- Total: ' + str(demisto.get(entry, 'Contents.total')) +entry = demisto.executeCommand('xb-events', {})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + res += '\n### Events:' + res += '\n- Recent: ' + str(int(demisto.get(entry, 'Contents.recent'))) + res += '\n- Total: ' + str(int(demisto.get(entry, 'Contents.total'))) +demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) diff --git a/Scripts/xblockouts.py b/Scripts/xblockouts.py new file mode 100644 index 000000000000..e6bd7916653e --- /dev/null +++ b/Scripts/xblockouts.py @@ -0,0 +1,41 @@ +import time + +rows = '100' +if demisto.args().has_key('rows'): + rows = demisto.args()['rows'] +days = '1' +if demisto.args().has_key('days'): + days = demisto.args()['days'] + +res = '## Exabeam Lockouts' +entry = demisto.executeCommand('xb-lockouts', {'numberOfResults': rows, 'num': days})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + lockouts = demisto.get(entry, 'Contents.lockouts') + if lockouts: + res += '\n### Total in the last ' + days + ' days: ' + str(len(lockouts)) + for l in lockouts: + info = demisto.get(l, 'user.info') + if info: + res += '\n\n\n![photo](data:image/png;base64,' + demisto.get(info, 'photo').replace('\n', '') + ')' + res += '\n|Account|Email|Name|Title|Department|Devision|DN|Location|Manager|Office|Cell|Group|First Seen|Last Seen|' + res += '\n|-------|-----|----|-----|----------|--------|--|--------|-------|------|----|-----|----------|---------|' + res += '\n| ' + demisto.get(info, 'accountId') + ' | ' + demisto.get(info, 'email') + ' | ' + demisto.get(info, 'fullName') + ' | ' + \ + demisto.get(info, 'title') + ' | ' + demisto.get(info, 'department') + ' | ' + demisto.get(info, 'division') + ' | ' + \ + demisto.get(info, 'dn') + ' | ' + demisto.get(info, 'location') + ', ' + demisto.get(info, 'country') + ' | ' + \ + demisto.get(info, 'manager') + ' | ' + demisto.get(info, 'phoneOffice') + ' | ' + demisto.get(info, 'phoneCell') + ' | ' + \ + demisto.get(info, 'group') + ' | ' + time.ctime(demisto.get(l, 'user.firstSeen') / 1000.0) + ' | ' + time.ctime(demisto.get(l, 'user.lastSeen') / 1000.0) + ' |' + res += '\nScore: **' + str(demisto.get(l, 'user.riskScore')) + '**' + res += '\n|ID|Accounts|Start|End|Label|LoginHost|Zones|InitialRisk|Risk|Last Activity Type|Last Activity Time|Account Changes|Account Lockouts|Assets|Events|Failed Logins|Reasons|' + res += '\n|--|--------|-----|---|-----|---------|-----|-----------|----|------------------|------------------|---------------|----------------|------|------|-------------|-------|' + lInfo = demisto.get(l, 'lockoutInfo') + if lInfo: + res += '\n| ' + demisto.get(lInfo, 'lockoutId') + ' | ' + ','.join(demisto.get(lInfo, 'accounts')) + ' | ' + time.ctime(demisto.get(lInfo, 'startTime') / 1000.0) + ' | ' + \ + time.ctime(demisto.get(lInfo, 'endTime') / 1000.0) + ' | ' + demisto.get(lInfo, 'label') + ' | ' + demisto.get(lInfo, 'loginHost') + ' | ' + \ + ','.join(demisto.get(lInfo, 'zones')) + ' | ' + str(demisto.get(lInfo, 'initialRiskScore')) + ' | ' + str(demisto.get(lInfo, 'riskScore')) + ' | ' + \ + str(demisto.get(lInfo, 'lastActivityType')) + ' | ' + time.ctime(demisto.get(lInfo, 'lastActivityTime') / 1000.0) + ' | ' + \ + str(demisto.get(lInfo, 'numOfAccountChanges')) + ' | ' + str(demisto.get(lInfo, 'numOfAccountLockouts')) + ' | ' + \ + str(demisto.get(lInfo, 'numOfAssets')) + ' | ' + str(demisto.get(lInfo, 'numOfEvents')) + ' | ' + str(demisto.get(lInfo, 'numOfFailedLogins')) + ' | ' + \ + str(demisto.get(lInfo, 'numOfReasons')) + ' |' + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) diff --git a/Scripts/xbnotable.py b/Scripts/xbnotable.py new file mode 100644 index 000000000000..56ec8ccfc4a1 --- /dev/null +++ b/Scripts/xbnotable.py @@ -0,0 +1,40 @@ +import time + +rows = '100' +if demisto.args().has_key('rows'): + rows = demisto.args()['rows'] +days = '1' +if demisto.args().has_key('days'): + days = demisto.args()['days'] + +res = '## Exabeam notable users' +entry = demisto.executeCommand('xb-notable', {'numberOfResults': rows, 'num': days})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + users = demisto.get(entry, 'Contents.users') + if users: + res += '\n### Total in the last ' + days + ' days: ' + str(len(users)) + for user in users: + info = demisto.get(user, 'user.info') + if info: + res += '\n\n\n![photo](data:image/png;base64,' + demisto.get(info, 'photo').replace('\n', '') + ')' + res += '\n|Account|Email|Name|Title|Department|Devision|DN|Location|Manager|Office|Cell|Group|First Seen|Last Seen|' + res += '\n|-------|-----|----|-----|----------|--------|--|--------|-------|------|----|-----|----------|---------|' + res += '\n| ' + demisto.get(info, 'accountId') + ' | ' + demisto.get(info, 'email') + ' | ' + demisto.get(info, 'fullName') + ' | ' + \ + demisto.get(info, 'title') + ' | ' + demisto.get(info, 'department') + ' | ' + demisto.get(info, 'division') + ' | ' + \ + demisto.get(info, 'dn') + ' | ' + demisto.get(info, 'location') + ', ' + demisto.get(info, 'country') + ' | ' + \ + demisto.get(info, 'manager') + ' | ' + demisto.get(info, 'phoneOffice') + ' | ' + demisto.get(info, 'phoneCell') + ' | ' + \ + demisto.get(info, 'group') + ' | ' + time.ctime(demisto.get(user, 'user.firstSeen') / 1000.0) + ' | ' + time.ctime(demisto.get(user, 'user.lastSeen') / 1000.0) + ' |' + res += '\nScore: **' + str(demisto.get(user, 'highestRiskScore')) + '**' + res += '\nHighest Risk Session:' + res += '\n|ID|Accounts|Start|End|Label|LoginHost|Zones|InitialRisk|Risk|Assets|Events|Reasons|SecurityEvents|' + res += '\n|--|--------|-----|---|-----|---------|-----|-----------|----|------|------|-------|--------------|' + session = demisto.get(user, 'highestRiskSession') + if session: + res += '\n| ' + demisto.get(session, 'sessionId') + ' | ' + ','.join(demisto.get(session, 'accounts')) + ' | ' + time.ctime(demisto.get(session, 'startTime') / 1000.0) + ' | ' + \ + time.ctime(demisto.get(session, 'endTime') / 1000.0) + ' | ' + demisto.get(session, 'label') + ' | ' + demisto.get(session, 'loginHost') + ' | ' + \ + ','.join(demisto.get(session, 'zones')) + ' | ' + str(demisto.get(session, 'initialRiskScore')) + ' | ' + str(demisto.get(session, 'riskScore')) + ' | ' + \ + str(demisto.get(session, 'numOfAssets')) + ' | ' + str(demisto.get(session, 'numOfEvents')) + ' | ' + str(demisto.get(session, 'numOfReasons')) + ' | ' + \ + str(demisto.get(session, 'numOfSecurityEvents')) + ' |' + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) diff --git a/Scripts/xbtimeline.py b/Scripts/xbtimeline.py new file mode 100644 index 000000000000..15fa3fc30ff4 --- /dev/null +++ b/Scripts/xbtimeline.py @@ -0,0 +1,13 @@ +import time + +res = [] +entry = demisto.executeCommand('xb-timeline', {'username': demisto.args()['username']})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + entities = demisto.get(entry, 'Contents.entities') + if entities: + for e in entities: + res.append({'1.ID': demisto.get(e, 'id'), '2.Type': demisto.get(e, 'tp'), '3.Start': time.ctime(demisto.get(e, 'st') / 1000.0), '4.End': time.ctime(demisto.get(e, 'et') / 1000.0), \ + '5.Initial Risk': str(demisto.get(e, 'irs')), '6.Risk': str(demisto.get(e, 'rs')), '7.OS': str(demisto.get(e, 'os')), '8.OE': str(demisto.get(e, 'oe'))}) + demisto.results({'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) diff --git a/Scripts/xbtriggeredrules.py b/Scripts/xbtriggeredrules.py new file mode 100644 index 000000000000..c41203c8a80a --- /dev/null +++ b/Scripts/xbtriggeredrules.py @@ -0,0 +1,12 @@ +res = [] +entry = demisto.executeCommand('xb-triggered-rules', {'containerId': demisto.args()['session']})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + model = demisto.get(entry, 'Contents.modelDefs') + if model: + for key in model: + m = model[key]['attributes'] + if m: + res.append({'1.ID': key, '2.Description': demisto.get(m, 'description'), '3.Type': demisto.get(m, 'modelType'), '4.Template': demisto.get(m, 'modelTemplate')}) + demisto.results({'ContentsFormat': formats['table'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry) diff --git a/Scripts/xbuser.py b/Scripts/xbuser.py new file mode 100644 index 000000000000..773af46fd03d --- /dev/null +++ b/Scripts/xbuser.py @@ -0,0 +1,31 @@ +import time + +res = '## Exabeam User Info' +entry = demisto.executeCommand('xb-userinfo', {'username': demisto.args()['username']})[0] +if entry['Type'] != entryTypes['error'] and entry['ContentsFormat'] == formats['json']: + info = demisto.get(entry, 'Contents.userInfo.info') + if info: + res += '\n\n\n![photo](data:image/png;base64,' + demisto.get(info, 'photo').replace('\n', '') + ')' + res += '\n|Account|Email|Name|Title|Department|Devision|DN|Location|Manager|Office|Cell|Group|First Seen|Last Seen|' + res += '\n|-------|-----|----|-----|----------|--------|--|--------|-------|------|----|-----|----------|---------|' + res += '\n| ' + demisto.get(info, 'accountId') + ' | ' + demisto.get(info, 'email') + ' | ' + demisto.get(info, 'fullName') + ' | ' + \ + demisto.get(info, 'title') + ' | ' + demisto.get(info, 'department') + ' | ' + demisto.get(info, 'division') + ' | ' + \ + demisto.get(info, 'dn') + ' | ' + demisto.get(info, 'location') + ', ' + demisto.get(info, 'country') + ' | ' + \ + demisto.get(info, 'manager') + ' | ' + demisto.get(info, 'phoneOffice') + ' | ' + demisto.get(info, 'phoneCell') + ' | ' + \ + demisto.get(info, 'group') + ' | ' + time.ctime(demisto.get(entry, 'Contents.userInfo.firstSeen') / 1000.0) + ' | ' + time.ctime(demisto.get(entry, 'Contents.userInfo.lastSeen') / 1000.0) + ' |' + res += '\nScore: **' + str(demisto.get(entry, 'Contents.userInfo.riskScore')) + '**, On watch: ' + str(demisto.get(entry, 'Contents.isOnWatchlist')) + res += '\n\n### Manager Info' + info = demisto.get(entry, 'Contents.managerInfo.info') + if info: + res += '\n\n\n![photo](data:image/png;base64,' + demisto.get(info, 'photo').replace('\n', '') + ')' + res += '\n|Account|Email|Name|Title|Department|Devision|DN|Location|Manager|Office|Cell|Group|First Seen|Last Seen|' + res += '\n|-------|-----|----|-----|----------|--------|--|--------|-------|------|----|-----|----------|---------|' + res += '\n| ' + demisto.get(info, 'accountId') + ' | ' + demisto.get(info, 'email') + ' | ' + demisto.get(info, 'fullName') + ' | ' + \ + demisto.get(info, 'title') + ' | ' + demisto.get(info, 'department') + ' | ' + demisto.get(info, 'division') + ' | ' + \ + demisto.get(info, 'dn') + ' | ' + demisto.get(info, 'location') + ', ' + demisto.get(info, 'country') + ' | ' + \ + demisto.get(info, 'manager') + ' | ' + demisto.get(info, 'phoneOffice') + ' | ' + demisto.get(info, 'phoneCell') + ' | ' + \ + demisto.get(info, 'group') + ' | ' + time.ctime(demisto.get(entry, 'Contents.managerInfo.firstSeen') / 1000.0) + ' | ' + time.ctime(demisto.get(entry, 'Contents.managerInfo.lastSeen') / 1000.0) + ' |' + res += '\nScore: **' + str(demisto.get(entry, 'Contents.managerInfo.riskScore')) + '**' + demisto.results({'ContentsFormat': formats['markdown'], 'Type': entryTypes['note'], 'Contents': res}) +else: + demisto.results(entry)