top of page

An AI-Integrated, Self-Healing Forensic Engine for Active Directory

The following script will be needed, you are welcome to add, remove and improve it, note that you don't need to have a Cisco secure endpoint account.

Script 1: Invoke-AIAnalyst.ps1 (The Engine)

Description: This file contains all the backend functions: Cisco API integration, the AbuseIPDB lookup, the "Shield" logic, and the connection to the local LLM.

 

Script 2: Get-SOCReport.ps1 (The Command Center)

Description: This is the main entry point. It handles the "Self-Healing" Sysmon installation, pulls the DC logs, and orchestrates the remote forensic connection.

"Prerequisites:

Ollama: Installed with llama3.2:1b pulled. (on the main computer where you will be running the scripts)

PowerShell 5.1+ running as Administrator.

API Keys: you will need API keys for Cisco and AbuseIPDB (VirusTotal) with your own keys.

 

Directory Structure: The scripts expect to live in an a path like D:\AD-SOC\ (or whatever path you choose, but make sure it is changed in the script.)

​​

"Disclaimer: This tool is for educational and authorized security testing purposes only. Automated blocking of IP addresses can impact network availability. Always test in a lab environment before deploying to production."

This is the SOC report: make a note of the names I mentioned above.

param(
    [string]$TargetWorkstation = "localhost" 
)

. "D:\AD-SOC\SOC_Tool\Invoke-AIAnalyst.ps1"
$DC = "srv-dc3"

Write-Host "`n--- [!] SOC COMMAND CENTER: SCANNING $TargetWorkstation ---" -ForegroundColor Cyan

# 1. Credentials for Remote Access
$Creds = Get-Credential -Message "Admin Access for $TargetWorkstation and $DC"

# 2. Cisco & DC Intelligence
$Cloud = Get-CiscoAlerts
Write-Host "[*] Harvesting DC Identity Logs..." -ForegroundColor Gray
$DCLogs = Get-WinEvent -ComputerName $DC -Credential $Creds -FilterHashtable @{LogName='Security'; ID=4624,4625} -MaxEvents 10 | ForEach-Object {
    [PSCustomObject]@{ Time=$_.TimeCreated; User=$_.Properties[5].Value; IP=$_.Properties[18].Value }
}

# 3. REMOTE FORENSICS (Corrected Logic)
Write-Host "[*] Reaching out to $TargetWorkstation for Sysmon Forensics..." -ForegroundColor Magenta
try {
    $Forensics = Invoke-Command -ComputerName $TargetWorkstation -Credential $Creds -ScriptBlock {
        $Logs = Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 5 -ErrorAction SilentlyContinue | Where-Object {$_.Id -eq 1}
        # We assign the loop to a variable then return the variable
        $Captured = foreach ($L in $Logs) {
            $Xml = [xml]$L.ToXml()
            [PSCustomObject]@{
                Time = $L.TimeCreated
                Process = ($Xml.Event.EventData.Data | Where-Object {$_.Name -eq "Image"}).'#text' -split "\\" | Select-Object -Last 1
                Command = ($Xml.Event.EventData.Data | Where-Object {$_.Name -eq "CommandLine"}).'#text'
            }
        }
        return $Captured
    } -ErrorAction Stop
    Write-Host "[✓] Remote Forensics Captured from $TargetWorkstation." -ForegroundColor Green
} catch {
    Write-Host "[X] Remote Forensic Link Failed: $($_.Exception.Message)" -ForegroundColor Red
}

# 4. AI Analysis
Write-Host "[*] Analyzing Hybrid Intel..." -ForegroundColor Yellow
$Report = "--- DC LOGS ---`n$($DCLogs | Out-String)`n--- REMOTE SYS-FORENSICS ($TargetWorkstation) ---`n$($Forensics | Out-String)`n--- CLOUD ---`n$Cloud"
$Verdict = Get-AIAnalysis -LogData $Report

# 5. Shield Logic
if ($Verdict -match "ACTION: BLOCK \[?([\d\.\w\-]+)\]?") {
    $T = $Matches[1]
    if ($T -match "^(10\.|192\.168\.|172\.|100\.)" -or $T -match "DC|Okta|srv") {
        Write-Host "[!] SHIELD: Block on $T Prevented." -ForegroundColor White -BackgroundColor Red
    } else {
        New-GuardrailBlock -Target $T -Node $TargetWorkstation -Reason $Verdict
    }
}

Write-Host "`n--- FINAL VERDICT ---`n$Verdict" -ForegroundColor Green

