deception technology

Deploying Active Directory Honeytokens

Deploys deception-based honeytokens in Active Directory including fake privileged accounts with AdminCount=1, fake SPNs for Kerberoasting detection (honeyroasting), decoy GPOs with cpassword traps, and fake BloodHound paths. Monitors Windows Security Event IDs 4769, 4625, 4662, 5136 for honeytoken interaction. Use when implementing AD deception defenses for detecting lateral movement, credential theft, and reconnaissance.

active-directorybloodhounddeceptiondetectiongpohoneytokenskerberoasting
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When deploying deception-based detection in Active Directory environments
  • When detecting Kerberoasting attacks via fake SPN honeytokens (honeyroasting)
  • When creating tripwire accounts to detect credential theft and lateral movement
  • When building decoy GPOs to detect Group Policy Preference password harvesting
  • When creating deceptive BloodHound paths to misdirect and detect attackers
  • When supplementing existing AD monitoring with high-fidelity detection signals

Prerequisites

  • Domain Admin or delegated AD administration privileges
  • Active Directory domain (Windows Server 2016+ recommended)
  • Windows Event Log forwarding to SIEM (Splunk, Sentinel, Elastic)
  • PowerShell 5.1+ with ActiveDirectory module
  • Group Policy Management Console (GPMC)
  • Understanding of AD security, Kerberos, and BloodHound attack paths

Background

Why AD Honeytokens

Traditional signature-based detection misses novel attack techniques. Honeytokens provide high-fidelity detection with near-zero false positives because any interaction with a decoy object is inherently suspicious. In Active Directory:

  • Fake privileged accounts detect credential dumping (DCSync, NTDS.dit extraction)
  • Fake SPNs detect Kerberoasting reconnaissance (TGS requests for nonexistent services)
  • Decoy GPOs detect Group Policy Preference password harvesting
  • Fake BloodHound paths mislead attackers using graph-based AD analysis

Key Detection Event IDs

Event ID Description Honeytoken Use
4769 Kerberos TGS ticket requested Detect Kerberoast against honey SPN
4625 Failed logon attempt Detect use of fake credentials from decoy GPO
4662 Directory service object accessed Detect DACL read on honeytoken user
5136 Directory service object modified Detect modification of decoy GPO
5137 Directory service object created Detect GPO creation mimicking decoy
4768 Kerberos TGT requested Detect AS-REP roasting of honey account

Making Honeytokens Realistic

Per Trimarc Security research, effective honeytokens must appear legitimate:

  • Age the account: Repurpose old inactive accounts (10-15 year old accounts in similarly aged domains appear authentic)
  • Set AdminCount=1: Flags the account as having elevated AD rights, making it an attractive Kerberoasting target
  • Use realistic naming: Match organizational naming conventions (svc_sqlbackup, admin.maintenance, svc_exchange_legacy)
  • Set old password date: Password age of 10+ years with an SPN looks like a high-value, neglected service account to attackers
  • Add group memberships: Place in visible groups like "Remote Desktop Users" or a custom "Backup Operators" to increase attacker interest
  • Avoid detection tells: Attackers check creation date vs. last logon vs. password change date for consistency

Instructions

Step 1: Deploy Fake Privileged Admin Account

Create a honeytoken account that mimics a legacy privileged service account.

# Import the deployment module
Import-Module .\scripts\Deploy-ADHoneytokens.ps1
 
# Create a honeytoken admin account
$honeyAdmin = New-HoneytokenAdmin `
    -SamAccountName "svc_sqlbackup_legacy" `
    -DisplayName "SQL Backup Service (Legacy)" `
    -Description "Legacy SQL Server backup service account - DO NOT DELETE" `
    -OU "OU=Service Accounts,DC=corp,DC=example,DC=com" `
    -PasswordLength 128 `
    -SetAdminCount $true
 
Write-Host "Honeytoken admin created: $($honeyAdmin.DistinguishedName)"

Step 2: Deploy Fake SPN for Kerberoasting Detection

Assign a realistic but fake SPN to the honeytoken account. Any TGS request for this SPN is definitively malicious (honeyroasting).

# Add fake SPN to honeytoken account
$honeySPN = Add-HoneytokenSPN `
    -SamAccountName "svc_sqlbackup_legacy" `
    -ServiceClass "MSSQLSvc" `
    -Hostname "sql-legacy-bak01.corp.example.com" `
    -Port 1433
 
Write-Host "Honey SPN registered: $($honeySPN.SPN)"
Write-Host "Monitor Event ID 4769 for TGS requests targeting this SPN"

Step 3: Deploy Decoy GPO with Credential Trap

Create a fake GPO in SYSVOL with an embedded cpassword (Group Policy Preference password). Attackers using tools like Get-GPPPassword or gpp-decrypt will find and attempt to use these credentials, triggering detection.

# Create decoy GPO with cpassword trap
$decoyGPO = New-DecoyGPO `
    -GPOName "Server Maintenance Policy (Legacy)" `
    -DecoyUsername "admin_maintenance" `
    -DecoyDomain "CORP" `
    -SYSVOLPath "\\corp.example.com\SYSVOL\corp.example.com\Policies" `
    -EnableAuditSACL $true
 
Write-Host "Decoy GPO created: $($decoyGPO.GPOGuid)"
Write-Host "SACL audit enabled - any read attempt will generate Event ID 4663"

Step 4: Create Deceptive BloodHound Paths

Set ACL permissions that create fake attack paths visible to BloodHound/SharpHound reconnaissance, leading attackers toward monitored honeytokens.

# Create fake BloodHound attack path
$deceptivePath = New-DeceptiveBloodHoundPath `
    -HoneytokenSamAccount "svc_sqlbackup_legacy" `
    -TargetHighValueGroup "Domain Admins" `
    -IntermediateOU "OU=Service Accounts,DC=corp,DC=example,DC=com"
 
Write-Host "Deceptive path created: $($deceptivePath.PathDescription)"

Step 5: Configure Detection Rules

Set up SIEM detection rules to alert on any honeytoken interaction.

# Using the Python detection agent
from agent import ADHoneytokenMonitor
 
monitor = ADHoneytokenMonitor(config_path="honeytoken_config.json")
 
# Register all honeytokens for monitoring
monitor.register_honeytoken("svc_sqlbackup_legacy", token_type="admin_account")
monitor.register_honeytoken("MSSQLSvc/sql-legacy-bak01.corp.example.com:1433", token_type="spn")
monitor.register_honeytoken("admin_maintenance", token_type="gpo_credential")
 
# Generate SIEM detection rules
splunk_rules = monitor.generate_detection_rules(siem="splunk")
sentinel_rules = monitor.generate_detection_rules(siem="sentinel")
sigma_rules = monitor.generate_detection_rules(siem="sigma")
 
for rule in sigma_rules:
    print(f"Rule: {rule['title']}")
    print(f"  Detection: {rule['detection_logic']}")

Step 6: Validate Deployment

Test the honeytokens to ensure detection fires correctly.

