Przejdź do treści

Trovares xGT - demo

Wprowadzenie

Źródło - An Introduction to Graph Analysis with xGT, Trovares

Poniższy przykład to analiza anomalii w ruchu sieciowym w Los Alamos National Lab - opis danych. Dane obejmują:

  • informacje o urządzeniach sieciowych (Devices) - wierzchołki grafu,
  • dane o ruchu sieciowym między urządzeniami (Netflow) - I typ krawędzi,
  • dane o zdarzeniach w urządzeniach (Host events) - II typ krawędzi.

Schematycznie reprezentacja logów ruchu sieciowego przekłada się na następujący graf:

graf LANL

Pierwsze trzy linie przedstawiają "logi" urządzenia, zawierające informacje o: 1. urządzeniu, 2. krawędziach I typu (ich atrybutach), 3. krawędziach II typu (ich atrybutach). Wpisy z logów przekładają się na graf widoczny niżej.

Łączenie się z serwerem Trovares xGT

Pierwszą rzeczą jaką trzeba zrobić to zaimportować potrzebne biblioteki oraz utworzyć połączenie z serwerem Trovares xGT.

In [ ]:
import xgt
import getpass
import os
conn=xgt.Connection(userid='kdmszkXX', credentials=getpass.getpass(), port=os.getuid()+20000)

Kolejną rzeczą jest upewnienie się, że na serwerze nie istnieje jeszcze żadna ramka krawędzi bądź wierzchołków. Poniższa komórka kodu usuwa wszystkie ramki danych oraz usuwa wszystkie przestrzenie nazw ramek.

In [ ]:
[conn.drop_frame(_) for _ in conn.get_edge_frames()]
[conn.drop_frame(_) for _ in conn.get_vertex_frames()]
[conn.drop_frame(_) for _ in conn.get_table_frames()]
[conn.drop_frame(_) for _ in ['lanl__Netflow','lanl__HostEvents','lanl__Devices']]
conn.drop_namespace('lanl')
conn.drop_namespace('results', force_drop=True)

Tworzenie definicji grafu

Następnie tworzymy od zera wszystie puste ramki:

  • wierzchołków - devices
  • krawędzi - netflow oraz host_events

    do których będziemy wczytywać dane z plików .csv. Należy zwrócić uwagę na schematy poszczególnych ramek.

In [ ]:
devices = conn.create_vertex_frame(
    name='lanl__Devices',
    schema=[['device', xgt.TEXT]],
    key='device')

host_events = conn.create_edge_frame(
    name='lanl__HostEvents',
    schema=[['epoch_time', xgt.INT],
            ['event_id', xgt.INT],
            ['log_host', xgt.TEXT],
            ['user_name', xgt.TEXT],
            ['domain_name', xgt.TEXT],
            ['logon_id', xgt.INT],
            ['process_name', xgt.TEXT],
            ['process_id', xgt.INT],
            ['parent_process_name', xgt.TEXT],
            ['parent_process_id', xgt.INT]],
    source=devices,
    target=devices,
    source_key='log_host',
    target_key='log_host')

netflow = conn.create_edge_frame(
    name='lanl__Netflow',
    schema=[['epoch_time', xgt.INT],
            ['duration', xgt.INT],
            ['src_device', xgt.TEXT],
            ['dst_device', xgt.TEXT],
            ['protocol', xgt.INT],
            ['src_port', xgt.INT],
            ['dst_port', xgt.INT],
            ['src_packets', xgt.INT],
            ['dst_packets', xgt.INT],
            ['src_bytes', xgt.INT],
            ['dst_bytes', xgt.INT]],
    source=devices,
    target=devices,
    source_key='src_device',
    target_key='dst_device')

Tworzymy funkcję pomocniczą, która wyświetla liczby krawędzi i wierzchołków w grafie.

In [ ]:
def print_data_summary():
  print('Devices (wierzcholki): {:,}'.format(devices.num_vertices))
  print('Netflow (krawedzie I): {:,}'.format(netflow.num_edges))
  print('Host event (krawedzie II): {:,}'.format(host_events.num_edges))

print_data_summary()

Wczytywanie danych

Wczytujemy krawędzie typu host_events oraz jednocześnie wierzchołki devices. Plik /tmp/wls_day-02_1v.csv zawierający te dane ma około 1,1GB. Jego wczytywanie trwa około 40 sekund.

In [ ]:
%%time
urls = ["/tmp/wls_day-02_1v.csv"]
host_events.load(urls)
print_data_summary()
# okolo 40s

Wczytujemy krawędzie typu netflow. Plik /tmp/nf_day-02.csv ma około 6 GB. Jego wczytywanie trwa około 4 minuty.

In [ ]:
%%time
if netflow.num_edges == 0:
    urls = ["/tmp/nf_day-02.csv"]
    netflow.load(urls)
    
# okolo 4 minuty

Sprawdźmy ile wierzchołków i krawędzi wczytano łącznie.

In [ ]:
print_data_summary()

Analityka przy Trovares xGT

Teraz przeanalizujmy wszystkie wystąpienia następującej sekwencji ruchu sieciowego, która może wskazywać na incydent bezpieczeństwa:

  1. urządzenie A włącza się (następuje zdarzenie typu Boot), a następnie uruchamia program (następuje zdarzenie typu Program start),
  2. w niedługim czasie po tym to samo urządzenie A wysyła wiadomość do innego urządzenia B (ruch sieciowy Netflow 1),
  3. urządzenie B posiada połączenie do urządzenia C, które zostało nawiązane przed uruchomieniem urządzenia A i trwa nadal po wiadomości wysłanej od A do B (ruch sieciowy Netflow 2).

Innymi słowy, szukamy w grafie takiego wzorca:

szukany wzorzec

Źródło obrazka

In [ ]:
%%time
q = """
MATCH (a)-[boot:lanl__HostEvents]->(a)-[program:lanl__HostEvents]->(a)
         <-[nf1:lanl__Netflow]-(b)-[nf2:lanl__Netflow]->(c)
WHERE a <> b AND b <> c AND a <> c
  AND nf1.src_port = 3128
  AND boot.event_id = 4608
  AND program.event_id = 4688
  AND program.epoch_time >= boot.epoch_time
  AND nf1.epoch_time >= program.epoch_time
  AND nf1.epoch_time - boot.epoch_time < 4
  AND nf2.duration >= 3600
  AND nf2.epoch_time < nf1.epoch_time
  AND nf2.epoch_time + nf2.duration >= nf1.epoch_time
RETURN a
INTO results__Answers
"""

conn.drop_frame('results__Answers')
conn.run_job(q)
print('Mozliwych incydentow bezpieczenstwa: ' + '{:,}'.format(conn.get_table_frame('results__Answers').num_rows))
Ta strona używa plików cookies.
Polityka Prywatności    AKCEPTUJĘ