Skip to main content

Threat Hunting

Threat hunting identifies malicious activity that evades automated detection by applying human analysis to security telemetry. This task covers the complete hunt cycle from hypothesis formation through investigation, documentation, and conversion of findings into persistent detections. Execute hunts on a scheduled cadence and in response to new threat intelligence relevant to your organisation’s risk profile.

Prerequisites

RequirementDetail
AccessRead access to SIEM, EDR console, and log aggregation platform
PermissionsQuery execution rights; incident creation rights if findings warrant
ToolsSIEM query interface, EDR console, spreadsheet for tracking
InformationCurrent threat intelligence reports, asset inventory, network topology
Time4-8 hours per hunt cycle

Verify SIEM query access before beginning:

-- Test query to confirm access (Wazuh example)
SELECT agent.name, rule.description, @timestamp
FROM wazuh-alerts-*
WHERE @timestamp > now() - 1h
LIMIT 10

Expected output shows recent alerts with agent names. If the query returns a permissions error, request the wazuh_read role from your identity provider administrator.

For EDR access, confirm you can view endpoint telemetry:

# Wazuh agent list verification
/var/ossec/bin/agent_control -l

Expected output lists managed agents with status. A count of zero agents indicates configuration issues with the EDR deployment rather than permission problems.

Procedure

Phase 1: Hypothesis Development

  1. Select a threat behaviour to investigate based on current intelligence or organisational risk. Good hypotheses are specific, testable, and grounded in attacker tradecraft. The hypothesis “Attackers may have compromised our network” is too vague. The hypothesis “An attacker with access to Office 365 credentials is forwarding email to an external address for exfiltration” is specific and testable.

    Structure your hypothesis using this format:

    HYPOTHESIS: [Actor type] is [technique] to [objective]
    DATA SOURCES: [Logs/telemetry required]
    INDICATORS: [Observable evidence if true]
    TIMEFRAME: [Investigation period]

    Example hypothesis document:

    HYPOTHESIS: An external attacker is using compromised credentials
    to access SharePoint and download sensitive documents
    outside business hours
    DATA SOURCES: Azure AD sign-in logs, SharePoint audit logs,
    Conditional Access logs
    INDICATORS: - Sign-ins from unusual locations
    - Large volume downloads (>50 files/session)
    - Access between 22:00-06:00 local time
    - Sign-ins without MFA challenge
    TIMEFRAME: Past 30 days
  2. Map the hypothesis to MITRE ATT&CK techniques to standardise documentation and enable cross-referencing with threat intelligence. For the SharePoint exfiltration hypothesis, relevant techniques include T1078 (Valid Accounts), T1213 (Data from Information Repositories), and T1567 (Exfiltration Over Web Service).

    Document the mapping:

    MITRE ATT&CK MAPPING:
    - T1078.004: Cloud Accounts
    - T1213.002: SharePoint
    - T1567.002: Exfiltration to Cloud Storage
  3. Identify required data sources and verify availability. Each hypothesis requires specific telemetry. Absent or incomplete data sources limit what you can detect.

    +------------------------------------------------------------------+
    | DATA SOURCE VERIFICATION |
    +------------------------------------------------------------------+
    | |
    | Hypothesis: SharePoint credential abuse |
    | |
    | +------------------------+ +------------------------+ |
    | | Azure AD Sign-in Logs | | SharePoint Audit Logs | |
    | | | | | |
    | | Required fields: | | Required fields: | |
    | | - userPrincipalName | | - UserId | |
    | | - ipAddress | | - Operation | |
    | | - location | | - ObjectId | |
    | | - createdDateTime | | - CreationTime | |
    | | - status | | - ClientIP | |
    | | | | | |
    | | Retention: 30 days | | Retention: 90 days | |
    | | Status: AVAILABLE | | Status: AVAILABLE | |
    | +------------------------+ +------------------------+ |
    | |
    | +------------------------+ |
    | | Conditional Access | |
    | | | |
    | | Required fields: | |
    | | - policyName | |
    | | - result | |
    | | - conditions | |
    | | | |
    | | Retention: 30 days | |
    | | Status: AVAILABLE | |
    | +------------------------+ |
    | |
    +------------------------------------------------------------------+

    Figure 1: Data source verification for SharePoint credential abuse hunt

    Query to verify Azure AD log ingestion:

    -- Check Azure AD log availability (30-day window)
    SELECT COUNT(*) as event_count,
    MIN(createdDateTime) as earliest,
    MAX(createdDateTime) as latest
    FROM azure_signin_logs
    WHERE createdDateTime > now() - 30d

    Expected output shows event count in thousands with timestamps spanning the full period. Gaps in the timestamp range indicate log ingestion failures.

