-
Notifications
You must be signed in to change notification settings - Fork 479
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into cli/export-rule
- Loading branch information
Showing
570 changed files
with
80,601 additions
and
0 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
ML-models/DGA/ML-DGA-20201216-1/dga_875109_1.0_dga_ngrams_create.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"script": {"lang": "painless", "source": "\nString nGramAtPosition(String text, int fieldcount, int n){\n if (fieldcount+n>text.length()){\n return null;\n }\n else \n {\n return text.substring(fieldcount, fieldcount+n);\n } \n}\n\nString[] secondLevelDomain(Map dynamic_domains, String domain, String subdomain, String registered_domain, String top_level_domain){\n\n if (registered_domain == null || registered_domain == '.') {\n return new String[] {'', ''};\n }\n\n if (dynamic_domains.containsKey(registered_domain) == true) {\n if (subdomain != null) {\n return new String[] {subdomain, registered_domain};\n }\n } \n\n return new String[] {registered_domain.substring(0, registered_domain.length()-top_level_domain.length()-1), top_level_domain};\n}\n\nString domain = ctx['dns']['question']['name'];\nString subdomain = ctx['dns']['question']['subdomain'];\nString registered_domain = ctx['dns']['question']['registered_domain'];\nString top_level_domain = ctx['dns']['question']['top_level_domain'];\n\nString[] ret = secondLevelDomain(params.dynamic_domains, domain, subdomain, registered_domain, top_level_domain);\n\nString sld = ret[0];\nString tld = ret[1];\n\nctx['f'] = new HashMap();\nctx['f']['tld'] = tld;\n\nfor (int i=0;i<sld.length();i++){\n String field = nGramAtPosition(sld, i, 1);\n if (field == null) {\n break;\n }\n ctx['f']['u'+ Integer.toString(i)] = field;\n}\nfor (int i=0;i<sld.length();i++){\n String field = nGramAtPosition(sld, i, 2);\n if (field == null) {\n break;\n }\n ctx['f']['b'+ Integer.toString(i)] = field;\n}\nfor (int i=0;i<sld.length();i++){\n String field = nGramAtPosition(sld, i, 3);\n if (field == null) {\n break;\n }\n ctx['f']['t'+ Integer.toString(i)] = field;\n}\n"}} |
1 change: 1 addition & 0 deletions
1
ML-models/DGA/ML-DGA-20201216-1/dga_875109_1.0_dga_ngrams_transform_delete.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"script": {"lang": "painless", "source": "\n def top_classes = ctx['ml_is_dga']['top_classes'];\n def malicious_probability = 0.0;\n def malicious_prediction = ctx['ml_is_dga']['malicious_prediction'];\n for (def class: top_classes) {\n if (class['class_name'] == 1) {\n malicious_probability = class['class_probability'];\n }\n }\n ctx.remove('ml_is_dga');\n ctx.remove('f');\n ctx['ml_is_dga'] = new HashMap();\n ctx['ml_is_dga']['malicious_prediction'] = malicious_prediction;\n ctx['ml_is_dga']['malicious_probability'] = malicious_probability;\n "}} |
1 change: 1 addition & 0 deletions
1
ML-models/DGA/ML-DGA-20201216-1/dga_875109_1.0_ingest_pipeline1.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"description": "A pipeline of pipelines for enriching DNS data. Ignores non-DNS data.", "processors": [{"pipeline": {"if": "ctx.type=='dns'", "name": "dns_dga_inference_enrich_pipeline"}}], "version": 1} |
1 change: 1 addition & 0 deletions
1
ML-models/DGA/ML-DGA-20201216-1/dga_875109_1.0_ingest_pipeline2.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"processors": [{"script": {"id": "dga_ngrams_create", "params": {"dynamic_domains": {"avsvmcloud.com": 0, "co.cc": 0, "cz.cc": 0, "ddns.net": 0, "dyndns.org": 0, "dynserv.com": 0, "github.io": 0, "mooo.com": 0, "mynumber.org": 0, "yi.org": 0}}}}, {"inference": {"field_map": {}, "inference_config": {"classification": {"num_top_classes": 1}}, "model_id": "dga_875109_1.0", "target_field": "ml_is_dga"}}, {"script": {"id": "dga_ngrams_transform_delete"}}]} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
## Red Team Automation | ||
|
||
[![Supported Python versions](https://img.shields.io/badge/python-3.7+-yellow.svg)](https://www.python.org/downloads/) | ||
[![Chat](https://img.shields.io/badge/chat-%23security--detection--rules-blueviolet)](https://ela.st/slack) | ||
|
||
The repo comes with some red team automation ([RTA](./)) python scripts that run on Windows, Mac OS, and \*nix. | ||
RTA scripts emulate known attacker behaviors and are an easy way too verify that your rules are active and working as expected. | ||
|
||
```console | ||
$ python -m rta -h | ||
usage: rta [-h] ttp_name | ||
|
||
positional arguments: | ||
ttp_name | ||
|
||
optional arguments: | ||
-h, --help show this help message and exit | ||
``` | ||
<<<<<<< HEAD | ||
ttp_name can be found in the [rta](./rta) directory. For example to execute `./rta/wevtutil_log_clear.py` script, run command: | ||
======= | ||
`ttp_name` is the name of a script that can be found in the [rta](./rta) directory. For example, to execute ./rta/wevtutil_log_clear.py script, run command: | ||
>>>>>>> 607d8cf06a298ec4edf8c0e326b3c1a9ace509ea | ||
```console | ||
$ python -m rta wevtutil_log_clear | ||
``` | ||
|
||
Most of the RTA scripts contain a comment with the rule name, in `signal.rule.name`, that maps to the Kibana Detection Signals. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
import glob | ||
import importlib | ||
import os | ||
|
||
from . import common | ||
|
||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
|
||
def get_ttp_list(os_types=None): | ||
scripts = [] | ||
if os_types and not isinstance(os_types, (list, tuple)): | ||
os_types = [os_types] | ||
|
||
for script in sorted(glob.glob(os.path.join(CURRENT_DIR, "*.py"))): | ||
base_name, _ = os.path.splitext(os.path.basename(script)) | ||
if base_name not in ("common", "main") and not base_name.startswith("_"): | ||
if os_types: | ||
# Import it and skip it if it's not supported | ||
importlib.import_module(__name__ + "." + base_name) | ||
if not any(base_name in common.OS_MAPPING[os_type] for os_type in os_types): | ||
continue | ||
|
||
scripts.append(script) | ||
|
||
return scripts | ||
|
||
|
||
def get_ttp_names(os_types=None): | ||
names = [] | ||
for script in get_ttp_list(os_types): | ||
basename, ext = os.path.splitext(os.path.basename(script)) | ||
names.append(basename) | ||
return names | ||
|
||
|
||
__all__ = ( | ||
"common" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
import argparse | ||
import importlib | ||
import os | ||
|
||
from . import get_ttp_names | ||
|
||
parser = argparse.ArgumentParser("rta") | ||
parser.add_argument("ttp_name") | ||
|
||
parsed_args, remaining = parser.parse_known_args() | ||
ttp_name, _ = os.path.splitext(os.path.basename(parsed_args.ttp_name)) | ||
|
||
if ttp_name not in get_ttp_names(): | ||
raise ValueError("Unknown RTA {}".format(ttp_name)) | ||
|
||
module = importlib.import_module("rta." + ttp_name) | ||
exit(module.main(*remaining)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: Adobe Hijack Persistence | ||
# RTA: adobe_hijack.py | ||
# ATT&CK: T1044 | ||
# Description: Replaces PE file that will run on Adobe Reader start. | ||
|
||
import os | ||
|
||
from . import common | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
def main(): | ||
rdr_cef_dir = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF" | ||
rdrcef_exe = os.path.join(rdr_cef_dir, "RdrCEF.exe") | ||
cmd_path = "C:\\Windows\\System32\\cmd.exe" | ||
backup = os.path.abspath("xxxxxx") | ||
backedup = False | ||
|
||
# backup original if it exists | ||
if os.path.isfile(rdrcef_exe): | ||
common.log("{} already exists, backing up file.".format(rdrcef_exe)) | ||
common.copy_file(rdrcef_exe, backup) | ||
backedup = True | ||
else: | ||
common.log("{} doesn't exist. Creating path.".format(rdrcef_exe)) | ||
os.makedirs(rdr_cef_dir) | ||
|
||
# overwrite original | ||
common.copy_file(cmd_path, rdrcef_exe) | ||
|
||
# cleanup | ||
if backedup: | ||
common.log("Putting back backup copy.") | ||
common.copy_file(backup, rdrcef_exe) | ||
os.remove(backup) | ||
else: | ||
common.remove_file(rdrcef_exe) | ||
os.removedirs(rdr_cef_dir) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: Application Compatibility Shims | ||
# RTA: appcompat_shim.py | ||
# ATT&CK: T1138 | ||
# Description: Use sdbinst.exe to install a binary patch/application shim. | ||
|
||
import time | ||
|
||
from . import common | ||
|
||
SHIM_FILE = common.get_path("bin", "CVE-2013-3893.sdb") | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
@common.dependencies(SHIM_FILE) | ||
def main(): | ||
common.log("Application Compatibility Shims") | ||
|
||
common.execute(["sdbinst.exe", "-q", "-p", SHIM_FILE]) | ||
time.sleep(2) | ||
|
||
common.log("Removing installed shim", log_type="-") | ||
common.execute(["sdbinst.exe", "-u", SHIM_FILE]) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: AT Command Lateral Movement | ||
# RTA: at_command.py | ||
# ATT&CK: T1053 | ||
# Description: Enumerates at tasks on target host, and schedules an at job for one hour in the future. Then checks the | ||
# status of that task, and deletes the task. | ||
|
||
import datetime | ||
import re | ||
import sys | ||
|
||
from . import common | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
def main(target_host=None): | ||
target_host = target_host or common.get_ip() | ||
host_str = '\\\\%s' % target_host | ||
|
||
# Current time at \\localhost is 11/16/2017 11:25:50 AM | ||
code, output = common.execute(['net', 'time', host_str]) | ||
match = re.search(r'Current time at .*? is (\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) (AM|PM)', output) | ||
groups = match.groups() | ||
m, d, y, hh, mm, ss, period = groups | ||
now = datetime.datetime(month=int(m), day=int(d), year=int(y), hour=int(hh), minute=int(mm), second=int(ss)) | ||
if period == 'PM' and hh != '12': | ||
now += datetime.timedelta(hours=12) | ||
|
||
# Add one hour | ||
task_time = now + datetime.timedelta(hours=1) | ||
|
||
# Round down minutes | ||
time_string = '%d:%d' % (task_time.hour, task_time.minute) | ||
|
||
# Enumerate all remote tasks | ||
common.execute(['at.exe', host_str]) | ||
|
||
# Create a job 1 hour into the future | ||
code, output = common.execute(['at', host_str, time_string, 'cmd /c echo hello world']) | ||
|
||
if code == 1 and 'deprecated' in output: | ||
common.log("Unable to continue RTA. Not supported in this version of Windows") | ||
return common.UNSUPPORTED_RTA | ||
|
||
if code == 0: | ||
job_id = re.search('ID = (\d+)', output).group(1) | ||
|
||
# Check status and delete | ||
common.execute(['at.exe', host_str, job_id]) | ||
common.execute(['at.exe', host_str, job_id, '/delete']) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main(*sys.argv[1:])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: Suspicious BitsAdmin Download File | ||
# RTA: bitsadmin_download.py | ||
# ATT&CK: T1197 | ||
# Description: Runs BitsAdmin to download file via command line. | ||
|
||
|
||
import os | ||
import subprocess | ||
|
||
from . import common | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
def main(): | ||
common.log("Running Windows BitsAdmin to Download") | ||
server, ip, port = common.serve_web() | ||
url = "http://" + ip + ":" + str(port) + "/bin/myapp.exe" | ||
dest_path = os.path.abspath("myapp-test.exe") | ||
fake_word = os.path.abspath("winword.exe") | ||
|
||
common.log("Emulating parent process: {parent}".format(parent=fake_word)) | ||
common.copy_file("C:\\Windows\\System32\\cmd.exe", fake_word) | ||
|
||
command = subprocess.list2cmdline(['bitsadmin.exe', '/Transfer', '/Download', url, dest_path]) | ||
common.execute([fake_word, "/c", command], timeout=15, kill=True) | ||
common.execute(['taskkill', '/f', '/im', 'bitsadmin.exe']) | ||
|
||
common.remove_files(dest_path, fake_word) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: Brute Force Login Attempts | ||
# RTA: brute_force_login.py | ||
# ATT&CK: T1110 | ||
# Description: Simulates brute force or password spraying tactics. | ||
# Remote audit failures must be enabled to trigger: `auditpol /set /subcategory:"Logon" /failure:enable` | ||
|
||
import random | ||
import string | ||
import sys | ||
import time | ||
|
||
from . import common | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
def main(username="rta-tester", remote_host=None): | ||
if not remote_host: | ||
common.log('A remote host is required to detonate this RTA', '!') | ||
return common.MISSING_REMOTE_HOST | ||
|
||
common.enable_logon_auditing(remote_host) | ||
|
||
common.log('Brute forcing login with invalid password against {}'.format(remote_host)) | ||
ps_command = ''' | ||
$PW = ConvertTo-SecureString "such-secure-passW0RD!" -AsPlainText -Force | ||
$CREDS = New-Object System.Management.Automation.PsCredential {username}, $PW | ||
Invoke-WmiMethod -ComputerName {host} -Class Win32_process -Name create -ArgumentList ipconfig -Credential $CREDS | ||
''' | ||
command = ['powershell', '-c', ps_command.format(username=username, host=remote_host)] | ||
|
||
# fail 4 times - the first 3 concurrently and wait for the final to complete | ||
for i in range(4): | ||
common.execute(command, wait=i == 3) | ||
|
||
time.sleep(1) | ||
|
||
common.log('Password spraying against {}'.format(remote_host)) | ||
|
||
# fail 5 times - the first 4 concurrently and wait for the final to complete | ||
for i in range(5): | ||
random_user = ''.join(random.sample(string.ascii_letters, 10)) | ||
command = ['powershell', '-c', ps_command.format(username=random_user, host=remote_host)] | ||
common.execute(command, wait=i == 4) | ||
|
||
# allow time for audit event to process | ||
time.sleep(2) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main(*sys.argv[1:])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
# or more contributor license agreements. Licensed under the Elastic License; | ||
# you may not use this file except in compliance with the Elastic License. | ||
|
||
# Name: Certutil Encode / Decode | ||
# RTA: certutil_file_obfuscation.py | ||
# ATT&CK: T1140 | ||
# Elastic Detection: Encoding or Decoding Files via CertUtil | ||
# Description: Uses certutil to create an encoded copy of cmd.exe. Then uses certutil to decode that copy. | ||
|
||
import os | ||
|
||
from . import common | ||
|
||
|
||
@common.requires_os(common.WINDOWS) | ||
def main(): | ||
common.log("Encoding target") | ||
encoded_file = os.path.abspath('encoded.txt') | ||
decoded_file = os.path.abspath('decoded.exe') | ||
common.execute(["c:\\Windows\\System32\\certutil.exe", "-encode", "c:\\windows\\system32\\cmd.exe", encoded_file]) | ||
|
||
common.log("Decoding target") | ||
common.execute(["c:\\Windows\\System32\\certutil.exe", "-decode", encoded_file, decoded_file]) | ||
|
||
common.log("Cleaning up") | ||
common.remove_file(encoded_file) | ||
common.remove_file(decoded_file) | ||
|
||
|
||
if __name__ == "__main__": | ||
exit(main()) |
Oops, something went wrong.