Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Monitoring bezpieczeństwa Linux: integracja auditd + OSSEC cz. II

30 lipca 2015, 20:55 | Teksty | komentarzy 6

Artykuł poświęcony jest integracji dwóch znanych i sprawdzonych narzędzi opensource do monitoringu bezpieczeństwa: oprogramowania do audytu zmian w systemie Linux (auditd) i Host IDS OSSEC. Celem artykułu jest poznanie ograniczeń i wykorzystanie zalet obu tych narzędzi tak, by działając w tandemie umożliwiły detekcję podejrzanych zachowań na poziomie wywołań systemowych (syscalls).

Po przeczytaniu cz. II będziesz wiedział jak:

  • pisać własny dekoder OSSEC na przykładzie logu audit.log
  • pisać własne reguły OSSEC
  • uruchomić i skonfigurować moduł Active Response w OSSEC

Snajper: OSSEC

Oprogramowanie HIDS OSSEC może realizować różne funkcje za pomocą poszczególnych modułów:

  • analiza logów pod kątem bezpieczeństwa dla wbudowanych i własnych reguł oraz dekoderów logów,
  • kontrola integralności plików,
  • rootkitcheck i sprawdzenie systemu zgodnie z określonym w pliku standardzie (to bardziej z przymrużeniem oka),
  • aktywna obrona poprzez uruchamianie skryptów/poleceń w przypadku wykrycia niepokojącego zdarzenia.

W dalszych krokach przygotujemy OSSEC do monitorowania uruchamianych poleceń w systemie Linux (dekoder), a w przypadku wykrycia programów z „czarnej listy” skonfigurujemy agenta OSSEC (reguła), aby reagował (aktywna obrona) np. poprzez wysłanie maila, ubicie procesu powłoki itp.

Źródłem informacji o uruchamianych poleceniach jest log auditd – audit.log.

Założenie:

Po udanym włamaniu atakujący z duzym prawdopodobieństwem zacznie się „rozglądać” po systemie, co musi pozostawić ślad w postaci zarejestrowanych poleceń z określonego zbioru, np.:

  • uname – informacja o systemie operacyjnym
  • w, who, whoami,  – informacja o użytkownikach systemowych
  • ifconfig – informacja o interfejsach sieciowych

Cel:

Naszym celem będzie wykrycie działań włamywacza na etapie rozpoznania systemu przed eskalacją uprawnień:

Fragment logu audit.logu zawieracjący wywołanie polecenie who:

type=SYSCALL msg=audit(1437917952.505:11145): arch=c000003e syscall=59 success=yes exit=0 a0=61c330 a1=61c2b0 a2=61c2c0 a3=0 items=2 ppid=12193 pid=12201 auid=1005 uid=1005 gid=1003 euid=1005 suid=1005 fsuid=1005 egid=1003 sgid=1003 fsgid=1003 tty=pts6 ses=63 comm="who" exe="/usr/bin/who" key="execve"
type=EXECVE msg=audit(1437917952.505:11145): argc=1 a0="who"
type=CWD msg=audit(1437917952.505:11145):  cwd="/home/bartek"
type=PATH msg=audit(1437917952.505:11145): item=0 name="/usr/bin/who" inode=14027611 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PATH msg=audit(1437917952.505:11145): item=1 name=(null) inode=13895173 dev=08:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=UNKNOWN[1327] msg=audit(1437917952.505:11145): proctitle="who"
  • id numer zdarzenia auditd  (co może przydać się do głębszej analizy narzędziami pakietu auditd)
  • auid – UID użytkownika, który wydał polecenie
  • tty – terminal, z którego zostało uruchomione polecenie
  • comm – uruchomione polecenie
  • key – nazwę reguły auditd

W katalogu /var/ossec/etc/ znajduje się plik decoder.xml, który służy do konfiguracji dekoderów dla analizowanych logów.

ossecflow

Schemat przetwarzania logów przez OSSEC, źródło: „OSSEC Host Based Intrusion Detection Guide”

