IOC Analysis

Intelligence

Indicators of Compromise (IOCs) are forensic artifacts that identify potentially malicious activity. Learn to analyze, correlate, and hunt for IOCs to detect and respond to threats.

🔍

IOC Lookup Tool

Search hashes, IPs, domains, and URLs across multiple threat intel sources

Examples (click to try):

The Pyramid of Pain

IOCs vary in value. Hash values are easy to change, while TTPs are hardest to modify. Focus on behavioral indicators and TTPs for more resilient detection.

IOC Types & Pyramid of Pain

Pyramid of Pain

⬆️ Harder to change⬇️ Easier to change

Source: David J. Bianco's Pyramid of Pain - The higher up the pyramid, the more pain for adversaries when you detect their indicators.

Hash-Based IOCs

File hashes uniquely identify malicious files but are easily defeated by minor modifications.

Calculating Hashes

bash
# Windows PowerShell
Get-FileHash -Algorithm MD5 malware.exe
Get-FileHash -Algorithm SHA256 malware.exe

# Linux
md5sum malware.exe
sha256sum malware.exe

# Multiple hashes at once
sha256sum * | tee hashes.txt

# Python
import hashlib
with open('malware.exe', 'rb') as f:
    md5 = hashlib.md5(f.read()).hexdigest()
    print(f"MD5: {md5}")

Hash Lookup Services

bash
# VirusTotal API lookup
curl -s "https://www.virustotal.com/api/v3/files/SHA256_HASH" \
  -H "x-apikey: YOUR_API_KEY" | jq '.data.attributes.last_analysis_stats'

# MalwareBazaar lookup
curl -s -X POST "https://mb-api.abuse.ch/api/v1/" \
  -d "query=get_info&hash=SHA256_HASH"

# Hybrid Analysis
curl -s "https://www.hybrid-analysis.com/api/v2/search/hash" \
  -H "api-key: YOUR_API_KEY" \
  -d "hash=SHA256_HASH"

Fuzzy Hashing (SSDEEP)

Fuzzy hashes detect similar files even with modifications. Useful for tracking malware families.

bash
# Generate SSDEEP hash
ssdeep malware.exe
# 384:H4lg5xF5zHNzP8DznYZrBPG3qG8qYGLr3:H4WFNEP8pYZrBPG3qG8qYGw

# Compare two files
ssdeep -d sample1.exe sample2.exe

# Compare against a hashset
ssdeep -m known_hashes.txt sample.exe

# Generate hashes for a directory
ssdeep -r /samples/ > ssdeep_hashes.txt

Network-Based IOCs

IP Address Analysis

bash
# WHOIS lookup
whois 192.168.1.1

# Reverse DNS
dig -x 192.168.1.1
nslookup 192.168.1.1

# Geolocation
curl -s "http://ip-api.com/json/8.8.8.8" | jq

# AbuseIPDB check
curl -s "https://api.abuseipdb.com/api/v2/check" \
  -H "Key: YOUR_API_KEY" \
  -G -d "ipAddress=192.168.1.1" | jq

# Shodan lookup
shodan host 192.168.1.1

# GreyNoise
curl -s "https://api.greynoise.io/v3/community/192.168.1.1" | jq

Domain Analysis

bash
# DNS records
dig ANY example.com
dig +short example.com A AAAA MX NS TXT

# Historical DNS (PassiveTotal/RiskIQ)
curl -s "https://api.passivetotal.org/v2/dns/passive" \
  -u "user:apikey" \
  -d '{"query": "example.com"}'

# Subdomain enumeration
subfinder -d example.com
amass enum -d example.com

# URLhaus check
curl -s -X POST "https://urlhaus-api.abuse.ch/v1/host/" \
  -d "host=example.com"

# Domain age check (WHOIS creation date)
whois example.com | grep -i "creation date"

URL Analysis

bash
# URLScan.io submission
curl -s "https://urlscan.io/api/v1/scan/" \
  -H "API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "http://suspicious-site.com", "visibility": "public"}'

# Check URL against URLhaus
curl -s -X POST "https://urlhaus-api.abuse.ch/v1/url/" \
  -d "url=http://suspicious-site.com"

