Blue Monday 1: bouw je eigen mini-SOC met Suricata en ElasticSearch

Als je aan de rode kant van informatiebeveiliging staat, ben je ook wel eens nieuwsgierig naar de blauwe klant. En maar goed ook: als rood en blauw samenwerken, kunnen daar heel goede en nuttige dingen uit komen. Purple teaming als voorbereiding op een red teaming bij klanten, het beter detecteren van aanvalspaden vanuit red teamers of juist het verbeteren van deze aanvalspaden zodat ze niet gedetecteerd worden. Tijd om deze nieuwsgierigheid om te zetten in een nieuw project: bouw je eigen mini-SOC en kijk wat er zoal langskomt op je VPS.

Nu is dat natuurlijk niet in één keer goed gegaan, maar zijn er gaandeweg wat aanpassingen nodig geweest om een efficiënte manier te vinden. Zo stond er al vrij snel een oplossing waarbij de nginx accesslog via rsyslog geschreven werd naar PostgreSQL. Deze oplossing wordt op een Ubuntu 20.04 droplet gehost (de 5$/mo versie). Aangezien de body message in JSON format is, was PostgreSQL een voor de hand liggende manier voor het opslaan van deze data. Deze gegevens werden vervolgens opgevraagd in de browser door middel van een API geschreven in Lumen.

Dit werkte op zich prima, ware het niet dat dit alleen zorgde dat de access logs van nginx in de database terecht kwamen terwijl je ook graag wilt weten of er bijvoorbeeld ssh of ftp logins zijn geprobeerd / gedaan. Nu kun je kijken of je specifiek deze functionaliteit kunt toevoegen aan de bestaande functionaliteit, maar dan zou het wel veel handmatig werk worden naarmate je meer protocollen wilt toevoegen aan je mini-SOC. En moest er dus een andere manier van detectie komen.

Nu is Suricata een bekende oplossing voor intrusion detection en intrusion prevention. En juist die eerste functionaliteit is interessant: er wordt gelogd welke pagina’s worden bezocht (of geprobeerd te bezoeken), welke SSH-logins plaatsvinden, welke sources worden opgevraagd, welke hosts worden geresolved et cetera. De nginx-naar-rsyslog werd dus vervangen door een Suricata-installatie, welke later via rsyslog in een PostgreSQL wordt opgeslagen. Suricata is op de volgende manier geinstalleerd:

apt install libpcre3-dbg libpcre3-dev autoconf automake libtool libpcap-dev libnet1-dev libyaml-dev libjansson4 libcap-ng-dev libmagic-dev libjansson-dev zlib1g-dev pkg-config rustc cargo
wget https://www.openinfosecfoundation.org/download/suricata-5.0.3.tar.gz
tar -xvzf suricata-5.0.3.tar.gz
cd suricata-5.0.3
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var

make
sudo make install
sudo make install-conf

Vervolgens moeten regels ervoor zorgen dat de opgevraagde pagina’s, logins of andere aanvalsmanieren worden gedetecteerd. Emerging Threats heeft een gratis repository publiek gemaakt met prima basic detectieregels. Deze kun je downloaden en gebruiken in je Suricata-installatie:

wget http://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz
tar zxvf emerging.rules.tar.gz
mkdir /var/lib/suricata/
mv rules /var/lib/suricata/

De regels heb je nu naar de juiste locatie gekopieerd, maar deze moeten echter vervolgens wel in je configuratie worden opgegeven. Zoek in /etc/suricata/suricata.yaml het kopje ‘rule-files’ en verander deze naar de file die je net hebt gedownload en hebt gekopieerd naar de juiste locatie:

rule-files:
  - emerging-exploit.rules

Je basisinstallatie staat nu: Suricata staat geinstalleerd met een regelset welke het één en ander kan detecteren. Je kunt Suricata op interface eth0 starten met het volgende commando:

sudo suricata -c /etc/suricata/suricata.yaml -i eth0

Om de alerts die worden gegenereerd door Suricata ook daadwerkelijk te loggen (om deze vervolgens weer op te slaan in een database), moet er nog wat getweakt worden met de manier hoe deze alerts worden gelogd. Door deze in een eve-log (wat een afkorting is voor Extensible Event Format) op te slaan, kun je deze vervolgens weer opslaan in je database. Met de volgende configuratie in /etc/suricata/suricata.yaml zorg je ervoor dat alle detectie met het level ‘alert’ in log.json terecht komen waarbij de prefix voor iedere log @cee is. Op deze manier kan rsyslog deze alerts herkennen en verder verwerken. De log wordt iedere 3 dagen gerotate, omdat de file anders enorm wordt. Aangezien bij iedere toevoeging aan de log de info toch direct wordt doorgestuurd naar de database, is dat prima. De config wordt dan als volgt:

- eve-log:
      json:
        preserve-order: yes
        compact: yes
        ensure-ascii: no
        escape-slash: no

      enabled: yes
      filetype: regular
      filename: log.json
      rotate-interval: 3d
      prefix: "@cee: "
      level: Alert