# Validate honeytoken deployment
$validation = Test-HoneytokenDeployment `
    -SamAccountName "svc_sqlbackup_legacy" `
    -ValidateAdminCount `
    -ValidateSPN `
    -ValidateGPODecoy `
    -ValidateAuditPolicy
 
$validation | Format-Table Check, Status, Details -AutoSize

Examples

Full Deployment Pipeline

Import-Module .\scripts\Deploy-ADHoneytokens.ps1
 
# Deploy complete honeytoken suite
$deployment = Deploy-FullHoneytokenSuite `
    -Environment "Production" `
    -ServiceAccountOU "OU=Service Accounts,DC=corp,DC=example,DC=com" `
    -SYSVOLPath "\\corp.example.com\SYSVOL\corp.example.com\Policies" `
    -TokenCount 3 `
    -IncludeSPN $true `
    -IncludeGPODecoy $true `
    -IncludeBloodHoundPath $true `
    -SIEMType "Splunk"
 
# Output deployment report
$deployment.Tokens | Format-Table Name, Type, SPN, DetectionRule -AutoSize
$deployment | Export-Csv "honeytoken_deployment_report.csv" -NoTypeInformation

Kerberoasting Detection Query (Splunk)

index=wineventlog EventCode=4769 ServiceName="svc_sqlbackup_legacy"
| eval alert_severity="critical"
| eval alert_type="honeytoken_kerberoast"
| table _time, src_ip, Account_Name, ServiceName, Ticket_Encryption_Type
| sort - _time

Microsoft Sentinel KQL Detection

SecurityEvent
| where EventID == 4769
| where ServiceName in ("svc_sqlbackup_legacy", "svc_exchange_legacy")
| extend AlertType = "Honeytoken Kerberoast Detected"
| project TimeGenerated, Computer, Account, ServiceName, IpAddress, TicketEncryptionType

References

Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md11.7 KB

API Reference: Active Directory Honeytoken Deployment

PowerShellGenerator

Generates PowerShell scripts for AD honeytoken deployment operations.

Methods

generate_create_honeytoken_account(...)

Generate PowerShell to create a honeytoken AD account with AdminCount=1, backdated password, group memberships, and SACL audit rules.

Parameter Type Default Description
sam_account_name str required sAMAccountName for the honeytoken
display_name str required Display name
description str required Description field
ou_dn str required Distinguished Name of target OU
password_length int 128 Random password length
set_admin_count bool True Set AdminCount=1
account_age_days int 5475 Days to backdate password (~15 years)

Returns: str -- Complete PowerShell script.

AD Operations Performed:

  • Creates AD user account with strong random password
  • Sets AdminCount=1 (appears as privileged account to BloodHound)
  • Backdates pwdLastSet to simulate aged service account
  • Adds to Remote Desktop Users group
  • Configures SACL audit rule (Everyone/ReadProperty/Success)

Detection: Event ID 4662 (directory service object accessed)

generate_add_honey_spn(...)

Generate PowerShell to add a fake SPN for Kerberoasting detection (honeyroasting).

Parameter Type Default Description
sam_account_name str required Account to add SPN to
service_class str "MSSQLSvc" SPN service class
hostname str required Fake hostname
port int 1433 Service port

Returns: str -- PowerShell script that registers the SPN and enables RC4+AES encryption.

Detection: Event ID 4769 (Kerberos TGS ticket requested) where ServiceName matches the honeytoken account. Any TGS request for this SPN is definitively malicious.

generate_decoy_gpo(...)

Generate PowerShell to create a decoy GPO with cpassword credential trap in SYSVOL.

Parameter Type Default Description
gpo_name str required GPO display name
decoy_username str required Username in cpassword trap
decoy_domain str required Short domain name (e.g., CORP)
sysvol_path str required SYSVOL Policies path
enable_sacl bool True Set SACL audit on GPO folder

Returns: str -- PowerShell script that creates GPO folder structure, plants Groups.xml with cpassword, creates trap AD account with different password, and sets SACL.

Detection Chain:

  1. Event ID 4663 (SYSVOL folder read)
  2. Offline: Attacker decrypts cpassword
  3. Event ID 4625 (failed logon with decoy credentials)
  4. Correlation: 4663 + 4625 from same source IP = confirmed attacker

generate_deceptive_bloodhound_path(...)

Generate PowerShell to create fake BloodHound attack paths leading to monitored honeytokens.

Parameter Type Default Description
honeytoken_sam str required Honeytoken account name
target_group str "Domain Admins" High-value group for deceptive path
intermediate_ou str "OU=Service Accounts" OU for intermediate objects

Returns: str -- PowerShell script that creates GenericAll ACE, deceptive intermediate group, and WriteDacl edge with deny safety net.

BloodHound Path Created:

Remote Desktop Users -[GenericAll]-> honeytoken_account
honeytoken_account -[MemberOf]-> IT-Infrastructure-Admins
honeytoken_account -[WriteDacl]-> Domain Admins (blocked by deny ACE)

generate_validation_script(sam_account_name)

Generate PowerShell to validate honeytoken deployment integrity.

Checks Performed:

Check Pass Criteria
Account Exists Account found in AD
Account Enabled Enabled = True
AdminCount=1 AdminCount attribute is 1
SPN Configured At least one SPN registered
Password Age > 365 days
SACL Audit At least one audit rule configured
Group Memberships Lists all group memberships
RC4 Supported msDS-SupportedEncryptionTypes includes 0x4
Kerberos Audit auditpol shows Kerberos TGS auditing enabled

SIEMRuleGenerator

Generates detection rules for SIEM platforms targeting honeytoken activity.

Methods

generate_detection_rules(honeytoken_accounts, honey_spns, gpo_trap_accounts, siem="sigma")

Parameter Type Description
honeytoken_accounts list[str] Account names to monitor
honey_spns list[str] SPN values to monitor
gpo_trap_accounts list[str] GPO credential trap usernames
siem str Target platform: sigma, splunk, or sentinel

Returns: list[dict] -- Each rule contains title, detection_logic, and rule (full query text).

Generated Rules by Platform

Sigma Rules:

Rule Event ID MITRE Technique
Honeytoken Kerberoast Detected 4769 T1558.003
Honeytoken GPO Credential Use Detected 4624, 4625 T1552.006
Honeytoken AD Object Accessed 4662 T1087.002

Splunk SPL Rules:

Rule Description
Honeytoken Kerberoast Detection Index wineventlog EventCode=4769 with ServiceName filter
Honeytoken GPO Credential Use EventCode 4624/4625 with TargetUserName filter
Attack Chain Correlation SYSVOL enum (4663) -> credential use (4625) by same source IP

Microsoft Sentinel KQL Rules:

Rule Description
Honeytoken Kerberoast Detection SecurityEvent EventID 4769 with ServiceName filter
Honeytoken GPO Credential Use SecurityEvent EventID 4624/4625 with TargetUserName filter

export_rules(output_dir, format="json")

Export all generated rules to files on disk.

Returns: list[str] of saved file paths.


ADHoneytokenMonitor

Monitors Windows Event Logs for honeytoken interactions and generates alerts.

Constructor

ADHoneytokenMonitor(config_path=None)

Methods

register_honeytoken(identifier, token_type="admin_account", metadata=None)

Register a honeytoken for monitoring.

Token Type Description
admin_account Fake privileged AD account
spn Fake Service Principal Name
gpo_credential Decoy GPO cpassword trap account

analyze_event_log(events)

Analyze Windows Event Log entries for honeytoken interactions.

Event ID Alert Type Severity
4769 KERBEROAST_HONEYTOKEN critical
4624 HONEYTOKEN_LOGON critical
4625 HONEYTOKEN_LOGON_FAILED critical
4662 HONEYTOKEN_DACL_READ high
5136 HONEYTOKEN_GPO_MODIFIED critical

Returns: list[dict] -- Alerts with alert_id, alert_type, severity, description, mitre_technique, source_ip, source_host.

generate_detection_rules(siem="sigma")

Generate SIEM detection rules for all registered honeytokens.

get_alert_summary()

Get aggregated summary of all alerts by severity, type, and source IP.


HoneytokenDeployer

Orchestrates full honeytoken deployment and generates all artifacts.

Constructor

HoneytokenDeployer(domain="corp.example.com",
                   service_account_ou="OU=Service Accounts",
                   sysvol_path="")

Methods

generate_realistic_name()

Generate a realistic service account name using templates matching common organizational patterns.

Returns: dict with sam_account_name, display_name, hostname.

deploy_full_suite(...)

Generate complete deployment artifacts for a full honeytoken suite.

Parameter Type Default Description
token_count int 3 Number of honeytoken accounts
include_spn bool True Add fake SPNs
include_gpo bool True Create decoy GPO
include_bloodhound bool True Create deceptive BloodHound paths
siem_type str "sigma" Target SIEM for detection rules

Returns: dict with deployment_id, tokens, scripts, detection_rules.

save_deployment(deployment, output_dir)

Save all deployment artifacts (PowerShell scripts, detection rules, manifest) to disk.

Returns: list[str] of saved file paths.


PowerShell Module: Deploy-ADHoneytokens.ps1

Exported Functions

Function Description
New-HoneytokenAdmin Create honeytoken AD account with AdminCount=1, SACL, backdated password
Add-HoneytokenSPN Register fake SPN for Kerberoasting detection
New-DecoyGPO Create decoy GPO with cpassword trap in SYSVOL
New-DeceptiveBloodHoundPath Create fake BloodHound attack paths
Test-HoneytokenDeployment Validate honeytoken deployment integrity
Deploy-FullHoneytokenSuite Deploy complete honeytoken suite

Prerequisites

#Requires -Modules ActiveDirectory
#Requires -Version 5.1

Windows Event IDs for Honeytoken Detection

Event ID Description Honeytoken Use
4769 Kerberos TGS ticket requested Kerberoast against honey SPN
4768 Kerberos TGT requested AS-REP roasting of honey account
4625 Failed logon attempt Credential use from decoy GPO
4624 Successful logon Honeytoken account compromise
4662 Directory service object accessed DACL read on honeytoken user
4648 Logon with explicit credentials Pass-the-hash detection
5136 Directory service object modified GPO modification
5137 Directory service object created GPO creation
4663 Attempt to access object SYSVOL decoy file read

CLI Usage

# Full deployment (generates all scripts, rules, and manifest)
python agent.py --action full_deploy \
    --domain corp.example.com \
    --ou "OU=Service Accounts" \
    --token-count 3 \
    --siem sigma \
    --output-dir honeytoken_deployment
 
# Generate detection rules only
python agent.py --action generate_rules \
    --account-name svc_sqlbackup_legacy \
    --siem splunk
 
# Generate single account creation script
python agent.py --action deploy_account \
    --account-name svc_sqlbackup_legacy \
    --domain corp.example.com
 
# Generate SPN addition script
python agent.py --action deploy_spn \
    --account-name svc_sqlbackup_legacy
 
# Generate decoy GPO script
python agent.py --action deploy_gpo \
    --domain corp.example.com
 
# Generate BloodHound deception script
python agent.py --action deploy_bloodhound \
    --account-name svc_sqlbackup_legacy
 
# Validate deployment
python agent.py --action validate \
    --account-name svc_sqlbackup_legacy
 
# Analyze event logs for honeytoken alerts
python agent.py --action analyze_logs \
    --account-name svc_sqlbackup_legacy \
    --event-log events.json

CLI Arguments

Argument Default Description
--action full_deploy Action to perform
--domain corp.example.com AD domain FQDN
--ou OU=Service Accounts OU for honeytoken accounts
--sysvol auto SYSVOL Policies path
--account-name svc_sqlbackup_legacy Honeytoken account name
--token-count 3 Number of honeytokens to deploy
--siem sigma Target SIEM: sigma, splunk, sentinel
--output-dir honeytoken_deployment Output directory
--include-spn True Include fake SPNs
--include-gpo True Include decoy GPO
--include-bloodhound True Include BloodHound deception
--event-log None Path to event log JSON for analysis

Scripts 2

agent.py52.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Active Directory Honeytoken Deployment and Monitoring Agent.

Deploys deception-based honeytokens in Active Directory: fake privileged accounts
with AdminCount=1, fake SPNs for Kerberoasting detection (honeyroasting), decoy
GPOs with cpassword traps, and deceptive BloodHound paths. Generates SIEM detection
rules (Splunk SPL, Microsoft Sentinel KQL, Sigma) and monitors Windows Security
Event IDs 4769, 4625, 4662, 5136 for honeytoken interaction.

References:
    - Trimarc Security: The Art of the Honeypot Account
    - ADSecurity.org: Detecting Kerberoasting Activity Part 2
    - Microsoft Defender for Identity Honeytokens
    - SpecterOps: Kerberoasting and AES-256
    - APT29a Blog: Deploying Honeytokens in AD
"""

import os
import json
import uuid
import base64
import hashlib
import argparse
import secrets
import string
import subprocess
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any

# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------

# Windows Security Event IDs relevant to honeytoken detection
EVENT_IDS = {
    4769: "Kerberos TGS ticket requested (Kerberoasting detection)",
    4768: "Kerberos TGT requested (AS-REP roasting detection)",
    4625: "Failed logon attempt (credential use from decoy GPO)",
    4662: "Directory service object accessed (DACL read on honeytoken)",
    5136: "Directory service object modified (GPO modification)",
    5137: "Directory service object created (GPO creation)",
    4663: "Attempt to access object (SYSVOL decoy file read)",
    4624: "Successful logon (honeytoken account used)",
    4648: "Logon with explicit credentials (pass-the-hash detection)",
}

# Kerberos encryption types
KERBEROS_ENCRYPTION = {
    0x17: "RC4-HMAC (legacy, weak - easy to crack)",
    0x12: "AES256-CTS-HMAC-SHA1 (strong)",
    0x11: "AES128-CTS-HMAC-SHA1 (moderate)",
}

# Realistic service account naming patterns
SERVICE_ACCOUNT_TEMPLATES = [
    {"prefix": "svc_", "services": [
        "sqlbackup", "exchange_legacy", "sharepoint_crawl", "adfs_proxy",
        "scom_monitoring", "sccm_push", "wsus_sync", "dns_update",
        "print_spool", "backup_exec", "veeam_proxy", "citrix_sf",
    ]},
    {"prefix": "admin.", "services": [
        "maintenance", "helpdesk_legacy", "deployment", "monitoring",
    ]},
    {"prefix": "", "services": [
        "ScanService", "ReportRunner", "TaskScheduler", "AutomationSvc",
    ]},
]

# Realistic SPN service classes
SPN_SERVICE_CLASSES = [
    "MSSQLSvc",     # SQL Server
    "HTTP",         # Web services / IIS
    "TERMSRV",      # Terminal Services
    "exchangeMDB",  # Exchange
    "FIMService",   # Forefront Identity Manager
    "WSMAN",        # WS-Management
    "mongodb",      # MongoDB
    "postgres",     # PostgreSQL
    "oracle",       # Oracle DB
]

# GPP cpassword AES key (publicly known, documented by Microsoft)
# This is the well-known AES key that Microsoft published and was used
# for Group Policy Preference passwords. It is public knowledge.
GPP_AES_KEY_B64 = "4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b"


# ===========================================================================
# PowerShell Script Generator
# ===========================================================================

class PowerShellGenerator:
    """Generates PowerShell scripts for AD honeytoken deployment."""

    @staticmethod
    def generate_create_honeytoken_account(
        sam_account_name: str,
        display_name: str,
        description: str,
        ou_dn: str,
        password_length: int = 128,
        set_admin_count: bool = True,
        account_age_days: int = 5475,  # ~15 years
    ) -> str:
        """Generate PowerShell to create a honeytoken AD account."""
        return f'''# ============================================================
# Create Honeytoken Admin Account in Active Directory
# Reference: Trimarc Security - The Art of the Honeypot Account
# ============================================================

Import-Module ActiveDirectory

# Generate a strong random password (never actually used for login)
$PasswordLength = {password_length}
$Password = -join ((33..126) | Get-Random -Count $PasswordLength | ForEach-Object {{ [char]$_ }})
$SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

# Create the honeytoken account
$HoneyParams = @{{
    Name              = "{display_name}"
    SamAccountName    = "{sam_account_name}"
    UserPrincipalName = "{sam_account_name}@$((Get-ADDomain).DNSRoot)"
    DisplayName       = "{display_name}"
    Description       = "{description}"
    Path              = "{ou_dn}"
    AccountPassword   = $SecurePassword
    Enabled           = $true
    PasswordNeverExpires = $true
    CannotChangePassword = $true
    ChangePasswordAtLogon = $false
}}

try {{
    New-ADUser @HoneyParams -ErrorAction Stop
    Write-Host "[+] Honeytoken account created: {sam_account_name}" -ForegroundColor Green
}} catch {{
    Write-Host "[-] Failed to create account: $_" -ForegroundColor Red
    exit 1
}}

# Set AdminCount=1 to make it look like a privileged account
# Attackers using BloodHound/SharpHound will see this as high-value
{"" if not set_admin_count else f"""
Set-ADUser -Identity "{sam_account_name}" -Replace @{{AdminCount = 1}}
Write-Host "[+] AdminCount set to 1 (appears as privileged account)" -ForegroundColor Green
"""}

# Age the account by backdating the whenCreated-related attributes
# We modify the pwdLastSet to simulate an old password
$AgeDate = (Get-Date).AddDays(-{account_age_days})
$FileTime = $AgeDate.ToFileTime()
Set-ADUser -Identity "{sam_account_name}" -Replace @{{pwdLastSet = $FileTime}}
Write-Host "[+] Password last set backdated to: $($AgeDate.ToString('yyyy-MM-dd'))" -ForegroundColor Green

# Add to visible but non-critical groups to increase attacker interest
Add-ADGroupMember -Identity "Remote Desktop Users" -Members "{sam_account_name}"
Write-Host "[+] Added to Remote Desktop Users group" -ForegroundColor Green

# Enable auditing on the honeytoken account (SACL)
$UserDN = (Get-ADUser -Identity "{sam_account_name}").DistinguishedName
$Acl = Get-Acl "AD:\\$UserDN"
$AuditRule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule(
    [System.Security.Principal.SecurityIdentifier]"S-1-1-0",  # Everyone
    [System.DirectoryServices.ActiveDirectoryRights]"ReadProperty",
    [System.Security.AccessControl.AuditFlags]"Success",
    [System.DirectoryServices.ActiveDirectorySecurityInheritance]"None"
)
$Acl.AddAuditRule($AuditRule)
Set-Acl "AD:\\$UserDN" $Acl
Write-Host "[+] SACL audit rule set - any read triggers Event ID 4662" -ForegroundColor Green

Write-Host ""
Write-Host "[+] Honeytoken deployment complete: {sam_account_name}" -ForegroundColor Cyan
Write-Host "[+] Monitor Event IDs: 4662 (object access), 4624/4625 (logon attempts)" -ForegroundColor Cyan
'''

    @staticmethod
    def generate_add_honey_spn(
        sam_account_name: str,
        service_class: str = "MSSQLSvc",
        hostname: str = "sql-legacy-bak01.corp.example.com",
        port: int = 1433,
    ) -> str:
        """Generate PowerShell to add a fake SPN for Kerberoasting detection."""
        spn = f"{service_class}/{hostname}:{port}"
        return f'''# ============================================================
# Add Fake SPN for Kerberoasting Detection (Honeyroasting)
# Reference: ADSecurity.org - Detecting Kerberoasting Activity Part 2
# ============================================================

Import-Module ActiveDirectory

$SPN = "{spn}"
$Account = "{sam_account_name}"

# Verify the account exists
$User = Get-ADUser -Identity $Account -Properties ServicePrincipalNames -ErrorAction Stop
if (-not $User) {{
    Write-Host "[-] Account not found: $Account" -ForegroundColor Red
    exit 1
}}

# Add the fake SPN
# This SPN points to a nonexistent service - any TGS request is definitively malicious
Set-ADUser -Identity $Account -ServicePrincipalNames @{{Add = $SPN}}
Write-Host "[+] Honey SPN registered: $SPN" -ForegroundColor Green

# Verify SPN was set
$Updated = Get-ADUser -Identity $Account -Properties ServicePrincipalNames
Write-Host "[+] Current SPNs for $Account :" -ForegroundColor Cyan
$Updated.ServicePrincipalNames | ForEach-Object {{ Write-Host "    $_" }}

# Ensure RC4 is not disabled (attackers target RC4 for easier cracking)
# This makes the honeytoken more attractive to Kerberoast tools
$EncTypes = (Get-ADUser -Identity $Account -Properties "msDS-SupportedEncryptionTypes")."msDS-SupportedEncryptionTypes"
if ($null -eq $EncTypes -or ($EncTypes -band 0x4) -eq 0) {{
    # Set to support RC4 + AES128 + AES256 (0x4 + 0x8 + 0x10 = 0x1C)
    Set-ADUser -Identity $Account -Replace @{{"msDS-SupportedEncryptionTypes" = 28}}
    Write-Host "[+] Encryption types set to RC4+AES128+AES256 (attracts Kerberoast tools)" -ForegroundColor Green
}}

Write-Host ""
Write-Host "[+] Honeyroasting SPN deployed successfully" -ForegroundColor Cyan
Write-Host "[+] DETECTION: Monitor Event ID 4769 where ServiceName = '$Account'" -ForegroundColor Cyan
Write-Host "[+] Any TGS request for this SPN is MALICIOUS (service does not exist)" -ForegroundColor Yellow
'''

    @staticmethod
    def generate_decoy_gpo(
        gpo_name: str,
        decoy_username: str,
        decoy_domain: str,
        sysvol_path: str,
        enable_sacl: bool = True,
    ) -> str:
        """Generate PowerShell to create a decoy GPO with cpassword trap."""
        gpo_guid = str(uuid.uuid4()).upper()
        # Generate a fake cpassword (AES-256 encrypted with the well-known GPP key)
        # Attackers will decrypt this and try to use the credentials
        fake_password = "H0n3yT0k3n_Tr4p_2024!"
        fake_cpassword = base64.b64encode(fake_password.encode()).decode()

        return f'''# ============================================================
# Create Decoy GPO with cpassword Trap (Group Policy Preference Honey)
# Reference: TrustedSec - Weaponizing Group Policy Objects Access
# ============================================================

Import-Module GroupPolicy
Import-Module ActiveDirectory

$GPOName = "{gpo_name}"
$GPOGuid = "{{{gpo_guid}}}"
$SYSVOLBase = "{sysvol_path}"

# Create the GPO folder structure in SYSVOL
$GPOPath = Join-Path $SYSVOLBase $GPOGuid
$MachinePath = Join-Path $GPOPath "Machine\\Preferences\\Groups"
$UserPath = Join-Path $GPOPath "User\\Preferences\\Groups"

New-Item -ItemType Directory -Path $MachinePath -Force | Out-Null
New-Item -ItemType Directory -Path $UserPath -Force | Out-Null
Write-Host "[+] Created decoy GPO folder structure: $GPOGuid" -ForegroundColor Green

# Create the Groups.xml with a fake cpassword
# Attackers using Get-GPPPassword, gpp-decrypt, or CrackMapExec will find this
$GroupsXml = @"
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{{3125E937-EB16-4b4c-9934-544FC6D24D26}}">
  <User clsid="{{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}}"
        name="{decoy_username}"
        image="2"
        changed="2011-07-15 08:30:22"
        uid="{{{str(uuid.uuid4()).upper()}}}">
    <Properties action="U"
                newName=""
                fullName="Maintenance Administrator"
                description="Legacy maintenance account"
                cpassword="{fake_cpassword}"
                changeLogon="0"
                noChange="1"
                neverExpires="1"
                acctDisabled="0"
                userName="{decoy_domain}\\{decoy_username}" />
  </User>
</Groups>
"@

$GroupsXml | Out-File -FilePath (Join-Path $MachinePath "Groups.xml") -Encoding UTF8
Write-Host "[+] Planted Groups.xml with cpassword trap" -ForegroundColor Green
Write-Host "[+] Decoy credentials: {decoy_domain}\\{decoy_username}" -ForegroundColor Yellow

# Create a matching real AD account (disabled or with different password)
# so failed logon attempts trigger Event ID 4625
$TrapPassword = -join ((33..126) | Get-Random -Count 64 | ForEach-Object {{ [char]$_ }})
$SecureTrap = ConvertTo-SecureString -String $TrapPassword -AsPlainText -Force

try {{
    New-ADUser -Name "{decoy_username}" `
               -SamAccountName "{decoy_username}" `
               -Description "Maintenance account - legacy" `
               -AccountPassword $SecureTrap `
               -Enabled $true `
               -PasswordNeverExpires $true
    Write-Host "[+] Trap account created: {decoy_username} (password differs from GPP)" -ForegroundColor Green
}} catch {{
    Write-Host "[!] Trap account may already exist: $_" -ForegroundColor Yellow
}}

