Skip to content
Notifications
Clear all

Step-by-step: Correlating Mandiant IOCs with internal firewall logs

4 Posts
4 Users
0 Reactions
3 Views
(@security_auditor_ray)
Eminent Member
Joined: 2 months ago
Posts: 17
Topic starter   [#517]

Having recently completed a SOC 2 Type II audit, one of the key observations was the need to formally operationalize our external threat intelligence feeds. Specifically, we needed to demonstrate a repeatable process for taking Indicators of Compromise (IOCs) from a premium source like Mandiant and correlating them against our internal network telemetry. While the concept is straightforward, the devil is in the details—particularly around scale, false positive tuning, and maintaining the integrity of the intelligence.

This post outlines a step-by-step methodology I've implemented for correlating Mandiant IOCs (primarily IP addresses and domains from their `malware_feed`) with our aggregated firewall deny logs. The goal is to transform raw intelligence into actionable security events and, ultimately, measurable risk reduction.

### Prerequisites & Tooling
* **Mandiant Advantage Threat Intelligence** with API access.
* A dedicated, isolated VM (Linux) for intelligence processing.
* Centralized firewall log aggregation (we use a SIEM, but this could be from a syslog server).
* Python 3.x with the `requests` library for API interaction.

### Step 1: Structured IOC Acquisition
Mandiant's API provides several feeds. For network-based correlation, I focus on the `malware_feed` and `osint_feed`, filtering for `type` = `ipv4` or `domain`. A critical step is enriching each IOC with its associated confidence value and first-seen timestamp from Mandiant. This metadata is crucial for later prioritization.

```python
import requests

auth_url = 'https://api.intelligence.mandiant.com/token'
api_url = 'https://api.intelligence.mandiant.com/v4/indicator'
# ... (authentication flow omitted for brevity)

params = {
'type': 'ipv4',
'limit': 1000,
'sort_by': 'last_seen',
'sort_order': 'desc'
}
response = requests.get(api_url, headers=headers, params=params)
ioc_data = response.json()
# Parse and store IOC, confidence, first_seen, last_seen to a local database.
```

### Step 2: Log Preparation and Normalization
Our firewall logs are ingested into a central repository. The key fields required for correlation are:
* Source IP (external)
* Destination IP (internal)
* Destination port
* Action (deny/permit)
* Timestamp
I create a daily extract of all `deny` logs, normalizing the IP addresses and timestamps into a consistent format (UTC).

### Step 3: Correlation Logic & Execution
The correlation is performed as a batch job. The script iterates through the day's firewall deny logs and checks the source IP against the local Mandiant IOC database. A match creates a "hit." However, not all hits are equal. My scoring logic considers:
* **Mandiant Confidence Score:** `high` confidence matches are treated as critical.
* **Temporal Relevance:** IOCs seen by Mandiant within the last 72 hours are weighted higher.
* **Internal Context:** Repeated denials from the same IOC to multiple internal hosts increases priority.

```sql
-- Example log correlation query (pseudo-SQL)
SELECT fw.timestamp, fw.src_ip, m.ioc_value, m.confidence, m.first_seen
FROM firewall_logs fw
INNER JOIN mandiant_iocs m ON fw.src_ip = m.ioc_value
WHERE fw.date = CURRENT_DATE - 1
AND fw.action = 'deny'
AND m.ioc_type = 'ipv4'
ORDER BY m.confidence DESC, fw.timestamp DESC;
```

### Step 4: Analysis, Tuning, and Feedback Loop
The raw output of Step 3 will typically contain noise. The next phase is critical:
* **False Positive Investigation:** Many IOCs are scanning IPs. Correlate hits with internal vulnerability scan schedules or known benign services (e.g., CDN nodes).
* **Thresholding:** Implement a threshold (e.g., >5 distinct destination ports targeted) to filter out background scanning.
* **Feedback to Mandiant:** If an IOC consistently generates no actionable alerts after tuning, its utility for *our specific environment* is low. This informs future subscription decisions.

### Key Pitfalls & Considerations
* **API Rate Limiting:** Mandiant's API has strict limits. Design your polling script to respect these and cache results efficiently.
* **Data Freshness:** IOCs can become stale rapidly. A process must be in place to refresh the local IOC database at least daily.
* **Compliance & Data Handling:** Ensure that storing and processing firewall logs alongside threat intelligence feeds complies with your data retention policies and any relevant regulatory frameworks (e.g., GDPR, if dealing with EU attacker IPs).
* **Beyond Correlation:** The real value begins when this correlated data feeds into a risk-scoring model or is used to automate firewall rule updates (with extreme caution).

This process has provided tangible evidence for our SOC 2 controls around threat monitoring and risk assessment. The initial implementation yielded a 15% true positive rate for actionable malicious activity after tuning, which is a significant improvement over previous, less structured approaches.

- RayS


- RayS


   
Quote
(@marketing_ops_geek)
Trusted Member
Joined: 1 month ago
Posts: 32
 

This is fascinating, thanks for sharing. I'm on the marketing ops side, but our security team just went through a similar scramble for SOC 2. That "devil in the details" part is so real, especially for false positives. How often do you refresh the Mandiant feed in your setup? I could see us drowning in alerts if we pull too frequently.


MartechStruggles


   
ReplyQuote
(@eval_rookie_42)
Reputable Member
Joined: 4 months ago
Posts: 158
 

Thanks for the breakdown. Seeing the prerequisite list helps me get my head around the starting point. Could you clarify what specs you recommend for that isolated VM? I'm wondering about the minimum viable setup for a smaller team on a tight budget.



   
ReplyQuote
(@the_devops_jester)
Active Member
Joined: 2 months ago
Posts: 9
 

Nice setup. We took a similar approach last year and it's been a lifesaver, though we learned the hard way about letting that Python script run wild. Our first version pulled the full feed every hour and nearly got our API key revoked for hammering Mandiant's endpoints. Now we do a daily full pull with a separate, lighter check for high-confidence IOCs every four hours.

Speaking of integrity, we also hash the downloaded JSON and store it alongside the data. Saved our bacon during an audit when they wanted to verify we weren't tampering with the intel feed. It's a small extra step, but it makes the whole process feel less like a hacky script and more like a real pipeline.

Looking forward to seeing how you handle the log correlation part. That's where we had our funniest false positive - our own CI/CD system getting blocked for a week because a vendor's IP got flagged.


It's always DNS.


   
ReplyQuote