Criminal IP is a threat intelligence platform that provides insights into IP addresses, domains, and other network components. It provides the necessary information to assess risks and identify potential threats, enabling security teams to react to malicious activity proactively. Integrating Wazuh with Criminal IP creates a synergy that enhances security monitoring, network management, and system administration.
Businesses can create an effective defense mechanism by leveraging detailed Criminal IP insights alongside Wazuh XDR capabilities, minimizing potential vulnerabilities and preventing attacks before they escalate. This post explores a step-by-step guide to integrating these two solutions to enhance security.
Requirements
We use the following infrastructure to demonstrate the integration of Wazuh and Criminal IP.
- Wazuh 4.10.0 central components (Wazuh server, Wazuh indexer, Wazuh dashboard) installed using the Quickstart guide on an Ubuntu 22.04 server.
- An Ubuntu 22.04 endpoint with a Wazuh agent installed and enrolled to the Wazuh server.
- A registered account with Criminal IP.
- A Kali Linux endpoint as an attacker for simulating events.
Configuration
Follow the steps to register with Criminal IP, get your API key, and configure Wazuh to query Criminal IP API. The returned data, including risk scores and threat indicators, is then used by Wazuh to automatically generate alerts, classify threats, or block the identified IP addresses.
Criminal IP
1. Log in to your Criminal IP account and generate your personalized API key.
2. Navigate to My Information from the dropdown at the top right corner.
3. Copy and save the API key generated for you, as you will use it later in this post.
Note: Free Criminal IP membership only comes with 50 free credits for IP address lookup. You can upgrade to a premium subscription for higher usage based on the activities of your monitored endpoints.
Wazuh server
Follow these steps to create a custom Python script and XML rules to query IP addresses detected by Wazuh.
1. Create a script file /var/ossec/integrations/custom-criminalip.py
with the following content to query the API of Criminal IP and process the data received:
#!/var/ossec/framework/python/bin/python3 # Shahidahktar@gmail.com # Developed by Shahid Akhter import sys import os import json import ipaddress import requests from requests.exceptions import ConnectionError, HTTPError from socket import socket, AF_UNIX, SOCK_DGRAM import time # Enable or disable debugging debug_enabled = True # Set to False to disable debug logging # File and socket paths pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) socket_addr = f'{pwd}/queue/sockets/queue' # Set paths for logging now = time.strftime("%a %b %d %H:%M:%S %Z %Y") log_file = f'{pwd}/logs/integrations.log' def debug(msg): """Log debug messages.""" if debug_enabled: timestamped_msg = f"{now}: {msg}\n" print(timestamped_msg) with open(log_file, "a") as f: f.write(timestamped_msg) def send_event(msg, agent=None): """Send an event to the Wazuh Manager.""" try: if not agent or agent["id"] == "000": string = f'1:criminalip:{json.dumps(msg)}' else: string = f'1:[{agent["id"]}] ({agent["name"]}) {agent["ip"] if "ip" in agent else "any"}->criminalip:{json.dumps(msg)}' debug(f"Sending Event: {string}") with socket(AF_UNIX, SOCK_DGRAM) as sock: sock.connect(socket_addr) sock.send(string.encode()) except Exception as e: debug(f"Error sending event: {e}") # Read configuration parameters try: alert_file = open(sys.argv[1]) alert = json.loads(alert_file.read()) alert_file.close() debug("Alert loaded successfully") except Exception as e: debug(f"Error reading alert file: {e}") sys.exit(1) # New Alert Output for CriminalIP Alert or Error calling the API alert_output = {} # Criminal IP API AUTH KEY criminalip_api_key = sys.argv[2] # API - HTTP Headers criminalip_apicall_headers = { "x-api-key": f"{criminalip_api_key}" } # Extract Event Source try: event_source = alert["rule"]["groups"] debug(f"Event source: {event_source}") except KeyError as e: debug(f"Missing expected key in alert: {e}") sys.exit(1) if any(group in ['web', 'sshd', 'invalid_login', 'firewall', 'ids', 'system', 'database', 'application'] for group in event_source): try: client_ip = alert["data"]["srcip"] # Extract client IP debug(f"Extracted Client IP: {client_ip}") if ipaddress.ip_address(client_ip).is_global: # Pass the client_ip value directly into the URL criminalip_search_url = f'https://api.criminalip.io/v1/asset/ip/report?ip={client_ip}&full=true' debug(f"CriminalIP API URL: {criminalip_search_url}") try: criminalip_api_response = requests.get(criminalip_search_url, headers=criminalip_apicall_headers) criminalip_api_response.raise_for_status() # Raise HTTPError for bad responses debug("API request successful") except ConnectionError as conn_err: alert_output["criminalip"] = {"error": 'Connection Error to CriminalIP API'} alert_output["integration"] = "criminalip" debug(f"ConnectionError: {conn_err}") send_event(alert_output, alert.get("agent")) except HTTPError as http_err: alert_output["criminalip"] = {"error": f'HTTP Error: {http_err}'} alert_output["integration"] = "criminalip" debug(f"HTTPError: {http_err}") send_event(alert_output, alert.get("agent")) except Exception as e: alert_output["criminalip"] = {"error": f'Unexpected Error: {e}'} alert_output["integration"] = "criminalip" debug(f"Unexpected Error: {e}") send_event(alert_output, alert.get("agent")) else: try: criminalip_api_response = criminalip_api_response.json() debug(f"API Response Data: {criminalip_api_response}") # Check if the response contains score information if "score" in criminalip_api_response and criminalip_api_response["score"]: # Generate Alert Output from CriminalIP Response score = criminalip_api_response["score"] issues = criminalip_api_response["issues"] alert_output["criminalip"] = { "ip": criminalip_api_response["ip"], "score_inbound": score.get("inbound", "Unknown"), "score_outbound": score.get("outbound", "Unknown"), "is_vpn": issues.get("is_vpn", False), "is_tor": issues.get("is_tor", False), "is_proxy": issues.get("is_proxy", False), "is_cloud": issues.get("is_cloud", False), "is_hosting": issues.get("is_hosting", False), "is_darkweb": issues.get("is_darkweb", False), "is_scanner": issues.get("is_scanner", False), "is_snort": issues.get("is_snort", False), "is_anonymous_vpn": issues.get("is_anonymous_vpn", False) } alert_output["integration"] = "criminalip" debug(f"Alert Output: {alert_output}") send_event(alert_output, alert.get("agent")) else: alert_output["criminalip"] = {"error": 'No score information found in CriminalIP response'} alert_output["integration"] = "criminalip" debug("No score information found in CriminalIP response") send_event(alert_output, alert.get("agent")) except Exception as e: alert_output["criminalip"] = {"error": f"Error parsing JSON response: {e}"} alert_output["integration"] = "criminalip" debug(f"Error parsing JSON response: {e}") send_event(alert_output, alert.get("agent")) else: debug(f"Client IP is not global: {client_ip}") sys.exit() except KeyError as e: alert_output["criminalip"] = {"error": f'Missing expected key: {e}'} alert_output["integration"] = "criminalip" debug(f"KeyError: {e}") send_event(alert_output, alert.get("agent")) sys.exit() else: debug(f"Event source is not found : {event_source}") sys.exit()
2. Set the ownership and permissions of the /var/ossec/integrations/custom-criminalip.py
file so that the root
user and the wazuh
group have access to it:
# chmod 750 /var/ossec/integrations/custom-criminalip.py # chown root:wazuh /var/ossec/integrations/custom-criminalip.py
3. Append the following configuration to the /var/ossec/etc/ossec.conf
file to enable Wazuh to query the Criminal IP API and enrich alerts for the specified groups. Replace <CRIMINALIP_API_KEY>
with your own Criminal IP API key:
<ossec_config> <integration> <name>custom-criminalip.py</name> <api_key><CRIMINALIP_API_KEY></api_key> <!-- Replace with your Criminal IP API key --> <group>web, sshd, invalid_login, firewall, ids, system, database, application</group> <alert_format>json</alert_format> </integration> </ossec_config>
Note: These groups are selected because they include events associated with IP addresses needed for this integration. As criminal IP requires IP addresses to process for a feedback.
4. Create a file /var/ossec/etc/rules/criminal_ip_ruleset.xml
with the following rules:
<group name="criminalip,"> <!-- Main Criminal IP Rule --> <rule id="100623" level="2"> <decoded_as>json</decoded_as> <field name="integration">criminalip</field> <description>Criminal IP Events</description> </rule> <!-- VPN Detection Rule --> <rule id="100624" level="6"> <if_sid>100623</if_sid> <field name="criminalip.is_vpn">true</field> <description>IP address associated with a VPN service detected: $(criminalip.ip)</description> </rule> <!-- TOR Detection Rule --> <rule id="100625" level="10"> <if_sid>100623</if_sid> <field name="criminalip.is_tor">true</field> <description>IP address associated with TOR network detected: $(criminalip.ip)</description> </rule> <!-- Proxy Detection Rule --> <rule id="100626" level="5"> <if_sid>100623</if_sid> <field name="criminalip.is_proxy">true</field> <description>IP address associated with a Proxy server detected: $(criminalip.ip)</description> </rule> <!-- Dark Web Activity Rule --> <rule id="100627" level="8"> <if_sid>100623</if_sid> <field name="criminalip.is_darkweb">true</field> <description>IP address associated with Dark web activity detected: $(criminalip.ip)</description> </rule> <!-- Critical Score Rule --> <rule id="100628" level="8"> <if_sid>100623</if_sid> <field name="criminalip.score_inbound">Critical</field> <description>Critical risk score for IP address: $(criminalip.ip)</description> </rule> <!-- Dangerous Score Rule --> <rule id="100629" level="9"> <if_sid>100623</if_sid> <field name="criminalip.score_inbound">Dangerous</field> <description>Dangerous risk score for IP address: $(criminalip.ip)</description> </rule> <!-- Moderate Score Rule --> <rule id="100630" level="6"> <if_sid>100623</if_sid> <field name="criminalip.score_inbound">Moderate</field> <description>Moderate risk score for IP address: $(criminalip.ip)</description> </rule> <!-- Low Score Rule --> <rule id="100631" level="3"> <if_sid>100623</if_sid> <field name="criminalip.score_inbound">Low</field> <description>Low risk score for IP address: $(criminalip.ip)</description> </rule> <!-- Hosting Detection Rule --> <rule id="100633" level="5"> <if_sid>100623</if_sid> <field name="criminalip.is_hosting">true</field> <description>IP address associated with a Hosting service detected: $(criminalip.ip)</description> </rule> <!-- Cloud Service Detection Rule --> <rule id="100634" level="4"> <if_sid>100623</if_sid> <field name="criminalip.is_cloud">true</field> <description>IP address associated with Cloud service detected : $(criminalip.ip)</description> </rule> <!-- Scanner Activity Detection Rule --> <rule id="100636" level="7"> <if_sid>100623</if_sid> <field name="criminalip.is_scanner">true</field> <description>IP address associated with scanner activity detected: $(criminalip.ip)</description> </rule> <!-- Mobile Network Detection Rule, This rule may cause high false positives and can be uncommented based on user preference <rule id="100637" level="4"> <if_sid>100623</if_sid> <field name="criminalip.is_mobile">true</field> <description>IP address associated with a Mobile network detected: $(criminalip.ip)</description> </rule> --> <!-- Anonymous VPN Detection Rule --> <rule id="100638" level="5"> <if_sid>100623</if_sid> <field name="criminalip.is_anonymous_vpn">true</field> <description>IP address associated with an Anonymous VPN detected: $(criminalip.ip)</description> </rule> <!-- Error: Missing Parameter --> <rule id="100640" level="5"> <if_sid>100623</if_sid> <field name="full_log">.*Missing Parameter.*</field> <description>CriminalIP API error: Missing parameter in request</description> </rule> <!-- Error: Invalid IP Address --> <rule id="100641" level="5"> <if_sid>100623</if_sid> <field name="full_log">.*Invalid IP Address.*</field> <description>CriminalIP API error: Invalid IP address format</description> </rule> <!-- Error: Internal Server Error --> <rule id="100642" level="7"> <if_sid>100623</if_sid> <field name="full_log">.*Internal Server Error.*</field> <description>CriminalIP API error: Internal server error encountered</description> </rule> </group>
Where:
- Rule
100623
is triggered when events associated with Criminal IP integration are observed, filtering logs related to the Criminal IP integration for further analysis. - Rule
100624
is triggered when IP addresses associated with VPN usage are detected, indicating potential obfuscation of traffic origin. - Rule
100625
is triggered when IP addresses associated with TOR network usage are observed, often linked with anonymized or malicious activity. - Rule
100626
is triggered when IP addresses associated with proxy server usage are observed, suggesting attempts to hide the real source of traffic. - Rule
100627
is triggered when IP addresses linked to dark web activity are observed, which may indicate malicious or illicit actions. - Rule
100628
is triggered when critical risk scores assigned by Criminal IP are observed, highlighting IP addresses that require immediate attention. - Rule
100629
is triggered when dangerous risk scores from Criminal IP are observed, marking IPs as potential threats that need closer monitoring. - Rule
100630
is triggered when moderate risk scores from Criminal IP are observed, indicating threats that are worthy of attention but not urgent. - Rule
100631
is triggered when low-risk scores from Criminal IP are observed, suggesting minimal threats but still worth monitoring. - Rule
100633
is triggered when IP addresses associated with a hosting service are observed. - Rule
100634
is triggered when cloud service usage linked to an IP address is observed, which could be used to host attacks or compromised activities. - Rule
100636
is triggered when scanner activity is observed, which may indicate vulnerability scanning or reconnaissance. - Rule
100637
is triggered when an IP address associated with mobile network usage is observed, often linked to mobile-specific threats or targeted attacks. - Rule
100638
is triggered when IP addresses associated with anonymous VPN usage are observed, which is commonly used to mask malicious activities. - Rule
100640
is triggered when missing parameters in requests to the Criminal IP API are observed, raising an alert for errors. - Rule
100641
is triggered when invalid IP address format errors in the Criminal IP API occur. - Rule
100642
is triggered when internal server errors in the Criminal IP API are detected, which could indicate issues with the API’s processing capabilities.
5. Set the ownership and permissions of the /var/ossec/etc/rules/criminal_ip_ruleset.xml
file:
# chmod 660 /var/ossec/etc/rules/criminal_ip_ruleset.xml # chown wazuh:wazuh /var/ossec/etc/rules/criminal_ip_ruleset.xml
6. Restart the Wazuh manager to apply the changes:
# systemctl restart wazuh-manager
Ubuntu endpoint
Perform the following steps to install an Apache web server and monitor its logs with the Wazuh agent.
1. Update local packages and install the Apache web server:
# apt update # apt install apache2
2. If the firewall is enabled, modify the firewall to allow external access to web ports. Skip this step if the firewall is disabled:
# ufw status # ufw app list # ufw allow 'Apache'
3. Check the status of the Apache service to verify that the web server is running:
# systemctl status apache2
4. Use the curl command or open http://<UBUNTU_IP>
in a browser to view the Apache landing page and verify the installation:
# curl http://<UBUNTU_IP>
5. Append the following configuration to the /var/ossec/etc/ossec.conf
file to monitor the Apache access logs:
<ossec_config> <localfile> <log_format>syslog</log_format> <location>/var/log/apache2/access.log</location> </localfile> </ossec_config>
6. Restart the Wazuh agent to apply the changes:
# systemctl restart wazuh-agent
Simulating Tor activity
Follow the steps below to test the integration by simulating an attack and generating an alert of an IP address associated with Tor network usage. In this scenario, we will simulate directory traversal using a known Tor IP address on the web server.
Perform the following steps on the Kali Linux endpoint.
1. Install Tor and proxychains:
# apt update # apt install tor proxychains4
2. Edit the proxychains configuration file /etc/proxychains4.conf
, and add or uncomment the Tor proxy socks4 127.0.0.1 9050
.
3. Start the Tor service and ensure Tor is running:
# systemctl start tor # systemctl status tor
4. Access the web server using the corresponding Ubuntu endpoint IP address. Replace <UBUNTU_IP>
with the IP address of the Ubuntu endpoint.
# proxychains curl "http://<UBUNTU_IP>/index.html?param=../../../../etc/passwd"
Wazuh will trigger a known web attack rule with rule ID 31106
containing the IP address of the Kali Linux endpoint, which is part of the selected web
group. This IP address is then sent to the criminal IP detection module. If the queried IP address is associated with the Tor network, Wazuh will generate an alert for that IP address, indicating that it is linked to suspicious or criminal activity.
View the alerts on the Wazuh dashboard
The alerts below are generated on the Wazuh dashboard when Wazuh queries IP addresses against the Criminal IP database and finds known malicious activity and risk scores. Perform the following steps to view the alerts on the Wazuh dashboard.
1. Navigate to Threat intelligence > Threat Hunting.
2. Click + Add filter. Filter for rule.groups
in the Field field.
3. Filter for is
in the Operator field.
4. Filter for criminalip
in the Value field.
5. Click Save to enable the filter.
Note: The alerts below resulted from public exposure to the web server and automated bot scanners scanning the network range.
Analyzing alerts generated by the integration, data is enriched with key fields that need to be investigated, such as:
- Inbound and Outbound Scores: Prioritize incidents based on these scores. A high outbound score may indicate a compromised internal system.
- Threat Indicators:
- Is VPN: suggests VPN traffic has been detected, potentially indicating an attempt to mask the source of the connection or packet origin.
- Is TOR: indicates the IP is associated with the TOR network and needs further investigation, as TOR is often linked to illicit activities.
- Is Scanner: Indicates potential reconnaissance activity, which can precede an attack.
- Is Dark Web: suggests the IP is associated with the dark web which is commonly used for illegal activities.
Conclusion
Integrating Wazuh with Criminal IP strengthens your cybersecurity by combining the real-time monitoring and log analysis of Wazuh with the detailed threat intelligence from Criminal IP. This combination allows you to gain a clearer view of potential risks, automate actions based on IP reputation data, and take faster, more informed steps to protect your infrastructure from evolving threats.
References