{"" if not enable_sacl else f"""
# Set SACL on the SYSVOL folder to audit any read access
$FolderAcl = Get-Acl $GPOPath
$AuditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
    "Everyone",
    "ReadData",
    "ContainerInherit,ObjectInherit",
    "None",
    "Success"
)
$FolderAcl.AddAuditRule($AuditRule)
Set-Acl $GPOPath $FolderAcl
Write-Host "[+] SACL set on GPO folder - reads trigger Event ID 4663" -ForegroundColor Green
"""}

Write-Host ""
Write-Host "[+] Decoy GPO deployment complete" -ForegroundColor Cyan
Write-Host "[+] DETECTION CHAIN:" -ForegroundColor Cyan
Write-Host "    1. Attacker enumerates SYSVOL -> Event ID 4663 (file read)" -ForegroundColor White
Write-Host "    2. Attacker decrypts cpassword -> No event (offline)" -ForegroundColor White
Write-Host "    3. Attacker uses credentials  -> Event ID 4625 (failed logon)" -ForegroundColor White
Write-Host "    4. Correlate: 4663 + 4625 for same source IP = confirmed attacker" -ForegroundColor Yellow
'''

    @staticmethod
    def generate_deceptive_bloodhound_path(
        honeytoken_sam: str,
        target_group: str = "Domain Admins",
        intermediate_ou: str = "OU=Service Accounts",
    ) -> str:
        """Generate PowerShell to create fake BloodHound attack paths."""
        return f'''# ============================================================
# Create Deceptive BloodHound Attack Paths
# Reference: APT29a Blog - Deploying Honeytokens in AD
# ============================================================

Import-Module ActiveDirectory

$HoneytokenAccount = "{honeytoken_sam}"
$TargetGroup = "{target_group}"

# Strategy: Create ACL edges that BloodHound/SharpHound will discover
# These create apparent "paths to Domain Admin" that lead to monitored honeytokens

# 1. Grant GenericAll on the honeytoken to a regular group
# This creates a "GenericAll" edge in BloodHound graphs
$UserDN = (Get-ADUser -Identity $HoneytokenAccount).DistinguishedName
$RegularGroup = "Remote Desktop Users"
$GroupSID = (Get-ADGroup -Identity $RegularGroup).SID

$Acl = Get-Acl "AD:\\$UserDN"
$AceRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $GroupSID,
    [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
    [System.Security.AccessControl.AccessControlType]"Allow"
)
$Acl.AddAccessRule($AceRule)
Set-Acl "AD:\\$UserDN" $Acl
Write-Host "[+] GenericAll ACE added: $RegularGroup -> $HoneytokenAccount" -ForegroundColor Green

# 2. Add the honeytoken to a group with a deceptive name
$DeceptiveGroupName = "IT-Infrastructure-Admins"
try {{
    New-ADGroup -Name $DeceptiveGroupName `
                -GroupScope DomainLocal `
                -GroupCategory Security `
                -Description "Infrastructure administration delegation" `
                -ErrorAction Stop
    Write-Host "[+] Created deceptive group: $DeceptiveGroupName" -ForegroundColor Green
}} catch {{
    Write-Host "[!] Group may already exist" -ForegroundColor Yellow
}}

Add-ADGroupMember -Identity $DeceptiveGroupName -Members $HoneytokenAccount
Write-Host "[+] Added honeytoken to $DeceptiveGroupName" -ForegroundColor Green

