Skip to content

Threat Intelligence Analysis Scripts

This section contains auditing tools written in Go to parse CloudTrail logs and analyze multi-stage attack scenarios.


1. CloudTrail Anomaly Detector (cloudtrail-anomaly.go)

Purpose

Parses AWS CloudTrail events and identifies multi-stage privilege escalation sequences, console logins without MFA, and logs-tampering indicators (like CloudTrail stop logging events).

Code Implementation

// Purpose: Parses AWS CloudTrail events and identifies multi-stage privilege escalation sequences, console logins without MFA, and logs-tampering indicators.
package main

import (
    "encoding/json"
    "fmt"
    "strings"
    "time"
)

// CloudTrailEvent represents a standard structured AWS CloudTrail log record.
type CloudTrailEvent struct {
    EventTime        string       `json:"eventTime"`
    EventName        string       `json:"eventName"`
    EventSource      string       `json:"eventSource"`
    AWSRegion        string       `json:"awsRegion"`
    SourceIPAddress  string       `json:"sourceIPAddress"`
    UserIdentity     UserIdentity `json:"userIdentity"`
    ErrorCode        string       `json:"errorCode,omitempty"`
    ErrorMessage     string       `json:"errorMessage,omitempty"`
    AdditionalFields string       `json:"additionalEventData,omitempty"`
}

// UserIdentity holds information about the caller who triggered the event.
type UserIdentity struct {
    Type           string         `json:"type"`
    PrincipalID    string         `json:"principalId"`
    ARN            string         `json:"arn"`
    AccountID      string         `json:"accountId"`
    SessionContext SessionContext `json:"sessionContext,omitempty"`
}

// SessionContext represents temporary credentials info.
type SessionContext struct {
    Attributes SessionAttributes `json:"attributes"`
}

// SessionAttributes contains MFA details.
type SessionAttributes struct {
    MFAUsed string `json:"mfaAuthenticated"`
}

// AnomalyFinding holds the suspicious patterns identified.
type AnomalyFinding struct {
    Type        string
    Description string
    ActorARN    string
    SourceIP    string
    Time        string
}

