🚧 Under construction — VoTechWorks is being built. A free tech program — complimentary, as our commitment to get America working.
voTechWorksGrade 13 · a vocational technology learning center, by urbanicity
newSchoolWorks.com › VoTechWorks › Technology & Design › Cybersecurity › Scripting for Cybersecurity › Lesson 11
TEC-CYBE44-05 · Lesson 11 · 16 clock hours · lab

Scripting for Threat Intelligence: IOC Extraction and Feed Parsing

Objective. Students write a Python script that extracts indicators of compromise (IP addresses, domains, and file hashes) from unstructured threat-report text using regular expressions and enriches each IOC with data from a public threat-intelligence feed.

⚠ Pending professional review

This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.

VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.

What Are Indicators of Compromise?

An indicator of compromise (IOC) is a piece of observable evidence that suggests a system may have been attacked or infected. Security analysts collect IOCs from threat reports, vendor advisories, and incident post-mortems and use them to hunt for malicious activity across their environments. The three most common IOC types are:

Threat reports are often published as plain text or PDF exports, meaning analysts must parse unstructured prose to pull out usable IOCs. Python's built-in `re` module makes this practical and repeatable.

Regular Expressions for IOC Extraction

The `re` module lets you describe a pattern and search text for all matches. The key function here is `re.findall(pattern, text)`, which returns a list of every non-overlapping match.

IPv4 pattern: An IPv4 address is four groups of one to three digits separated by dots. A working pattern is:

```python

import re

ipv4_pattern = r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b'

```

The `\b` word-boundary anchors prevent matching digits that are part of longer strings. Note that this pattern matches syntactically valid-looking addresses; you may still see values like `999.0.0.1`. Filter those with a quick range check if needed.

Domain pattern: Domains end in a known top-level domain (TLD). A practical pattern for common TLDs is:

```python

domain_pattern = r'\b(?:[a-zA-Z0-9-]+\.)+(?:com|net|org|io|gov|edu|co|uk|ru|cn)\b'

```

Adjust the TLD list to match your threat landscape.

MD5 and SHA-256 hash patterns: MD5 hashes are exactly 32 hexadecimal characters; SHA-256 hashes are exactly 64.

```python

md5_pattern = r'\b[a-fA-F0-9]{32}\b'

sha256_pattern = r'\b[a-fA-F0-9]{64}\b'

```

Combine both into one list with `re.findall(md5_pattern, text) + re.findall(sha256_pattern, text)`.

Building the Extraction Script

Your script should accept a filename as a command-line argument (`sys.argv[1]`), read the file, run all three patterns, deduplicate each list with `list(set(...))`, then write a JSON file.

```python

import re, json, sys

def extract_iocs(text):

ips = list(set(re.findall(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', text)))

domains = list(set(re.findall(

r'\b(?:[a-zA-Z0-9-]+\.)+(?:com|net|org|io|gov|edu|co|uk|ru|cn)\b', text)))

hashes = list(set(

re.findall(r'\b[a-fA-F0-9]{64}\b', text) +

re.findall(r'\b[a-fA-F0-9]{32}\b', text)))

return {"ips": ips, "domains": domains, "hashes": hashes}

with open(sys.argv[1]) as f:

text = f.read()

result = extract_iocs(text)

with open("iocs.json", "w") as out:

json.dump(result, out, indent=2)

print("Done. IOCs written to iocs.json")

```

Deduplication matters because threat reports often repeat the same IP or domain multiple times. Wrap each list in `set()` before converting back to a list.

Enriching IOCs with AbuseIPDB

Once you have a list of IP addresses, you can query the AbuseIPDB API to retrieve an abuse confidence score (0–100) for each one. A score of 100 means the IP is widely reported as malicious.

The API returns HTTP 429 (Too Many Requests) when you exceed your rate limit. Handle this with a retry loop using `time.sleep()`:

```python

import requests, time

API_KEY = "YOUR_FREE_KEY_HERE"

HEADERS = {"Key": API_KEY, "Accept": "application/json"}

def enrich_ip(ip, retries=3):

url = "https://api.abuseipdb.com/api/v2/check"

params = {"ipAddress": ip, "maxAgeInDays": 90}

for attempt in range(retries):

resp = requests.get(url, headers=HEADERS, params=params)

if resp.status_code == 429:

print(f"Rate limited. Waiting before retry {attempt+1}...")

time.sleep(60)

continue

resp.raise_for_status()

data = resp.json()["data"]

return {"ip": ip, "abuseScore": data["abuseConfidenceScore"]}

return {"ip": ip, "abuseScore": None, "error": "rate_limit_exceeded"}

```