Na rysunku przedstawiono kolejność przetwarzania zdarzeń z logów monitorowanych przez OSSEC. W pierwszej kolejności wybierane są dekodery odpowiadające analizowanym plikom (predecoding), w fazie dekodowania za pomocą wyrażeń regularnych następuje „wyłuskanie” interesujacych wartości z logu np. numery IP, numery UID użytkowników, uruchamiane polecenia itp. W dalszym etapie wartości te sprawdzane są względem zawartych w OSSEC reguł (przygotowywanych w plikach XML) i jeśli dopasowanie jest pozytywne to następuje eskalacja zdarzenia w postaci wysłania alarmu (alert). Ostatnim krokiem jest reakacja na alert, która może wiązać się z przekazaniem do bazy danych lub logu alarmów OSSEC, można wygenerować powiadomienie do administratora np. poprzez email lub wykonać skrypt (Active Response).

Własny dekoder logu

W pliku dekoder.xml znajdziemy przykłady dekoderów dla auditd, ale zmodyfikujemy i je wykorzystamy do napisania dekodera pod własne potrzeby. Do konfiguracji dekoderów w pliku xml korzystamy ze składni wyrażeń regularnych stosowanych regex w OSSEC.

Konfiguracja rozpoczyna się od wpisu dotyczącego nadrzędnego dekodera (parent), którego zadaniem jest rozpoznanie z jakim typem logu mamy do czynienia. Charakterystyczną cechą logów auditd jest to, że każda linia rozpoczyna się od wyrazu type.

<decoder name="auditd">
  <prematch>^type=</prematch>
</decoder>

W dalszym kroku będziemy konfigurować dekoder linii SYSCALL. W tym celu zmodyfikujemy i rozszerzymy zastany w pliku decoder.xml wpis auditd-

Dekoder o nazwie auditd-custom-syscall zostanie uruchomiony po dekoderze nadrzędnym auditd, czyli po rozpoznaniu, że analizowany plik zawiera linie rozpoczynające się od type. W logu auditd.log mamy różne linie m.in. SYSCALL, PATH, CWD, EXECVE, w tym wypadku zainsteresowani jesteśmy danymi z linii SYSCALL, czyli jest to nasz charakterystyczny wyraz, który posłuży nam do dopasowań w regułach regex. W przypadku zastosowania <prematch_offset=”after_parent”>, początkiem linii jest wszystko to, co występuje po wyrazach dopasowanych przez poprzedni, nadrzędny dekoder, czyli po type=. 

<decoder name="auditd-custom-syscall">
  <parent>auditd</parent>
  <prematch offset="after_parent">^SYSCALL </prematch>
  <regex offset="after_parent">^SYSCALL msg=audit\(\d\d\d\d\d\d\d\d\d\d.\d\d\d:(\d+)\): arch=\w+ syscall=\d+ success=\S+ exit=\S+ a0=\w+ a1=\w+ a2=\w+ a3=\w+ items=\d+ ppid=\d+ pid=\d+ auid=(\d+) uid=\d+ gid=\d+ euid=\d+ suid=\d+ fsuid=\d+ egid=\d+ sgid=\d+ fsgid=\d+ tty=(\S+) ses=\d+ comm="(\S+)" exe="\S+" key=(\S+)</regex>
  <order>id,srcport,user,extra_data,status</order>
</decoder>

Gdy nasz dekoder rozpoznaje już właściwą linię można przystąpić do ekstrakcji odpowiednich pól w linii <regex>. Poniżej w linii <order> przyporządkowuje się wybrane wartości z logu odpowiednim referencjom. Nazwy tych referencji są ściśle ustalone, a ich liste można znaleźć w komentarzu na górze pliku decoder.xml. Z tego też powodu pisząc własny dekoder często jesteśmy zmuszeni przyporządkować nietypowe nazwy dla niektórych wartości np. wartość tty z logu auditd.log będzie przyporządkowane polu url reguł OSSEC.

Wartości, które chcemy wybierać z logu za pomocą wyrażeń regularnych umieszczamy w nawiasach okrągłych ():

1.Wartość ID (tu 11145) zdarzenia zarejestrowana w logu audit.log umieszczona jest w polu msg=audit(1437917952.505:11145)
i po zdekodowaniu podporządkujemy ją atrybutowi id.

msg=audit\(\d\d\d\d\d\d\d\d\d\d.\d\d\d:(\d+)\):

Wyrażenie regularne \d+ oznacza jedną lub więcej cyfr.

2.UID użytkownika, który wydał polecenie umieszczony jest w polu auid=1005,  wartość tę przyporządkujemy atrybutowi srcport

auid=(\d+)

3. Numer pseudoterminala z którego zostało wydane polecenie tty=pts6, wartość tę przyporządkujemy atrybutowi user

