osquery & StreamAlert – Part 1

I’ve recently come across some open source tools that relieve some of the burdens of security engineering.

For many organizations, the traditional SIEM/logger infrastructure requires a significant amount of time, effort and expertise, resulting in an “infrastructure creep” that plagues many engineers.  Its not uncommon to find a dedicated engineer devoted to maintaining the architecture for an Arcsight/QRadar/Splunk ES instance.

StreamAlert aims to relieve some of that pain, by leveraging a serverless architecture, which can be deployed to AWS via Terraform.

In the next few posts, I plan to cover the following:

  • Configure scheduled osquery query on my linux endpoint.
  • Feed the resulting data to a Kinesis stream established by StreamAlert.
  • Configure StreamAlert to alert when a condition is met.
  • Feed StreamAlert alerts to Slack

osquery

Osquery is a neat open source solution to a problem that million dollar tools try to solve. It allows you to interact intuitively with endpoints in your environment in a consistent way, regardless of platform.

Since osquery is essentially a database representation of your OS, we can extract the data with some SQL kung fu.

Lets start with a query to show listening ports:

SELECT * from listening_ports;

pid port protocol family address
1103 53 6 2 127.0.1.1
47882 99 6 2 0.0.0.0
47665 80 6 10 ::
781 5353 17 2 0.0.0.0
781 54764 17 2 0.0.0.0
1103 53 17 2 127.0.1.1
43701 68 17 2 0.0.0.0
2936 631 17 2 0.0.0.0
781 5353 17 10 ::
781 38423 17 10 ::
861 58 255 10 ::
805 0 0 0

I want to filter this down further, to only include PID, Port, and Address of entries not related to the loopback address:

SELECT listening.pid, listening.port, listening.address
FROM listening_ports AS listening
WHERE listening.address NOT LIKE ‘127%’;

pid port address
47882 99 0.0.0.0
47665 80 ::
781 5353 0.0.0.0
781 54764 0.0.0.0
43701 68 0.0.0.0
2936 631 0.0.0.0
781 5353 ::
781 38423 ::
861 58 ::
805 0

While this information is important, there is a significant amount of context missing.  Lets take a look at the columns within the “processes” osquery table:

pid|name|path|cmdline|state|cwd|root|uid|gid|euid|egid|suid|sgid|on_disk|wired_size|resident_size|total_size|user_time|system_time|start_time|parent|pgroup|threads|nice

The columns that are of interest are: pid,parent,name,path,cmdline,uid,gid,suid,sgid

SELECT pid,parent,name,path,cmdline,uid,gid,suid,sgid
FROM processes;

pid parent name path cmdline uid gid suid sgid
47664 47661 apache2 /usr/sbin/apache2 /usr/sbin/apache2 -k start 0 0 0 0
47665 47661 apache2 /usr/sbin/apache2 /usr/sbin/apache2 -k start 0 0 0 0
47882 9057 nc /bin/nc.openbsd nc -l 99 0 0 0 0

There is still room for improvement though, as I can add additional context from the users and groups table:

SELECT proc.pid,proc.parent,proc.name,proc.path,proc.cmdline,proc.uid,users.username,proc.gid,groups.groupname,proc.suid,proc.sgid
FROM processes AS proc
           JOIN users AS users
           ON users.uid = proc.uid
           JOIN groups AS groups
           ON groups.gid = proc.gid

pid parent name path cmdline uid username gid groupname suid sgid
47664 47661 apache2 /usr/sbin/apache2 /usr/sbin/apache2 -k start 33 www-data 33 www-data 33 33
47665 47661 apache2 /usr/sbin/apache2 /usr/sbin/apache2 -k start 33 www-data 33 www-data 33 33
47882 9057 nc /bin/nc.openbsd nc -l 99 0 root 0 root 0 0

With everything combined, we end up with a query of:

SELECT listening.pid,listening.port,listening.address,proc.parent,proc.name,proc.path,proc.cmdline,proc.uid,users.username,proc.gid,groups.groupname,proc.suid,proc.sgid
FROM listening_ports AS listening
           JOIN processes AS proc
           ON listening.pid = proc.pid
           JOIN users AS users
           ON users.uid = proc.uid
           JOIN groups AS groups
           ON groups.gid = proc.gid
WHERE listening.address NOT LIKE ‘127%’;

pid port address parent name path cmdline uid username gid groupname suid sgid
47882 99 0.0.0.0 9057 nc /bin/nc.openbsd nc -l 99 0 root 0 root 0 0
47665 80 :: 47661 apache2 /usr/sbin/apache2 /usr/sbin/apache2 -k start 33 www-data 33 www-data 33 33
781 5353 0.0.0.0 1 avahi-daemon /usr/sbin/avahi-daemon avahi-daemon: running [armen-virtual-machine.local] 110 avahi 118 avahi 110 118
781 54764 0.0.0.0 1 avahi-daemon /usr/sbin/avahi-daemon avahi-daemon: running [armen-virtual-machine.local] 110 avahi 118 avahi 110 118
43701 68 0.0.0.0 861 dhclient /sbin/dhclient /sbin/dhclient -d -q -sf /usr/lib/NetworkManager/nm-dhcp-helper -pf /var/run/dhclient-ens33.pid -lf /var/lib/NetworkManager/dhclient-3f62f967-c4f1-3c06-9f67-1f8f775a7eb1-ens33.lease -cf /var/lib/NetworkManager/dhclient-ens33.conf ens33 0 root 0 root 0 0
2936 631 0.0.0.0 1 cups-browsed /usr/sbin/cups-browsed /usr/sbin/cups-browsed 0 root 0 root 0 0
781 5353 :: 1 avahi-daemon /usr/sbin/avahi-daemon avahi-daemon: running [armen-virtual-machine.local] 110 avahi 118 avahi 110 118
781 38423 :: 1 avahi-daemon /usr/sbin/avahi-daemon avahi-daemon: running [armen-virtual-machine.local] 110 avahi 118 avahi 110 118
861 58 :: 1 NetworkManager /usr/sbin/NetworkManager /usr/sbin/NetworkManager –no-daemon 0 root 0 root 0 0
805 0 1 dbus-daemon /usr/bin/dbus-daemon /usr/bin/dbus-daemon –system –address=systemd: –nofork –nopidfile –systemd-activation 106 messagebus 110 messagebus 106 110

osquery -> AWS

Now that we have a decent query, we can setup the osquery daemon to continuously execute this query, and push the results to the desired destination.  In this case, I’ll be setting the destination as the Kinesis stream established during the StreamAlert deployment.   Use this as a reference for configuring the osquery.conf file.

You will need the AWS IAM information to set the Kinesis stream, which is printed after every execution of:

./stream_alert_cli.py lambda deploy _____

Modify your osquery.conf file to resemble:

Run osqueryd –verbose to validate that osquery is sending the data:

 

Stay tuned for part 2.

Leave a Reply

Your email address will not be published. Required fields are marked *