mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-28 15:10:58 +03:00
feat: upgrade 5 skills with full content for v1.1.0
Replaced stub SKILL.md files with complete implementations: - analyzing-linux-audit-logs-for-intrusion (257 lines, full auditd workflow) - analyzing-windows-amcache-artifacts (237 lines, AmcacheParser + timeline) - detecting-oauth-token-theft (266 lines, Azure AD token protection) - implementing-devsecops-security-scanning (372 lines, full CI/CD pipeline) - implementing-privileged-session-monitoring (323 lines, PAM session audit) Also bumps index.json to version 1.1.0.
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,13 +1,16 @@
|
|||||||
---
|
---
|
||||||
name: analyzing-linux-audit-logs-for-intrusion
|
name: analyzing-linux-audit-logs-for-intrusion
|
||||||
description: >
|
description: >
|
||||||
Parse and analyze Linux auditd logs to detect intrusion indicators
|
Uses the Linux Audit framework (auditd) with ausearch and aureport utilities
|
||||||
including unauthorized file access, privilege escalation, syscall
|
to detect intrusion attempts, unauthorized access, privilege escalation, and
|
||||||
anomalies, and suspicious process execution using ausearch and Python.
|
suspicious system activity. Covers audit rule configuration, log querying,
|
||||||
|
timeline reconstruction, and integration with SIEM platforms. Activates for
|
||||||
|
requests involving auditd analysis, Linux audit log investigation, ausearch
|
||||||
|
queries, aureport summaries, or host-based intrusion detection on Linux.
|
||||||
domain: cybersecurity
|
domain: cybersecurity
|
||||||
subdomain: log-analysis
|
subdomain: incident-response
|
||||||
tags: [auditd, linux-forensics, syscall-monitoring, intrusion-detection]
|
tags: [auditd, ausearch, aureport, linux-security, intrusion-detection, HIDS, forensics]
|
||||||
version: "1.0"
|
version: 1.0.0
|
||||||
author: mahipal
|
author: mahipal
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
---
|
---
|
||||||
@@ -141,6 +144,9 @@ ausearch -k exec_from_tmp -ts this-week
|
|||||||
# Search for SSH key modifications
|
# Search for SSH key modifications
|
||||||
ausearch -k ssh_key_tampering -ts this-month
|
ausearch -k ssh_key_tampering -ts this-month
|
||||||
|
|
||||||
|
# Search for a specific event by audit event ID
|
||||||
|
ausearch -a 12345
|
||||||
|
|
||||||
# Search events in a specific time range
|
# Search events in a specific time range
|
||||||
ausearch -ts 03/15/2026 08:00:00 -te 03/15/2026 18:00:00
|
ausearch -ts 03/15/2026 08:00:00 -te 03/15/2026 18:00:00
|
||||||
|
|
||||||
@@ -156,20 +162,29 @@ Use `aureport` to produce aggregate summaries for triage:
|
|||||||
# Summary of all authentication events
|
# Summary of all authentication events
|
||||||
aureport -au -ts this-week --summary
|
aureport -au -ts this-week --summary
|
||||||
|
|
||||||
# Report of all failed events
|
# Report of all failed events (login, access, etc.)
|
||||||
aureport --failed --summary -ts today
|
aureport --failed --summary -ts today
|
||||||
|
|
||||||
# Report of executable runs
|
# Report of executable runs
|
||||||
aureport -x --summary -ts today
|
aureport -x --summary -ts today
|
||||||
|
|
||||||
# Report of all anomaly events
|
# Report of all anomaly events (segfaults, promiscuous mode, etc.)
|
||||||
aureport --anomaly -ts this-week
|
aureport --anomaly -ts this-week
|
||||||
|
|
||||||
# Report of file access events
|
# Report of file access events
|
||||||
aureport -f --summary -ts today
|
aureport -f --summary -ts today
|
||||||
|
|
||||||
# Report of all events by key (maps to custom rule keys)
|
# Report of all events by key (maps to your custom rule keys)
|
||||||
aureport -k --summary -ts this-month
|
aureport -k --summary -ts this-month
|
||||||
|
|
||||||
|
# Report of all system calls
|
||||||
|
aureport -s --summary -ts today
|
||||||
|
|
||||||
|
# Report of events grouped by user
|
||||||
|
aureport -u --summary -ts this-week
|
||||||
|
|
||||||
|
# Detailed time-based event report for timeline building
|
||||||
|
aureport -ts 03/15/2026 08:00:00 -te 03/15/2026 18:00:00 --summary
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Reconstruct the Attack Timeline
|
### Step 5: Reconstruct the Attack Timeline
|
||||||
@@ -177,55 +192,66 @@ aureport -k --summary -ts this-month
|
|||||||
Combine ausearch queries to build a chronological narrative:
|
Combine ausearch queries to build a chronological narrative:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Identify the initial access timestamp
|
# Step 5a: Identify the initial access timestamp
|
||||||
ausearch -m USER_LOGIN -ua 0 --success yes -ts this-week -i | head -50
|
ausearch -m USER_LOGIN -ua 0 --success yes -ts this-week -i | head -50
|
||||||
|
|
||||||
# Trace what the attacker did after gaining access
|
# Step 5b: Trace what the attacker did after gaining access
|
||||||
ausearch -ua <UID> -ts "03/15/2026 14:00:00" -te "03/15/2026 18:00:00" -i | aureport -f -i
|
# Get all events from the compromised account within the incident window
|
||||||
|
ausearch -ua <UID> -ts "03/15/2026 14:00:00" -te "03/15/2026 18:00:00" -i \
|
||||||
|
| aureport -f -i
|
||||||
|
|
||||||
# Extract all commands executed during the incident window
|
# Step 5c: Extract all commands executed during the incident window
|
||||||
ausearch -m EXECVE -ts "03/15/2026 14:00:00" -te "03/15/2026 18:00:00" -i
|
ausearch -m EXECVE -ts "03/15/2026 14:00:00" -te "03/15/2026 18:00:00" -i
|
||||||
|
|
||||||
# Check for persistence mechanisms installed
|
# Step 5d: Check for persistence mechanisms installed
|
||||||
ausearch -k cron_persistence -ts "03/15/2026 14:00:00" -i
|
ausearch -k cron_persistence -ts "03/15/2026 14:00:00" -i
|
||||||
ausearch -k ssh_key_tampering -ts "03/15/2026 14:00:00" -i
|
ausearch -k ssh_key_tampering -ts "03/15/2026 14:00:00" -i
|
||||||
|
|
||||||
|
# Step 5e: Check for lateral movement (outbound connections)
|
||||||
|
ausearch -k network_connection -ts "03/15/2026 14:00:00" -i
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Forward Audit Logs to SIEM
|
### Step 6: Forward Audit Logs to SIEM
|
||||||
|
|
||||||
Configure `audisp-remote` or `auditbeat` to ship logs to a central SIEM:
|
Configure `audisp-remote` or `auditbeat` to ship logs to a central SIEM for correlation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using audisp-remote plugin (/etc/audit/plugins.d/au-remote.conf)
|
# Option A: Using audisp-remote plugin
|
||||||
|
# Edit /etc/audit/plugins.d/au-remote.conf
|
||||||
active = yes
|
active = yes
|
||||||
direction = out
|
direction = out
|
||||||
path = /sbin/audisp-remote
|
path = /sbin/audisp-remote
|
||||||
type = always
|
type = always
|
||||||
|
|
||||||
# Remote target (/etc/audit/audisp-remote.conf)
|
# Configure remote target in /etc/audit/audisp-remote.conf
|
||||||
remote_server = siem.internal.corp
|
remote_server = siem.internal.corp
|
||||||
port = 6514
|
port = 6514
|
||||||
transport = tcp
|
transport = tcp
|
||||||
|
|
||||||
|
# Option B: Using Elastic Auditbeat
|
||||||
|
# Install auditbeat and configure /etc/auditbeat/auditbeat.yml
|
||||||
|
# Auditbeat reads directly from the kernel audit framework
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Concepts
|
## Key Concepts
|
||||||
|
|
||||||
| Term | Definition |
|
| Term | Definition |
|
||||||
|------|------------|
|
|------|------------|
|
||||||
| **auditd** | Linux Audit daemon that receives kernel audit events and writes to `/var/log/audit/audit.log` |
|
| **auditd** | The Linux Audit daemon that receives audit events from the kernel and writes them to `/var/log/audit/audit.log` |
|
||||||
| **auditctl** | CLI to control the audit system: add/remove rules, check status, set backlog size |
|
| **auditctl** | Command-line utility to control the audit system: add/remove rules, check status, set backlog size |
|
||||||
| **ausearch** | Query tool for searching audit logs by message type, user, file, key, or time range |
|
| **ausearch** | Query tool that searches audit logs by message type, user, file, key, time range, or event ID |
|
||||||
| **aureport** | Reporting tool that generates aggregate summaries for triage and compliance |
|
| **aureport** | Reporting tool that generates aggregate summaries of audit events for triage and compliance |
|
||||||
| **audit rule key (-k)** | User-defined label on audit rules for fast filtering with ausearch and aureport |
|
| **audit rule key (-k)** | A user-defined label attached to an audit rule, enabling fast filtering of related events with ausearch and aureport |
|
||||||
| **augenrules** | Merges `/etc/audit/rules.d/` files into `audit.rules` and loads into the kernel |
|
| **syscall auditing** | Kernel-level monitoring of system calls (execve, open, connect, ptrace) that captures process and file activity |
|
||||||
|
| **augenrules** | Utility that merges all files in `/etc/audit/rules.d/` into `/etc/audit/audit.rules` and loads them into the kernel |
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- [ ] auditd is running and rules are loaded (`auditctl -l` returns expected rule count)
|
- [ ] auditd is running and rules are loaded (`auditctl -l` returns expected rule count)
|
||||||
- [ ] No audit backlog overflow (`auditctl -s` shows lost: 0)
|
- [ ] No audit backlog overflow (`auditctl -s` shows `backlog: 0` or low value, lost: 0)
|
||||||
- [ ] ausearch returns events for each custom key
|
- [ ] ausearch returns events for each custom key (`ausearch -k <key> -ts today` returns results)
|
||||||
- [ ] aureport generates non-empty summaries for authentication, executable, and file events
|
- [ ] aureport generates non-empty summaries for authentication, executable, and file events
|
||||||
- [ ] Timeline reconstruction produces a coherent chronological sequence
|
- [ ] Timeline reconstruction produces a coherent chronological sequence of attacker actions
|
||||||
- [ ] Critical file watches trigger alerts on test modifications
|
- [ ] Critical file watches trigger alerts on test modifications (`touch /etc/shadow` generates an event)
|
||||||
- [ ] Logs are forwarding to central SIEM
|
- [ ] Logs are forwarding to central SIEM (verify with a test event and confirm receipt)
|
||||||
- [ ] Audit rules persist across reboot (rules in `/etc/audit/rules.d/`)
|
- [ ] Audit rules persist across reboot (rules in `/etc/audit/rules.d/`, not only via `auditctl`)
|
||||||
|
|||||||
@@ -1,81 +1,237 @@
|
|||||||
---
|
---
|
||||||
name: analyzing-windows-amcache-artifacts
|
name: analyzing-windows-amcache-artifacts
|
||||||
description: >
|
description: >
|
||||||
Parse and analyze Windows Amcache.hve registry hive to extract program
|
Parses and analyzes the Windows Amcache.hve registry hive to extract evidence
|
||||||
execution evidence, file metadata, SHA-1 hashes, and device connection
|
of program execution, application installation, and driver loading for digital
|
||||||
history for digital forensics and incident response investigations.
|
forensics investigations. Uses Eric Zimmerman's AmcacheParser and Timeline
|
||||||
|
Explorer for artifact extraction, SHA-1 hash correlation with threat intel,
|
||||||
|
and timeline reconstruction. Activates for requests involving Amcache forensics,
|
||||||
|
program execution evidence, Windows artifact analysis, or application compatibility
|
||||||
|
cache investigation.
|
||||||
domain: cybersecurity
|
domain: cybersecurity
|
||||||
subdomain: digital-forensics
|
subdomain: digital-forensics
|
||||||
tags: [amcache, windows-forensics, registry-analysis, execution-artifacts]
|
tags: [amcache, windows-forensics, program-execution, AmcacheParser, eric-zimmerman, timeline-analysis, DFIR]
|
||||||
version: "1.0"
|
version: 1.0.0
|
||||||
author: mahipal
|
author: mahipal
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
---
|
---
|
||||||
|
|
||||||
# Analyzing Windows Amcache Artifacts
|
# Analyzing Windows Amcache Artifacts
|
||||||
|
|
||||||
Extract execution evidence from Amcache.hve including application paths,
|
|
||||||
SHA-1 hashes, timestamps, and publisher metadata for DFIR investigations.
|
|
||||||
|
|
||||||
|
|
||||||
## When to Use
|
## When to Use
|
||||||
|
|
||||||
- When investigating security incidents that require analyzing windows amcache artifacts
|
- Determining which programs have existed or executed on a Windows system during incident response
|
||||||
- When building detection rules or threat hunting queries for this domain
|
- Correlating SHA-1 hashes from Amcache against known malware databases (VirusTotal, CIRCL, MISP)
|
||||||
- When SOC analysts need structured procedures for this analysis type
|
- Building an application installation and execution timeline for forensic investigations
|
||||||
- When validating security monitoring coverage for related attack techniques
|
- Identifying deleted executables that leave traces in Amcache even after file removal
|
||||||
|
- Investigating insider threats by documenting which portable or unauthorized applications were present
|
||||||
|
- Analyzing driver loading history to detect rootkits or malicious kernel modules
|
||||||
|
|
||||||
|
**Do not use** as sole proof of program execution. Amcache proves file existence and metadata registration, but ShimCache (AppCompatCache) and Prefetch provide stronger execution evidence. Use all three artifacts together for conclusive analysis.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Familiarity with digital forensics concepts and tools
|
- A forensic image or live triage copy of `C:\Windows\appcompat\Programs\Amcache.hve` (and associated `.LOG1`, `.LOG2` transaction logs)
|
||||||
- Access to a test or lab environment for safe execution
|
- Eric Zimmerman's AmcacheParser (`AmcacheParser.exe`) downloaded from https://ericzimmerman.github.io/
|
||||||
- Python 3.8+ with required dependencies installed
|
- Eric Zimmerman's Timeline Explorer for viewing parsed CSV output
|
||||||
- Appropriate authorization for any testing activities
|
- Optionally: Registry Explorer for manual hive inspection
|
||||||
|
- A SHA-1 whitelist of known-good executables (e.g., NSRL hashset) for filtering
|
||||||
|
- .NET 6+ runtime installed (required by current EZ tools)
|
||||||
|
- Write access to an output directory for CSV results
|
||||||
|
|
||||||
## Example Output
|
## Workflow
|
||||||
|
|
||||||
```text
|
### Step 1: Acquire the Amcache.hve File
|
||||||
$ AmcacheParser.exe -f "C:\Evidence\Amcache.hve" --csv /analysis/amcache_output
|
|
||||||
|
|
||||||
AmcacheParser v1.5.1 - Amcache.hve Parser
|
Extract the Amcache hive from a forensic image or live system:
|
||||||
============================================
|
|
||||||
Input: C:\Evidence\Amcache.hve (12.4 MB)
|
|
||||||
Last Write Time: 2024-01-18 23:59:45 UTC
|
|
||||||
|
|
||||||
[+] Parsing File entries... Found: 4,567
|
```powershell
|
||||||
[+] Parsing Program entries... Found: 234
|
# From a live system (requires elevated privileges and raw copy tool)
|
||||||
[+] Parsing Driver entries... Found: 189
|
# Amcache.hve is locked by the system; use a raw disk copy tool
|
||||||
[+] Parsing Device Container entries Found: 45
|
# Option A: FTK Imager - mount image and navigate to:
|
||||||
[+] Parsing Shortcut entries... Found: 312
|
# C:\Windows\appcompat\Programs\Amcache.hve
|
||||||
|
# Also collect: Amcache.hve.LOG1, Amcache.hve.LOG2
|
||||||
|
|
||||||
--- Unassociated File Entries (No Known Publisher) ---
|
# Option B: Using KAPE for automated triage collection
|
||||||
SHA-1 | Path | Name | Size | First Run (UTC) | Publisher
|
kape.exe --tsource C: --tdest D:\Evidence\%m --target Amcache
|
||||||
--------------------|-----------------------------------------------|-------------------|-----------|-----------------------|----------
|
|
||||||
a1b2c3d4e5f6a7b8...| C:\ProgramData\Updates\ | update_client.exe | 1,258,496 | 2024-01-15 14:36:30 | (none)
|
|
||||||
b2c3d4e5f6a7b8c9...| C:\Windows\Temp\ | mimikatz.exe | 1,250,816 | 2024-01-16 02:30:15 | (none)
|
|
||||||
c3d4e5f6a7b8c9d0...| C:\Windows\Temp\ | procdump64.exe | 421,376 | 2024-01-16 02:28:00 | Sysinternals
|
|
||||||
d4e5f6a7b8c9d0e1...| C:\ProgramData\svc\ | updater.exe | 345,088 | 2024-01-15 14:37:00 | (none)
|
|
||||||
e5f6a7b8c9d0e1f2...| C:\Users\jsmith\AppData\Local\Temp\ | psexec.exe | 834,936 | 2024-01-16 02:40:00 | Sysinternals
|
|
||||||
f6a7b8c9d0e1f2a3...| C:\Users\jsmith\Downloads\ | netscan.exe | 512,000 | 2024-01-15 15:10:22 | (none)
|
|
||||||
|
|
||||||
--- Program Entries (Recently Installed) ---
|
# Option C: From a mounted forensic image (E: = mounted image)
|
||||||
Name | Version | Publisher | Install Date | Source
|
copy "E:\Windows\appcompat\Programs\Amcache.hve" D:\Evidence\
|
||||||
------------------------|---------------|------------------------|-----------------|--------
|
copy "E:\Windows\appcompat\Programs\Amcache.hve.LOG1" D:\Evidence\
|
||||||
PuTTY | 0.80 | Simon Tatham | 2024-01-14 | MSI
|
copy "E:\Windows\appcompat\Programs\Amcache.hve.LOG2" D:\Evidence\
|
||||||
WinSCP | 6.1.2 | Martin Prikryl | 2024-01-14 | MSI
|
|
||||||
7-Zip | 23.01 | Igor Pavlov | 2024-01-15 | MSI
|
|
||||||
(Unknown) | (Unknown) | (none) | 2024-01-15 | Manual
|
|
||||||
|
|
||||||
--- Driver Entries (Suspicious) ---
|
|
||||||
Name | SHA-1 | Signer | Install Date
|
|
||||||
------------------------|---------------------|-----------------------|-------------
|
|
||||||
WinDivert64.sys | 1a2b3c4d5e6f... | (self-signed) | 2024-01-15
|
|
||||||
npf.sys | 2b3c4d5e6f7a... | Nmap Project | 2024-01-15
|
|
||||||
|
|
||||||
Summary:
|
|
||||||
Total execution artifacts: 4,567
|
|
||||||
Unsigned/suspicious entries: 6
|
|
||||||
Recently installed programs: 4 (2 suspicious)
|
|
||||||
Suspicious drivers: 2
|
|
||||||
CSV exported to: /analysis/amcache_output/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Always collect the transaction log files (`.LOG1`, `.LOG2`) alongside the hive. AmcacheParser replays uncommitted transactions from these logs to recover the most complete data.
|
||||||
|
|
||||||
|
### Step 2: Parse Amcache with AmcacheParser
|
||||||
|
|
||||||
|
Run AmcacheParser against the acquired hive:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Basic parsing with CSV output
|
||||||
|
AmcacheParser.exe -f "D:\Evidence\Amcache.hve" --csv "D:\Evidence\Output"
|
||||||
|
|
||||||
|
# Parse with a SHA-1 whitelist to exclude known-good entries (NSRL)
|
||||||
|
AmcacheParser.exe -f "D:\Evidence\Amcache.hve" -w "D:\Whitelists\nsrl_sha1.txt" --csv "D:\Evidence\Output"
|
||||||
|
|
||||||
|
# Parse with a SHA-1 inclusion list (only show matches against known-bad hashes)
|
||||||
|
AmcacheParser.exe -f "D:\Evidence\Amcache.hve" -b "D:\IOCs\malware_sha1.txt" --csv "D:\Evidence\Output"
|
||||||
|
|
||||||
|
# Include deleted entries with high-precision timestamps
|
||||||
|
AmcacheParser.exe -f "D:\Evidence\Amcache.hve" --csv "D:\Evidence\Output" -i --mp
|
||||||
|
```
|
||||||
|
|
||||||
|
AmcacheParser produces multiple CSV files in the output directory:
|
||||||
|
|
||||||
|
| Output File | Contents |
|
||||||
|
|-------------|----------|
|
||||||
|
| `Amcache_AssociatedFileEntries.csv` | File entries with SHA-1 hashes, paths, sizes, and timestamps |
|
||||||
|
| `Amcache_UnassociatedFileEntries.csv` | Orphaned file entries from older Amcache format |
|
||||||
|
| `Amcache_ProgramEntries.csv` | Installed program metadata (name, publisher, version, install date) |
|
||||||
|
| `Amcache_DeviceContainers.csv` | USB and device connection history |
|
||||||
|
| `Amcache_DevicePnps.csv` | Plug-and-Play device driver information |
|
||||||
|
| `Amcache_DriverBinaries.csv` | Loaded driver binaries with paths and hashes |
|
||||||
|
|
||||||
|
### Step 3: Analyze File Entries for Suspicious Programs
|
||||||
|
|
||||||
|
Open the `AssociatedFileEntries.csv` in Timeline Explorer and examine key columns:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key columns to review:
|
||||||
|
- ProgramId : Links file to its parent program entry
|
||||||
|
- SHA1 : Hash for threat intel lookups
|
||||||
|
- FullPath : Original file location on disk
|
||||||
|
- FileSize : Size of the executable
|
||||||
|
- FileKeyLastWriteTimestamp : When the Amcache entry was last updated
|
||||||
|
- Name : File name
|
||||||
|
- Publisher : Code signing publisher (blank = unsigned)
|
||||||
|
- BinProductVersion : Version string from the PE header
|
||||||
|
- LinkDate : PE compilation timestamp (useful for detecting timestomping)
|
||||||
|
```
|
||||||
|
|
||||||
|
Filter for suspicious indicators:
|
||||||
|
|
||||||
|
```
|
||||||
|
# In Timeline Explorer, apply these filters:
|
||||||
|
|
||||||
|
# 1. Find unsigned executables (potentially malicious)
|
||||||
|
Publisher column = (empty)
|
||||||
|
|
||||||
|
# 2. Find executables from suspicious paths
|
||||||
|
FullPath contains: \temp\, \appdata\, \downloads\, \public\, \programdata\
|
||||||
|
|
||||||
|
# 3. Find executables with recent timestamps during incident window
|
||||||
|
FileKeyLastWriteTimestamp between: 2026-03-15 00:00:00 and 2026-03-16 00:00:00
|
||||||
|
|
||||||
|
# 4. Find executables with suspicious compilation dates (timestomping)
|
||||||
|
LinkDate year < 2015 AND FileKeyLastWriteTimestamp year = 2026
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Correlate SHA-1 Hashes with Threat Intelligence
|
||||||
|
|
||||||
|
Extract SHA-1 hashes and check against malware databases:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Extract unique SHA-1 hashes from the parsed output
|
||||||
|
# Using PowerShell to extract the SHA1 column
|
||||||
|
Import-Csv "D:\Evidence\Output\Amcache_AssociatedFileEntries.csv" |
|
||||||
|
Select-Object -ExpandProperty SHA1 -Unique |
|
||||||
|
Where-Object { $_ -ne "" } |
|
||||||
|
Out-File "D:\Evidence\Output\extracted_hashes.txt"
|
||||||
|
|
||||||
|
# Check hashes against VirusTotal using vt-cli
|
||||||
|
foreach ($hash in Get-Content "D:\Evidence\Output\extracted_hashes.txt") {
|
||||||
|
vt file $hash --format json | Select-Object -Property meaningful_name, last_analysis_stats
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check hashes against CIRCL hashlookup
|
||||||
|
foreach ($hash in Get-Content "D:\Evidence\Output\extracted_hashes.txt") {
|
||||||
|
Invoke-RestMethod -Uri "https://hashlookup.circl.lu/lookup/sha1/$hash"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cross-reference with NSRL to identify known-good vs. unknown
|
||||||
|
# Unknown hashes that are not in NSRL warrant closer investigation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Analyze Program Entries for Unauthorized Installations
|
||||||
|
|
||||||
|
Review the `ProgramEntries.csv` for software the attacker may have installed:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key columns in ProgramEntries:
|
||||||
|
- ProgramName : Display name of installed application
|
||||||
|
- ProgramVersion : Version string
|
||||||
|
- Publisher : Software publisher
|
||||||
|
- InstallDate : When the program was installed
|
||||||
|
- Source : Installation source (msi, exe, etc.)
|
||||||
|
- UninstallKey : Registry uninstall path
|
||||||
|
- PathsList : Installation directories
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for:
|
||||||
|
- Remote access tools (AnyDesk, TeamViewer, ngrok, Chisel)
|
||||||
|
- Hacking tools (Mimikatz, PsExec, Cobalt Strike)
|
||||||
|
- Tunneling utilities (plink, socat, WireGuard)
|
||||||
|
- Programs installed during the incident window
|
||||||
|
- Programs installed to non-standard locations
|
||||||
|
|
||||||
|
### Step 6: Analyze Driver Binaries for Rootkit Evidence
|
||||||
|
|
||||||
|
Review the `DriverBinaries.csv` for suspicious loaded drivers:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key columns in DriverBinaries:
|
||||||
|
- DriverName : Name of the driver
|
||||||
|
- DriverInBox : Whether it shipped with Windows (false = third-party)
|
||||||
|
- DriverSigned : Whether the driver has a valid signature
|
||||||
|
- DriverTimeStamp : Compilation timestamp
|
||||||
|
- Product : Product associated with the driver
|
||||||
|
- ProductVersion : Driver version
|
||||||
|
- SHA1 : Hash of the driver binary
|
||||||
|
```
|
||||||
|
|
||||||
|
Filter for `DriverInBox = false` and `DriverSigned = false` to find unsigned third-party drivers that may be rootkits or vulnerable drivers used in BYOVD (Bring Your Own Vulnerable Driver) attacks.
|
||||||
|
|
||||||
|
### Step 7: Build a Timeline from Amcache Data
|
||||||
|
|
||||||
|
Combine Amcache data with other artifacts for a comprehensive timeline:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Merge Amcache CSV with other EZ Tools output using Timeline Explorer
|
||||||
|
# Load the following CSVs into Timeline Explorer:
|
||||||
|
# - Amcache_AssociatedFileEntries.csv (file evidence)
|
||||||
|
# - Amcache_ProgramEntries.csv (install evidence)
|
||||||
|
# - Prefetch output from PECmd.exe (execution evidence)
|
||||||
|
# - ShimCache output from AppCompatCacheParser.exe (execution evidence)
|
||||||
|
|
||||||
|
# Sort all entries by timestamp to reconstruct the attack sequence
|
||||||
|
# Timeline Explorer supports multi-file loading and column-based sorting
|
||||||
|
|
||||||
|
# Export the combined timeline
|
||||||
|
# File > Save to CSV > combined_timeline.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Concepts
|
||||||
|
|
||||||
|
| Term | Definition |
|
||||||
|
|------|------------|
|
||||||
|
| **Amcache.hve** | A Windows registry hive at `C:\Windows\appcompat\Programs\Amcache.hve` that stores metadata about applications, files, and drivers for application compatibility purposes |
|
||||||
|
| **Associated File Entry** | An Amcache record linked to a specific program installation, containing file path, size, hash, and timestamps |
|
||||||
|
| **Unassociated File Entry** | An orphaned Amcache record from an older format that is not linked to a program entry; common on Windows 7/8 systems |
|
||||||
|
| **Program Entry** | Amcache record containing installation metadata: program name, version, publisher, install date, and uninstall key |
|
||||||
|
| **SHA-1 Hash** | Cryptographic hash stored in Amcache for each registered file, enabling malware identification through threat intelligence lookups |
|
||||||
|
| **LinkDate** | The PE compilation timestamp embedded in the executable header; discrepancy with file system timestamps may indicate timestomping |
|
||||||
|
| **Transaction Logs** | `.LOG1` and `.LOG2` files containing uncommitted registry transactions that AmcacheParser replays for complete data recovery |
|
||||||
|
| **NSRL (National Software Reference Library)** | NIST-maintained database of SHA-1 hashes for known commercial software, used as a whitelist to filter benign entries |
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] Amcache.hve and transaction logs (LOG1, LOG2) were collected from the forensic image
|
||||||
|
- [ ] AmcacheParser produced all expected CSV output files without errors
|
||||||
|
- [ ] SHA-1 hashes were extracted and checked against VirusTotal or CIRCL hashlookup
|
||||||
|
- [ ] Unsigned executables in suspicious paths have been flagged for further analysis
|
||||||
|
- [ ] Program entries show all software installations within the incident window
|
||||||
|
- [ ] Driver binaries have been checked for unsigned or out-of-box entries
|
||||||
|
- [ ] LinkDate vs. FileKeyLastWriteTimestamp comparison has been performed to detect timestomping
|
||||||
|
- [ ] Amcache findings are correlated with Prefetch and ShimCache for execution confirmation
|
||||||
|
- [ ] Final timeline integrates Amcache data with other forensic artifacts
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
---
|
---
|
||||||
name: detecting-oauth-token-theft
|
name: detecting-oauth-token-theft
|
||||||
description: >
|
description: >
|
||||||
Detect OAuth access token theft and misuse by analyzing sign-in logs for
|
Detects and responds to OAuth token theft and replay attacks in cloud
|
||||||
impossible travel, new device patterns, token replay from unusual IPs,
|
environments, focusing on Microsoft Entra ID (Azure AD) token protection,
|
||||||
and anomalous scope requests via Microsoft Graph and Okta APIs.
|
conditional access policies, and sign-in anomaly detection. Covers access
|
||||||
|
token theft, refresh token replay, Primary Refresh Token (PRT) abuse, and
|
||||||
|
pass-the-cookie attacks. Activates for requests involving OAuth token theft
|
||||||
|
detection, token replay prevention, Azure AD conditional access token
|
||||||
|
protection, or cloud identity attack investigation.
|
||||||
domain: cybersecurity
|
domain: cybersecurity
|
||||||
subdomain: identity-security
|
subdomain: cloud-security
|
||||||
tags: [oauth, token-theft, identity-attacks, impossible-travel]
|
tags: [oauth, token-theft, azure-ad, entra-id, conditional-access, token-replay, identity-security, PRT]
|
||||||
version: "1.0"
|
version: 1.0.0
|
||||||
author: mahipal
|
author: mahipal
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
---
|
---
|
||||||
@@ -30,21 +34,31 @@ license: Apache-2.0
|
|||||||
- Microsoft Entra ID P2 license (required for Identity Protection risk detections and conditional access)
|
- Microsoft Entra ID P2 license (required for Identity Protection risk detections and conditional access)
|
||||||
- Global Administrator or Security Administrator role in the Entra admin center
|
- Global Administrator or Security Administrator role in the Entra admin center
|
||||||
- Microsoft Defender for Cloud Apps (MDCA) license for session anomaly detection
|
- Microsoft Defender for Cloud Apps (MDCA) license for session anomaly detection
|
||||||
- Access to Entra ID Sign-in Logs and Audit Logs (Diagnostic Settings to Log Analytics or Sentinel)
|
- Access to Entra ID Sign-in Logs and Audit Logs (requires Diagnostic Settings configured to Log Analytics or Sentinel)
|
||||||
- Familiarity with OAuth 2.0 authorization flows (authorization code, device code, client credentials)
|
- Familiarity with OAuth 2.0 authorization flows (authorization code, device code, client credentials)
|
||||||
|
- Microsoft Sentinel or equivalent SIEM ingesting Entra ID sign-in and audit logs
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
### Step 1: Understand the Token Theft Attack Surface
|
### Step 1: Understand the Token Theft Attack Surface
|
||||||
|
|
||||||
Key token types and theft vectors:
|
Identify which token types are at risk and how they are stolen:
|
||||||
|
|
||||||
| Token Type | Lifetime | Theft Vector | Impact |
|
```
|
||||||
|---|---|---|---|
|
Token Type | Lifetime | Theft Vector | Impact
|
||||||
| Access Token | 60-90 min | Memory dump, proxy interception | API access for token lifetime |
|
----------------------|-------------|----------------------------------|------------------
|
||||||
| Refresh Token | Up to 90 days | Browser cookie theft, malware | Persistent access |
|
Access Token | 60-90 min | Memory dump, proxy interception | API access for token lifetime
|
||||||
| Primary Refresh Token | Session-based | Mimikatz, AADInternals | Full SSO to all M365/Azure apps |
|
Refresh Token | Up to 90 days| Browser cookie theft, malware | Persistent access, new access tokens
|
||||||
| Session Cookie | Varies | XSS, AitM proxy | Full session hijacking |
|
Primary Refresh Token | Session-based| Mimikatz, AADInternals, malware | Full SSO to all M365/Azure apps
|
||||||
|
Session Cookie | Varies | XSS, browser exploit, AitM proxy | Full session hijacking
|
||||||
|
Device Code Token | 15 min auth | Phishing (device code flow abuse)| Attacker gets refresh token via social engineering
|
||||||
|
```
|
||||||
|
|
||||||
|
Common attack techniques:
|
||||||
|
- **AitM Phishing (Adversary-in-the-Middle)**: Attacker proxies the legitimate login page via tools like Evilginx2, capturing session cookies and tokens after the user completes MFA
|
||||||
|
- **Device Code Phishing**: Attacker generates a device code, sends it to the victim via email/Teams, victim authenticates, attacker receives the token
|
||||||
|
- **PRT Extraction**: Attacker with local admin on a device extracts the Primary Refresh Token using Mimikatz (`sekurlsa::cloudap`) or AADInternals
|
||||||
|
- **Browser Cookie Theft**: Malware or infostealer exfiltrates browser cookies containing session tokens
|
||||||
|
|
||||||
### Step 2: Configure Entra ID Sign-in Risk Detection
|
### Step 2: Configure Entra ID Sign-in Risk Detection
|
||||||
|
|
||||||
@@ -54,118 +68,199 @@ Enable Identity Protection to flag anomalous token usage:
|
|||||||
Entra Admin Center > Protection > Identity Protection > Risk Detections
|
Entra Admin Center > Protection > Identity Protection > Risk Detections
|
||||||
|
|
||||||
Key risk detections for token theft:
|
Key risk detections for token theft:
|
||||||
- Anomalous Token : Unusual token characteristics
|
- Anomalous Token : Token has unusual characteristics (claim anomalies)
|
||||||
- Token Issuer Anomaly : Token from unusual issuer
|
- Token Issuer Anomaly : Token issued by an unusual token issuer
|
||||||
- Unfamiliar Sign-in : New location for user
|
- Unfamiliar Sign-in : Sign-in from a location not seen before for the user
|
||||||
- Impossible Travel : Geographically impossible sign-ins
|
- Impossible Travel : Sign-ins from geographically distant locations in impossible time
|
||||||
- Malicious IP Address : Known malicious source
|
- Malicious IP Address : Sign-in from a known malicious IP
|
||||||
|
- Suspicious Browser : Sign-in from a suspicious or attacker-controlled browser
|
||||||
```
|
```
|
||||||
|
|
||||||
Configure risk-based conditional access:
|
Configure risk-based conditional access:
|
||||||
|
|
||||||
```
|
```
|
||||||
Policy: "Block High-Risk Sign-ins"
|
Entra Admin Center > Protection > Conditional Access > New Policy
|
||||||
Users: All users (exclude break-glass accounts)
|
|
||||||
Conditions: Sign-in Risk = High
|
|
||||||
Grant: Block access
|
|
||||||
|
|
||||||
Policy: "Require MFA for Medium-Risk"
|
Policy Name: "Block High-Risk Sign-ins - Token Theft Protection"
|
||||||
Conditions: Sign-in Risk = Medium
|
Assignments:
|
||||||
Grant: Require MFA + password change
|
Users: All users (exclude break-glass accounts)
|
||||||
|
Cloud Apps: All cloud apps
|
||||||
|
Conditions:
|
||||||
|
Sign-in Risk: High
|
||||||
|
Grant:
|
||||||
|
Block access
|
||||||
|
|
||||||
|
Policy Name: "Require MFA for Medium-Risk Sign-ins"
|
||||||
|
Assignments:
|
||||||
|
Users: All users
|
||||||
|
Cloud Apps: All cloud apps
|
||||||
|
Conditions:
|
||||||
|
Sign-in Risk: Medium
|
||||||
|
Grant:
|
||||||
|
Require multifactor authentication
|
||||||
|
Require password change
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Enable Token Protection
|
### Step 3: Enable Token Protection (Preview)
|
||||||
|
|
||||||
Bind sign-in session tokens to device TPM:
|
Configure Token Protection to bind sign-in session tokens to the device:
|
||||||
|
|
||||||
```
|
```
|
||||||
Entra Admin Center > Protection > Conditional Access > New Policy
|
Entra Admin Center > Protection > Conditional Access > New Policy
|
||||||
|
|
||||||
Policy: "Enforce Token Protection"
|
Policy Name: "Enforce Token Protection for Desktop Sessions"
|
||||||
Users: Pilot group (expand after validation)
|
Assignments:
|
||||||
Cloud Apps: Office 365 Exchange Online, SharePoint Online
|
Users: All users (start with a pilot group)
|
||||||
Conditions: Device Platforms = Windows
|
Cloud Apps: Office 365 Exchange Online, Office 365 SharePoint Online
|
||||||
Session: Require token protection for sign-in sessions
|
Conditions:
|
||||||
Grant: Require compliant or Hybrid Azure AD joined device
|
Device Platforms: Windows
|
||||||
|
Session:
|
||||||
|
Require token protection for sign-in sessions (Preview): Enabled
|
||||||
|
Grant:
|
||||||
|
Require device to be marked as compliant
|
||||||
|
OR Require Hybrid Azure AD joined device
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Token Protection ensures that access tokens are cryptographically bound to the device's Trusted Platform Module (TPM). If an attacker steals a token and replays it from a different device, the token is rejected because the proof-of-possession key does not match.
|
||||||
|
|
||||||
### Step 4: Detect Token Replay in Sign-in Logs
|
### Step 4: Detect Token Replay in Sign-in Logs
|
||||||
|
|
||||||
KQL queries for Microsoft Sentinel or Log Analytics:
|
Query Entra sign-in logs for indicators of token theft:
|
||||||
|
|
||||||
```kusto
|
```kusto
|
||||||
// Detect anomalous token usage
|
// KQL query for Microsoft Sentinel or Log Analytics
|
||||||
|
// Detect sign-ins where the token was issued in one location and used in another
|
||||||
SigninLogs
|
SigninLogs
|
||||||
| where TimeGenerated > ago(7d)
|
| where TimeGenerated > ago(7d)
|
||||||
| where RiskDetail contains "token" or RiskEventTypes_V2 has "anomalousToken"
|
| where RiskDetail contains "token" or RiskEventTypes_V2 has "anomalousToken"
|
||||||
| project TimeGenerated, UserPrincipalName, IPAddress, Location,
|
| project TimeGenerated, UserPrincipalName, IPAddress, Location,
|
||||||
RiskDetail, RiskLevelDuringSignIn, AppDisplayName
|
RiskDetail, RiskLevelDuringSignIn, AppDisplayName,
|
||||||
|
DeviceDetail, ClientAppUsed, TokenIssuerType
|
||||||
| sort by TimeGenerated desc
|
| sort by TimeGenerated desc
|
||||||
|
|
||||||
// Detect impossible travel with token reuse
|
// Detect impossible travel with token reuse
|
||||||
SigninLogs
|
SigninLogs
|
||||||
| where TimeGenerated > ago(7d)
|
| where TimeGenerated > ago(7d)
|
||||||
| where ResultType == 0
|
| where ResultType == 0 // Successful sign-ins only
|
||||||
| summarize Locations=make_set(Location), IPs=make_set(IPAddress),
|
| summarize Locations=make_set(Location), IPs=make_set(IPAddress),
|
||||||
Count=count() by UserPrincipalName, bin(TimeGenerated, 1h)
|
Count=count() by UserPrincipalName, bin(TimeGenerated, 1h)
|
||||||
| where array_length(Locations) > 1
|
| where array_length(Locations) > 1
|
||||||
|
| sort by TimeGenerated desc
|
||||||
|
|
||||||
// Detect device code flow abuse (phishing)
|
// Detect device code flow abuse (often used in phishing)
|
||||||
SigninLogs
|
SigninLogs
|
||||||
| where TimeGenerated > ago(7d)
|
| where TimeGenerated > ago(7d)
|
||||||
| where AuthenticationProtocol == "deviceCode"
|
| where AuthenticationProtocol == "deviceCode"
|
||||||
| project TimeGenerated, UserPrincipalName, IPAddress, Location, AppDisplayName
|
| project TimeGenerated, UserPrincipalName, IPAddress, Location,
|
||||||
|
AppDisplayName, DeviceDetail, ResultType
|
||||||
|
| sort by TimeGenerated desc
|
||||||
|
|
||||||
|
// Detect token replay: same token used from multiple IPs
|
||||||
|
AADNonInteractiveUserSignInLogs
|
||||||
|
| where TimeGenerated > ago(7d)
|
||||||
|
| where ResultType == 0
|
||||||
|
| summarize IPs=make_set(IPAddress), IPCount=dcount(IPAddress)
|
||||||
|
by UserPrincipalName, CorrelationId
|
||||||
|
| where IPCount > 1
|
||||||
|
| sort by IPCount desc
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Investigate and Respond
|
### Step 5: Investigate and Respond to Token Theft
|
||||||
|
|
||||||
|
When a token theft event is detected, follow this response procedure:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Revoke all refresh tokens for compromised user
|
# Step 5a: Revoke all refresh tokens for the compromised user
|
||||||
|
# Microsoft Graph PowerShell
|
||||||
Connect-MgGraph -Scopes "User.ReadWrite.All"
|
Connect-MgGraph -Scopes "User.ReadWrite.All"
|
||||||
Revoke-MgUserSignInSession -UserId "user@contoso.com"
|
Revoke-MgUserSignInSession -UserId "user@contoso.com"
|
||||||
|
|
||||||
# Force password reset
|
# Step 5b: Force password reset
|
||||||
Update-MgUser -UserId "user@contoso.com" -PasswordProfile @{
|
Update-MgUser -UserId "user@contoso.com" -PasswordProfile @{
|
||||||
ForceChangePasswordNextSignIn = $true
|
ForceChangePasswordNextSignIn = $true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Review and revoke malicious OAuth app consent grants
|
# Step 5c: Review and revoke OAuth app consent grants
|
||||||
Get-MgUserOauth2PermissionGrant -UserId "user@contoso.com"
|
# Check for malicious app consent (common post-compromise persistence)
|
||||||
|
Get-MgUserOauth2PermissionGrant -UserId "user@contoso.com" |
|
||||||
|
Select-Object ClientId, ConsentType, Scope
|
||||||
|
|
||||||
|
# Remove suspicious OAuth grants
|
||||||
Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId "<grant-id>"
|
Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId "<grant-id>"
|
||||||
|
|
||||||
# Check for mail forwarding rules (common post-compromise action)
|
# Step 5d: Review enterprise app registrations for rogue apps
|
||||||
|
Get-MgServicePrincipal -Filter "displayName eq 'Suspicious App'" |
|
||||||
|
Select-Object AppId, DisplayName, SignInAudience
|
||||||
|
|
||||||
|
# Step 5e: Check for mail forwarding rules (common post-compromise action)
|
||||||
Get-MgUserMailFolderRule -UserId "user@contoso.com" -MailFolderId "Inbox" |
|
Get-MgUserMailFolderRule -UserId "user@contoso.com" -MailFolderId "Inbox" |
|
||||||
Where-Object { $_.Actions.ForwardTo -ne $null }
|
Where-Object { $_.Actions.ForwardTo -ne $null -or $_.Actions.RedirectTo -ne $null }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Enable Continuous Access Evaluation (CAE)
|
### Step 6: Implement Continuous Access Evaluation (CAE)
|
||||||
|
|
||||||
|
Enable CAE to revoke tokens in near-real-time when conditions change:
|
||||||
|
|
||||||
```
|
```
|
||||||
Entra Admin Center > Protection > Conditional Access > Continuous Access Evaluation
|
Entra Admin Center > Protection > Conditional Access > Continuous Access Evaluation
|
||||||
|
|
||||||
|
Settings:
|
||||||
Strictly enforce location policies: Enabled
|
Strictly enforce location policies: Enabled
|
||||||
|
|
||||||
CAE triggers near-real-time token revocation when:
|
CAE ensures that when you revoke a user's session or change their
|
||||||
- User account disabled/deleted
|
risk level, the enforcement happens within minutes rather than waiting
|
||||||
- Password changed/reset
|
for the access token to naturally expire (60-90 minutes).
|
||||||
- Admin explicitly revokes tokens
|
|
||||||
- Identity Protection detects elevated risk
|
Critical events that trigger immediate token revocation with CAE:
|
||||||
|
- User account disabled or deleted
|
||||||
|
- Password changed or reset
|
||||||
|
- MFA enabled for the user
|
||||||
|
- Admin explicitly revokes refresh tokens
|
||||||
|
- Azure AD Identity Protection detects elevated user risk
|
||||||
|
- Network location change violates conditional access policy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Configure Defender for Cloud Apps Session Policies
|
||||||
|
|
||||||
|
Set up real-time session monitoring to detect and block suspicious token usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
Microsoft Defender for Cloud Apps > Policies > Session Policies
|
||||||
|
|
||||||
|
Policy: "Block download from unmanaged device with stolen token"
|
||||||
|
Session Control Type: Monitor and block activities
|
||||||
|
Activity Source: App = Office 365, SharePoint Online
|
||||||
|
Activity Filter: Device tag does not equal "Compliant"
|
||||||
|
Activity Type: Download
|
||||||
|
Action: Block
|
||||||
|
|
||||||
|
Policy: "Alert on mass file download (exfiltration via stolen token)"
|
||||||
|
Session Control Type: Monitor only
|
||||||
|
Activity Source: App = Office 365
|
||||||
|
Activity Filter: Repeated activity > 10 downloads in 5 minutes
|
||||||
|
Action: Alert administrators
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Concepts
|
## Key Concepts
|
||||||
|
|
||||||
| Term | Definition |
|
| Term | Definition |
|
||||||
|------|------------|
|
|------|------------|
|
||||||
| **Primary Refresh Token (PRT)** | Long-lived device-bound token providing SSO to all Azure AD apps |
|
| **Primary Refresh Token (PRT)** | A long-lived token issued to a registered device that provides SSO to all Azure AD-integrated applications, cryptographically bound to the device's TPM |
|
||||||
| **Token Protection** | Conditional access feature binding tokens to device TPM |
|
| **Token Protection** | Entra ID conditional access feature that binds sign-in session tokens to the device, preventing replay from other devices |
|
||||||
| **Continuous Access Evaluation** | Near-real-time policy enforcement on token revocation |
|
| **Continuous Access Evaluation (CAE)** | Protocol that enables near-real-time enforcement of security policies by allowing resource providers to subscribe to Entra ID critical events |
|
||||||
| **AitM (Adversary-in-the-Middle)** | Phishing that proxies auth flow to capture session cookies post-MFA |
|
| **AitM (Adversary-in-the-Middle)** | Phishing technique where an attacker proxies the legitimate authentication flow to capture session cookies after the victim completes MFA |
|
||||||
| **Device Code Flow** | OAuth grant for input-constrained devices; abused in phishing campaigns |
|
| **Device Code Flow** | OAuth 2.0 authorization grant for input-constrained devices; abused by attackers who send device codes to victims via phishing |
|
||||||
|
| **Proof of Possession (PoP)** | Cryptographic mechanism where a token includes a claim tied to a device key, ensuring the token can only be used by the device that obtained it |
|
||||||
|
| **Refresh Token** | Long-lived OAuth token (up to 90 days) used to obtain new access tokens without re-authentication; primary target for persistent access |
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- [ ] Identity Protection risk detections generating alerts for anomalous tokens
|
- [ ] Identity Protection risk detections are enabled and generating alerts for anomalous token activity
|
||||||
- [ ] Conditional access policies block high-risk sign-ins and require MFA for medium-risk
|
- [ ] Conditional access policies block high-risk sign-ins and require MFA for medium-risk
|
||||||
- [ ] Token Protection confirmed working (test from unregistered device fails)
|
- [ ] Token Protection policy is applied to pilot group and confirmed working (test from unregistered device fails)
|
||||||
- [ ] KQL queries return results against synthetic anomaly events
|
- [ ] KQL queries in Sentinel return results when tested against synthetic token anomaly events
|
||||||
- [ ] CAE enabled and verified (revoke session, confirm access blocked within minutes)
|
- [ ] Continuous Access Evaluation is enabled and verified (revoke session, confirm access blocked within minutes)
|
||||||
- [ ] Incident response runbook includes token revocation and OAuth consent review
|
- [ ] Defender for Cloud Apps session policies are active and monitoring download activity
|
||||||
|
- [ ] Device code flow is restricted via conditional access (block or require compliant device)
|
||||||
|
- [ ] Incident response runbook includes token revocation, password reset, and OAuth consent review steps
|
||||||
|
- [ ] Mail forwarding rules and OAuth app grants are audited for compromised accounts
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
---
|
---
|
||||||
name: implementing-devsecops-security-scanning
|
name: implementing-devsecops-security-scanning
|
||||||
description: >
|
description: >
|
||||||
Integrate security scanning into CI/CD pipelines using tools like Semgrep,
|
Integrates Static Application Security Testing (SAST), Dynamic Application
|
||||||
Trivy, and Gitleaks. Covers SAST, SCA, container scanning, and secret
|
Security Testing (DAST), and Software Composition Analysis (SCA) into CI/CD
|
||||||
detection with structured JSON output for pipeline gates.
|
pipelines using open-source tools. Covers Semgrep for SAST, Trivy for SCA
|
||||||
|
and container scanning, OWASP ZAP for DAST, and Gitleaks for secrets
|
||||||
|
detection. Activates for requests involving DevSecOps pipeline setup,
|
||||||
|
automated security scanning in CI/CD, SAST/DAST/SCA integration, or
|
||||||
|
shift-left security implementation.
|
||||||
domain: cybersecurity
|
domain: cybersecurity
|
||||||
subdomain: application-security
|
subdomain: application-security
|
||||||
tags: [devsecops, sast, sca, container-security, ci-cd]
|
tags: [devsecops, SAST, DAST, SCA, semgrep, trivy, owasp-zap, gitleaks, CI-CD, shift-left]
|
||||||
version: "1.0"
|
version: 1.0.0
|
||||||
author: mahipal
|
author: mahipal
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
---
|
---
|
||||||
@@ -17,26 +21,32 @@ license: Apache-2.0
|
|||||||
## When to Use
|
## When to Use
|
||||||
|
|
||||||
- Setting up automated security scanning in a new or existing CI/CD pipeline
|
- Setting up automated security scanning in a new or existing CI/CD pipeline
|
||||||
- Shifting security left by catching vulnerabilities before production
|
- Shifting security left by catching vulnerabilities before code reaches production
|
||||||
- Meeting compliance requirements (SOC 2, PCI-DSS, ISO 27001) mandating automated security testing
|
- Meeting compliance requirements (SOC 2, PCI-DSS, ISO 27001) that mandate automated security testing
|
||||||
- Integrating SAST, DAST, and SCA for comprehensive application security coverage
|
- Integrating SAST, DAST, and SCA together to achieve comprehensive application security coverage
|
||||||
- Establishing security gates that block deployments with critical/high vulnerabilities
|
- Establishing security gates that block deployments containing critical or high-severity vulnerabilities
|
||||||
|
|
||||||
**Do not use** as a replacement for manual penetration testing. Automated scanning catches common patterns but cannot replace human-driven assessments for business logic flaws.
|
**Do not use** as a replacement for manual penetration testing. Automated scanning catches common vulnerability patterns but cannot replace human-driven security assessments for business logic flaws and complex attack chains.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- CI/CD platform: GitHub Actions, GitLab CI, Jenkins, or Azure DevOps
|
- CI/CD platform: GitHub Actions, GitLab CI, Jenkins, or Azure DevOps
|
||||||
- Container runtime (Docker) for running scanning tools
|
- Container runtime (Docker) for running scanning tools
|
||||||
- A staging environment URL for DAST scanning
|
- A staging environment URL for DAST scanning (DAST cannot test static code)
|
||||||
- Tool requirements: Semgrep (free), Trivy (free), OWASP ZAP (free), Gitleaks (free)
|
- Repository access with permissions to modify CI/CD workflow files
|
||||||
|
- Tool-specific requirements:
|
||||||
|
- Semgrep: free for open-source rulesets (`p/security-audit`, `p/owasp-top-ten`)
|
||||||
|
- Trivy: free, no account required
|
||||||
|
- OWASP ZAP: free, Docker image available
|
||||||
|
- Gitleaks: free, no account required
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
### Step 1: Add Secrets Detection with Gitleaks
|
### Step 1: Add Secrets Detection with Gitleaks
|
||||||
|
|
||||||
|
Secrets detection runs first because leaked credentials are the highest-priority finding. Add to `.github/workflows/security.yml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# .github/workflows/security.yml
|
|
||||||
name: DevSecOps Security Pipeline
|
name: DevSecOps Security Pipeline
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -51,15 +61,39 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0 # Full history for scanning all commits
|
||||||
|
|
||||||
- name: Run Gitleaks
|
- name: Run Gitleaks
|
||||||
uses: gitleaks/gitleaks-action@v2
|
uses: gitleaks/gitleaks-action@v2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Configure `.gitleaks.toml` in the repository root for custom rules and allowlists:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[extend]
|
||||||
|
useDefault = true
|
||||||
|
|
||||||
|
[allowlist]
|
||||||
|
description = "Global allowlist"
|
||||||
|
paths = [
|
||||||
|
'''\.gitleaks\.toml''',
|
||||||
|
'''test/fixtures/.*''',
|
||||||
|
'''docs/examples/.*'''
|
||||||
|
]
|
||||||
|
|
||||||
|
[[rules]]
|
||||||
|
id = "custom-internal-api-key"
|
||||||
|
description = "Internal API key pattern"
|
||||||
|
regex = '''INTERNAL_KEY_[A-Za-z0-9]{32}'''
|
||||||
|
tags = ["internal", "api-key"]
|
||||||
|
```
|
||||||
|
|
||||||
### Step 2: Add SAST Scanning with Semgrep
|
### Step 2: Add SAST Scanning with Semgrep
|
||||||
|
|
||||||
|
Semgrep performs static code analysis to find security vulnerabilities, bugs, and code patterns:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
sast-scan:
|
sast-scan:
|
||||||
name: SAST (Semgrep)
|
name: SAST (Semgrep)
|
||||||
@@ -68,22 +102,59 @@ jobs:
|
|||||||
image: semgrep/semgrep
|
image: semgrep/semgrep
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run Semgrep SAST scan
|
- name: Run Semgrep SAST scan
|
||||||
run: |
|
run: |
|
||||||
semgrep scan \
|
semgrep scan \
|
||||||
--config p/security-audit \
|
--config p/security-audit \
|
||||||
--config p/owasp-top-ten \
|
--config p/owasp-top-ten \
|
||||||
|
--config p/secrets \
|
||||||
--severity ERROR \
|
--severity ERROR \
|
||||||
--error \
|
--error \
|
||||||
--json --output semgrep-results.json .
|
--json \
|
||||||
- uses: actions/upload-artifact@v4
|
--output semgrep-results.json \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Upload SAST results
|
||||||
if: always()
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: semgrep-results
|
name: semgrep-results
|
||||||
path: semgrep-results.json
|
path: semgrep-results.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Add SCA and Container Scanning with Trivy
|
For custom rules, create `.semgrep/custom-rules.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
rules:
|
||||||
|
- id: no-exec-user-input
|
||||||
|
patterns:
|
||||||
|
- pattern: exec($INPUT)
|
||||||
|
- pattern-not: exec("...")
|
||||||
|
message: >
|
||||||
|
User input passed to exec(). This is a command injection vulnerability.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python]
|
||||||
|
metadata:
|
||||||
|
cwe: "CWE-78: OS Command Injection"
|
||||||
|
owasp: "A03:2021 - Injection"
|
||||||
|
|
||||||
|
- id: no-raw-sql-queries
|
||||||
|
patterns:
|
||||||
|
- pattern: cursor.execute(f"...")
|
||||||
|
- pattern: cursor.execute("..." + ...)
|
||||||
|
message: >
|
||||||
|
SQL query built with string concatenation or f-strings. Use parameterized queries.
|
||||||
|
severity: ERROR
|
||||||
|
languages: [python]
|
||||||
|
metadata:
|
||||||
|
cwe: "CWE-89: SQL Injection"
|
||||||
|
owasp: "A03:2021 - Injection"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Add SCA Scanning with Trivy
|
||||||
|
|
||||||
|
Trivy scans dependencies, container images, IaC files, and generates SBOM:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
sca-scan:
|
sca-scan:
|
||||||
@@ -91,7 +162,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Trivy filesystem scan (dependencies)
|
|
||||||
|
- name: Run Trivy filesystem scan (dependencies)
|
||||||
uses: aquasecurity/trivy-action@0.28.0
|
uses: aquasecurity/trivy-action@0.28.0
|
||||||
with:
|
with:
|
||||||
scan-type: 'fs'
|
scan-type: 'fs'
|
||||||
@@ -100,66 +172,156 @@ jobs:
|
|||||||
exit-code: '1'
|
exit-code: '1'
|
||||||
format: 'json'
|
format: 'json'
|
||||||
output: 'trivy-fs-results.json'
|
output: 'trivy-fs-results.json'
|
||||||
- name: Build and scan container image
|
|
||||||
run: |
|
- name: Run Trivy IaC scan (Terraform, CloudFormation)
|
||||||
docker build -t app:${{ github.sha }} .
|
uses: aquasecurity/trivy-action@0.28.0
|
||||||
- uses: aquasecurity/trivy-action@0.28.0
|
with:
|
||||||
|
scan-type: 'config'
|
||||||
|
scan-ref: '.'
|
||||||
|
severity: 'CRITICAL,HIGH'
|
||||||
|
exit-code: '1'
|
||||||
|
format: 'json'
|
||||||
|
output: 'trivy-iac-results.json'
|
||||||
|
|
||||||
|
- name: Upload SCA results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: trivy-results
|
||||||
|
path: trivy-*.json
|
||||||
|
|
||||||
|
container-scan:
|
||||||
|
name: Container Image Scan (Trivy)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [sast-scan] # Build image only after SAST passes
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
run: docker build -t app:${{ github.sha }} .
|
||||||
|
|
||||||
|
- name: Scan container image
|
||||||
|
uses: aquasecurity/trivy-action@0.28.0
|
||||||
with:
|
with:
|
||||||
image-ref: 'app:${{ github.sha }}'
|
image-ref: 'app:${{ github.sha }}'
|
||||||
severity: 'CRITICAL,HIGH'
|
severity: 'CRITICAL,HIGH'
|
||||||
exit-code: '1'
|
exit-code: '1'
|
||||||
|
format: 'json'
|
||||||
|
output: 'trivy-image-results.json'
|
||||||
|
|
||||||
|
- name: Generate SBOM
|
||||||
|
uses: aquasecurity/trivy-action@0.28.0
|
||||||
|
with:
|
||||||
|
image-ref: 'app:${{ github.sha }}'
|
||||||
|
format: 'cyclonedx'
|
||||||
|
output: 'sbom.json'
|
||||||
|
|
||||||
|
- name: Upload SBOM
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: sbom
|
||||||
|
path: sbom.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 4: Add DAST Scanning with OWASP ZAP
|
### Step 4: Add DAST Scanning with OWASP ZAP
|
||||||
|
|
||||||
|
DAST runs against a deployed staging environment. It is slower than SAST/SCA and should run asynchronously or on a schedule:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dast-scan:
|
dast-scan:
|
||||||
name: DAST (OWASP ZAP)
|
name: DAST (OWASP ZAP)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [deploy-staging]
|
needs: [deploy-staging] # Must run after app is deployed to staging
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: ZAP Baseline Scan
|
|
||||||
|
- name: Run ZAP Baseline Scan (fast, suitable for CI)
|
||||||
uses: zaproxy/action-baseline@v0.14.0
|
uses: zaproxy/action-baseline@v0.14.0
|
||||||
with:
|
with:
|
||||||
target: ${{ vars.STAGING_URL }}
|
target: ${{ vars.STAGING_URL }}
|
||||||
rules_file_name: '.zap/rules.tsv'
|
rules_file_name: '.zap/rules.tsv'
|
||||||
|
cmd_options: '-a -j'
|
||||||
|
|
||||||
|
# For nightly full scans, use action-full-scan instead:
|
||||||
|
# - name: Run ZAP Full Scan (comprehensive, 30-60 min)
|
||||||
|
# uses: zaproxy/action-full-scan@v0.12.0
|
||||||
|
# with:
|
||||||
|
# target: ${{ vars.STAGING_URL }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Configure `.zap/rules.tsv` alert thresholds:
|
Create `.zap/rules.tsv` to configure alert thresholds:
|
||||||
|
|
||||||
```tsv
|
```tsv
|
||||||
|
10010 IGNORE (Cookie No HttpOnly Flag - acceptable for non-sensitive cookies)
|
||||||
|
10011 IGNORE (Cookie Without Secure Flag - staging uses HTTP)
|
||||||
|
90033 WARN (Loosely Scoped Cookie)
|
||||||
|
10038 FAIL (Content Security Policy Header Not Set)
|
||||||
40012 FAIL (Cross Site Scripting - Reflected)
|
40012 FAIL (Cross Site Scripting - Reflected)
|
||||||
40014 FAIL (Cross Site Scripting - Persistent)
|
40014 FAIL (Cross Site Scripting - Persistent)
|
||||||
40018 FAIL (SQL Injection)
|
40018 FAIL (SQL Injection)
|
||||||
90019 FAIL (Server Side Code Injection)
|
90019 FAIL (Server Side Code Injection)
|
||||||
10038 FAIL (Content Security Policy Header Not Set)
|
90020 FAIL (Remote OS Command Injection)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Enforce Security Gates
|
### Step 5: Aggregate Results and Enforce Security Gates
|
||||||
|
|
||||||
|
Create a summary job that aggregates all scan results and enforces pass/fail gates:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
security-gate:
|
security-gate:
|
||||||
name: Security Gate
|
name: Security Gate
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [secrets-scan, sast-scan, sca-scan]
|
needs: [secrets-scan, sast-scan, sca-scan, container-scan]
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- name: Check scan results
|
- name: Check scan results
|
||||||
run: |
|
run: |
|
||||||
|
echo "Checking security scan results..."
|
||||||
|
|
||||||
|
# Fail the pipeline if any upstream job failed
|
||||||
if [[ "${{ needs.secrets-scan.result }}" == "failure" ]]; then
|
if [[ "${{ needs.secrets-scan.result }}" == "failure" ]]; then
|
||||||
echo "BLOCKED: Secrets detected"; exit 1
|
echo "BLOCKED: Secrets detected in repository"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${{ needs.sast-scan.result }}" == "failure" ]]; then
|
if [[ "${{ needs.sast-scan.result }}" == "failure" ]]; then
|
||||||
echo "BLOCKED: SAST critical/high findings"; exit 1
|
echo "BLOCKED: SAST found critical/high vulnerabilities"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${{ needs.sca-scan.result }}" == "failure" ]]; then
|
if [[ "${{ needs.sca-scan.result }}" == "failure" ]]; then
|
||||||
echo "BLOCKED: Vulnerable dependencies"; exit 1
|
echo "BLOCKED: SCA found critical/high vulnerable dependencies"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${{ needs.container-scan.result }}" == "failure" ]]; then
|
||||||
|
echo "BLOCKED: Container image has critical/high vulnerabilities"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "All security gates passed"
|
echo "All security gates passed"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Configure Pre-commit Hooks
|
### Step 6: Configure Branch Protection Rules
|
||||||
|
|
||||||
|
Enforce the security pipeline as a required status check:
|
||||||
|
|
||||||
|
```
|
||||||
|
GitHub Repository > Settings > Branches > Branch Protection Rules
|
||||||
|
|
||||||
|
Branch name pattern: main
|
||||||
|
Require status checks to pass before merging: Enabled
|
||||||
|
Required status checks:
|
||||||
|
- Secrets Detection (Gitleaks)
|
||||||
|
- SAST (Semgrep)
|
||||||
|
- SCA & Container Scan (Trivy)
|
||||||
|
- Security Gate
|
||||||
|
Require branches to be up to date before merging: Enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Set Up Developer Feedback Loop
|
||||||
|
|
||||||
|
Configure pre-commit hooks so developers catch issues before pushing:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# .pre-commit-config.yaml
|
# .pre-commit-config.yaml
|
||||||
@@ -168,36 +330,43 @@ repos:
|
|||||||
rev: v8.22.1
|
rev: v8.22.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: gitleaks
|
- id: gitleaks
|
||||||
|
|
||||||
- repo: https://github.com/semgrep/semgrep
|
- repo: https://github.com/semgrep/semgrep
|
||||||
rev: v1.102.0
|
rev: v1.102.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: semgrep
|
- id: semgrep
|
||||||
args: ['--config', 'p/security-audit', '--error']
|
args: ['--config', 'p/security-audit', '--config', 'p/owasp-top-ten', '--error']
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Install and activate pre-commit:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install pre-commit
|
pip install pre-commit
|
||||||
pre-commit install
|
pre-commit install
|
||||||
pre-commit run --all-files
|
pre-commit run --all-files # Test against existing codebase
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Concepts
|
## Key Concepts
|
||||||
|
|
||||||
| Term | Definition |
|
| Term | Definition |
|
||||||
|------|------------|
|
|------|------------|
|
||||||
| **SAST** | Static Application Security Testing - analyzes source code without execution |
|
| **SAST (Static Application Security Testing)** | Analyzes source code without executing it to find security vulnerabilities; runs fast, catches issues early, but cannot find runtime flaws |
|
||||||
| **DAST** | Dynamic Application Security Testing - tests running applications |
|
| **DAST (Dynamic Application Security Testing)** | Tests a running application by sending requests and analyzing responses; finds runtime issues but requires a deployed environment |
|
||||||
| **SCA** | Software Composition Analysis - scans dependencies for known vulnerabilities |
|
| **SCA (Software Composition Analysis)** | Scans project dependencies against vulnerability databases (NVD, GitHub Advisory) to find known-vulnerable libraries |
|
||||||
| **SBOM** | Software Bill of Materials - inventory of all components |
|
| **SBOM (Software Bill of Materials)** | Machine-readable inventory of all components and dependencies in an application, used for vulnerability tracking and compliance |
|
||||||
| **Shift Left** | Moving security testing earlier in the SDLC |
|
| **Shift Left** | Security practice of moving security testing earlier in the SDLC, from post-deployment to pre-commit and CI stages |
|
||||||
| **Security Gate** | CI/CD checkpoint blocking deployment on scan failures |
|
| **Security Gate** | A CI/CD pipeline checkpoint that blocks deployment if security scan results exceed defined severity thresholds |
|
||||||
|
| **Pre-commit Hook** | Local Git hook that runs security checks before code is committed, providing the fastest developer feedback loop |
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- [ ] Gitleaks blocks commits containing hardcoded secrets
|
- [ ] Gitleaks blocks commits and PRs containing hardcoded secrets (test with a dummy API key)
|
||||||
- [ ] Semgrep runs on every PR and reports findings
|
- [ ] Semgrep scan runs on every PR and reports findings as annotations or comments
|
||||||
- [ ] Trivy detects known-vulnerable dependencies
|
- [ ] Trivy filesystem scan detects a known-vulnerable dependency (test by adding a vulnerable package)
|
||||||
- [ ] OWASP ZAP baseline scan runs against staging URL
|
- [ ] Trivy container scan runs successfully against the built Docker image
|
||||||
- [ ] Security gate blocks merges when critical/high findings exist
|
- [ ] SBOM is generated and stored as a build artifact in CycloneDX or SPDX format
|
||||||
- [ ] Branch protection rules enforce required status checks
|
- [ ] OWASP ZAP baseline scan runs against the staging URL without crashing
|
||||||
- [ ] Pre-commit hooks catch issues locally before push
|
- [ ] Security gate job blocks merges to main when any scan finds critical/high severity issues
|
||||||
|
- [ ] Branch protection rules enforce required status checks before merge
|
||||||
|
- [ ] Pre-commit hooks catch secrets and SAST findings locally before push
|
||||||
|
- [ ] Developer documentation explains how to interpret scan results and fix common findings
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
---
|
---
|
||||||
name: implementing-privileged-session-monitoring
|
name: implementing-privileged-session-monitoring
|
||||||
description: >
|
description: >
|
||||||
Monitor and audit privileged user sessions including SSH, RDP, and
|
Implements privileged session monitoring and recording using Privileged Access
|
||||||
database access. Tracks session metadata, records commands, detects
|
Management (PAM) solutions, focusing on CyberArk Privileged Session Manager
|
||||||
anomalous activity, and enforces session policies for PAM compliance.
|
(PSM) and open-source alternatives. Covers session recording configuration,
|
||||||
|
keystroke logging, real-time monitoring, risk-based session analysis, and
|
||||||
|
compliance audit trail generation. Activates for requests involving privileged
|
||||||
|
session recording, PAM session monitoring, CyberArk PSM configuration,
|
||||||
|
administrator activity monitoring, or compliance session auditing.
|
||||||
domain: cybersecurity
|
domain: cybersecurity
|
||||||
subdomain: identity-access-management
|
subdomain: identity-access-management
|
||||||
tags: [pam, session-monitoring, privileged-access, audit-logging]
|
tags: [PAM, CyberArk, PSM, privileged-session, session-recording, session-monitoring, compliance]
|
||||||
version: "1.0"
|
version: 1.0.0
|
||||||
author: mahipal
|
author: mahipal
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
---
|
---
|
||||||
@@ -16,174 +20,304 @@ license: Apache-2.0
|
|||||||
|
|
||||||
## When to Use
|
## When to Use
|
||||||
|
|
||||||
- Deploying session recording for all privileged access to critical servers and databases
|
- Deploying or configuring session recording for all privileged access to critical servers and databases
|
||||||
- Meeting compliance requirements (PCI-DSS 10.2, SOX, HIPAA, ISO 27001) mandating privileged activity monitoring
|
- Meeting compliance requirements (PCI-DSS 10.2, SOX, HIPAA, ISO 27001) that mandate privileged activity monitoring
|
||||||
- Investigating incidents where an administrator may have performed unauthorized actions
|
- Investigating an incident where an administrator or third-party vendor may have performed unauthorized actions
|
||||||
- Implementing real-time alerting for high-risk commands during privileged sessions
|
- Implementing real-time alerting for high-risk commands executed during privileged sessions
|
||||||
- Establishing a forensic audit trail of all administrative actions on production infrastructure
|
- Establishing a forensic audit trail of all administrative actions on production infrastructure
|
||||||
|
|
||||||
**Do not use** for monitoring standard user sessions; use EDR/UBA for general user behavior monitoring.
|
**Do not use** for monitoring standard user sessions or endpoint activity; use EDR/UBA solutions for general user behavior monitoring. Privileged session monitoring focuses specifically on elevated-access sessions.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- CyberArk PAM or Privilege Cloud with Digital Vault, or open-source alternative (Teleport)
|
- CyberArk PAM Self-Hosted or Privilege Cloud deployment with Digital Vault configured
|
||||||
- PSM (Privileged Session Manager) or PSMP installed on hardened jump server
|
- CyberArk Privileged Session Manager (PSM) or PSM for SSH (PSMP) installed on a hardened Windows/Linux jump server
|
||||||
- Network architecture routing all privileged access through the PSM proxy
|
- Network architecture where all privileged access is routed through the PSM proxy (no direct RDP/SSH to targets)
|
||||||
- Sufficient storage for recordings (estimate: 50-250 KB/min for RDP, 5-20 KB/min for SSH)
|
- PVWA (Password Vault Web Access) deployed and accessible for session review
|
||||||
|
- Active Directory integration for authenticating PAM users
|
||||||
|
- Sufficient storage for session recordings (estimate: 50-250 KB per minute for RDP, 5-20 KB per minute for SSH)
|
||||||
|
- Alternatively for open-source: Teleport, Apache Guacamole with session recording, or `script`/`ttyrec` for Linux
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
### Step 1: Route All Privileged Access Through PSM
|
### Step 1: Architecture — Route All Privileged Access Through PSM
|
||||||
|
|
||||||
|
Ensure no direct privileged access bypasses the recording proxy:
|
||||||
|
|
||||||
```
|
```
|
||||||
Architecture:
|
Architecture Overview:
|
||||||
Admin User --> PVWA (Web Portal) --> PSM (Jump Server) --> Target Server
|
|
||||||
|
Admin User ──> PVWA (Web Portal) ──> PSM (Jump Server) ──> Target Server
|
||||||
|
│ │ │
|
||||||
|
│ Credentials never │ Session is │
|
||||||
|
│ exposed to admin │ recorded and │
|
||||||
|
│ │ stored in Vault │
|
||||||
|
└── MFA + AD Auth ──────────────────> │ │
|
||||||
|
└── RDP/SSH proxy ──>│
|
||||||
|
|
||||||
Network Controls:
|
Network Controls:
|
||||||
- DENY direct RDP (3389) / SSH (22) to targets from user networks
|
- Firewall: DENY direct RDP (3389) and SSH (22) to target servers from user networks
|
||||||
- ALLOW RDP/SSH to targets ONLY from PSM server IPs
|
- Firewall: ALLOW RDP/SSH to target servers ONLY from PSM server IPs
|
||||||
- ALLOW PVWA access (443) from admin user networks
|
- Firewall: ALLOW PVWA access (443) from admin user networks
|
||||||
|
- PSM server: Hardened, no internet access, local admin access restricted
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Configure PSM Connection Components
|
### Step 2: Configure PSM Connection Components
|
||||||
|
|
||||||
|
Define how PSM connects to target systems. In the PVWA administration console:
|
||||||
|
|
||||||
```
|
```
|
||||||
PVWA > Administration > Connection Components
|
PVWA > Administration > Configuration > Connection Components
|
||||||
|
|
||||||
For Windows RDP:
|
For Windows RDP targets:
|
||||||
Connection Component: PSM-RDP
|
Connection Component: PSM-RDP
|
||||||
Record Sessions: Yes
|
Protocol: RDP
|
||||||
Recording Format: AVI (video) + Keystrokes (text)
|
Client Application: mstsc.exe
|
||||||
Record Windows Titles: Yes
|
Recording Settings:
|
||||||
|
Record Sessions: Yes
|
||||||
|
Recording Format: AVI (video) + Keystrokes (text)
|
||||||
|
Record Windows Titles: Yes
|
||||||
|
|
||||||
For Linux SSH:
|
For Linux SSH targets:
|
||||||
Connection Component: PSM-SSH
|
Connection Component: PSM-SSH
|
||||||
Record Sessions: Yes
|
Protocol: SSH
|
||||||
Record Unix Commands: Yes
|
Client Application: PSM-SecureCRT or PSM-Putty
|
||||||
|
Recording Settings:
|
||||||
|
Record Sessions: Yes
|
||||||
|
Recording Format: AVI + Text commands
|
||||||
|
Record Unix Commands: Yes
|
||||||
|
|
||||||
|
For Database targets (SQL Server Management Studio):
|
||||||
|
Connection Component: PSM-SSMS
|
||||||
|
Protocol: Custom
|
||||||
|
Client Application: SSMS.exe
|
||||||
|
Recording Settings:
|
||||||
|
Record Sessions: Yes
|
||||||
|
Record SQL Queries: Yes (via keystroke logging)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Configure Session Recording Policies
|
### Step 3: Configure Session Recording Policies
|
||||||
|
|
||||||
```
|
Define recording rules based on risk level and compliance requirements:
|
||||||
PVWA > Platform Management > Session Management
|
|
||||||
|
|
||||||
|
```
|
||||||
|
PVWA > Administration > Platform Management > [Platform] > Session Management
|
||||||
|
|
||||||
|
Session Recording Settings:
|
||||||
Enable Session Recording: Yes
|
Enable Session Recording: Yes
|
||||||
Keystroke Logging: Enable Transcript + Window Events
|
Recording Type: Record and Save (not just Monitor)
|
||||||
Storage: Vault (encrypted, tamper-proof)
|
|
||||||
|
|
||||||
Retention periods (per compliance):
|
Keystroke Logging:
|
||||||
PCI-DSS: 1 year available, 3 months accessible
|
Enable Transcript: Yes
|
||||||
SOX: 7 years
|
Enable Window Events: Yes
|
||||||
HIPAA: 6 years
|
|
||||||
|
|
||||||
Per-Safe policies:
|
Storage:
|
||||||
Production-Servers-Admin: Record all, real-time monitoring
|
Recordings Storage Location: Vault (encrypted, tamper-proof)
|
||||||
Third-Party-Vendor-Access: Record all, dual authorization required
|
Retention Period: 90 days (adjust per compliance requirement)
|
||||||
|
|
||||||
|
PCI-DSS: Retain for 1 year, available for 3 months
|
||||||
|
SOX: Retain for 7 years
|
||||||
|
HIPAA: Retain for 6 years
|
||||||
|
|
||||||
|
Compression:
|
||||||
|
Enable Recording Compression: Yes
|
||||||
|
Compression Level: Medium (balance storage vs. quality)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 4: Enable Real-Time Monitoring and Alerting
|
For granular control, configure per-safe recording policies:
|
||||||
|
|
||||||
Configure CyberArk Privileged Threat Analytics (PTA):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
Safe: Production-Servers-Admin
|
||||||
|
Record all sessions: Yes
|
||||||
|
|
||||||
|
Safe: Development-Servers
|
||||||
|
Record all sessions: No (optional for non-production)
|
||||||
|
|
||||||
|
Safe: Third-Party-Vendor-Access
|
||||||
|
Record all sessions: Yes
|
||||||
|
Enable real-time monitoring: Yes
|
||||||
|
Require dual authorization: Yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Enable Real-Time Session Monitoring
|
||||||
|
|
||||||
|
Configure live session monitoring for SOC analysts:
|
||||||
|
|
||||||
|
```
|
||||||
|
PVWA > Monitoring > Privileged Session Monitoring
|
||||||
|
|
||||||
|
Live Monitoring Dashboard:
|
||||||
|
- Active Sessions: Shows all current privileged sessions in real-time
|
||||||
|
- Session Details: User, target, duration, risk score
|
||||||
|
- Actions Available:
|
||||||
|
- Watch: View the session in real-time (read-only)
|
||||||
|
- Suspend: Temporarily freeze the session
|
||||||
|
- Terminate: Immediately end the session
|
||||||
|
|
||||||
|
Configure monitoring alerts in CyberArk Privileged Threat Analytics (PTA):
|
||||||
|
|
||||||
PTA > Configuration > Security Events
|
PTA > Configuration > Security Events
|
||||||
|
|
||||||
Rule: High-Risk Command Detected
|
Rule: High-Risk Command Detected
|
||||||
Trigger patterns:
|
Trigger: Unix command matches pattern
|
||||||
|
Patterns:
|
||||||
- rm -rf /
|
- rm -rf /
|
||||||
- chmod 777
|
- chmod 777
|
||||||
- useradd / passwd root
|
- iptables -F
|
||||||
- wget http* | sh / curl * | bash
|
- useradd
|
||||||
|
- passwd root
|
||||||
|
- dd if=/dev/
|
||||||
|
- wget http* | sh
|
||||||
|
- curl * | bash
|
||||||
- nc -e /bin/sh
|
- nc -e /bin/sh
|
||||||
|
- python -c 'import socket,subprocess'
|
||||||
Action: Alert SOC + Flag session as high-risk
|
Action: Alert SOC + Flag session as high-risk
|
||||||
|
|
||||||
Rule: Credential Access Attempt
|
Rule: Credential Access Attempt
|
||||||
Trigger:
|
Trigger: Windows process matches
|
||||||
|
Patterns:
|
||||||
- mimikatz.exe
|
- mimikatz.exe
|
||||||
- procdump.exe targeting lsass
|
- procdump.exe targeting lsass
|
||||||
- ntdsutil.exe
|
- ntdsutil.exe
|
||||||
|
- secretsdump
|
||||||
Action: Terminate session + Alert SOC + Lock account
|
Action: Terminate session + Alert SOC + Lock account
|
||||||
|
|
||||||
Rule: Unusual Session Duration
|
Rule: Unusual Session Duration
|
||||||
Trigger: Session > 4 hours
|
Trigger: Session duration exceeds 4 hours
|
||||||
Action: Alert SOC for review
|
Action: Alert SOC for review
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Configure Session Review Workflow
|
### Step 5: Configure Session Review Workflow
|
||||||
|
|
||||||
|
Set up the post-session review process for auditors:
|
||||||
|
|
||||||
```
|
```
|
||||||
PVWA > Recordings > Search and Review
|
PVWA > Recordings > Search and Review
|
||||||
|
|
||||||
Review features:
|
Search Filters:
|
||||||
- Video playback with timeline scrubbing
|
- Date range
|
||||||
- Keystroke transcript alongside video
|
- Target server
|
||||||
- Window title log for application tracking
|
- User who initiated the session
|
||||||
- Risk events highlighted on timeline
|
- Safe name
|
||||||
|
- Session risk score (from PTA)
|
||||||
|
- Session duration
|
||||||
|
|
||||||
|
Review Workflow:
|
||||||
|
1. Auditor opens recorded session in PVWA HTML5 player
|
||||||
|
2. Video playback with timeline scrubbing
|
||||||
|
3. Keystroke transcript displayed alongside video
|
||||||
|
4. Window title log shows which applications were opened
|
||||||
|
5. Risk events are highlighted on the timeline with markers
|
||||||
|
6. Auditor marks session as: Reviewed-OK, Reviewed-Suspicious, or Requires-Investigation
|
||||||
|
|
||||||
|
Fast-Forward Features:
|
||||||
|
- Jump to keystrokes (skip idle time)
|
||||||
|
- Jump to risk events (flagged by PTA)
|
||||||
- Text search within keystroke transcript
|
- Text search within keystroke transcript
|
||||||
- Auditor can mark: Reviewed-OK, Suspicious, Requires-Investigation
|
- Filter by window title changes
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Open-Source Alternative - Teleport
|
### Step 6: Open-Source Alternative — Teleport for Session Recording
|
||||||
|
|
||||||
|
For environments without CyberArk, Teleport provides session recording for SSH, RDP, and Kubernetes:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# /etc/teleport.yaml
|
# /etc/teleport.yaml - Session recording configuration
|
||||||
teleport:
|
teleport:
|
||||||
nodename: teleport-proxy.corp.internal
|
nodename: teleport-proxy.corp.internal
|
||||||
|
data_dir: /var/lib/teleport
|
||||||
|
|
||||||
auth_service:
|
auth_service:
|
||||||
enabled: yes
|
enabled: yes
|
||||||
session_recording: "node-sync"
|
session_recording: "node-sync" # Record at the node level, sync to auth server
|
||||||
|
|
||||||
|
# Session recording storage (S3 for production)
|
||||||
audit_sessions_uri: "s3://teleport-session-recordings/sessions?region=us-east-1"
|
audit_sessions_uri: "s3://teleport-session-recordings/sessions?region=us-east-1"
|
||||||
|
|
||||||
|
# Enhanced session recording (captures commands even in nested shells)
|
||||||
enhanced_recording:
|
enhanced_recording:
|
||||||
enabled: true
|
enabled: true
|
||||||
command_events: true
|
command_events: true
|
||||||
network_events: true
|
network_events: true
|
||||||
|
disk_events: true
|
||||||
|
|
||||||
|
ssh_service:
|
||||||
|
enabled: yes
|
||||||
|
enhanced_recording:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
proxy_service:
|
||||||
|
enabled: yes
|
||||||
|
web_listen_addr: 0.0.0.0:443
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Query recorded sessions with `tsh`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List recorded sessions
|
# List recorded sessions
|
||||||
tsh recordings ls --from=2026-03-15
|
tsh recordings ls --from=2026-03-15 --to=2026-03-19
|
||||||
|
|
||||||
# Play back a session
|
# Play back a specific session
|
||||||
tsh play <session-id>
|
tsh play <session-id>
|
||||||
|
|
||||||
# Export session events for SIEM
|
# Export session events as JSON (for SIEM ingestion)
|
||||||
tsh recordings export <session-id> --format=json > session_events.json
|
tsh recordings export <session-id> --format=json > session_events.json
|
||||||
|
|
||||||
|
# Search for sessions containing specific commands
|
||||||
|
tsh recordings ls --query='command == "rm -rf"'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 7: Forward Session Metadata to SIEM
|
### Step 7: Forward Session Metadata to SIEM
|
||||||
|
|
||||||
```
|
Send session events and alerts to the SIEM for correlation with other security data:
|
||||||
CyberArk PTA > SIEM Integration
|
|
||||||
Protocol: TCP + TLS (Syslog CEF)
|
|
||||||
Destination: siem.corp.internal:6514
|
|
||||||
|
|
||||||
Events forwarded:
|
```
|
||||||
- Session start/stop with user, target, duration
|
CyberArk PTA Integration:
|
||||||
- High-risk command alerts
|
SIEM Connector: Syslog (CEF format) or REST API
|
||||||
|
Target: Splunk, Microsoft Sentinel, QRadar, or Elastic
|
||||||
|
|
||||||
|
Events Forwarded:
|
||||||
|
- Session start/stop with user, target, and duration
|
||||||
|
- High-risk command detection alerts
|
||||||
- Session termination events
|
- Session termination events
|
||||||
- Dual-authorization approvals/denials
|
- Failed connection attempts
|
||||||
|
- Dual-authorization requests and approvals/denials
|
||||||
|
|
||||||
|
Syslog Configuration (PTA):
|
||||||
|
PTA > Configuration > SIEM Integration
|
||||||
|
Protocol: TCP + TLS
|
||||||
|
Destination: siem.corp.internal:6514
|
||||||
|
Format: CEF (Common Event Format)
|
||||||
|
|
||||||
|
Example CEF Event:
|
||||||
|
CEF:0|CyberArk|PTA|12.6|HighRiskCommand|High Risk Command Detected|8|
|
||||||
|
src=10.1.5.42 suser=admin1 dhost=prod-db-01 cs1=rm -rf /var/log
|
||||||
|
cs2=PSM-SSH cs3=Production-Servers-Admin
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Concepts
|
## Key Concepts
|
||||||
|
|
||||||
| Term | Definition |
|
| Term | Definition |
|
||||||
|------|------------|
|
|------|------------|
|
||||||
| **PSM** | Privileged Session Manager - proxy recording all sessions in video and text |
|
| **PSM (Privileged Session Manager)** | CyberArk component that acts as a proxy/jump server, recording all privileged sessions in video and text format |
|
||||||
| **PSMP** | PSM for SSH Proxy - Linux-based proxy for SSH, SCP, SFTP sessions |
|
| **PSMP (PSM for SSH Proxy)** | Linux-based PSM proxy specifically for SSH, SCP, and SFTP sessions |
|
||||||
| **PTA** | Privileged Threat Analytics - behavioral analytics and risk scoring for sessions |
|
| **Connection Component** | CyberArk configuration that defines how PSM launches client applications (RDP, SSH, SSMS) to connect to target systems |
|
||||||
| **Dual Authorization** | Two authorized users must approve before a privileged session is established |
|
| **Privileged Threat Analytics (PTA)** | CyberArk module that applies behavioral analytics and risk scoring to recorded sessions to detect anomalous activity |
|
||||||
| **Session Isolation** | All admin access proxied through PAM; no direct connections to targets |
|
| **Dual Authorization** | Security control requiring two authorized users to approve a privileged session before it is established |
|
||||||
| **Keystroke Transcript** | Searchable text log of all keystrokes during a recorded session |
|
| **Session Isolation** | Architecture principle where administrators never directly connect to targets; all access is proxied through the PAM system |
|
||||||
|
| **Keystroke Transcript** | Text log of all keystrokes typed during a recorded session, searchable for audit and forensic purposes |
|
||||||
|
| **Vaulting** | Storing privileged credentials in an encrypted digital vault so they are never exposed to the end user |
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- [ ] All privileged access routes through PSM (direct RDP/SSH blocked by firewall)
|
- [ ] All privileged access to production targets routes through PSM (direct RDP/SSH is blocked by firewall)
|
||||||
- [ ] Session recordings stored encrypted with tamper protection
|
- [ ] Session recordings are being stored in the Vault with encryption and tamper protection
|
||||||
- [ ] Keystroke transcripts captured and searchable for SSH and RDP
|
- [ ] Keystroke transcripts are captured and searchable for SSH and RDP sessions
|
||||||
- [ ] PTA rules trigger alerts for high-risk commands (test with benign trigger)
|
- [ ] PTA rules trigger alerts for high-risk commands (test with a benign trigger pattern)
|
||||||
- [ ] Real-time monitoring dashboard shows active sessions with correct metadata
|
- [ ] Real-time monitoring dashboard shows active sessions with correct metadata
|
||||||
- [ ] Recordings play back in PVWA HTML5 player with timeline and transcript
|
- [ ] Session recordings play back correctly in PVWA HTML5 player with timeline and transcript
|
||||||
- [ ] Retention policies match compliance requirements
|
- [ ] Storage estimates are validated and retention policies match compliance requirements
|
||||||
- [ ] Dual authorization enforced for vendor and high-risk access
|
- [ ] Dual authorization is enforced for vendor and high-risk target access
|
||||||
- [ ] Session metadata and alerts forwarding to SIEM
|
- [ ] Session metadata and alerts are forwarding to SIEM and correlating correctly
|
||||||
|
- [ ] Auditors can search, review, and annotate sessions through the PVWA interface
|
||||||
|
- [ ] Terminated sessions leave a complete recording up to the point of termination
|
||||||
|
|||||||
Reference in New Issue
Block a user