What You Will Achieve
By the end of this playbook you will have:
- A Python script that pulls malicious IPs from isMalicious and formats them for your firewall
- iptables, pfSense, Palo Alto, and cloud implementation examples
- A cron schedule that keeps blocklists fresh every 6 hours
- Change detection so only new IPs are added (no duplicate rules)
Prerequisites
| Requirement | Details | |---|---| | isMalicious API key | Free tier gives 1,000 checks/day; Pro for bulk export | | Python 3.9+ | Runs the sync script | | Root/admin access | Required to modify firewall rules |
Step 1: Fetch Malicious IPs from isMalicious
The STIX/TAXII feed (Pro) is the cleanest way to pull IOCs in bulk. For free tier, use the bulk check endpoint.
Using the TAXII feed (Pro)
import base64
import requests
TAXII_URL = "https://api.ismalicious.com/taxii/api-root/collections/malicious-ips/objects"
API_KEY = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
HDR = {"X-API-KEY": base64.b64encode(f"{API_KEY}:{API_SECRET}".encode()).decode()}
def fetch_malicious_ips():
resp = requests.get(
TAXII_URL,
params={"limit": 1000},
headers=HDR
)
resp.raise_for_status()
bundle = resp.json()
ips = []
for obj in bundle.get("objects", []):
if obj.get("type") == "indicator":
pattern = obj.get("pattern", "")
# Extract IPv4 from STIX pattern: [ipv4-addr:value = '1.2.3.4']
if "ipv4-addr:value" in pattern:
ip = pattern.split("'")[1]
ips.append(ip)
return ips
Step 2: iptables Integration
blocklist_update.sh
#!/bin/bash
set -euo pipefail
CHAIN="ISMALICIOUS_BLOCK"
BLOCKLIST="/tmp/ismalicious_ips.txt"
# Fetch fresh blocklist
python3 /opt/ismalicious/fetch_ips.py > "$BLOCKLIST"
# Create chain if it doesn't exist
iptables -N "$CHAIN" 2>/dev/null || true
iptables -F "$CHAIN"
# Re-add all rules
while IFS= read -r ip; do
[[ -z "$ip" ]] && continue
iptables -A "$CHAIN" -s "$ip" -j DROP
iptables -A "$CHAIN" -d "$ip" -j DROP
done < "$BLOCKLIST"
# Ensure chain is referenced from INPUT/OUTPUT/FORWARD
iptables -C INPUT -j "$CHAIN" 2>/dev/null || iptables -I INPUT 1 -j "$CHAIN"
iptables -C OUTPUT -j "$CHAIN" 2>/dev/null || iptables -I OUTPUT 1 -j "$CHAIN"
iptables -C FORWARD -j "$CHAIN" 2>/dev/null || iptables -I FORWARD 1 -j "$CHAIN"
echo "$(date): Updated $(wc -l < "$BLOCKLIST") blocked IPs"
Add to cron
# Every 6 hours
0 */6 * * * /opt/ismalicious/blocklist_update.sh >> /var/log/ismalicious_blocklist.log 2>&1
Step 3: pfSense with pfBlockerNG
pfBlockerNG cannot send the X-API-KEY header. Use a cron job on the firewall (or a jump host) to download with curl and Base64 credentials, then point pfBlockerNG at the local file (see blocklist guide):
curl -fsS -H "X-API-KEY: $(echo -n 'KEY:SECRET' | base64)" \
"https://api.ismalicious.com/blocklist/download/blocklist-ips-all.txt" \
-o /var/db/pfblockerng/ismalicious-ips.txt
Step 4: AWS Security Group Automation
import boto3
from fetch_ips import fetch_malicious_ips
ec2 = boto3.client("ec2", region_name="us-east-1")
SG_ID = "sg-XXXXXXXXXXXXXXXXX"
def update_security_group():
ips = fetch_malicious_ips()
# Remove all existing deny rules
sg = ec2.describe_security_groups(GroupIds=[SG_ID])["SecurityGroups"][0]
if sg.get("IpPermissionsEgress"):
ec2.revoke_security_group_egress(
GroupId=SG_ID,
IpPermissions=sg["IpPermissionsEgress"]
)
# Add new deny rules in batches of 50 (AWS limit)
ip_ranges = [{"CidrIp": f"{ip}/32", "Description": "isMalicious block"} for ip in ips[:50]]
if ip_ranges:
ec2.authorize_security_group_egress(
GroupId=SG_ID,
IpPermissions=[{
"IpProtocol": "-1",
"IpRanges": ip_ranges
}]
)
print(f"Updated {len(ip_ranges)} blocked IPs in {SG_ID}")
if __name__ == "__main__":
update_security_group()
Step 5: Palo Alto Networks
PAN-OS EDL URLs cannot send X-API-KEY. Host the list yourself: cron downloads blocklist-ips-all.txt (or critical) via curl + Base64 credentials to an internal HTTPS server or object storage, then point the EDL at that URL.
Validation
After deploying, verify a known malicious IP is blocked:
# Test connectivity to a known malicious IP (should timeout/be blocked)
curl --connect-timeout 3 http://185.220.101.1/ || echo "Blocked successfully"
# Check iptables hit count
iptables -L ISMALICIOUS_BLOCK -v -n | head -20
Monitoring & Alerting
Log every blocked connection for SOC review:
# Log instead of silently drop (for SIEM ingestion)
iptables -A ISMALICIOUS_BLOCK -s "$ip" -j LOG --log-prefix "ISMALICIOUS_BLOCKED: "
iptables -A ISMALICIOUS_BLOCK -s "$ip" -j DROP
Route these logs to your SIEM and create an alert rule for high-frequency hits (potential active attack).