Phase 2: Investigation

  1. Execute baseline queries to understand normal patterns before searching for anomalies. Establish what typical behaviour looks like for the activity you are investigating.

    For the SharePoint example, first establish baseline access patterns:

    -- Baseline: Normal SharePoint access hours by user
    SELECT userPrincipalName,
    HOUR(createdDateTime) as access_hour,
    COUNT(*) as access_count
    FROM sharepoint_audit
    WHERE CreationTime > now() - 30d
    AND Operation = 'FileDownloaded'
    GROUP BY userPrincipalName, HOUR(createdDateTime)
    ORDER BY userPrincipalName, access_hour

    Document baseline findings before proceeding:

    BASELINE FINDINGS:
    - 94% of file downloads occur 08:00-18:00 local time
    - Average downloads per user per day: 12
    - Maximum downloads per user per day: 87 (finance team)
    - Users with after-hours access: 23 (identified roles)
  2. Execute detection queries targeting the specific indicators from your hypothesis. Start with broad queries and narrow based on results.

    Query for after-hours SharePoint access:

    -- Detection: After-hours file downloads
    SELECT UserId,
    ClientIP,
    ObjectId,
    CreationTime,
    Operation
    FROM sharepoint_audit
    WHERE CreationTime > now() - 30d
    AND Operation = 'FileDownloaded'
    AND (HOUR(CreationTime) < 6 OR HOUR(CreationTime) > 22)
    ORDER BY CreationTime DESC

    Query for high-volume download sessions:

    -- Detection: High-volume download sessions (>50 files in 1 hour)
    SELECT UserId,
    ClientIP,
    DATE_TRUNC('hour', CreationTime) as session_hour,
    COUNT(*) as download_count
    FROM sharepoint_audit
    WHERE CreationTime > now() - 30d
    AND Operation = 'FileDownloaded'
    GROUP BY UserId, ClientIP, DATE_TRUNC('hour', CreationTime)
    HAVING COUNT(*) > 50
    ORDER BY download_count DESC

    Query for sign-ins from unusual locations:

    -- Detection: Sign-ins from countries not in approved list
    SELECT userPrincipalName,
    ipAddress,
    location.countryOrRegion,
    createdDateTime,
    status.errorCode
    FROM azure_signin_logs
    WHERE createdDateTime > now() - 30d
    AND location.countryOrRegion NOT IN ('GB', 'KE', 'UG', 'ET', 'JO')
    AND status.errorCode = 0 -- Successful sign-ins only
    ORDER BY createdDateTime DESC
  3. Correlate findings across data sources. A single anomalous event requires context from related telemetry to determine whether it represents malicious activity or legitimate behaviour.

    +------------------------------------------------------------------+
    | CORRELATION WORKFLOW |
    +------------------------------------------------------------------+
    | |
    | SHAREPOINT ANOMALY AZURE AD CONTEXT |
    | +-------------------+ +-------------------+ |
    | | UserId: jsmith | | Same user: | |
    | | Time: 02:15 UTC +------>| Sign-in: 02:10 | |
    | | Files: 156 | | Location: Lagos | |
    | | ClientIP: x.x.x.x | | MFA: Not required | |
    | +-------------------+ +-------------------+ |
    | | | |
    | | | |
    | v v |
    | +-------------------+ +-------------------+ |
    | | EDR CONTEXT | | HISTORICAL | |
    | | | | | |
    | | No endpoint | | Prior sign-ins: | |
    | | associated with | | All from London | |
    | | this IP | | MFA always used | |
    | +-------------------+ +-------------------+ |
    | | | |
    | +-------------+-------------+ |
    | | |
    | v |
    | +----------------------------+ |
    | | ASSESSMENT: HIGH SUSPICION | |
    | | - Unusual location | |
    | | - No MFA challenge | |
    | | - Bulk download | |
    | | - Outside business hours | |
    | +----------------------------+ |
    | |
    +------------------------------------------------------------------+

    Figure 2: Cross-source correlation for suspicious SharePoint activity

    Correlation query joining Azure AD and SharePoint data:

    -- Correlate SharePoint downloads with Azure AD sign-ins
    SELECT sp.UserId,
    sp.ClientIP,
    sp.CreationTime as download_time,
    sp.ObjectId as file_path,
    az.location.countryOrRegion as signin_country,
    az.conditionalAccessStatus,
    az.mfaDetail.authMethod
    FROM sharepoint_audit sp
    JOIN azure_signin_logs az
    ON sp.UserId = az.userPrincipalName
    AND az.createdDateTime BETWEEN sp.CreationTime - INTERVAL '1 hour'
    AND sp.CreationTime
    WHERE sp.CreationTime > now() - 30d
    AND sp.Operation = 'FileDownloaded'
    AND (HOUR(sp.CreationTime) < 6 OR HOUR(sp.CreationTime) > 22)
    ORDER BY sp.CreationTime DESC
  4. Investigate each finding to classify as true positive, false positive, or requiring further investigation. Document your analysis for each finding.

    Classification criteria:

    Finding characteristicsClassificationAction
    Matches known malicious indicators, no legitimate explanationTrue positiveEscalate to incident response
    Matches indicators but legitimate business reason confirmedFalse positiveDocument, tune detection
    Ambiguous, requires additional contextRequires investigationGather additional data

    For each finding, document:

    FINDING #1
    ----------
    User: jsmith@example.org
    Event: 156 file downloads, 02:15 UTC, IP: 102.89.xx.xx (Lagos)
    INVESTIGATION:
    - Contacted user's manager: User not travelling
    - Checked HR system: User based in London office
    - Reviewed prior 90 days: No prior access from Nigeria
    - Checked approved travel: No travel authorisation
    CLASSIFICATION: TRUE POSITIVE - Credential compromise suspected
    ACTION: Escalate to incident response
    REFERENCE: INC-2024-0892

