The integration is open source and lives on GitHub: Q-Feeds/Q-Feeds-Wazuh-Integration. Always take it from there so you get the current version. You need root access on the Wazuh manager, outbound HTTPS to api.qfeeds.com or taxii.qfeeds.com, and a Q-Feeds API token or TAXII credentials. See Get your threat feeds.
Prerequisites
- Wazuh manager: 4.x or later, installed in
/var/ossec - Privileges: root on the manager
- Packages:
curl. Python comes with Wazuh, at/var/ossec/framework/python/bin/python3, so you do not have to install it - Credentials: a Q-Feeds API token for standard mode, or a TAXII username and password for TAXII mode
- Network: outbound access to
api.qfeeds.comortaxii.qfeeds.comon port 443
Get the scripts
git clone https://github.com/Q-Feeds/Q-Feeds-Wazuh-Integration.git /tmp/qfeeds-wazuh
cd /tmp/qfeeds-wazuh
No git on the manager? Download the archive instead:
curl -sL https://github.com/Q-Feeds/Q-Feeds-Wazuh-Integration/archive/refs/heads/main.tar.gz | tar xz -C /tmp
cd /tmp/Q-Feeds-Wazuh-Integration-main
Install
sudo bash install.sh
The installer asks a handful of questions, writes the configuration, installs the updater, decoders, rules and a cron job, and then downloads the feeds for the first time. What it asks, in order:
- Integration mode: standard API or TAXII 2.1.
- Credentials: your API token, or your TAXII username and password.
- Feeds or collections: which feeds to enable. In TAXII mode the installer discovers the API root and lists the available collections.
- Skip expired indicators (TAXII only): ignore indicators whose
valid_untildate has passed. - IPv6 (standard mode): include IPv6 addresses in the IP feed.
- Active Response: block matched IP addresses on the local firewall, with a timeout you choose.
- IP whitelist: addresses that must never raise an alert. Put your own management addresses here.
- Cron schedule: every 20 minutes in standard mode, once a day at a random hour in TAXII mode. TAXII collections can be large, so the daily runs are staggered across customers.
- First download (TAXII only): you can skip it and let the first cron run do the work in the background.
What gets installed
| Component | Location |
|---|---|
| Configuration | /etc/qfeeds/qfeeds_wazuh.conf |
| Updater | /usr/local/bin/qfeeds-wazuh-updater.py |
| Decoders | /var/ossec/etc/decoders/qfeeds_decoders.xml |
| Rules | /var/ossec/etc/rules/qfeeds_rules.xml |
| CDB lists | /var/ossec/etc/lists/qfeeds-* |
| Log | /var/log/qfeeds_wazuh.log |
| Schedule | root crontab |
The installer also adds the CDB list references, and optionally the Active Response configuration, to /var/ossec/etc/ossec.conf. Those blocks sit between marker comments so the uninstaller can remove them cleanly, and a backup of the original file is kept.
How it works
- Update cycle: the updater first asks the API whether your licence has new data. If not, it exits without downloading anything, which is why a schedule of every twenty minutes is not a burden.
- CDB lists: indicators are written in Wazuh's
key:valueformat. In standard mode the value is empty, in TAXII mode it holds the threat context from the STIX description, such asthreat=Trojan;category=Bot C&C. - Rules: IP matches raise 100200 and 100201, domain matches 100210 to 100213, malicious URLs 100220 and hashes 100230 to 100232, all at level 10 in the
qfeedsrule group. - Decoders: the package adds an Unbound DNS decoder, in both the RFC5424 and RFC3164 log formats, and Sysmon decoders that split the combined
Hashesfield into separate MD5, SHA-1 and SHA-256 values. - CIDR handling: Wazuh matches IP ranges in dot notation, so only /8, /16, /24 and /32 are supported. Other prefix lengths are skipped.
- Malicious URLs: each entry is stored twice, with and without the scheme, because proxy logs usually include
https://and other sources do not. - Restart: the manager is only restarted when the lists actually changed. Wazuh 4.x compiles the CDB lists during that restart.
Verify
sudo QFEEDS_FORCE_UPDATE=1 /var/ossec/framework/python/bin/python3 /usr/local/bin/qfeeds-wazuh-updater.py
tail -f /var/log/qfeeds_wazuh.log
wc -l /var/ossec/etc/lists/qfeeds-malware-ip
grep -i qfeeds /var/ossec/logs/ossec.log
The first command forces an update and ignores the licence schedule, which is the quickest way to confirm the chain works end to end. To test a rule, run /var/ossec/bin/wazuh-logtest and paste a log line containing an address from the list.
In the dashboard, go to Threat Hunting and filter on rule.groups: qfeeds, or on a single rule such as rule.id: 100200.
Configuration
All settings live in /etc/qfeeds/qfeeds_wazuh.conf. Options such as the API token, IPv6 and the whitelists can be edited there directly and take effect on the next run. To switch feeds on or off, or to add Active Response afterwards, it is easier to run the installer again, because the rules file and ossec.conf have to change along with it.
Domain detection through Unbound
Do you run OPNsense with the Wazuh agent and want DNS queries checked as well? Enable Log Queries under Services, Unbound DNS, Advanced, keep the log verbosity at the default level, and add the resolver log to the agent configuration in /var/ossec/etc/ossec.conf on OPNsense:
<localfile>
<log_format>syslog</log_format>
<location>/var/log/resolver/latest.log</location>
</localfile>
Restart the agent with service wazuh-agent restart. Note that query logging costs resolver performance, that a plugin update can overwrite this block, and that domains already blocked by the OPNsense DNSBL never reach the resolver log.
Uninstall
sudo bash uninstall.sh
This removes the cron job, the CDB lists and their compiled files, the decoders, the rules, the configuration including any TAXII credentials, the updater, and the blocks it added to ossec.conf. Backups of ossec.conf are kept. The <localfile> entry for Unbound on an OPNsense agent is left alone, so remove that yourself if you no longer need it.
Troubleshooting
- No alerts: check that the lists contain data with
wc -l /var/ossec/etc/lists/qfeeds-malware-ip, that the references are present withgrep qfeeds /var/ossec/etc/ossec.conf, and restart the manager. - The updater downloads nothing: read
tail -50 /var/log/qfeeds_wazuh.logand test your token withcurl -s "https://api.qfeeds.com/licenses?api_token=YOUR_TOKEN". - Lists not compiled: Wazuh 4.x does this during a restart. On older versions run
sudo /var/ossec/bin/ossec-makelists. - Active Response does not block: check the configuration with
grep -A5 "Q-FEEDS-AR" /var/ossec/etc/ossec.confand the log at/var/ossec/logs/active-responses.log. - No hash alerts: hash matching needs TAXII mode plus Sysmon on your Windows endpoints, with hash logging enabled in the Sysmon configuration.
- Support: support@qfeeds.com or the support page. Found a bug in the scripts? Open an issue in the GitHub repository.