******************************************************************************************************

This is the Invoke-AIAnalyst Script:

# ==============================================================================
# --- SOC ENGINE: INVOKE-AIANALYST.PS1 (BUILD 37.0 - COMMAND CENTER) ---
# ==============================================================================

$CiscoClientID = "YOUR_CISCO_CLIENT_ID"
$CiscoAPIKey   = "YOUR_CISCO_API_KEY"
$CiscoHost     = "api.amp.cisco.com"
$AbuseIPDBKey  = "VirusTotal key"
$AssetFilePath = "D:\AD-SOC\Known_Assets.csv" # this is a list of assets that will be use as a reference to have less false positives.

# --- ASSET CONTEXT ---
function Get-AssetContext {
    if (Test-Path $AssetFilePath) {
        return Import-Csv $AssetFilePath | Select-Object -First 50 | Out-String
    }
    return "No Asset Reference Found."
}

# --- CISCO CLOUD ---
function Get-CiscoAlerts {
    $Pair = "${CiscoClientID}:${CiscoAPIKey}"; $Bytes = [System.Text.Encoding]::ASCII.GetBytes($Pair); $Base64 = [Convert]::ToBase64String($Bytes)
    $Headers = @{ "Authorization" = "Basic $Base64"; "Accept" = "application/json" }
    try {
        $Events = (Invoke-RestMethod -Method Get -Uri "https://$CiscoHost/v1/events?limit=5" -Headers $Headers -TimeoutSec 10).data
        if ($Events) { return $Events | ForEach-Object { "[CISCO] Host: $($_.computer.hostname) | Threat: $($_.detection)" } }
        return "Cisco: Clean."
    } catch { return "Cisco: Offline." }
}

# --- IP INTEL ---
function Get-IPIntel {
    param([string]$IPAddress)
    if ($IPAddress -match "^(10\.|192\.168\.|172\.|100\.)" -or $IPAddress -eq "::1") { return "Internal (Safe)" }
    try {
        $Resp = Invoke-RestMethod -Method Get -Uri "https://api.abuseipdb.com/api/v2/check?ipAddress=$IPAddress" -Headers @{"Key"=$AbuseIPDBKey}
        return "Abuse Score: $($Resp.data.abuseConfidenceScore)%"
    } catch { return "Intel Offline" }
}

# --- THE SHIELD (FIREWALL BLOCK) ---
function New-GuardrailBlock {
    param([string]$Target, [string]$Node, [string]$Reason)
    Write-Host "`n[!!!] BLOCK AUTHORIZATION REQUIRED [!!!]" -ForegroundColor Red -BackgroundColor Yellow
    Write-Host "Target: $Target | Node: $Node | Reason: $Reason"
    $Choice = Read-Host "Apply Block? (Y/N)"
    if ($Choice -eq "Y") {
        Invoke-Command -ComputerName $Node -ScriptBlock { param($T) New-NetFirewallRule -DisplayName "SOC-BLOCK-$T" -Direction Inbound -Action Block -RemoteAddress $T } -ArgumentList $Target
        return "SUCCESS: $Target Blocked."
    }
    return "SKIPPED."
}

# --- AI ADVISOR ---
function Get-AIAnalysis {
    param([string]$LogData)
    $SystemPrompt = @"
You are a Senior SOC Manager. 
CRITICAL OUTPUT RULES:
1. If healthy, ONLY write 'SYSTEM HEALTHY' and a 1-sentence summary.
2. DO NOT list every authorized user.
3. If threat exists, start with 'ACTION: BLOCK [IP/Host]'.
4. Explain HOW a threat is moving via LOCAL/REMOTE PROCESSES.
5. IGNORE all 10.x, 172.x, 192.x IPs for blocking.
"@
    $Body = @{ model="llama3.2:1b"; messages=@(@{role="system";content=$SystemPrompt},@{role="user";content=$LogData}); stream=$false } | ConvertTo-Json -Compress
    try {
        return (Invoke-RestMethod -Method Post -Uri "http://localhost:11434/api/chat" -Body $Body -ContentType "application/json").message.content
    } catch { return "AI Engine Offline." }
}

#######################################################################################################

Remember to do this test in a lab and not in a working environment, this is a great way to learn scripting and troubleshoot, you are going to run into issues while running these two scripts but that is the purpose, it is to learn!! good hunting.

  • Facebook - Black Circle
  • Twitter - Black Circle

© 2023 by IT SERVICES.  Proudly created with Wix.com

bottom of page