tty=(\S+)

Wyrażenie regularne \S+ oznacza dowolne znaki nie będące spacjami

4. Wydane przez użytkownika polecenie comm=„who”, wartość ta będzie zapisana w polu extra_data

comm="(\S+)"

5. Nazwa reguły auditd (key), wartość ta będzie zapisana w polu status

key=(\S+)

Przygotowanie dekodera, który będzie parsował w logi okazuje się nie być wcale zadniem karkołonnym. W naszym przypadku skorzystaliśmy z logu auditd, który nie jest za bardzo wdzięczny do analizy ponieważ dla jednego zdarzenia generowany log jest wielolinijkowy (patrz wyżej), a w zależności od typu zdarzenia liczba linii jest różna. OSSEC posiada opcję monitorowania logów wielolinijkowych pod warunkiem, że liczba linii jest stała – to ograniczenie musimy mieć na względzie dekodując log auditd dlatego w prezentowanym przykładzie skupiłem się wyłącznie na linii oznaczonej wyrazem SYSCALL.

Wpis w pliku konfiguracyjnym /var/ossec/etc/ossec.conf, który wskazuje, żeby agent OSSEC analizował log auditd wygląda zatem następująco:

<localfile>
    <log_format>syslog</log_format>
    <location>/var/log/audit/audit.log</location>
</localfile>

Testujemy dekoder

Wśróde binarek OSSEC w katalogu /var/ossec/bin znajduje się przydatne do testowania dekoderów narzędzie ossec-logtest. Po uruchomieniu wklejamy linię z naszego logu i sprawdzamy, czy dekoder poprawnie ją dekoduję. Wynik powinien wyglądać tak:

testRule

Debuggowanie przygotowanego dekodera za pomocą narzędzia ossec-logtest

Piszemy nowe reguły

Gdy przygotowaliśmy dekoder, który będzie analizował log z systemu monitorującego czas na napisanie reguł, które będą wykrywały incydenty i eskalowały je poprzez powiadomienia o różnym stopniu krytyczności. OSSEC ma możliwość definiowania 16 poziomów krytyczności, gdzie poziom 0 oznacza brak zagrożenia i jest stosowany do „wyciszania” fałszywych alarmów lub jako reguła nadrzędna dla reguły potomnej, co będzie pokazane na przykładzie. Własne reguły umieszcza się w pliku /var/ossec/rules/local_rules.xml, co ma zapewnić zachowanie reguł w przypadku aktualizacji oprogramowania do nowej wersji.

Pierwszą regułą będzie wykrycie wywołania systemowego execve(), dla którego przygotowaliśmy regułę w auditd. Dla przypomnienia reguła ta umożliwia logowanie wszystkich uruchomień programów wykonywalnych na poziomie jądra systemu. Za pomocą nazwy tej reguły można „wyłapywać” w OSSEC’u tego typu zdarzenia. Ponieważ generowanie alarmów dla każdego uruchomionego programu dawałoby zbyt dużo fałszywych powiadomień, główna reguła będzie miała poziom 0.

Reguła nadrzędna wskazująca, że został uruchomiony program wykonywalny za pomocą execve()

<rule id="100001" level="0">
    <decoded_as>auditd-custom-syscall</decoded_as>
    <status>execve</execve>
    <description>Auditd wykryl execve</description>
</rule>
  • <rule> – numery własych reguł posiadają numerację z przedziału 100 000 – 119 999
  • <decoded_as> – reguła dotyczy zdarzeń zdekodowanych za pomocą dekodera o nazwie auditd-custom-syscall
  • <status> – w polu status znajduje się wpis execve, który jest nazwą (key) reguły w auditd
  • <description> – opis reguły

W omawianym przykładzie założylismy, że naszym celem jest wychwycenie wszystkich podejrzanych działań, które podejmie potencjalny włamywacz w celu rozpoznania naszego systemu, zatem musi zostać wygenerowany alarm, gdy zostaną wydane takie polecenia jak: w, who, whoami itp.

<var name="RECON_CMDS">w|who|whoami</var>

<rule id="100002" level="12">
    <if_sid>100001</if_sid>
    <extra_data>$RECON_CMDS</extra_data>
    <description>Ktos rozpoznaje system!</description>