Restart Suricata vervolgens (service suricata restart), bezoek de URL van je VPS, SSH er nog eens naar, doe een pull van je GitHub repo en check wat er in log.json terechtkomt. Spoiler: nogal veel. Op dit moment kwam ik er achter dat wanneer ik dit met PostgreSQL en een Lumen API moest opvragen het wel even zou duren voordat deze succesvol een search query heeft uitgevoerd. Tijd om na te denken over een betere oplossing om gegevens op te slaan. Nu zou het rijtje met Suricata en rsyslog niet compleet zijn als ik er nog wat buzzwords zoals ElasticSearch en Docker aan toe zou voegen, dus wellicht zou een goed alternatief zijn. Nog een spoiler: ja zeker, aangezien ElasticSearch bedoeld is om grote hoeveelheden data op te slaan om vervolgens daar gemakkelijk doorheen te kunnen query’en. Een goede oplossing voor analyse op grote datasets, in tegenstelling tot PostgreSQL en de Lumen API. De volgende stap is ervoor zorgen dat ElasticSearch wordt geinstalleerd en er via rsyslog gegevens naar deze ElasticSearch database (mag je het een database noemen?) worden geschreven. ElasticSearch installeren en starten heb ik gedaan op de volgende manier:

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
apt install apt-transport-https
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-7.x.list
apt update
apt -y install default-jre elasticsearch
/bin/systemctl daemon-reload
/bin/systemctl enable elasticsearch.service
systemctl start elasticsearch.service

Hierna draait ElasticSearch op poort 9200 op je VPS. Wil je checken of je ElasticSearch alive is, run dan op je VPS het volgende commando:

curl localhost:9200

Wil je er for some reason vanaf buitenaf bij, zorg er dan voor dat je poort 9200 open zet in je firewall en de volgende twee regels toevoegt aan /etc/elasticsearch/elasticsearch.yml:

http.host: 0.0.0.0
http.port: 9200

Je kunt vervolgens checken of je installatie van buitenaf beschikbaar is door localhost in het vorige curl-commando te vervangen door de IP van je VPS. Zorg er wel voor dat je http gebruikt in plaats van https.

Krijg je iets terug dat lijkt op onderstaande, dan werkt je installatie:

{
  "name" : "nom-honey",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "W_KwRyFYQ0mGXgHNqCKTpg",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

De laatste stap is nu om ervoor te zorgen dat je Suricata de logs schrijft naar ElasticSearch via rsyslog. Daarvoor is rsyslog nodig met de juiste configuratie. Allereerst zal rsyslog moeten worden geinstalleerd met een aantal modules:

apt install rsyslog rsyslog-elasticsearch rsyslog-mmjsonparse

De eerste module zorgt ervoor dat je ElasticSearch kunt gebruiken om naar te schrijven met rsyslog, de tweede dat JSON goed geparsed wordt bij het invoeren in de database. De configuratiefiles van rsyslog staan in /etc/rsyslog.d. Daar kun je vervolgens je configuratie aanmaken voor rsyslog. Op basis van volgorde van filename verwerkt rsyslog deze configuratiebestanden, dus is de naam 52-elastic.conf de way to go. Dit configuratiebstand krijgt vervolgens de volgende inhoud:

module(load="imfile")

input(type="imfile"
      File="/var/log/suricata/log.json"
      Tag="elastic:")

module(load="omelasticsearch")
module(load="mmjsonparse")

action(type="mmjsonparse")

template(name="rsyslog-index" type="string" string="elastic-log")

template(name="json-template"
  type="list") {
  property(name="$!all-json")
}

if($syslogtag == 'elastic:') then {
  action(type="omelasticsearch"
      template="json-template"
      searchIndex="rsyslog-index"
      dynSearchIndex="on"
      errorfile="/var/log/omelasticsearch.log")
}

In het kort: wat dit bestand doet is het lezen van log.json (de eve-log), een template maken waarin de index (ik vergelijk het een beetje met een table name zoals we kennen in SQL, al zullen ElasticSearch-groupies nu heel hard gaan gillen) wordt gedefinieerd, alle JSON uit de body van de eve-log wordt geparsed en vervolgens het plaatsen van de logs in ElasticSearch. Hier wordt geen host of URL opgegeven, omdat deze standaard is ingesteld op localhost:9200. Uiteindelijk is dit je setup:

Restart rsyslog om de configuratie te laden en check of de events automatisch in de ElasticSearch instance worden geplaatst. ElasticHQ1 is een overzichtelijke applicatie die dit voor je kan doen. Deze kun je lokaal draaien in een Docker container (hier, zie je, Docker!) om gemakkelijk je informatie inzichtelijk te maken. Dat ziet er ongeveer zo uit:

En joe, gefeliciteerd! Je mini-SOC staat. Benieuwd hoe we hier een aanvalsparadijs van gaan maken? Of een overzichtelijk dashboard? In een volgende Blue Monday laat ik je zien hoe dat moet.