Add 5 new cybersecurity skills: AFL++ fuzzing, Sysmon scheduled task detection, ModSecurity WAF logging, MITRE Navigator TTP analysis, PowerShell script block hunting

This commit is contained in:
mukul975
2026-03-11 00:41:59 +01:00
parent 546f1ae6ef
commit aea97ff9ff
20 changed files with 1857 additions and 0 deletions
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Mahipal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,55 @@
---
name: performing-fuzzing-with-aflplusplus
description: >
Perform coverage-guided fuzzing of compiled binaries using AFL++ (American Fuzzy Lop Plus Plus)
to discover memory corruption, crashes, and security vulnerabilities. The tester instruments
target binaries with afl-cc/afl-clang-fast, manages input corpora with afl-cmin and afl-tmin,
runs parallel fuzzing campaigns with afl-fuzz, and triages crashes using CASR or GDB scripts.
Activates for requests involving binary fuzzing, crash discovery, coverage-guided testing, or
AFL++ fuzzing campaigns.
domain: cybersecurity
subdomain: application-security
tags: [fuzzing, aflplusplus, coverage-guided, crash-triage, binary-analysis, security-testing]
version: "1.0"
author: mahipal
license: Apache-2.0
---
# Performing Fuzzing with AFL++
## Overview
AFL++ is a community-maintained fork of American Fuzzy Lop (AFL) that provides coverage-guided
fuzzing for compiled binaries. It instruments targets at compile time or via QEMU/Unicorn mode
for binary-only fuzzing, then mutates input corpora to discover new code paths. AFL++ includes
advanced scheduling (MOpt, rare), custom mutators, CMPLOG for input-to-state comparison solving,
and persistent mode for high-throughput fuzzing.
## Prerequisites
- AFL++ installed (`apt install afl++` or build from source)
- Target binary source code (for compile-time instrumentation) or QEMU mode for binary-only
- Initial seed corpus of valid inputs for the target format
- Linux system with /proc/sys/kernel/core_pattern configured
## Steps
1. Instrument the target binary with `afl-cc` or `afl-clang-fast`
2. Prepare seed corpus directory with minimal valid inputs
3. Minimize corpus with `afl-cmin` to remove redundant seeds
4. Run `afl-fuzz` with appropriate flags (-i input -o output)
5. Monitor fuzzing progress via afl-whatsup and UI stats
6. Triage crashes with `afl-tmin` minimization and CASR/GDB analysis
7. Report unique crashes with reproduction steps
## Expected Output
```
+++ Findings +++
unique crashes: 12
unique hangs: 3
last crash: 00:02:15 ago
+++ Coverage +++
map density: 4.23% / 8.41%
paths found: 1847
exec speed: 2145/sec
```
@@ -0,0 +1,64 @@
# AFL++ Fuzzing — API Reference
## Installation
```bash
apt install afl++ # Ubuntu/Debian
# Or build from source:
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus && make all
```
## AFL++ CLI Tools
| Tool | Description |
|------|-------------|
| `afl-cc` / `afl-clang-fast` | Compile-time instrumentation compiler wrapper |
| `afl-fuzz` | Main fuzzer — coverage-guided mutation engine |
| `afl-cmin` | Corpus minimization — remove redundant seeds |
| `afl-tmin` | Test case minimization — shrink individual inputs |
| `afl-whatsup` | Multi-instance campaign status summary |
| `afl-plot` | Generate fuzzing progress plots |
| `afl-showmap` | Display coverage map for a single input |
## afl-fuzz Key Flags
| Flag | Description |
|------|-------------|
| `-i <dir>` | Input seed corpus directory |
| `-o <dir>` | Output directory for findings |
| `-m <MB>` | Memory limit (use `none` for ASAN) |
| `-t <ms>` | Execution timeout per test case |
| `-x <dict>` | Optional fuzzing dictionary |
| `-p <sched>` | Power schedule: fast, coe, explore, rare, mmopt |
| `-l <level>` | CMPLOG instrumentation level (2=transforms, 3=all) |
| `-c <bin>` | CMPLOG binary for input-to-state |
| `-M <name>` | Main fuzzer instance (parallel mode) |
| `-S <name>` | Secondary fuzzer instance (parallel mode) |
| `-Q` | QEMU mode (binary-only fuzzing) |
| `-U` | Unicorn mode |
## fuzzer_stats File Fields
| Field | Description |
|-------|-------------|
| `execs_done` | Total executions completed |
| `execs_per_sec` | Current execution speed |
| `corpus_count` | Total paths in corpus |
| `saved_crashes` | Unique crashes discovered |
| `saved_hangs` | Unique hangs discovered |
| `stability` | Execution stability percentage |
| `bitmap_cvg` | Code coverage bitmap density |
## Crash Triage Tools
| Tool | Purpose |
|------|---------|
| `casr-afl` | CASR crash severity analysis for AFL++ |
| `afl-tmin` | Minimize crash inputs |
| `gdb --batch -ex run` | Reproduce crash under debugger |
## External References
- [AFL++ Documentation](https://aflplus.plus/docs/)
- [AFL++ GitHub](https://github.com/AFLplusplus/AFLplusplus)
- [CASR Crash Triage](https://github.com/ispras/casr)
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
# For authorized testing only
"""AFL++ fuzzing campaign management and crash triage agent."""
import json
import sys
import argparse
import os
import subprocess
import glob
from datetime import datetime
def instrument_target(source_path, output_path, compiler="afl-clang-fast",
sanitizer=None):
"""Compile target with AFL++ instrumentation."""
cmd = [compiler, "-o", output_path, source_path]
if sanitizer == "asan":
cmd.insert(1, "-fsanitize=address")
elif sanitizer == "ubsan":
cmd.insert(1, "-fsanitize=undefined")
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
return {
"compiler": compiler,
"source": source_path,
"output": output_path,
"sanitizer": sanitizer,
"success": result.returncode == 0,
"stderr": result.stderr[:500] if result.stderr else "",
}
def minimize_corpus(afl_cmin_path, target_binary, input_dir, output_dir):
"""Minimize seed corpus using afl-cmin."""
cmd = [afl_cmin_path or "afl-cmin", "-i", input_dir, "-o", output_dir,
"--", target_binary]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
before = len(os.listdir(input_dir)) if os.path.isdir(input_dir) else 0
after = len(os.listdir(output_dir)) if os.path.isdir(output_dir) else 0
return {
"before": before,
"after": after,
"reduction_pct": round((1 - after / max(before, 1)) * 100, 1),
"success": result.returncode == 0,
}
def parse_fuzzer_stats(output_dir):
"""Parse afl-fuzz fuzzer_stats file for campaign metrics."""
stats_path = os.path.join(output_dir, "default", "fuzzer_stats")
if not os.path.exists(stats_path):
stats_path = os.path.join(output_dir, "fuzzer_stats")
if not os.path.exists(stats_path):
return {"error": f"fuzzer_stats not found in {output_dir}"}
stats = {}
with open(stats_path, "r") as f:
for line in f:
if ":" in line:
key, val = line.split(":", 1)
stats[key.strip()] = val.strip()
return {
"start_time": stats.get("start_time", ""),
"last_update": stats.get("last_update", ""),
"execs_done": int(stats.get("execs_done", 0)),
"execs_per_sec": float(stats.get("execs_per_sec", 0)),
"paths_total": int(stats.get("corpus_count", stats.get("paths_total", 0))),
"paths_found": int(stats.get("paths_found", 0)),
"unique_crashes": int(stats.get("saved_crashes", stats.get("unique_crashes", 0))),
"unique_hangs": int(stats.get("saved_hangs", stats.get("unique_hangs", 0))),
"stability": stats.get("stability", ""),
"bitmap_cvg": stats.get("bitmap_cvg", ""),
"command_line": stats.get("command_line", ""),
}
def triage_crashes(output_dir):
"""Enumerate and classify crash files from AFL++ output."""
crash_dirs = [
os.path.join(output_dir, "default", "crashes"),
os.path.join(output_dir, "crashes"),
]
crash_dir = None
for d in crash_dirs:
if os.path.isdir(d):
crash_dir = d
break
if not crash_dir:
return {"crashes": [], "total": 0}
crashes = []
for filename in sorted(os.listdir(crash_dir)):
if filename.startswith("README") or filename == ".state":
continue
filepath = os.path.join(crash_dir, filename)
size = os.path.getsize(filepath)
sig_parts = filename.split(",")
signal = ""
for part in sig_parts:
if part.startswith("sig:"):
signal = part.split(":")[1]
crashes.append({
"filename": filename,
"size_bytes": size,
"signal": signal,
"path": filepath,
})
return {"crashes": crashes, "total": len(crashes)}
def minimize_crash(afl_tmin_path, target_binary, crash_file, output_file):
"""Minimize a crash test case with afl-tmin."""
cmd = [afl_tmin_path or "afl-tmin", "-i", crash_file, "-o", output_file,
"--", target_binary]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
orig_size = os.path.getsize(crash_file) if os.path.exists(crash_file) else 0
min_size = os.path.getsize(output_file) if os.path.exists(output_file) else 0
return {
"original_size": orig_size,
"minimized_size": min_size,
"reduction_pct": round((1 - min_size / max(orig_size, 1)) * 100, 1),
"success": result.returncode == 0,
}
def run_whatsup(output_dir):
"""Run afl-whatsup to get multi-instance campaign summary."""
cmd = ["afl-whatsup", "-s", output_dir]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
return {"output": result.stdout[:2000] if result.stdout else result.stderr[:500]}
def run_audit(args):
"""Execute AFL++ fuzzing campaign audit."""
print(f"\n{'='*60}")
print(f" AFL++ FUZZING CAMPAIGN AUDIT")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
report = {}
if args.output_dir:
stats = parse_fuzzer_stats(args.output_dir)
report["fuzzer_stats"] = stats
print(f"--- FUZZER STATS ---")
print(f" Executions: {stats.get('execs_done', 0):,}")
print(f" Exec/sec: {stats.get('execs_per_sec', 0)}")
print(f" Paths: {stats.get('paths_total', 0)}")
print(f" Crashes: {stats.get('unique_crashes', 0)}")
print(f" Hangs: {stats.get('unique_hangs', 0)}")
print(f" Stability: {stats.get('stability', '')}")
print(f" Coverage: {stats.get('bitmap_cvg', '')}")
crash_data = triage_crashes(args.output_dir)
report["crash_triage"] = crash_data
print(f"\n--- CRASH TRIAGE ({crash_data['total']} crashes) ---")
for c in crash_data["crashes"][:20]:
print(f" {c['filename']} ({c['size_bytes']}B) signal={c['signal']}")
if args.instrument_src and args.instrument_out:
inst = instrument_target(args.instrument_src, args.instrument_out,
sanitizer=args.sanitizer)
report["instrumentation"] = inst
print(f"\n--- INSTRUMENTATION ---")
print(f" {'SUCCESS' if inst['success'] else 'FAILED'}: {inst['source']}")
return report
def main():
parser = argparse.ArgumentParser(description="AFL++ Fuzzing Campaign Agent")
parser.add_argument("--output-dir", help="AFL++ output directory to analyze")
parser.add_argument("--instrument-src", help="Source file to instrument")
parser.add_argument("--instrument-out", help="Output path for instrumented binary")
parser.add_argument("--sanitizer", choices=["asan", "ubsan"],
help="Address or undefined behavior sanitizer")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
report = run_audit(args)
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()