</rule>
  •  <rule level=”12″> – tym razem eskalujemy zdarzenie nadając stopień krytyczności np. 12
  • <if_sid> – reguła zadziała tylko wtedy, gdy wcześniej „odpaliła” reguła o numerze 100001
  • <extra_data> – jeśli w polu extra_data zawarte będzie któreś słowo z listy RECON_CMDS to zostanie wywołany alarm

Aby zapobiec niespodziewanym sytuacjom w zależności od danego systemu, np. zablokowania konta root i innych niespodziewanych zdarzeń warto korzystać z reguł pomocniczych o poziomie krytycznośc 0 (opcja ignore) i za ich pomocą budować wyjątki. W tym przykładzie zapropnuję takie dwie reguły pomocnicze, aby nie zablokować własnego systemu. Przykład ma pokazać jak elastycznie możemy „żonglować” regułami, aby optymalnie je dostsować do konkretnego systemu.

<rule id="100003" level="0">
    <if_sid>100002</if_sid>
    <srcport>^0</srcport>
    <description>RECON_CMDS wykonane przez root</description>
</rule>

<rule id="100004" level="0">
    <if_sid>100002</if_sid>
    <user>pts0|(none)</user>
    <description>RECON_CMDS wydane z pts0</description>
</rule>

Testujemy reguły

Ponownie uruchamiamy narzędzie ossec-logtest tym razem z przełącznikiem -v (verbose)

testRule2

Debuggowanie reguł za pomocą ossec-logtest z przełącznikiem -v (verbose)

Polecenie who zostało wykonane przez nieuprzywilejowanego użytkownika bartek z pseudoterminala innego niż pts/0 – co w naszym przykładzie oznacza eskalację zdarzenie i wygenerowanie alertu.

Aktywna obrona – Active response

Pomimo faktu, że OSSEC jest systemem wykrywania włamań to jednak za pomocą modułu Active Response istnieje możliwość powstrzymania wykrytego ataku. Idea modułu Active Response polega na uruchomieni odpowiedniego skryptu, który ma zadziałać w przypadku spełnienia określonych warunków. W katalogu /var/ossec/active-response/bin znajdziemy kilka przykładowych skryptów, które można wykrozystać i są to m.in.:

  • firewall-drop.sh – blokuje ruch sieciowy poprzez dodanie wpisu do firewall’a (przygotowany pod iptables, ipfw,pf)
  • host-deny.sh – blokowanie hosta dodanie wpisu do pliku /etc/hosts
  • disable-account.sh – blokada konta użytkownika

W naszym przykładzie możemy przyjąć, że chcemy „ubić” sesję użytkownika, który rozgląda się po naszym systemie. Do tego celu wykorzystam informację o uruchomionym przez atakującego terminalu (tty), który w OSSEC’u przyporządkowałem polu o nazwie user.

Przykładowy skrypt kill-tty.sh

#!/bin/sh

TTY=$2
TTYNO=`echo ${TTY} |awk '{split($0,a,"pts"); print a[2]}'`

ps -t pts/${TTYNO} | awk '/[0-9]/ {print $1}' |xargs sudo kill -9

Zadaniem skryptu jest odnalezienie i zamknięcie wszystkich procesów związanych  z danym pseudoterminalem. Parametrem przekazywanym do skryptu jest numer pseudoterminala. Warto zwrócić tu uwagę, że jest to drugi argument ($2)przekazywany do naszego skryptu przez Active Response, mi się zdarzyło naciąć na ten problem przy pisaniu własnego skryptu, w debuggowaniu pomógł ponownie log auditd i podgląd jakie argumenty i w jakiej kolejności są przekazywane przez ten moduł.

Kolejnym krokiem jest konfiguracja modułu Active Response w pliku /var/ossec/etc/ossec.conf poprzez dodanie wpisu o skrypcie:

<command>
    <name>kill-tty</name>
    <executable>kill-tty.sh</executable>
    <expect>user</expect>
    <timeout_allowed>no</timeout_allowed>
</command>
  •  <name> – zarejestrowana w OSSEC nazwa skryptu
  • <executable> – nazwa pliku skryptu
  • <expect> – parametr związany z numerem pseudoterminala przekazywany do skryptu
  • <timeout_allowed> – opcja umożliwiająca cofnięcie blokady. np usnięcie wpisu z iptables

Następny wpis dotyczy konfiguracji tego, że skrypt kill-tty.sh ma zostać uruchamiany, gdy zadziała reguła tylko o numerze 100 002.