Phase 3: Documentation and Handoff

  1. Document all findings regardless of classification. False positives inform detection tuning. Ambiguous findings may become relevant in future investigations.

    Create a hunt report with the following structure:

    THREAT HUNT REPORT
    ==================
    Hunt ID: TH-2024-047
    Analyst: [Your name]
    Date: 2024-11-16
    Duration: 6 hours
    HYPOTHESIS
    ----------
    An external attacker is using compromised credentials to access
    SharePoint and download sensitive documents outside business hours.
    MITRE ATT&CK: T1078.004, T1213.002, T1567.002
    DATA SOURCES USED
    -----------------
    - Azure AD sign-in logs (30 days)
    - SharePoint audit logs (30 days)
    - Conditional Access logs (30 days)
    QUERIES EXECUTED
    ----------------
    [Include all queries with results summary]
    FINDINGS
    --------
    Total findings: 3
    True positives: 1
    False positives: 1
    Requires investigation: 1
    [Detailed finding documentation]
    DETECTION OPPORTUNITIES
    -----------------------
    Based on this hunt, the following detections should be created:
    1. Alert on sign-ins from non-approved countries followed by
    SharePoint access (priority: HIGH)
    2. Alert on >50 file downloads in 1-hour window (priority: MEDIUM)
    RECOMMENDATIONS
    ---------------
    1. Enable Conditional Access policy to require MFA for
    all SharePoint access regardless of location
    2. Implement geographic access restrictions for high-risk
    document libraries
  2. Convert validated findings into persistent detections. Each true positive represents a detection gap that should be closed to catch similar activity automatically in future.

    +------------------------------------------------------------------+
    | HYPOTHESIS-TO-DETECTION PIPELINE |
    +------------------------------------------------------------------+
    | |
    | HUNT FINDING DETECTION RULE |
    | +------------------+ +------------------+ |
    | | True positive: | | Rule name: | |
    | | Credential abuse +------->| Suspicious | |
    | | from unusual | | SharePoint | |
    | | location | | access pattern | |
    | +------------------+ +------------------+ |
    | | |
    | v |
    | +------------------+ |
    | | TESTING | |
    | | | |
    | | - Backtest 90d | |
    | | - FP rate check | |
    | | - Threshold tune | |
    | +------------------+ |
    | | |
    | v |
    | +------------------+ |
    | | PRODUCTION | |
    | | | |
    | | - Deploy rule | |
    | | - Set severity | |
    | | - Assign owner | |
    | +------------------+ |
    | |
    +------------------------------------------------------------------+

    Figure 3: Converting hunt findings to production detections

    Example SIEM detection rule (Wazuh format):

    <rule id="100201" level="10">
    <if_sid>87801</if_sid>
    <field name="azure.signin.location.countryOrRegion">
    ^(?!GB|KE|UG|ET|JO)
    </field>
    <field name="azure.signin.status.errorCode">0</field>
    <description>
    Successful sign-in from non-approved country: $(azure.signin.location.countryOrRegion)
    </description>
    <group>authentication,credential_abuse,T1078</group>
    </rule>

    Example correlation rule for SharePoint after sign-in:

    <rule id="100202" level="12">
    <if_matched_sid>100201</if_matched_sid>
    <field name="sharepoint.operation">FileDownloaded</field>
    <timeframe>3600</timeframe>
    <description>
    SharePoint file download following sign-in from non-approved country
    </description>
    <group>exfiltration,T1213</group>
    </rule>
  3. Hand off true positive findings to incident response if they represent active threats. Provide the incident handler with:

    • Complete finding documentation
    • All relevant log entries
    • User and asset context
    • Your preliminary assessment
    • Queries for further investigation

    Create an incident referral:

    INCIDENT REFERRAL
    =================
    From: Threat Hunting (TH-2024-047)
    To: Incident Response
    Priority: HIGH
    SUMMARY
    -------
    Suspected credential compromise for user jsmith@example.org.
    Evidence of bulk file exfiltration from SharePoint.
    EVIDENCE
    --------
    - Sign-in from Lagos, Nigeria at 02:10 UTC (user based London)
    - No MFA challenge (Conditional Access gap)
    - 156 files downloaded from /sites/finance/ at 02:15-02:47 UTC
    - No prior history of Nigeria access
    - User's manager confirms no travel
    RECOMMENDED ACTIONS
    -------------------
    1. Suspend user account pending investigation
    2. Revoke active sessions
    3. Review downloaded files for sensitivity
    4. Investigate source IP for other activity
    ATTACHED
    --------
    - Full query results (CSV)
    - Timeline of events
    - User profile from HR system

