Open philrz opened 3 years ago
In looking at what's possible today, the approach described in the Zeek Customization article seems to be technically capable of achieving this. Since the Zeek & Suricata "runner" scripts take packet data off stdin and feed it through Zeek or Suricata, respectively, an approach like the one described here can be used to apply the bpf filter with tcpdump
. Next I'll walk through a quick example of me doing this on my Mac.
First, I copied the "stock" runner scripts from their original locations to an outside location so they won't be disturbed during app upgrades. Normally something in a home directory might be appropriate, but since this is just a quick test I'll use /tmp
here.
$ cp /Applications/Brim.app/Contents/Resources/app/zdeps/zeek/ /tmp
$ cp /Applications/Brim.app/Contents/Resources/app/zdeps/zeek/zeekrunner /tmp
Next I make two changes to each of the scripts:
Point the dir
variable at the base path for the Zeek/Suricata binaries. As described in the Zeek Customization article, this could be a wholly separate install that has other customizations, but since my only interest here is in adding the upstream tcpdump
, I'm just pointing dir
at the location of the binaries that came packaged with Brim.
Rather than having the runner script exec
the zeek
or suricata
binaries, respectively, I instead exec
the application of the bpf filter via tcpdump
. Since I'm working on the Mac in this case, I hit the issue described here and hence had to add the cat
line shown below, but it's implied that should not be necessary on other platforms and hence one could start off with the exec tcpdump ...
Here's the modified version of each:
zeekrunnner
#!/usr/bin/env bash
dir="/Applications/Brim.app/Contents/Resources/app/zdeps/zeek"
export ZEEKPATH=$dir/share/zeek:$dir/share/zeek/policy:$dir/share/zeek/site
export ZEEK_PLUGIN_PATH=$dir/lib/zeek/plugins
# The packet filter and loaded scripts are disabled because they emit either
# timeless logs or logs with timestamp set to execution time rather than time
# of capture.
exec cat <(printf "\0\0\0\0") - | \
tcpdump -r - -w - ip host 134.71.3.16 | \
"$dir/bin/zeek" \
-C -r - \
--exec "event zeek_init() { Log::disable_stream(PacketFilter::LOG); Log::disable_stream(LoadedScripts::LOG); }" \
local
suricatarunner
#!/usr/bin/env bash
dir="/Applications/Brim.app/Contents/Resources/app/zdeps/suricata"
if [ -z "$BRIM_SURICATA_USER_DIR" ]; then
userdir="$dir"
ruledir="$dir/var/lib/suricata/rules"
else
userdir="$BRIM_SURICATA_USER_DIR"
ruledir="$userdir/rules"
if [ ! -d "$ruledir" ]; then
mkdir -p "$ruledir"
fi
if [ ! -f "$ruledir/suricata.rules" ]; then
cp "$dir/var/lib/suricata/rules/suricata.rules" "$ruledir"
fi
fi
cp "$dir/brim-conf.yaml" "$userdir/brim-conf-run.yaml"
echo "
rule-files:
- $ruledir/suricata.rules
" >> "$userdir/brim-conf-run.yaml"
exec cat <(printf "\0\0\0\0") - | \
tcpdump -r - -w - ip host 134.71.3.16 | \
exec "$dir/bin/suricata" -c "$userdir/brim-conf-run.yaml" --set classification-file="$dir/etc/suricata/classification.config" --set reference-config-file="$dir/etc/suricata/reference.config" --set threshold-file="$dir/etc/suricata/threshold.config" --set magic-file="$dir/share/file/magic.mgc" -r -
Then in the Brim Preferences menu, I point the Suricata Runner and Zeek Runner settings at the paths for each modified script, then restart Brim as prompted.
In the restarted Brim app, importing a pcap that contains this IP such as https://archive.wrccdc.org/pcaps/2018/wrccdc.2018-03-23.010014000000000.pcap.gz (uncompressed), we see the desired effect of only logs that were made based on packets that successfully passed through the bpf filter.
Zeek logs:
Suricata logs:
All that said, I respect this is not the easiest way to go about this. Challenges I see:
It's a fairly advanced move to modify these Runner scripts. For instance, due to limitations on Windows, we use compiled Go code for these, so that's even more burden on the user.
Modifying the bpf filter in two places is tedious and error prone.
I could definitely envision a smoother approach similar to what we see with Wireshark such that there'd be a single option among the Preferences in the app to specify the filter and have this automatically applied upstream of the log generation similar to what we've done here. I'll hold this issue open to track interest in that approach.
In a 1-on-1 chat with @mccanne, he confirmed my hunch that we could probably do this pretty easily with our pcap
tool. Its code is embedded as part of zqd
and we also ship it as a standalone binary with Brim. It can create packet indexes and extract flows, and could likely be extended to do this pipelined filtering as well, effectively taking the place of tcpdump
in the examples shown above, with the currently-active bpf filter from the app passed down somehow.
In the time since this issue was first opened, Brim's pcap processing is now handled by a separate tool Brimcap that's bundled with the app. The same recipe above that describes modifying the runner scripts to handle the filtering should still be possible with Brimcap. The Custom Brimcap Config article provides some additional detail that might be useful for anyone wanting to attempt this. It's also still true that Brimcap itself could potentially still handle the packet filtering during the brimcap analyze
phase, so I'll hold this issue open in the event we want to address that one day.
A community user inquired:
Indeed, as the user says, a bpf filter is one common way to do this kind of filtering in other tools. In Wireshark for instance, there's an optional bpf "capture filter" that specifies traffic to be included/excluded when capturing traffic off a live interface.