<active-response>
	<command>kill-tty</command>
	<location>local</location>
	<rules_id>100002</rules_id>
</active-response>

W celu sprawdzenia, czy wszystko przebiega prawidłowo otwieramy na monitorowanym hoście 2 terminale:

  • na pierwszym terminalu uruchamiamy podgląd logu alerts OSSEC – tail -f /var/ossec/logs/alerts/alerts.log 
  • w drugim oknie logujemy się na nieuprzywilejowanego użytkownika i wydajemy polecenie who.

W efekcie drugi terminal powinien zostać „ubity” ,a w logu alarmów OSSEC powinien znaleźć się wpis dotyczący reguły 100002.

terminale

Przykład „ubicia” sesji za pomocą modułu Active Response

Zastosowany przykład z użyciem tych poleceń do rekonesansu systemu miał PoC do przedstawiania, w jaki sposób można skonfigurować OSSEC to walki z intruzami nie na poziomie sieci ale na poziomie hosta.

Podsumowanie

OSSEC jest narzędziem bardzo elastycznym i jego konfiguracja pozwala nam na odbiór danych z różnych źródeł, ich zdekodowanie poprzez przygotowanie własnych dekoderów oraz reguł dla, których mają być generowane alarmy. Przedstawiony przykład miał pokazać, że możliwości bogatej konfiguracji OSSEC sprawiają, że z systemu typu HIDS można przemienić w system HIPS (powstrzymywania ataków).  Dzięki odpowiednim źródłom informacji (tutaj log wywołań systemowych z auditd)  i modułu OSSEC’a Active Response można powstrzymywać niepokojące zdarzenia na poziomie hosta.

Warto eksperymentować z ustawieniami OSSEC’a, modyfikacją i tworzeniem nowych dekoderów oraz pisaniem nowych reguł i warto wtedy pamiętać o binarce ossec-logtest, która świetnie pomaga w debuggowaniu dekoderów i reguł.

Bartek Jerzman

 

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. Sławek

    siedzę właśnie w zbliżonym temacie, dzięki za opis

    Odpowiedz
  2. Uczestnik prowadzonego przeze mnie szkolenia dla innych uczestników (przyszłych, obecnych, byłych). Dobra robota Bartek!

    Odpowiedz
  3. Dam

    Czy w OSSEC da się zrobić zdalnie uplaod (diplojment) różnych konfigów klienckich na Windowsy i Linuksy?

    Odpowiedz
  4. jacek

    Mam pytanie odnośnie instalacji agenta 2.8 na Windowsie w polskiej wersji językowej – podczas próby zapisu konfiguracji wyskakuje komunikat:
    „Unable to set permissions on new configuration file”
    a w logach widnieje:
    „ossec-win32ui: INFO: Running the following command (C:\Windows\system32\cmd.exe /c echo y|cacls „client.keys” /T /G Administrators:f)”
    w polskich windowsach nie ma grupy administrators (jest spolszczona wersja administratorzy) więc to chyba będzie problem ale jak można to rozwiązać?

    Odpowiedz
    • mikolaj

      Utworzyć grupe Administrators :)

      Odpowiedz
  5. Piotrek

    Artykuł zawiera absurdalną ilość błędów, został napisany „z palca” bez jakichkolwiek testów.
    Niestety dałem się „złapać” na fajny opis, ale w praktycznym użyciu straciłem mnóstwo czasu z powodu błędów w artykule.
    Po pierwsze autor nie napisał w jakiej wersji systemu były prowadzone testy, a okazuje się że ma to kolosalne znaczeni z powodu AuditD (tą informację możemy znaleźć w dokumentacji OSSEC-a).
    Po drugie autor nie zwrócił uwagi na to, że warto by było zmienić id roli, bez zmiany id mamy błąd.
    Po czwarte role zawierają błędy, np: execve (w dodatku auditd zwraca execv a nie execve)
    Po piąte błędne jest powiązanie dekodera z rolą, to nie ma prawa działać tak jak to opisał autor !!!!
    Plus kilka innych problemów o których już nawet nie pamiętam.
    Potencjalny czytelniku, nie trać czasu na czytanie tego artykułu, idź od razu do dokumentacji OSSEC, tam jest dokładnie to samo, ale napisane poprawnie !!!

    Odpowiedz

Odpowiedz