Variants

Minimal Capacity Hunt

Organisations without dedicated security staff can conduct simplified hunts using built-in cloud platform capabilities.

For Microsoft 365 environments, use the built-in Advanced Hunting in Microsoft Defender:

// Simplified hunt: Unusual sign-in locations
SigninLogs
| where TimeGenerated > ago(30d)
| where ResultType == 0
| summarize Countries = make_set(LocationDetails.countryOrRegion),
SigninCount = count() by UserPrincipalName
| where array_length(Countries) > 3
| order by SigninCount desc

For Google Workspace, use the Admin Console investigation tool with these search parameters:

  • Event: Login
  • Time range: Last 30 days
  • Filter: Suspicious login = Yes

Document findings in a spreadsheet if no formal case management exists.

Intelligence-Driven Hunt

When threat intelligence indicates a specific actor or campaign targeting your sector, structure the hunt around known indicators and techniques.

  1. Extract indicators from the intelligence report
  2. Map techniques to data sources you have available
  3. Query for both exact indicator matches and behavioural patterns
  4. Document negative findings (absence of indicators is useful intelligence)

Example hunt for a known credential phishing campaign:

-- Search for known phishing infrastructure
SELECT srcip, dstip, url, timestamp
FROM web_proxy_logs
WHERE timestamp > now() - 14d
AND (
domain LIKE '%login-microsoftonline%'
OR domain LIKE '%sharepoint-auth%'
OR domain IN ('malicious-domain-1.com', 'malicious-domain-2.net')
)

Automated Hunt Queries

Schedule recurring queries for high-priority hypotheses that should run continuously rather than periodically.