# Google Safe Browsing
curl -s "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client":{"clientId":"test"},"threatInfo":{"threatTypes":["MALWARE"],"platformTypes":["ANY_PLATFORM"],"threatEntryTypes":["URL"],"threatEntries":[{"url":"http://suspicious-site.com"}]}}'

YARA Rules

YARA is the pattern matching swiss army knife for malware researchers. Create rules to identify malware families based on strings, byte patterns, and file characteristics.

Basic YARA Rule Structure

yara
rule ExampleMalware {
    meta:
        author = "Analyst Name"
        description = "Detects ExampleMalware family"
        date = "2024-01-01"
        reference = "https://example.com/report"
        hash = "abc123..."
        
    strings:
        $string1 = "malicious_string" ascii wide
        $string2 = { 4D 5A 90 00 }  // MZ header
        $regex1 = /http:\/\/[a-z0-9]+\.evil\.com/
        $b64_config = "YWRtaW4==" base64
        
    condition:
        uint16(0) == 0x5A4D and     // PE file
        filesize < 500KB and
        (2 of ($string*) or $regex1)
}

Advanced YARA Patterns

yara
rule Cobalt_Strike_Beacon {
    meta:
        description = "Detects Cobalt Strike Beacon payloads"
        
    strings:
        // Default Cobalt Strike watermark
        $watermark = { 00 00 00 00 00 00 00 00 00 00 00 00 }
        
        // Common strings
        $s1 = "%s (admin)" ascii
        $s2 = "beacon.dll" ascii
        $s3 = "ReflectiveLoader" ascii
        
        // Config markers
        $config = { 00 01 00 01 00 02 }
        
        // Sleep mask
        $sleep = { 4C 8B DC 49 89 5B 08 49 89 6B 10 }
        
    condition:
        uint16(0) == 0x5A4D and
        (
            2 of ($s*) or
            ($config and $watermark) or
            $sleep
        )
}

rule Mimikatz_Memory {
    meta:
        description = "Detects Mimikatz in memory"
        
    strings:
        $s1 = "sekurlsa::" ascii wide
        $s2 = "kerberos::" ascii wide
        $s3 = "lsadump::" ascii wide
        $s4 = "gentilkiwi" ascii wide
        $s5 = "mimikatz" ascii wide nocase
        
    condition:
        3 of them
}

Running YARA Scans

bash
# Scan a single file
yara rules.yar suspicious_file.exe

# Scan a directory recursively
yara -r rules.yar /path/to/scan/

# Scan with multiple rule files
yara rule1.yar rule2.yar target.exe

# Output matching strings
yara -s rules.yar target.exe

# Scan process memory (Linux)
yara -p rules.yar 1234

# Timeout for large files
yara -t 60 rules.yar large_file.bin

# Python YARA scanning
import yara
rules = yara.compile(filepath='rules.yar')
matches = rules.match('/path/to/file')
for match in matches:
    print(f"Matched: {match.rule}")

Sigma Rules

Sigma is a generic signature format for SIEM systems. Write once, convert to any SIEM query language.

yaml
title: Suspicious PowerShell Download
id: 3b6ab547-8ec2-4991-b9d2-2b06702a48d7
status: experimental
description: Detects PowerShell download cradle patterns
author: Security Team
date: 2024/01/01
references:
    - https://attack.mitre.org/techniques/T1059/001/
logsource:
    category: process_creation
    product: windows
detection:
    selection_img:
        - Image|endswith: '\powershell.exe'
        - OriginalFileName: 'PowerShell.EXE'
    selection_cli:
        CommandLine|contains|all:
            - 'Net.WebClient'
            - 'DownloadString'
    condition: all of selection_*
falsepositives:
    - Legitimate scripts downloading content
level: high
tags:
    - attack.execution
    - attack.t1059.001
    - attack.command_and_control
    - attack.t1105
bash
# Convert Sigma to various formats
# Install: pip install sigma-cli

# Convert to Splunk
sigma convert -t splunk -p splunk_windows rule.yml

# Convert to Elastic/EQL
sigma convert -t lucene -p ecs_windows rule.yml

# Convert to Microsoft Sentinel
sigma convert -t azure_monitor rule.yml

