echothrust/howtos

A list of OpenBSD (mostly) material

View on GitHub

OpenBSD and findingsd

This is something that i’ve been wanting to write for so long, but every time i even tried to start putting down my thoughts, i changed my mind. Hopefully this time around will be different 🤞.

echoCTF and findingsd

echoCTF.RED is a framework that allows one to manage the entire life-cycle of cybersecurity exercises or competitions (ctf). Part of its features, is the ability to track the services that are running on a host and keep monitor who’s accessing them as well as when.

These are the echoCTF findings!

In oversimplified terms, findings are services that are listening on a target host, that we want to be able to know who is accessing them and when. At the same findings let the user know, that a particular service might warrant a further investigation.

So lets assume we have a target that is running an nginx web server (80/tcp), openssh (22/tcp) and snmpd (161/udp) among other things. So these 3 services will be our findings for this target. We want to know when a user is accessing these services for the first time so that we can give them hints (eg when they access the tcp port 80 for nginx we let them know that there is also udp services running).

the requirements

So we want to be able to monitor specific services but we do have some things to consider.

This means that the obvious solution of using tcpdump is out of the question but not entirely. Managing filtering rules is a pain even for the simplest cases not to mention having to filter based on 100s of services and destination hosts. However libpcap might be an option.

the match, the log and the label

In order to achieve this monitoring of services we utilize two features from OpenBSD’s PF. The ability to match a packet based on a set of given rules and the ability to log a packet.

match-ing

For those that use OpenBSD the most common use case is something like the following entry in the /etc/pf.conf file, which scrubs (performs cleanups) on incoming packets.

match in all scrub (no-df)

or when natting can be seen used in the following form

match out on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1

The match rules follow the same syntax as pass, however as can be seen from the examples, they usually need to perform something to the matched packets, even though its not a pass or block.

log-ing

So we’ve covered part of our requirements with regards to matching specific packets but we still dont do anything with them. How can we receive and process these packets that matched our criteria?

OpenBSD already has a way to log packets that pass or block through the use of log pf rule parameter. By default, this logs packets to a virtual interface, pflog0. However, we cant use the default interface if we also want to log firewall actions (eg blocked packets), since it will get extremely noisy for us when we want to analyze eg attacks. Well, it turns out OpenBSD has another neat feature, we can have as many virtual interfaces as we like and we can instruct PF to log only a specific set of packets to it.

So our previous match rules can be modified to log to a specific interface, like so:

match in (log pflog1) all scrub (no-df)
match out (log pflog1) on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1

This will log all packets that match the criteria to the pseudo interface pflog1.

label-ing

So now we’ve covered matching and loging but all the actions we saw already perform an unwanted action to our packets (scrub & nat-to). The last piece of the puzzle is another awesome feature of OpenBSD’s PF, which is the labeling of packet.

Labels are an internal PF functionality that allows you to add a symbolic a label to the rule, which can be used to identify the rule later on, and this has almost 0 overhead and no effect on the packet it self. Whats more we can have some macros for packet details which can later allow us even better control to the tracking of our rules.

The following macros can be used in label:

Again, using the previous rules as an example, we will add the destination address and destination port as labels

match in log (to pflog1) all scrub (no-df) label "$dstaddr:$dstport"
match out log (to pflog1) on tl0 from 192.168.1.0/24 to any nat-to 198.51.100.1 label "$dstaddr:$dstport"

putting it all together

So now we can create rules that perform no action on the packets, other than logging them to an interface of our choice.

match log (to pflog1) inet proto tcp from 1.2.3.4 to 5.6.7.8 port 1337 label "$dstaddr:$dstport"

This could be further optimized by replacing source and destination IP’s with tables, which will require only a single rule for any number of source/destination combinations.

match log (to pflog1) inet proto tcp from <players> to <targets> port 1337 label "$dstaddr:$dstport"