# Example scheduled hunt configuration (Wazuh)
scheduled_hunts:
- name: "Impossible travel detection"
schedule: "0 */4 * * *" # Every 4 hours
query: |
SELECT userPrincipalName,
location1, location2,
time1, time2,
distance_km,
required_hours,
actual_hours
FROM (
-- Subquery calculating travel feasibility
)
WHERE actual_hours < required_hours
threshold: 1
action: create_alert
- name: "Service account interactive login"
schedule: "0 * * * *" # Hourly
query: |
SELECT userPrincipalName, ipAddress, appDisplayName
FROM azure_signin_logs
WHERE userPrincipalName LIKE 'svc-%'
AND appDisplayName NOT IN ('Approved App 1', 'Approved App 2')
threshold: 1
action: create_alert

Verification

Confirm hunt completion by verifying each phase produced expected outputs:

HUNT COMPLETION CHECKLIST
=========================
Phase 1: Hypothesis
[ ] Hypothesis documented with ATT&CK mapping
[ ] Data sources identified and availability confirmed
[ ] Investigation timeframe defined
Phase 2: Investigation
[ ] Baseline queries executed and documented
[ ] Detection queries executed
[ ] All findings correlated across sources
[ ] Each finding classified (TP/FP/needs investigation)
Phase 3: Documentation
[ ] Hunt report completed
[ ] Queries saved for reuse
[ ] Detection rules drafted for true positives
[ ] Incidents created for active threats

Verify detection rules before production deployment:

-- Backtest new detection against historical data
SELECT COUNT(*) as alert_count,
COUNT(DISTINCT userPrincipalName) as unique_users
FROM azure_signin_logs
WHERE createdDateTime > now() - 90d
AND location.countryOrRegion NOT IN ('GB', 'KE', 'UG', 'ET', 'JO')
AND status.errorCode = 0

Expected output provides baseline alert volume. More than 50 alerts per day indicates the detection threshold needs tuning to reduce analyst burden.

Troubleshooting

SymptomCauseResolution
Query returns no results when data should existField names incorrect for your SIEM platformCheck platform documentation for exact field names; use field discovery query
Query timeout after 5+ minutesQuery scanning too much data without filtersAdd time range filter first; use indexed fields in WHERE clause
Too many false positives in resultsBaseline not established; thresholds too lowRun baseline analysis first; increase thresholds based on normal patterns
Cannot correlate across data sourcesTimestamps not aligned; user identifiers differNormalise timestamps to UTC; create lookup table for user identifier mapping
Log retention insufficient for hunt timeframeLogs aged out before analysisAdjust hunt timeframe to available retention; request retention extension for future hunts
Hypothesis too broad to investigateMultiple techniques combinedSplit into separate hypotheses; investigate one technique at a time
EDR telemetry gaps on some endpointsAgent not deployed or unhealthyQuery agent status; remediate unhealthy agents before hunting on those endpoints
Cannot access required data sourcesPermissions not provisionedRequest access through IAM process; document access requirements for future hunters
Hunt taking longer than allocated timeScope creep; following tangential leadsTime-box investigation; document tangential findings for separate future hunts
Detection rule generating alerts on historical dataRule applied retroactively to existing logsConfigure rule with start time; suppress alerts for events before rule creation
Findings do not match threat intelligenceIntelligence outdated or not applicable to environmentValidate intelligence recency; confirm techniques are relevant to your technology stack
Cannot determine if finding is true or false positiveInsufficient context about user/assetEngage HR, manager, or asset owner for context; document as “requires investigation” if unresolved

Hunt Cadence and Prioritisation

Schedule hunts based on threat landscape and available capacity:

Hunt typeFrequencyTriggerPriority
Intelligence-drivenWithin 48 hours of relevant intelligenceNew sector-specific threat reportHigh
Technique-basedMonthly rotation through priority techniquesMITRE ATT&CK coverage planMedium
Baseline validationQuarterlyCalendar scheduleLow
Post-incidentWithin 1 week of significant incidentIncident closureHigh

Maintain a hunt backlog prioritised by:

  1. Techniques observed in sector-specific attacks
  2. Techniques with no current detection coverage
  3. Techniques targeting your highest-value assets
  4. Techniques newly added to ATT&CK or emerging in threat reports

See also