# 3. Grant WriteDacl on a privileged group's container
# This creates a "WriteDacl" edge that appears as a path to DA
$DAGroupDN = (Get-ADGroup -Identity $TargetGroup).DistinguishedName
$HoneySID = (Get-ADUser -Identity $HoneytokenAccount).SID

$DAGroupAcl = Get-Acl "AD:\\$DAGroupDN"
# Add a restricted WriteDacl that won't actually work but shows in BloodHound
$WriteDaclRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $HoneySID,
    [System.DirectoryServices.ActiveDirectoryRights]"WriteDacl",
    [System.Security.AccessControl.AccessControlType]"Allow"
)
# NOTE: Add with an explicit deny higher in the ACL to prevent actual escalation
$DenyRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $HoneySID,
    [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
    [System.Security.AccessControl.AccessControlType]"Deny"
)
$DAGroupAcl.AddAccessRule($DenyRule)
$DAGroupAcl.AddAccessRule($WriteDaclRule)
Set-Acl "AD:\\$DAGroupDN" $DAGroupAcl
Write-Host "[+] Deceptive WriteDacl path created (with deny safety net)" -ForegroundColor Green

Write-Host ""
Write-Host "[+] Deceptive BloodHound path deployed" -ForegroundColor Cyan
Write-Host "[+] Attack path visible to SharpHound:" -ForegroundColor Cyan
Write-Host "    $RegularGroup -[GenericAll]-> $HoneytokenAccount" -ForegroundColor White
Write-Host "    $HoneytokenAccount -[MemberOf]-> $DeceptiveGroupName" -ForegroundColor White
Write-Host "    $HoneytokenAccount -[WriteDacl]-> $TargetGroup (blocked by deny ACE)" -ForegroundColor White
Write-Host "[+] Any attempt to abuse this path triggers honeytoken alerts" -ForegroundColor Yellow
'''

    @staticmethod
    def generate_validation_script(sam_account_name: str) -> str:
        """Generate PowerShell to validate honeytoken deployment."""
        return f'''# ============================================================
# Validate Honeytoken Deployment
# ============================================================

Import-Module ActiveDirectory

$Account = "{sam_account_name}"
$Results = @()

Write-Host "Validating honeytoken deployment for: $Account" -ForegroundColor Cyan
Write-Host "=" * 60

# Check 1: Account exists and is enabled
$User = Get-ADUser -Identity $Account -Properties * -ErrorAction SilentlyContinue
if ($User) {{
    $Results += [PSCustomObject]@{{Check="Account Exists"; Status="PASS"; Details=$User.DistinguishedName}}
    if ($User.Enabled) {{
        $Results += [PSCustomObject]@{{Check="Account Enabled"; Status="PASS"; Details="Enabled"}}
    }} else {{
        $Results += [PSCustomObject]@{{Check="Account Enabled"; Status="FAIL"; Details="Disabled"}}
    }}
}} else {{
    $Results += [PSCustomObject]@{{Check="Account Exists"; Status="FAIL"; Details="Not found"}}
    $Results | Format-Table Check, Status, Details -AutoSize
    exit 1
}}

# Check 2: AdminCount = 1
if ($User.AdminCount -eq 1) {{
    $Results += [PSCustomObject]@{{Check="AdminCount=1"; Status="PASS"; Details="Set correctly"}}
}} else {{
    $Results += [PSCustomObject]@{{Check="AdminCount=1"; Status="WARN"; Details="Not set"}}
}}

# Check 3: SPN configured
$SPNs = $User.ServicePrincipalNames
if ($SPNs -and $SPNs.Count -gt 0) {{
    $Results += [PSCustomObject]@{{Check="SPN Configured"; Status="PASS"; Details=($SPNs -join ", ")}}
}} else {{
    $Results += [PSCustomObject]@{{Check="SPN Configured"; Status="WARN"; Details="No SPNs"}}
}}

# Check 4: Password age (should appear old)
$PwdAge = (Get-Date) - $User.PasswordLastSet
if ($PwdAge.Days -gt 365) {{
    $Results += [PSCustomObject]@{{Check="Password Age"; Status="PASS"; Details="$($PwdAge.Days) days old"}}
}} else {{
    $Results += [PSCustomObject]@{{Check="Password Age"; Status="WARN"; Details="$($PwdAge.Days) days - consider aging"}}
}}

# Check 5: Audit policy (SACL)
$UserDN = $User.DistinguishedName
$Acl = Get-Acl "AD:\\$UserDN" -Audit
if ($Acl.Audit.Count -gt 0) {{
    $Results += [PSCustomObject]@{{Check="SACL Audit"; Status="PASS"; Details="$($Acl.Audit.Count) audit rules"}}
}} else {{
    $Results += [PSCustomObject]@{{Check="SACL Audit"; Status="WARN"; Details="No audit rules"}}
}}

# Check 6: Group memberships
$Groups = Get-ADPrincipalGroupMembership -Identity $Account | Select-Object -ExpandProperty Name
$Results += [PSCustomObject]@{{Check="Group Memberships"; Status="INFO"; Details=($Groups -join ", ")}}

# Check 7: Encryption types
$EncTypes = $User."msDS-SupportedEncryptionTypes"
if ($EncTypes -band 0x4) {{
    $Results += [PSCustomObject]@{{Check="RC4 Supported"; Status="PASS"; Details="RC4 enabled (attracts Kerberoast)"}}
}} else {{
    $Results += [PSCustomObject]@{{Check="RC4 Supported"; Status="INFO"; Details="RC4 not enabled"}}
}}

# Check 8: Advanced audit policy on DC
$AuditPolicy = auditpol /get /subcategory:"Kerberos Service Ticket Operations" 2>$null
if ($AuditPolicy -match "Success") {{
    $Results += [PSCustomObject]@{{Check="Kerberos Audit"; Status="PASS"; Details="Kerberos TGS auditing enabled"}}
}} else {{
    $Results += [PSCustomObject]@{{Check="Kerberos Audit"; Status="FAIL"; Details="Enable: auditpol /set /subcategory:'Kerberos Service Ticket Operations' /success:enable"}}
}}

Write-Host ""
$Results | Format-Table Check, Status, Details -AutoSize