func main() {
    // Simulated CloudTrail logs representing a multi-stage attack flow:
    // 1. ConsoleLogin from a foreign IP without MFA.
    // 2. StopLogging to attempt defense evasion.
    // 3. CreateUser followed immediately by AttachUserPolicy (privilege escalation chain).
    // 4. Multiple KMS decryption Access Denied events (recon/probing).
    cloudTrailLogsJSON := `[
        {
            "eventTime": "2026-06-28T18:00:00Z",
            "eventName": "ConsoleLogin",
            "eventSource": "signin.amazonaws.com",
            "awsRegion": "us-east-1",
            "sourceIPAddress": "198.51.100.42",
            "userIdentity": {
                "type": "IAMUser",
                "arn": "arn:aws:iam::123456789012:user/dev-operator",
                "accountId": "123456789012",
                "sessionContext": {
                    "attributes": {
                        "mfaAuthenticated": "false"
                    }
                }
            }
        },
        {
            "eventTime": "2026-06-28T18:01:05Z",
            "eventName": "StopLogging",
            "eventSource": "cloudtrail.amazonaws.com",
            "awsRegion": "us-west-2",
            "sourceIPAddress": "198.51.100.42",
            "userIdentity": {
                "type": "IAMUser",
                "arn": "arn:aws:iam::123456789012:user/dev-operator",
                "accountId": "123456789012"
            }
        },
        {
            "eventTime": "2026-06-28T18:02:15Z",
            "eventName": "CreateUser",
            "eventSource": "iam.amazonaws.com",
            "awsRegion": "us-east-1",
            "sourceIPAddress": "198.51.100.42",
            "userIdentity": {
                "type": "IAMUser",
                "arn": "arn:aws:iam::123456789012:user/dev-operator",
                "accountId": "123456789012"
            }
        },
        {
            "eventTime": "2026-06-28T18:02:30Z",
            "eventName": "AttachUserPolicy",
            "eventSource": "iam.amazonaws.com",
            "awsRegion": "us-east-1",
            "sourceIPAddress": "198.51.100.42",
            "userIdentity": {
                "type": "IAMUser",
                "arn": "arn:aws:iam::123456789012:user/dev-operator",
                "accountId": "123456789012"
            }
        },
        {
            "eventTime": "2026-06-28T18:04:10Z",
            "eventName": "Decrypt",
            "eventSource": "kms.amazonaws.com",
            "awsRegion": "us-east-1",
            "sourceIPAddress": "198.51.100.42",
            "errorCode": "AccessDenied",
            "errorMessage": "User arn:aws:iam::123456789012:user/dev-operator is not authorized to perform kms:Decrypt on resource",
            "userIdentity": {
                "type": "IAMUser",
                "arn": "arn:aws:iam::123456789012:user/dev-operator",
                "accountId": "123456789012"
            }
        }
    ]`

    fmt.Println("==================================================")
    fmt.Println("🛡️ CloudTrail Threat Hunting & Anomaly Audit Engine")
    fmt.Println("==================================================")

    var events []CloudTrailEvent
    if err := json.Unmarshal([]byte(cloudTrailLogsJSON), &events); err != nil {
        fmt.Printf("Error unmarshaling logs: %v\n", err)
        return
    }

    var findings []AnomalyFinding

    // Keep track of event frequencies to identify rapid multi-stage privilege escalation
    // Maps: Actor ARN -> Slice of Events (Name + Time)
    actorChains := make(map[string][]struct {
        Name string
        Time time.Time
    })

    for _, event := range events {
        parsedTime, err := time.Parse(time.RFC3339, event.EventTime)
        if err != nil {
            parsedTime = time.Now()
        }

        // Track actions per actor for sequence mapping
        actorARN := event.UserIdentity.ARN
        actorChains[actorARN] = append(actorChains[actorARN], struct {
            Name string
            Time time.Time
        }{Name: event.EventName, Time: parsedTime})

        // Rule 1: ConsoleLogin without MFA
        if event.EventName == "ConsoleLogin" {
            mfa := event.UserIdentity.SessionContext.Attributes.MFAUsed
            if mfa == "false" || mfa == "" {
                findings = append(findings, AnomalyFinding{
                    Type:        "DEFENSE BYPASS",
                    Description: "Console login succeeded without MFA enforcement.",
                    ActorARN:    actorARN,
                    SourceIP:    event.SourceIPAddress,
                    Time:        event.EventTime,
                })
            }
        }

        // Rule 2: Defense Evasion - CloudTrail Alteration
        if event.EventName == "StopLogging" || event.EventName == "DeleteTrail" || event.EventName == "UpdateTrail" {
            findings = append(findings, AnomalyFinding{
                Type:        "LOG TAMPERING",
                Description: fmt.Sprintf("Defense evasion indicator: Action '%s' executed on audit logging service.", event.EventName),
                ActorARN:    actorARN,
                SourceIP:    event.SourceIPAddress,
                Time:        event.EventTime,
            })
        }

        // Rule 3: KMS AccessDenied Decrypt probing
        if event.EventSource == "kms.amazonaws.com" && event.ErrorCode == "AccessDenied" {
            if strings.Contains(strings.ToLower(event.EventName), "decrypt") {
                findings = append(findings, AnomalyFinding{
                    Type:        "RECONNAISSANCE / DATA PROBING",
                    Description: "Multiple unauthorized attempts to decrypt KMS keys (AccessDenied).",
                    ActorARN:    actorARN,
                    SourceIP:    event.SourceIPAddress,
                    Time:        event.EventTime,
                })
            }
        }
    }

    // Rule 4: Multi-stage Privilege Escalation Analysis (Sequence correlation)
    // Check if the same actor executes 'CreateUser' then 'AttachUserPolicy' within 5 minutes.
    for actor, chain := range actorChains {
        for i := 0; i < len(chain)-1; i++ {
            if chain[i].Name == "CreateUser" {
                // Scan subsequent events within 5 minutes
                for j := i + 1; j < len(chain); j++ {
                    if chain[j].Name == "AttachUserPolicy" {
                        diff := chain[j].Time.Sub(chain[i].Time)
                        if diff < 5*time.Minute {
                            findings = append(findings, AnomalyFinding{
                                Type:        "PRIVILEGE ESCALATION SEQUENCE",
                                Description: fmt.Sprintf("Critical pattern: 'CreateUser' followed by 'AttachUserPolicy' by same user within %.1f seconds.", diff.Seconds()),
                                ActorARN:    actor,
                                SourceIP:    "Multi-session / Correlated",
                                Time:        chain[j].Time.Format(time.RFC3339),
                            })
                        }
                    }
                }
            }
        }
    }

    // Print results
    if len(findings) == 0 {
        fmt.Println("Scan complete. No anomalous sequences or security indicators identified.")
    } else {
        fmt.Printf("Hunting Complete: Found %d critical security events / anomalies:\n\n", len(findings))
        for _, f := range findings {
            fmt.Printf("[%s] Time: %s | Source IP: %s\n", f.Type, f.Time, f.SourceIP)
            fmt.Printf("   - Actor:  %s\n", f.ActorARN)
            fmt.Printf("   - Details: %s\n\n", f.Description)
        }
    }
}