Return `None` for the score rather than crashing when retries are exhausted. This keeps your output file valid JSON regardless of API errors.

Safety and Responsible Use

Always run these scripts inside your designated Ubuntu lab VM, never on a production network or against live systems without authorization. Querying external APIs with real IOCs from classified or sensitive reports may expose that data to a third party — use only the sample files provided by your instructor. Store your API key in an environment variable, not hard-coded in source files that may be shared or submitted. Threat intelligence data can contain live malicious URLs; do not click or browse to any IOC directly from your workstation.

Connection to Exam Objectives

CompTIA CySA+ covers threat intelligence as a core domain. Expect exam questions on IOC types, threat-intelligence feeds, and how analysts operationalize intelligence. CompTIA Security+ also addresses threat data and indicators under its threat-management objectives. The ISC2 CC covers the concept of threat intelligence at a foundational level.

Key terms8

Indicator of Compromise (IOC)Observable evidence — such as an IP address, domain, or file hash — that suggests a system has been attacked or is communicating with malicious infrastructure.
re.findall()A Python function in the re module that searches a string for all non-overlapping matches to a regular expression pattern and returns them as a list.
Regular Expression (regex)A sequence of characters that defines a search pattern, used here to identify IP addresses, domain names, and file hashes inside unstructured text.
DeduplicationThe process of removing duplicate entries from a collection; in IOC extraction, converting a list to a set eliminates repeated values before writing output.
Threat Intelligence FeedA structured or automated data source that provides current information about threats, such as the AbuseIPDB API, which returns abuse confidence scores for IP addresses.
HTTP 429 Too Many RequestsAn HTTP status code returned by an API when the caller has exceeded the allowed request rate; scripts should detect this and wait before retrying.
Abuse Confidence ScoreA numeric value (0–100) returned by AbuseIPDB indicating how strongly the community believes an IP address is involved in malicious activity.
SHA-256 HashA 256-bit (64 hexadecimal character) cryptographic digest of a file, used as an IOC to identify known malicious files regardless of filename.
In class: Instructor demo: use re.findall with patterns for IPv4 addresses, domain names, and MD5/SHA256 hashes to extract IOCs from a plain-text threat report, printing results to stdout. · Lab exercise: students write a complete IOC-extraction script that accepts a text file argument, extracts all three IOC types into separate lists, deduplicates them, and writes a JSON file with keys ips, domains, hashes and their respective arrays. · Enrichment extension: students add a function that submits each extracted IP to the AbuseIPDB API and appends the returned abuse score to each IP entry in the JSON output, handling rate-limit errors with a retry after a short sleep.
Materials: Ubuntu VM, Python 3 re and json module docs, sample threat-report text files provided by instructor, free AbuseIPDB API account, course lab guide chapter 11, CompTIA CySA+ objectives (threat intelligence domain)
Check: JSON output matches instructor answer key for all three IOC types with correct deduplication, and the enrichment function handles a simulated rate-limit error (HTTP 429) without crashing; both required to pass.

Practice check8

Answer each question, then check it. Nothing is recorded; this is your own practice.

Security+ / CySA+ — Security Operations / Threat Intelligence
1. An analyst runs `re.findall(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b', text)` on a threat report. What does the function return?
CySA+ — Threat Intelligence
2. A student's IOC-extraction script finds the same domain repeated eight times in the report. After running `list(set(domains))`, how many times does that domain appear in the output JSON?
CySA+ — Threat Intelligence / IOC Analysis
3. Which regular expression pattern correctly matches a SHA-256 file hash?
CySA+ — Threat Intelligence / Automation
4. The AbuseIPDB API returns HTTP 429. What should a well-written enrichment function do next?
Security+ — Security Program Management and Oversight / Secure Coding
5. Why should an API key for AbuseIPDB be stored in an environment variable rather than hard-coded in the Python script?
CySA+ — Threat Intelligence
6. A student queries AbuseIPDB for an IP and receives an abuse confidence score of 95. What does this value most likely indicate?
Security+ / CySA+ — Security Operations
7. Which of the following best describes the purpose of word-boundary anchors (`\b`) in IOC-extraction regex patterns?
CySA+ — Threat Intelligence / Incident Response
8. A threat analyst wants to operationalize IOCs extracted from a report by blocking malicious IPs at the perimeter firewall. Which step should come FIRST?
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.