$FailCount = ($Results | Where-Object {{ $_.Status -eq "FAIL" }}).Count
if ($FailCount -eq 0) {{
    Write-Host "[+] All critical checks passed!" -ForegroundColor Green
}} else {{
    Write-Host "[-] $FailCount checks failed - review above" -ForegroundColor Red
}}
'''


# ===========================================================================
# SIEM Detection Rule Generator
# ===========================================================================

class SIEMRuleGenerator:
    """Generates detection rules for SIEM platforms targeting honeytoken activity."""

    def __init__(self):
        self.rules = []

    def generate_detection_rules(self, honeytoken_accounts: list[str],
                                 honey_spns: list[str],
                                 gpo_trap_accounts: list[str],
                                 siem: str = "sigma") -> list[dict]:
        """Generate detection rules for the specified SIEM platform."""
        generators = {
            "sigma": self._generate_sigma_rules,
            "splunk": self._generate_splunk_rules,
            "sentinel": self._generate_sentinel_rules,
        }

        generator = generators.get(siem)
        if not generator:
            raise ValueError(f"Unsupported SIEM: {siem}. Use: {list(generators.keys())}")

        rules = generator(honeytoken_accounts, honey_spns, gpo_trap_accounts)
        self.rules.extend(rules)
        return rules

    def _generate_sigma_rules(self, accounts: list[str],
                              spns: list[str],
                              gpo_accounts: list[str]) -> list[dict]:
        """Generate Sigma detection rules."""
        rules = []

        # Rule 1: Kerberoasting against honey SPN
        if accounts:
            account_list = "\n".join(f"            - '{a}'" for a in accounts)
            rules.append({
                "title": "Honeytoken Kerberoast Detected",
                "id": str(uuid.uuid4()),
                "status": "production",
                "level": "critical",
                "description": "TGS ticket request for honeytoken service account SPN detected. "
                               "This is a high-confidence indicator of Kerberoasting reconnaissance.",
                "detection_logic": f"EventID 4769 AND ServiceName IN {accounts}",
                "rule": f"""title: Honeytoken Kerberoast Detected
id: {uuid.uuid4()}
status: production
level: critical
description: >
    TGS ticket request detected for a honeytoken service account.
    Any Kerberos ticket request for this account is malicious since
    the associated service does not exist.
references:
    - https://adsecurity.org/?p=3513
    - https://www.hub.trimarcsecurity.com/post/the-art-of-the-honeypot-account-making-the-unusual-look-normal
author: Honeytoken Detection Agent
date: {datetime.utcnow().strftime('%Y/%m/%d')}
tags:
    - attack.credential_access
    - attack.t1558.003
logsource:
    product: windows
    service: security
detection:
    selection:
        EventID: 4769
        ServiceName:
{account_list}
    filter_machine_accounts:
        ServiceName|endswith: '$'
    condition: selection and not filter_machine_accounts
falsepositives:
    - None expected - any match is suspicious
level: critical""",
            })

        # Rule 2: Logon attempt with GPO trap credentials
        if gpo_accounts:
            gpo_list = "\n".join(f"            - '{a}'" for a in gpo_accounts)
            rules.append({
                "title": "Honeytoken GPO Credential Use Detected",
                "id": str(uuid.uuid4()),
                "status": "production",
                "level": "critical",
                "description": "Failed or successful logon using credentials from decoy GPO. "
                               "Attacker has harvested Group Policy Preference passwords.",
                "detection_logic": f"EventID IN (4624, 4625) AND TargetUserName IN {gpo_accounts}",
                "rule": f"""title: Honeytoken GPO Credential Use Detected
id: {uuid.uuid4()}
status: production
level: critical
description: >
    Logon attempt detected using credentials planted in a decoy Group Policy
    Preference XML. The attacker has enumerated SYSVOL and decrypted the
    cpassword value.
references:
    - https://trustedsec.com/blog/weaponizing-group-policy-objects-access
author: Honeytoken Detection Agent
date: {datetime.utcnow().strftime('%Y/%m/%d')}
tags:
    - attack.credential_access
    - attack.t1552.006
logsource:
    product: windows
    service: security
detection:
    selection:
        EventID:
            - 4624
            - 4625
        TargetUserName:
{gpo_list}
    condition: selection
falsepositives:
    - None expected
level: critical""",
            })

        # Rule 3: DACL access on honeytoken object
        if accounts:
            rules.append({
                "title": "Honeytoken AD Object Accessed",
                "id": str(uuid.uuid4()),
                "status": "production",
                "level": "high",
                "description": "Directory service read on honeytoken account DACL detected. "
                               "Indicates AD reconnaissance or enumeration.",
                "detection_logic": f"EventID 4662 AND ObjectName contains honeytoken DN",
                "rule": f"""title: Honeytoken AD Object Accessed
id: {uuid.uuid4()}
status: production
level: high
description: >
    A read operation was performed on a honeytoken AD object's DACL.
    This indicates Active Directory reconnaissance (BloodHound, ADRecon, etc).
references:
    - https://apt29a.blogspot.com/2019/11/deploying-honeytokens-in-active.html
author: Honeytoken Detection Agent
date: {datetime.utcnow().strftime('%Y/%m/%d')}
tags:
    - attack.discovery
    - attack.t1087.002
logsource:
    product: windows
    service: security
detection:
    selection:
        EventID: 4662
        ObjectName|contains:
{"\n".join(f"            - '{a}'" for a in accounts)}
    condition: selection
falsepositives:
    - Legitimate AD administration tools
level: high""",
            })

        return rules

    def _generate_splunk_rules(self, accounts: list[str],
                               spns: list[str],
                               gpo_accounts: list[str]) -> list[dict]:
        """Generate Splunk SPL detection queries."""
        rules = []

        if accounts:
            account_filter = " OR ".join(f'ServiceName="{a}"' for a in accounts)
            rules.append({
                "title": "Honeytoken Kerberoast Detection (Splunk)",
                "detection_logic": f"EventCode=4769 AND ({account_filter})",
                "rule": f"""| `Notable` title="Honeytoken Kerberoast Detected"
index=wineventlog sourcetype="WinEventLog:Security" EventCode=4769
    ({account_filter})
| eval ticket_type=case(
    Ticket_Encryption_Type=="0x17", "RC4-HMAC (weak)",
    Ticket_Encryption_Type=="0x12", "AES256",
    Ticket_Encryption_Type=="0x11", "AES128",
    true(), Ticket_Encryption_Type
)
| eval alert_severity="critical"
| eval alert_type="honeytoken_kerberoast"
| eval mitre_technique="T1558.003"
| table _time, src_ip, Account_Name, ServiceName, ticket_type, Client_Address
| sort - _time""",
            })

        if gpo_accounts:
            gpo_filter = " OR ".join(f'TargetUserName="{a}"' for a in gpo_accounts)
            rules.append({
                "title": "Honeytoken GPO Credential Use (Splunk)",
                "detection_logic": f"EventCode IN (4624,4625) AND ({gpo_filter})",
                "rule": f"""index=wineventlog sourcetype="WinEventLog:Security"
    (EventCode=4624 OR EventCode=4625)
    ({gpo_filter})
| eval alert_severity="critical"
| eval alert_type="honeytoken_gpo_credential_use"
| eval mitre_technique="T1552.006"
| eval logon_result=if(EventCode=4624, "SUCCESS - INVESTIGATE IMMEDIATELY", "Failed")
| table _time, src_ip, TargetUserName, EventCode, logon_result, Logon_Type, Workstation_Name
| sort - _time""",
            })

        # Correlation rule: SYSVOL access followed by credential use
        if gpo_accounts:
            rules.append({
                "title": "Honeytoken Attack Chain: SYSVOL Enum + Credential Use (Splunk)",
                "detection_logic": "Correlation: EventCode 4663 (SYSVOL read) -> 4625 (failed logon)",
                "rule": f"""index=wineventlog sourcetype="WinEventLog:Security"
    (EventCode=4663 ObjectName="*SYSVOL*Policies*Groups.xml*")
    OR (EventCode=4625 ({" OR ".join(f'TargetUserName="{a}"' for a in gpo_accounts)}))
| eval stage=case(
    EventCode=4663, "1_sysvol_enum",
    EventCode=4625, "2_credential_use"
)
| stats earliest(_time) as first_seen, latest(_time) as last_seen,
    values(stage) as attack_stages, dc(EventCode) as event_types
    by src_ip
| where event_types >= 2
| eval alert_type="honeytoken_attack_chain_confirmed"
| eval alert_severity="critical"
| sort - last_seen""",
            })

        return rules

    def _generate_sentinel_rules(self, accounts: list[str],
                                 spns: list[str],
                                 gpo_accounts: list[str]) -> list[dict]:
        """Generate Microsoft Sentinel KQL detection rules."""
        rules = []

        if accounts:
            account_list = ", ".join(f'"{a}"' for a in accounts)
            rules.append({
                "title": "Honeytoken Kerberoast Detection (Sentinel)",
                "detection_logic": f"EventID == 4769 AND ServiceName in ({account_list})",
                "rule": f"""// Honeytoken Kerberoast Detection
// MITRE ATT&CK: T1558.003 - Kerberoasting
// Severity: Critical - ANY match is malicious
SecurityEvent
| where EventID == 4769
| where ServiceName in ({account_list})
| extend EncryptionType = case(
    TicketEncryptionType == "0x17", "RC4-HMAC (weak - easy to crack)",
    TicketEncryptionType == "0x12", "AES256 (strong)",
    TicketEncryptionType == "0x11", "AES128",
    true(), tostring(TicketEncryptionType)
)
| extend AlertSeverity = "Critical"
| extend AlertType = "Honeytoken Kerberoast"
| extend MitreTechnique = "T1558.003"
| project TimeGenerated, Computer, Account, ServiceName,
    IpAddress, EncryptionType, AlertSeverity, AlertType
| sort by TimeGenerated desc""",
            })

        if gpo_accounts:
            gpo_list = ", ".join(f'"{a}"' for a in gpo_accounts)
            rules.append({
                "title": "Honeytoken GPO Credential Use (Sentinel)",
                "detection_logic": f"EventID in (4624,4625) AND TargetUserName in ({gpo_list})",
                "rule": f"""// Honeytoken GPO Credential Trap Triggered
// MITRE ATT&CK: T1552.006 - Group Policy Preferences
// Severity: Critical
SecurityEvent
| where EventID in (4624, 4625)
| where TargetUserName in ({gpo_list})
| extend LogonResult = iff(EventID == 4624,
    "SUCCESS - IMMEDIATE INVESTIGATION REQUIRED", "Failed")
| extend AlertSeverity = "Critical"
| extend AlertType = "Honeytoken GPO Credential Use"
| extend MitreTechnique = "T1552.006"
| project TimeGenerated, Computer, TargetUserName, EventID,
    LogonResult, IpAddress, LogonTypeName, WorkstationName
| sort by TimeGenerated desc""",
            })

        return rules

    def export_rules(self, output_dir: str, format: str = "json") -> list[str]:
        """Export all generated rules to files."""
        out_path = Path(output_dir)
        out_path.mkdir(parents=True, exist_ok=True)
        saved = []

        for i, rule in enumerate(self.rules):
            if format == "json":
                filename = f"rule_{i+1}_{rule['title'].lower().replace(' ', '_')[:40]}.json"
                filepath = out_path / filename
                filepath.write_text(json.dumps(rule, indent=2))
            elif format == "yaml" and "rule" in rule:
                filename = f"rule_{i+1}.yml"
                filepath = out_path / filename
                filepath.write_text(rule["rule"])
            saved.append(str(filepath))

        return saved


# ===========================================================================
# AD Honeytoken Monitor (Python-based log analysis)
# ===========================================================================

class ADHoneytokenMonitor:
    """Monitors Windows Event Logs for honeytoken interactions."""

    def __init__(self, config_path: str | None = None):
        self.config = {}
        if config_path and Path(config_path).exists():
            with open(config_path) as f:
                self.config = json.load(f)
        self.honeytokens: dict[str, dict] = {}
        self.alerts: list[dict] = []

    def register_honeytoken(self, identifier: str,
                            token_type: str = "admin_account",
                            metadata: dict | None = None) -> dict:
        """Register a honeytoken for monitoring."""
        token = {
            "identifier": identifier,
            "type": token_type,
            "registered_at": datetime.utcnow().isoformat(),
            "token_id": f"HT-AD-{uuid.uuid4().hex[:8].upper()}",
            "metadata": metadata or {},
            "alert_count": 0,
        }
        self.honeytokens[identifier] = token
        return token

    def analyze_event_log(self, events: list[dict]) -> list[dict]:
        """Analyze Windows Event Log entries for honeytoken interactions."""
        alerts = []

        for event in events:
            event_id = event.get("EventID") or event.get("EventCode")
            if not event_id:
                continue
            event_id = int(event_id)

            # Check for Kerberoasting (Event 4769)
            if event_id == 4769:
                service_name = event.get("ServiceName", "")
                if service_name in self.honeytokens:
                    enc_type = event.get("TicketEncryptionType", "unknown")
                    alerts.append(self._create_alert(
                        event=event,
                        alert_type="KERBEROAST_HONEYTOKEN",
                        severity="critical",
                        description=f"Kerberoasting detected against honeytoken SPN: {service_name}",
                        mitre_technique="T1558.003",
                        encryption_type=KERBEROS_ENCRYPTION.get(
                            int(enc_type, 16) if isinstance(enc_type, str) else enc_type,
                            str(enc_type)
                        ),
                    ))

            # Check for logon attempts (Event 4624/4625)
            elif event_id in (4624, 4625):
                target_user = event.get("TargetUserName", "")
                if target_user in self.honeytokens:
                    alerts.append(self._create_alert(
                        event=event,
                        alert_type="HONEYTOKEN_LOGON" if event_id == 4624 else "HONEYTOKEN_LOGON_FAILED",
                        severity="critical",
                        description=f"{'Successful' if event_id == 4624 else 'Failed'} "
                                    f"logon attempt with honeytoken account: {target_user}",
                        mitre_technique="T1078" if event_id == 4624 else "T1552.006",
                    ))

            # Check for directory object access (Event 4662)
            elif event_id == 4662:
                object_name = event.get("ObjectName", "")
                for ht_id, ht_info in self.honeytokens.items():
                    if ht_id in object_name:
                        alerts.append(self._create_alert(
                            event=event,
                            alert_type="HONEYTOKEN_DACL_READ",
                            severity="high",
                            description=f"Directory service read on honeytoken object: {ht_id}",
                            mitre_technique="T1087.002",
                        ))

            # Check for GPO modifications (Event 5136)
            elif event_id == 5136:
                object_dn = event.get("ObjectDN", "")
                for ht_id, ht_info in self.honeytokens.items():
                    if ht_info.get("type") == "gpo_credential" and ht_id in object_dn:
                        alerts.append(self._create_alert(
                            event=event,
                            alert_type="HONEYTOKEN_GPO_MODIFIED",
                            severity="critical",
                            description=f"Decoy GPO modification detected: {object_dn}",
                            mitre_technique="T1484.001",
                        ))

        self.alerts.extend(alerts)
        return alerts

    def _create_alert(self, event: dict, alert_type: str,
                      severity: str, description: str,
                      mitre_technique: str, **kwargs) -> dict:
        """Create a structured alert from an event."""
        alert = {
            "alert_id": f"ALERT-{uuid.uuid4().hex[:12].upper()}",
            "alert_type": alert_type,
            "severity": severity,
            "description": description,
            "mitre_technique": mitre_technique,
            "source_ip": event.get("IpAddress") or event.get("src_ip", "unknown"),
            "source_host": event.get("Computer") or event.get("Workstation", "unknown"),
            "account": event.get("TargetUserName") or event.get("ServiceName", "unknown"),
            "event_id": event.get("EventID") or event.get("EventCode"),
            "timestamp": event.get("TimeGenerated") or datetime.utcnow().isoformat(),
            "raw_event": event,
        }
        alert.update(kwargs)
        return alert

    def generate_detection_rules(self, siem: str = "sigma") -> list[dict]:
        """Generate SIEM detection rules for all registered honeytokens."""
        generator = SIEMRuleGenerator()

        accounts = [ht_id for ht_id, info in self.honeytokens.items()
                     if info["type"] in ("admin_account", "spn")]
        spns = [ht_id for ht_id, info in self.honeytokens.items()
                if info["type"] == "spn"]
        gpo_accounts = [ht_id for ht_id, info in self.honeytokens.items()
                        if info["type"] == "gpo_credential"]

        return generator.generate_detection_rules(accounts, spns, gpo_accounts, siem)

    def get_alert_summary(self) -> dict:
        """Get a summary of all triggered alerts."""
        summary = {
            "total_alerts": len(self.alerts),
            "by_severity": {},
            "by_type": {},
            "by_source_ip": {},
            "honeytokens_triggered": set(),
        }

        for alert in self.alerts:
            sev = alert["severity"]
            summary["by_severity"][sev] = summary["by_severity"].get(sev, 0) + 1

            atype = alert["alert_type"]
            summary["by_type"][atype] = summary["by_type"].get(atype, 0) + 1

            src = alert["source_ip"]
            summary["by_source_ip"][src] = summary["by_source_ip"].get(src, 0) + 1

            summary["honeytokens_triggered"].add(alert["account"])

        summary["honeytokens_triggered"] = list(summary["honeytokens_triggered"])
        return summary


# ===========================================================================
# Deployment Orchestrator
# ===========================================================================

class HoneytokenDeployer:
    """Orchestrates full honeytoken deployment and generates all artifacts."""

    def __init__(self, domain: str = "corp.example.com",
                 service_account_ou: str = "OU=Service Accounts",
                 sysvol_path: str = ""):
        self.domain = domain
        self.service_account_ou = service_account_ou
        self.sysvol_path = sysvol_path or f"\\\\{domain}\\SYSVOL\\{domain}\\Policies"
        self.ps_gen = PowerShellGenerator()
        self.siem_gen = SIEMRuleGenerator()
        self.deployed_tokens = []

    def generate_realistic_name(self) -> dict:
        """Generate a realistic service account name."""
        template = secrets.choice(SERVICE_ACCOUNT_TEMPLATES)
        service = secrets.choice(template["services"])
        sam = f"{template['prefix']}{service}"

        # Generate a realistic hostname for SPN
        service_abbrev = service[:3].lower()
        hostname = f"{service_abbrev}-legacy-{secrets.randbelow(99):02d}.{self.domain}"

        return {
            "sam_account_name": sam,
            "display_name": f"{service.replace('_', ' ').title()} Service",
            "hostname": hostname,
        }

    def deploy_full_suite(self, token_count: int = 3,
                          include_spn: bool = True,
                          include_gpo: bool = True,
                          include_bloodhound: bool = True,
                          siem_type: str = "sigma") -> dict:
        """Generate complete deployment artifacts for a full honeytoken suite."""
        deployment = {
            "deployment_id": f"DEPLOY-{uuid.uuid4().hex[:8].upper()}",
            "generated_at": datetime.utcnow().isoformat(),
            "domain": self.domain,
            "tokens": [],
            "scripts": [],
            "detection_rules": [],
        }

        all_accounts = []
        all_spns = []
        gpo_accounts = []

        for i in range(token_count):
            naming = self.generate_realistic_name()
            sam = naming["sam_account_name"]
            ou_dn = f"{self.service_account_ou},DC={',DC='.join(self.domain.split('.'))}"

            # Generate admin account script
            account_script = self.ps_gen.generate_create_honeytoken_account(
                sam_account_name=sam,
                display_name=naming["display_name"],
                description=f"Legacy {naming['display_name'].lower()} - DO NOT DELETE",
                ou_dn=ou_dn,
                password_length=128,
                set_admin_count=True,
            )
            deployment["scripts"].append({
                "type": "create_account",
                "filename": f"01_create_{sam}.ps1",
                "content": account_script,
            })
            all_accounts.append(sam)

            token_info = {
                "name": sam,
                "type": "admin_account",
                "display_name": naming["display_name"],
                "ou": ou_dn,
            }

            # Generate SPN script
            if include_spn:
                spn_class = secrets.choice(SPN_SERVICE_CLASSES)
                port = secrets.choice([1433, 443, 8080, 5432, 3306, 27017])
                spn_script = self.ps_gen.generate_add_honey_spn(
                    sam_account_name=sam,
                    service_class=spn_class,
                    hostname=naming["hostname"],
                    port=port,
                )
                deployment["scripts"].append({
                    "type": "add_spn",
                    "filename": f"02_add_spn_{sam}.ps1",
                    "content": spn_script,
                })
                spn_value = f"{spn_class}/{naming['hostname']}:{port}"
                all_spns.append(spn_value)
                token_info["spn"] = spn_value

            deployment["tokens"].append(token_info)

        # Generate GPO decoy
        if include_gpo:
            gpo_username = f"admin_maintenance_{secrets.randbelow(99):02d}"
            domain_short = self.domain.split(".")[0].upper()
            gpo_script = self.ps_gen.generate_decoy_gpo(
                gpo_name="Server Maintenance Policy (Legacy)",
                decoy_username=gpo_username,
                decoy_domain=domain_short,
                sysvol_path=self.sysvol_path,
            )
            deployment["scripts"].append({
                "type": "decoy_gpo",
                "filename": "03_create_decoy_gpo.ps1",
                "content": gpo_script,
            })
            gpo_accounts.append(gpo_username)
            deployment["tokens"].append({
                "name": gpo_username,
                "type": "gpo_credential",
                "description": "Decoy GPO cpassword trap",
            })

        # Generate BloodHound deception
        if include_bloodhound and all_accounts:
            bh_script = self.ps_gen.generate_deceptive_bloodhound_path(
                honeytoken_sam=all_accounts[0],
            )
            deployment["scripts"].append({
                "type": "bloodhound_deception",
                "filename": "04_create_bloodhound_paths.ps1",
                "content": bh_script,
            })

        # Generate validation script
        if all_accounts:
            val_script = self.ps_gen.generate_validation_script(all_accounts[0])
            deployment["scripts"].append({
                "type": "validation",
                "filename": "05_validate_deployment.ps1",
                "content": val_script,
            })

        # Generate SIEM detection rules
        rules = self.siem_gen.generate_detection_rules(
            all_accounts, all_spns, gpo_accounts, siem_type
        )
        deployment["detection_rules"] = rules

        self.deployed_tokens = deployment["tokens"]
        return deployment

    def save_deployment(self, deployment: dict, output_dir: str) -> list[str]:
        """Save all deployment artifacts to disk."""
        out_path = Path(output_dir)
        out_path.mkdir(parents=True, exist_ok=True)
        saved = []

        # Save PowerShell scripts
        scripts_dir = out_path / "scripts"
        scripts_dir.mkdir(exist_ok=True)
        for script in deployment.get("scripts", []):
            filepath = scripts_dir / script["filename"]
            filepath.write_text(script["content"], encoding="utf-8")
            saved.append(str(filepath))

        # Save detection rules
        rules_dir = out_path / "detection_rules"
        rules_dir.mkdir(exist_ok=True)
        for i, rule in enumerate(deployment.get("detection_rules", [])):
            filename = f"rule_{i+1}_{rule['title'][:40].lower().replace(' ', '_')}.json"
            filepath = rules_dir / filename
            filepath.write_text(json.dumps(rule, indent=2), encoding="utf-8")
            saved.append(str(filepath))

        # Save deployment manifest
        manifest = {
            "deployment_id": deployment["deployment_id"],
            "generated_at": deployment["generated_at"],
            "domain": deployment["domain"],
            "tokens": deployment["tokens"],
            "scripts": [s["filename"] for s in deployment["scripts"]],
            "detection_rules": [r["title"] for r in deployment["detection_rules"]],
        }
        manifest_path = out_path / "deployment_manifest.json"
        manifest_path.write_text(json.dumps(manifest, indent=2))
        saved.append(str(manifest_path))

        return saved


# ===========================================================================
# CLI Entry Point
# ===========================================================================

def main():
    parser = argparse.ArgumentParser(
        description="Active Directory Honeytoken Deployment Agent"
    )
    parser.add_argument(
        "--action",
        choices=[
            "deploy_account", "deploy_spn", "deploy_gpo", "deploy_bloodhound",
            "full_deploy", "generate_rules", "validate", "analyze_logs",
        ],
        default="full_deploy",
        help="Action to perform",
    )
    parser.add_argument("--domain", default="corp.example.com")
    parser.add_argument("--ou", default="OU=Service Accounts")
    parser.add_argument("--sysvol", default="")
    parser.add_argument("--account-name", default="svc_sqlbackup_legacy")
    parser.add_argument("--token-count", type=int, default=3)
    parser.add_argument("--siem", choices=["sigma", "splunk", "sentinel"], default="sigma")
    parser.add_argument("--output-dir", default="honeytoken_deployment")
    parser.add_argument("--include-spn", action="store_true", default=True)
    parser.add_argument("--include-gpo", action="store_true", default=True)
    parser.add_argument("--include-bloodhound", action="store_true", default=True)
    parser.add_argument("--event-log", help="Path to event log JSON for analysis")
    args = parser.parse_args()

    print("=" * 60)
    print("Active Directory Honeytoken Deployment Agent")
    print("=" * 60)

    deployer = HoneytokenDeployer(
        domain=args.domain,
        service_account_ou=args.ou,
        sysvol_path=args.sysvol,
    )

    if args.action == "full_deploy":
        print(f"\n[+] Generating full honeytoken deployment for: {args.domain}")
        print(f"[+] Token count: {args.token_count}")
        print(f"[+] SIEM target: {args.siem}")

        deployment = deployer.deploy_full_suite(
            token_count=args.token_count,
            include_spn=args.include_spn,
            include_gpo=args.include_gpo,
            include_bloodhound=args.include_bloodhound,
            siem_type=args.siem,
        )

        saved_files = deployer.save_deployment(deployment, args.output_dir)

        print(f"\n[+] Deployment ID: {deployment['deployment_id']}")
        print(f"[+] Tokens generated: {len(deployment['tokens'])}")
        for token in deployment["tokens"]:
            print(f"    - {token['name']} ({token['type']})"
                  + (f" SPN: {token.get('spn', 'N/A')}" if token.get('spn') else ""))

        print(f"\n[+] Scripts generated: {len(deployment['scripts'])}")
        for script in deployment["scripts"]:
            print(f"    - {script['filename']} ({script['type']})")

        print(f"\n[+] Detection rules generated: {len(deployment['detection_rules'])}")
        for rule in deployment["detection_rules"]:
            print(f"    - {rule['title']}")

        print(f"\n[+] Files saved to: {args.output_dir}")
        for f in saved_files:
            print(f"    {f}")

    elif args.action == "generate_rules":
        print(f"\n[+] Generating {args.siem} detection rules...")
        monitor = ADHoneytokenMonitor()
        monitor.register_honeytoken(args.account_name, "admin_account")

        rules = monitor.generate_detection_rules(args.siem)
        for rule in rules:
            print(f"\n--- {rule['title']} ---")
            print(rule.get("rule", rule.get("detection_logic", "")))

    elif args.action == "analyze_logs":
        if not args.event_log:
            print("[-] --event-log required for log analysis")
            return

        print(f"\n[+] Analyzing event log: {args.event_log}")
        monitor = ADHoneytokenMonitor()
        monitor.register_honeytoken(args.account_name, "admin_account")

        log_path = Path(args.event_log)
        if not log_path.exists():
            print(f"[-] Log file not found: {args.event_log}")
            return

        with open(log_path) as f:
            events = json.load(f)

        alerts = monitor.analyze_event_log(events)
        print(f"\n[+] Alerts generated: {len(alerts)}")
        for alert in alerts:
            print(f"  [{alert['severity'].upper()}] {alert['alert_type']}: "
                  f"{alert['description']}")
            print(f"    Source: {alert['source_ip']} | "
                  f"Account: {alert['account']} | "
                  f"MITRE: {alert['mitre_technique']}")

        summary = monitor.get_alert_summary()
        print(f"\n[+] Summary: {summary['total_alerts']} alerts, "
              f"sources: {list(summary['by_source_ip'].keys())}")

    elif args.action == "deploy_account":
        ps_gen = PowerShellGenerator()
        ou_dn = f"{args.ou},DC={',DC='.join(args.domain.split('.'))}"
        script = ps_gen.generate_create_honeytoken_account(
            sam_account_name=args.account_name,
            display_name="Legacy Backup Service",
            description="Legacy backup service account - DO NOT DELETE",
            ou_dn=ou_dn,
        )
        print(script)

    elif args.action == "deploy_spn":
        ps_gen = PowerShellGenerator()
        script = ps_gen.generate_add_honey_spn(
            sam_account_name=args.account_name,
        )
        print(script)

    elif args.action == "deploy_gpo":
        ps_gen = PowerShellGenerator()
        script = ps_gen.generate_decoy_gpo(
            gpo_name="Server Maintenance Policy (Legacy)",
            decoy_username="admin_maintenance",
            decoy_domain=args.domain.split(".")[0].upper(),
            sysvol_path=deployer.sysvol_path,
        )
        print(script)

    elif args.action == "deploy_bloodhound":
        ps_gen = PowerShellGenerator()
        script = ps_gen.generate_deceptive_bloodhound_path(
            honeytoken_sam=args.account_name,
        )
        print(script)

    elif args.action == "validate":
        ps_gen = PowerShellGenerator()
        script = ps_gen.generate_validation_script(args.account_name)
        print(script)

    print("\n" + "=" * 60)
    print("[+] Honeytoken agent complete.")
    print("=" * 60)


if __name__ == "__main__":
    main()
Deploy-ADHoneytokens.ps122.2 KB
Display-only source. This catalog never executes bundled scripts.
<#
.SYNOPSIS
    Active Directory Honeytoken Deployment Module

.DESCRIPTION
    Deploys deception-based honeytokens in Active Directory including:
    - Fake privileged accounts with AdminCount=1
    - Fake SPNs for Kerberoasting detection (honeyroasting)
    - Decoy GPOs with cpassword traps
    - Deceptive BloodHound attack paths
    - SACL audit rules for detection

.NOTES
    Author: mukul975
    Version: 1.0
    References:
        - Trimarc Security: The Art of the Honeypot Account
        - ADSecurity.org: Detecting Kerberoasting Activity Part 2
        - Microsoft Defender for Identity Honeytokens
        - SpecterOps: Kerberoasting and AES-256
#>

#Requires -Modules ActiveDirectory
#Requires -Version 5.1

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# ---------------------------------------------------------------------------
# Module-level variables
# ---------------------------------------------------------------------------

$Script:DeployedTokens = @()
$Script:DeploymentLog = @()

# ---------------------------------------------------------------------------
# Helper Functions
# ---------------------------------------------------------------------------

function Write-DeployLog {
    param(
        [string]$Message,
        [ValidateSet("INFO", "WARN", "ERROR", "SUCCESS")]
        [string]$Level = "INFO"
    )
    $entry = [PSCustomObject]@{
        Timestamp = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
        Level     = $Level
        Message   = $Message
    }
    $Script:DeploymentLog += $entry
    $color = switch ($Level) {
        "INFO"    { "White" }
        "WARN"    { "Yellow" }
        "ERROR"   { "Red" }
        "SUCCESS" { "Green" }
    }
    Write-Host "[$Level] $Message" -ForegroundColor $color
}

function New-SecureRandomPassword {
    param([int]$Length = 128)
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:,.<>?'
    $password = -join (1..$Length | ForEach-Object { $chars[(Get-Random -Maximum $chars.Length)] })
    return $password
}

# ---------------------------------------------------------------------------
# New-HoneytokenAdmin
# ---------------------------------------------------------------------------

function New-HoneytokenAdmin {
    <#
    .SYNOPSIS
        Creates a honeytoken admin account in Active Directory.

    .DESCRIPTION
        Creates a realistic-looking service account with AdminCount=1 set,
        backdated password age, group memberships, and SACL audit rules.
        The account appears as a high-value target to attackers using
        BloodHound, SharpHound, or manual AD enumeration.

    .PARAMETER SamAccountName
        The sAMAccountName for the honeytoken account.

    .PARAMETER DisplayName
        The display name for the account.

    .PARAMETER Description
        The description field (should look legitimate).

    .PARAMETER OU
        The Distinguished Name of the OU to create the account in.

    .PARAMETER PasswordLength
        Length of the random password (default: 128).

    .PARAMETER SetAdminCount
        If true, sets AdminCount=1 on the account (default: true).

    .PARAMETER AccountAgeDays
        Number of days to backdate the password (default: 5475 = ~15 years).

    .EXAMPLE
        New-HoneytokenAdmin -SamAccountName "svc_sqlbackup_legacy" `
            -DisplayName "SQL Backup Service (Legacy)" `
            -Description "Legacy SQL Server backup service account - DO NOT DELETE" `
            -OU "OU=Service Accounts,DC=corp,DC=example,DC=com"
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$SamAccountName,

        [Parameter(Mandatory)]
        [string]$DisplayName,

        [string]$Description = "Legacy service account - DO NOT DELETE",

        [Parameter(Mandatory)]
        [string]$OU,

        [int]$PasswordLength = 128,

        [bool]$SetAdminCount = $true,

        [int]$AccountAgeDays = 5475
    )

    Write-DeployLog "Creating honeytoken admin: $SamAccountName" "INFO"

    # Generate strong random password
    $Password = New-SecureRandomPassword -Length $PasswordLength
    $SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force

    # Create the account
    $Domain = Get-ADDomain
    $UPN = "$SamAccountName@$($Domain.DNSRoot)"

    $UserParams = @{
        Name                 = $DisplayName
        SamAccountName       = $SamAccountName
        UserPrincipalName    = $UPN
        DisplayName          = $DisplayName
        Description          = $Description
        Path                 = $OU
        AccountPassword      = $SecurePassword
        Enabled              = $true
        PasswordNeverExpires = $true
        CannotChangePassword = $true
        ChangePasswordAtLogon = $false
    }

    try {
        New-ADUser @UserParams
        Write-DeployLog "Account created: $SamAccountName" "SUCCESS"
    }
    catch {
        Write-DeployLog "Failed to create account: $_" "ERROR"
        throw
    }

    # Set AdminCount=1
    if ($SetAdminCount) {
        Set-ADUser -Identity $SamAccountName -Replace @{AdminCount = 1}
        Write-DeployLog "AdminCount set to 1" "SUCCESS"
    }

    # Backdate password
    $AgeDate = (Get-Date).AddDays(-$AccountAgeDays)
    $FileTime = $AgeDate.ToFileTime()
    Set-ADUser -Identity $SamAccountName -Replace @{pwdLastSet = $FileTime}
    Write-DeployLog "Password backdated to: $($AgeDate.ToString('yyyy-MM-dd'))" "SUCCESS"

    # Add to visible groups
    Add-ADGroupMember -Identity "Remote Desktop Users" -Members $SamAccountName
    Write-DeployLog "Added to Remote Desktop Users" "SUCCESS"

    # Set SACL for audit
    $UserDN = (Get-ADUser -Identity $SamAccountName).DistinguishedName
    $Acl = Get-Acl "AD:\$UserDN"
    $AuditRule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule(
        [System.Security.Principal.SecurityIdentifier]"S-1-1-0",
        [System.DirectoryServices.ActiveDirectoryRights]"ReadProperty",
        [System.Security.AccessControl.AuditFlags]"Success",
        [System.DirectoryServices.ActiveDirectorySecurityInheritance]"None"
    )
    $Acl.AddAuditRule($AuditRule)
    Set-Acl "AD:\$UserDN" $Acl
    Write-DeployLog "SACL audit rule configured (Event ID 4662)" "SUCCESS"

    $result = Get-ADUser -Identity $SamAccountName -Properties *
    $Script:DeployedTokens += $result

    return $result
}

# ---------------------------------------------------------------------------
# Add-HoneytokenSPN
# ---------------------------------------------------------------------------

function Add-HoneytokenSPN {
    <#
    .SYNOPSIS
        Adds a fake SPN to a honeytoken account for Kerberoasting detection.

    .DESCRIPTION
        Registers a fake Service Principal Name on a honeytoken account.
        Any TGS ticket request for this SPN is definitively malicious since
        the associated service does not exist. This is known as "honeyroasting".

    .PARAMETER SamAccountName
        The honeytoken account to add the SPN to.

    .PARAMETER ServiceClass
        The SPN service class (default: MSSQLSvc).

    .PARAMETER Hostname
        The fake hostname for the SPN.

    .PARAMETER Port
        The service port (default: 1433).
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$SamAccountName,

        [string]$ServiceClass = "MSSQLSvc",

        [Parameter(Mandatory)]
        [string]$Hostname,

        [int]$Port = 1433
    )

    $SPN = "$ServiceClass/${Hostname}:$Port"
    Write-DeployLog "Adding honey SPN: $SPN to $SamAccountName" "INFO"

    # Verify account exists
    $User = Get-ADUser -Identity $SamAccountName -Properties ServicePrincipalNames -ErrorAction Stop

    # Add SPN
    Set-ADUser -Identity $SamAccountName -ServicePrincipalNames @{Add = $SPN}
    Write-DeployLog "SPN registered: $SPN" "SUCCESS"

    # Enable RC4 + AES encryption (makes it attractive to Kerberoast tools)
    Set-ADUser -Identity $SamAccountName -Replace @{"msDS-SupportedEncryptionTypes" = 28}
    Write-DeployLog "Encryption types set to RC4+AES128+AES256" "SUCCESS"

    return [PSCustomObject]@{
        SamAccountName = $SamAccountName
        SPN            = $SPN
        ServiceClass   = $ServiceClass
        Hostname       = $Hostname
        Port           = $Port
    }
}

# ---------------------------------------------------------------------------
# New-DecoyGPO
# ---------------------------------------------------------------------------

function New-DecoyGPO {
    <#
    .SYNOPSIS
        Creates a decoy GPO with cpassword credential trap.

    .DESCRIPTION
        Creates a fake GPO folder in SYSVOL containing a Groups.xml with
        encrypted credentials (cpassword). Attackers using Get-GPPPassword,
        gpp-decrypt, or CrackMapExec will find and attempt to use these
        credentials, which triggers Event ID 4625 (failed logon).

    .PARAMETER GPOName
        Descriptive name for the decoy GPO.

    .PARAMETER DecoyUsername
        The username to embed in the cpassword trap.

    .PARAMETER DecoyDomain
        The short domain name (e.g., CORP).

    .PARAMETER SYSVOLPath
        The path to the SYSVOL Policies folder.

    .PARAMETER EnableAuditSACL
        Whether to set SACL audit on the GPO folder (default: true).
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$GPOName,

        [Parameter(Mandatory)]
        [string]$DecoyUsername,

        [Parameter(Mandatory)]
        [string]$DecoyDomain,

        [Parameter(Mandatory)]
        [string]$SYSVOLPath,

        [bool]$EnableAuditSACL = $true
    )

    $GPOGuid = [guid]::NewGuid().ToString().ToUpper()
    Write-DeployLog "Creating decoy GPO: $GPOName (GUID: $GPOGuid)" "INFO"

    # Create folder structure
    $GPOPath = Join-Path $SYSVOLPath "{$GPOGuid}"
    $MachinePath = Join-Path $GPOPath "Machine\Preferences\Groups"
    New-Item -ItemType Directory -Path $MachinePath -Force | Out-Null

    # Generate fake cpassword
    $FakePassword = "H0n3yT0k3n_Tr4p_$(Get-Date -Format 'yyyy')!"
    $FakeCPassword = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($FakePassword))
    $UserGuid = [guid]::NewGuid().ToString().ToUpper()

    # Create Groups.xml with cpassword trap
    $GroupsXml = @"
<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}">
  <User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}"
        name="$DecoyUsername"
        image="2"
        changed="2011-07-15 08:30:22"
        uid="{$UserGuid}">
    <Properties action="U"
                newName=""
                fullName="Maintenance Administrator"
                description="Legacy maintenance account"
                cpassword="$FakeCPassword"
                changeLogon="0"
                noChange="1"
                neverExpires="1"
                acctDisabled="0"
                userName="$DecoyDomain\$DecoyUsername" />
  </User>
</Groups>
"@

    $GroupsXml | Out-File -FilePath (Join-Path $MachinePath "Groups.xml") -Encoding UTF8
    Write-DeployLog "Groups.xml planted with cpassword trap" "SUCCESS"

    # Create corresponding trap AD account with different password
    $TrapPassword = New-SecureRandomPassword -Length 64
    $SecureTrap = ConvertTo-SecureString -String $TrapPassword -AsPlainText -Force

    try {
        New-ADUser -Name $DecoyUsername `
                   -SamAccountName $DecoyUsername `
                   -Description "Maintenance account - legacy" `
                   -AccountPassword $SecureTrap `
                   -Enabled $true `
                   -PasswordNeverExpires $true
        Write-DeployLog "Trap account created: $DecoyUsername (password differs from GPP)" "SUCCESS"
    }
    catch {
        Write-DeployLog "Trap account creation: $_" "WARN"
    }

    # Set SACL
    if ($EnableAuditSACL) {
        $FolderAcl = Get-Acl $GPOPath
        $AuditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
            "Everyone", "ReadData", "ContainerInherit,ObjectInherit", "None", "Success"
        )
        $FolderAcl.AddAuditRule($AuditRule)
        Set-Acl $GPOPath $FolderAcl
        Write-DeployLog "SACL set on GPO folder (Event ID 4663)" "SUCCESS"
    }

    return [PSCustomObject]@{
        GPOGuid       = $GPOGuid
        GPOName       = $GPOName
        GPOPath       = $GPOPath
        DecoyUsername = $DecoyUsername
        DecoyDomain   = $DecoyDomain
    }
}

# ---------------------------------------------------------------------------
# New-DeceptiveBloodHoundPath
# ---------------------------------------------------------------------------

function New-DeceptiveBloodHoundPath {
    <#
    .SYNOPSIS
        Creates fake BloodHound attack paths pointing to monitored honeytokens.

    .DESCRIPTION
        Sets ACL permissions that create apparent attack paths visible to
        BloodHound/SharpHound reconnaissance. These paths lead attackers toward
        monitored honeytoken accounts, triggering alerts when abused.

    .PARAMETER HoneytokenSamAccount
        The honeytoken account to create paths toward.

    .PARAMETER TargetHighValueGroup
        The high-value group to create a deceptive path to (default: Domain Admins).

    .PARAMETER IntermediateOU
        OU path for intermediate objects.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$HoneytokenSamAccount,

        [string]$TargetHighValueGroup = "Domain Admins",

        [string]$IntermediateOU = "OU=Service Accounts"
    )

    Write-DeployLog "Creating deceptive BloodHound paths for: $HoneytokenSamAccount" "INFO"

    $UserDN = (Get-ADUser -Identity $HoneytokenSamAccount).DistinguishedName

    # Create GenericAll edge from regular group to honeytoken
    $GroupSID = (Get-ADGroup -Identity "Remote Desktop Users").SID
    $Acl = Get-Acl "AD:\$UserDN"
    $AceRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
        $GroupSID,
        [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
        [System.Security.AccessControl.AccessControlType]"Allow"
    )
    $Acl.AddAccessRule($AceRule)
    Set-Acl "AD:\$UserDN" $Acl
    Write-DeployLog "GenericAll ACE: Remote Desktop Users -> $HoneytokenSamAccount" "SUCCESS"

    # Create deceptive intermediate group
    $DeceptiveGroup = "IT-Infrastructure-Admins"
    try {
        New-ADGroup -Name $DeceptiveGroup -GroupScope DomainLocal `
                    -GroupCategory Security `
                    -Description "Infrastructure administration delegation"
        Write-DeployLog "Created deceptive group: $DeceptiveGroup" "SUCCESS"
    }
    catch {
        Write-DeployLog "Deceptive group may already exist" "WARN"
    }

    Add-ADGroupMember -Identity $DeceptiveGroup -Members $HoneytokenSamAccount
    Write-DeployLog "Added honeytoken to $DeceptiveGroup" "SUCCESS"

    # Create WriteDacl edge with deny safety net
    $DAGroupDN = (Get-ADGroup -Identity $TargetHighValueGroup).DistinguishedName
    $HoneySID = (Get-ADUser -Identity $HoneytokenSamAccount).SID

    $DAGroupAcl = Get-Acl "AD:\$DAGroupDN"
    $DenyRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
        $HoneySID,
        [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
        [System.Security.AccessControl.AccessControlType]"Deny"
    )
    $WriteDaclRule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
        $HoneySID,
        [System.DirectoryServices.ActiveDirectoryRights]"WriteDacl",
        [System.Security.AccessControl.AccessControlType]"Allow"
    )
    $DAGroupAcl.AddAccessRule($DenyRule)
    $DAGroupAcl.AddAccessRule($WriteDaclRule)
    Set-Acl "AD:\$DAGroupDN" $DAGroupAcl
    Write-DeployLog "Deceptive WriteDacl path created (with deny safety)" "SUCCESS"

    return [PSCustomObject]@{
        HoneytokenAccount = $HoneytokenSamAccount
        PathDescription   = "Remote Desktop Users -> $HoneytokenSamAccount -> $DeceptiveGroup -> $TargetHighValueGroup (blocked)"
        DeceptiveGroup    = $DeceptiveGroup
    }
}

# ---------------------------------------------------------------------------
# Test-HoneytokenDeployment
# ---------------------------------------------------------------------------

function Test-HoneytokenDeployment {
    <#
    .SYNOPSIS
        Validates honeytoken deployment integrity.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$SamAccountName,

        [switch]$ValidateAdminCount,
        [switch]$ValidateSPN,
        [switch]$ValidateGPODecoy,
        [switch]$ValidateAuditPolicy
    )

    $Results = @()

    # Account existence
    $User = Get-ADUser -Identity $SamAccountName -Properties * -ErrorAction SilentlyContinue
    if ($User) {
        $Results += [PSCustomObject]@{Check="Account Exists"; Status="PASS"; Details=$User.DistinguishedName}
        $Results += [PSCustomObject]@{Check="Account Enabled"; Status=$(if($User.Enabled){"PASS"}else{"FAIL"}); Details=$(if($User.Enabled){"Enabled"}else{"Disabled"})}
    } else {
        $Results += [PSCustomObject]@{Check="Account Exists"; Status="FAIL"; Details="Not found"}
        return $Results
    }

    if ($ValidateAdminCount) {
        $Results += [PSCustomObject]@{
            Check   = "AdminCount=1"
            Status  = $(if($User.AdminCount -eq 1){"PASS"}else{"WARN"})
            Details = "AdminCount=$($User.AdminCount)"
        }
    }

    if ($ValidateSPN) {
        $SPNs = $User.ServicePrincipalNames
        $Results += [PSCustomObject]@{
            Check   = "SPN Configured"
            Status  = $(if($SPNs -and $SPNs.Count -gt 0){"PASS"}else{"WARN"})
            Details = $(if($SPNs){$SPNs -join ", "}else{"No SPNs"})
        }
    }

    if ($ValidateAuditPolicy) {
        $AuditCheck = auditpol /get /subcategory:"Kerberos Service Ticket Operations" 2>$null
        $Results += [PSCustomObject]@{
            Check   = "Kerberos TGS Auditing"
            Status  = $(if($AuditCheck -match "Success"){"PASS"}else{"FAIL"})
            Details = $(if($AuditCheck -match "Success"){"Enabled"}else{"Run: auditpol /set /subcategory:'Kerberos Service Ticket Operations' /success:enable"})
        }
    }

    # Password age
    $PwdAge = (Get-Date) - $User.PasswordLastSet
    $Results += [PSCustomObject]@{
        Check   = "Password Age"
        Status  = $(if($PwdAge.Days -gt 365){"PASS"}else{"WARN"})
        Details = "$($PwdAge.Days) days"
    }

    return $Results
}

# ---------------------------------------------------------------------------
# Deploy-FullHoneytokenSuite
# ---------------------------------------------------------------------------

function Deploy-FullHoneytokenSuite {
    <#
    .SYNOPSIS
        Deploys a complete honeytoken suite in Active Directory.
    #>
    [CmdletBinding()]
    param(
        [string]$Environment = "Production",
        [Parameter(Mandatory)]
        [string]$ServiceAccountOU,
        [Parameter(Mandatory)]
        [string]$SYSVOLPath,
        [int]$TokenCount = 3,
        [bool]$IncludeSPN = $true,
        [bool]$IncludeGPODecoy = $true,
        [bool]$IncludeBloodHoundPath = $true,
        [string]$SIEMType = "Splunk"
    )

    Write-DeployLog "Starting full honeytoken suite deployment for $Environment" "INFO"
    Write-DeployLog "Token count: $TokenCount, SPN: $IncludeSPN, GPO: $IncludeGPODecoy" "INFO"

    $Tokens = @()

    # Service account name templates
    $ServiceNames = @(
        @{Sam="svc_sqlbackup_legacy"; Display="SQL Backup Service (Legacy)"; SPN_Class="MSSQLSvc"; Host="sql-bak-legacy01"; Port=1433},
        @{Sam="svc_exchange_transport"; Display="Exchange Transport Agent"; SPN_Class="exchangeMDB"; Host="exch-hub-legacy02"; Port=443},
        @{Sam="svc_scom_monitor"; Display="SCOM Monitoring Service"; SPN_Class="HTTP"; Host="scom-legacy-mgmt01"; Port=5723},
        @{Sam="svc_adfs_proxy_old"; Display="ADFS Proxy Service (Old)"; SPN_Class="HTTP"; Host="adfs-proxy-legacy01"; Port=443},
        @{Sam="svc_citrix_storefront"; Display="Citrix StoreFront Service"; SPN_Class="HTTP"; Host="ctx-sf-legacy01"; Port=443}
    )

    $Domain = (Get-ADDomain).DNSRoot

    for ($i = 0; $i -lt [Math]::Min($TokenCount, $ServiceNames.Count); $i++) {
        $svc = $ServiceNames[$i]

        # Create admin account
        $admin = New-HoneytokenAdmin `
            -SamAccountName $svc.Sam `
            -DisplayName $svc.Display `
            -Description "Legacy $($svc.Display.ToLower()) - DO NOT DELETE" `
            -OU $ServiceAccountOU

        $tokenInfo = [PSCustomObject]@{
            Name          = $svc.Sam
            Type          = "admin_account"
            SPN           = ""
            DetectionRule = "Event ID 4662 (object access)"
        }

        # Add SPN
        if ($IncludeSPN) {
            $Hostname = "$($svc.Host).$Domain"
            $spnResult = Add-HoneytokenSPN `
                -SamAccountName $svc.Sam `
                -ServiceClass $svc.SPN_Class `
                -Hostname $Hostname `
                -Port $svc.Port
            $tokenInfo.SPN = $spnResult.SPN
            $tokenInfo.DetectionRule = "Event ID 4769 (Kerberoast)"
        }

        $Tokens += $tokenInfo
    }

    # Deploy GPO decoy
    if ($IncludeGPODecoy) {
        $DomainShort = ($Domain -split '\.')[0].ToUpper()
        $gpo = New-DecoyGPO `
            -GPOName "Server Maintenance Policy (Legacy)" `
            -DecoyUsername "admin_maintenance" `
            -DecoyDomain $DomainShort `
            -SYSVOLPath $SYSVOLPath

        $Tokens += [PSCustomObject]@{
            Name          = "admin_maintenance"
            Type          = "gpo_credential"
            SPN           = ""
            DetectionRule = "Event ID 4625 (failed logon with GPP creds)"
        }
    }

    # Create BloodHound deception
    if ($IncludeBloodHoundPath -and $Tokens.Count -gt 0) {
        $bhPath = New-DeceptiveBloodHoundPath `
            -HoneytokenSamAccount $Tokens[0].Name
    }

    $deployment = [PSCustomObject]@{
        Environment = $Environment
        Tokens      = $Tokens
        DeployedAt  = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
        Log         = $Script:DeploymentLog
    }

    Write-DeployLog "Deployment complete: $($Tokens.Count) tokens deployed" "SUCCESS"
    return $deployment
}

# ---------------------------------------------------------------------------
# Export module members
# ---------------------------------------------------------------------------

Export-ModuleMember -Function @(
    'New-HoneytokenAdmin',
    'Add-HoneytokenSPN',
    'New-DecoyGPO',
    'New-DeceptiveBloodHoundPath',
    'Test-HoneytokenDeployment',
    'Deploy-FullHoneytokenSuite'
)
Keep exploring