# Convert to SIEM format with pipeline
sigma convert -t splunk -p splunk_windows -p windows_audit rules/*.yml

# Validate rules
sigma check rule.yml

Threat Hunting Queries

Splunk Hunting Queries

spl
# Hunt for encoded PowerShell
index=windows EventCode=4688 
| where like(CommandLine, "%powershell%") AND (like(CommandLine, "%-enc%") OR like(CommandLine, "%-e %") OR like(CommandLine, "%base64%"))
| stats count by Computer, User, CommandLine

# Unusual parent-child processes
index=windows EventCode=4688
| eval parent_child=ParentProcessName."->"ProcessName
| where NOT match(parent_child, "explorer.exe->cmd.exe|svchost.exe->msiexec.exe")
| rare parent_child

# LSASS access detection
index=windows EventCode=4663 ObjectName="*lsass*"
| stats count by Computer, ProcessName, AccessMask
| where ProcessName!="System"

# Suspicious scheduled tasks
index=windows (EventCode=4698 OR EventCode=4702)
| where like(TaskContent, "%powershell%") OR like(TaskContent, "%cmd.exe%")
| table _time, Computer, TaskName, TaskContent

Elastic/KQL Queries

kql
// Encoded PowerShell detection
event.code: "4688" and process.command_line: (*powershell* AND (*-enc* OR *-e * OR *base64*))

// Potential credential dumping
event.code: "10" and winlog.event_data.TargetImage: *lsass.exe and 
not process.executable: (*\Windows\System32\* OR *\Windows\SysWOW64\*)

// Lateral movement via WMI
event.code: "1" and process.parent.name: "wmiprvse.exe" and 
process.name: ("cmd.exe" OR "powershell.exe")

// Persistence via registry run keys
registry.path: *\CurrentVersion\Run* and 
event.action: "modification" and 
registry.data.strings: (*powershell* OR *cmd* OR *.exe)

Microsoft Defender/KQL

kql
// Suspicious process injection
DeviceEvents
| where ActionType == "CreateRemoteThreadApiCall"
| where InitiatingProcessFileName !in~ ("csrss.exe", "lsass.exe", "services.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine

// PowerShell web requests
DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("WebClient", "Invoke-WebRequest", "wget", "curl", "DownloadString")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine

// Potential Cobalt Strike activity
DeviceNetworkEvents
| where RemotePort in (80, 443, 8080, 8443)
| where InitiatingProcessFileName in~ ("rundll32.exe", "regsvr32.exe", "mshta.exe")
| summarize count() by InitiatingProcessFileName, RemoteIP, RemotePort

IOC Management

STIX/TAXII Format

json
{
  "type": "indicator",
  "spec_version": "2.1",
  "id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
  "created": "2024-01-01T00:00:00.000Z",
  "modified": "2024-01-01T00:00:00.000Z",
  "name": "Malicious IP Address",
  "description": "C2 server used by APT group",
  "indicator_types": ["malicious-activity"],
  "pattern": "[ipv4-addr:value = '192.168.1.100']",
  "pattern_type": "stix",
  "valid_from": "2024-01-01T00:00:00.000Z",
  "kill_chain_phases": [
    {
      "kill_chain_name": "mitre-attack",
      "phase_name": "command-and-control"
    }
  ],
  "labels": ["c2", "apt"]
}

OpenIOC Format

xml
<?xml version="1.0" encoding="UTF-8"?>
<ioc xmlns="http://openioc.org/schemas/OpenIOC_1.1" 
     id="12345678-1234-1234-1234-123456789012">
  <short_description>Malware Family XYZ</short_description>
  <authored_by>Security Team</authored_by>
  <authored_date>2024-01-01T00:00:00</authored_date>
  <definition>
    <Indicator operator="OR">
      <IndicatorItem condition="is">
        <Context document="FileItem" search="FileItem/Md5sum"/>
        <Content type="md5">d41d8cd98f00b204e9800998ecf8427e</Content>
      </IndicatorItem>
      <IndicatorItem condition="contains">
        <Context document="ProcessItem" search="ProcessItem/name"/>
        <Content type="string">malware.exe</Content>
      </IndicatorItem>
    </Indicator>
  </definition>
</ioc>

IOC Enrichment Pipeline

Automate IOC enrichment by integrating multiple threat intelligence sources. Use tools like MISP, OpenCTI, or custom scripts to automatically enrich IOCs with context from VirusTotal, Shodan, and threat feeds.