Archive: Day 29, Month 2, Year 2016

Aktive Verteidigung gegen Krypto-Trojaner

29.02.2016 yahe code legacy security thoughts

Mit Locky sieht die IT-Welt derzeit einen der koordiniertesten Trojanerangriff der jüngeren Zeit. Während er sich Anfangs als Schläfer getarnt haben soll, findet er inzwischen auf unterschiedlichsten Wegen sein Ziel: als Word- oder Excel-Dokument mit schädlichem Makro; als JavaScript-Datei, die sich z.B. als angebliches Sipgate-Fax tarnt; oder gar als altmodische und als ausgestorben geglaubte Batch-Datei. Bei den Opfern des Verschlüsselungstrojaners handelt es sich auch um größere Organisationen wie Krankenhäuser und ein Fraunhofer-Institut. Man ging zeitweise von 5000 Neuinfektionen pro Stunde aus.

Die Vorschläge für Gegenmaßnahmen sehen derzeit noch eher mager aus. Die einen raten zur Symptombekämpfung durch Backups, deaktivierte Makros und Virenscannern. Andere wiederum versuchen, den Krypto-Trojaner anhand seiner Funktionsweise zu erkennen und so eine Anti-Malware-Software auf Heuristikbasis zu entwickeln.

Um sich erfolgreich gegen solch einen Trojanerangriff zur Wehr zu setzen, muss man jedoch an mehreren Baustellen aktiv werden und anstatt unterschiedlichste Teilmaßnahmen einzuführen, sollte man sich überlegen, welche Kombination von Maßnahmen zu einem ganzheitlichen Schutz führen kann. Die folgende Auflistung soll dabei eine kleine Hilfestellung für einen aktiven Umgang mit solch einem Infektionsrisiko bieten. Das folgende Dreiergespann aus Vermeidung, Erkennung und Behebung ist auch in der Medizin durchaus weit verbreitet.

Zuerst einmal sollte man natürlich das Thema Vermeidung betrachten. Hierzu zählen Dinge wie das Deaktivieren der Makrofunktion in Office-Anwendungen und die Aufklärung von Mailnutzern darüber, dass Office-Anhänge von außen nicht zu öffnen und ZIP-Dateien von außen nicht zu entpacken sind. Auch das Deaktivieren von JavaScript auf exponierten Arbeitsplätzen oder gar der Wechsel auf ein Betriebssystem mit konsequenter Trennung von Ausführungsrechten und Dateinamen kann eine Option darstellen.

Anschließend sollte man sich darum kümmern, eine Erkennung eines erfolgreichen Angriffs zu ermöglichen. Erst, wenn eine Infektion erkannt werden kann, kann sie im Anschluss auch behoben werden. Leider ist es noch häufig so, dass eine Erkennung lediglich durch Virenscanner erfolgt. Diese sind jedoch so spezifisch an einzelne Schädlinge und deren Verhalten angepasst, dass neue Generationen häufig für längere Zeit unentdeckt bleiben. Anstatt Verhaltensmuster der Schädlinge zu untersuchen, ist es daher sinnvoller, Standardverhaltensmuster seiner Mitarbeiter zu aggregieren und Abweichungen von diesem Standardverhalten in einem Sicherheitsmonitoring zu sammeln. So ist es möglich, auch neue Schädlinge anhand eines vom Durchschnitt abweichenden Verhaltens zu erkennen. Beispielsweise könnte zum Erkennen eines Krypto-Trojaners die durchschnittliche Anzahl an neu erstellten, bearbeiteten und gelöschten Dateien pro Tag herhalten. Während ein typischer Büroarbeiter eher selten viele Dateien gleichzeitig anlegt und gleichzeitig viele Dateien löscht, ist genau das das Hauptgeschäft von Krypto-Trojanern. Solch eine Erkennung von Abweichungen kann mit Canaries ergänzt werden. Dabei handelt es sich um Dateien, die extra als Opfer für einen Verschlüsselungstrojaner bereitgestellt werden und deren Bearbeitung als ein eindeutiges Indiz für das Vorhandensein eines Krypto-Trojaners dienen kann. Das Ziel der Erkennung ist es, von einem Problem zu erfahren, noch bevor der Nutzer etwa Ungewöhnliches feststellt.

Abschließend muss das Thema der Behebung betrachtet werden. Hierzu zählen an erster Stelle regelmäßige Backups. Das häufig kommunizierte Mantra, Dateien auf einem externen Datenträger zu sichern und diesen anschließend wieder vom Computer zu trennen, stellt in den meisten Umgebungen keinen ausreichenden Schutz dar. Denn während des Backups kann auch der externe Datenträger befallen und verschlüsselt werden. Der eigentliche Wunsch hinter solch einer Aussage ist vielmehr, eine Sicherung zu erstellen, die von einer eventuellen Infektion nicht beeinflusst werden kann. Sinnvolle Varianten können hierbei extern durchgeführte Backups sein, die nicht vom infizierten Nutzer angestoßen und demnach auch nicht vom infizierten Nutzer modifiziert werden können. Auch lokale Backups unter der Hoheit eines anderen Systemnutzers stellen eine Möglichkeit dar. Noch sinnvoller als ein einfaches Backup ist eine Versionierung, die zwar mehr Speicherplatz benötigt, dafür aber auch eine selektive Wiederherstellung von Dateiinhalten unterschiedlichster Zeitpunkte ermöglicht.

Die Implementierung eines entsprechenden Schutzes ist auch mit einfachen Tools möglich, wobei speziell entwickelte Werkzeuge wesentlich mehr Komfort bieten können. Im Folgenden soll eine Erkennung und Behandlung eines Krypto-Trojaner-Angriffs mit Hilfe von Mercurial dargestellt werden. Anbei folgt ein beispielhaftes Skript zur Erkennung von Abweichungen in der Bearbeitung von Dateien. Das Script ermittelt Abweichungen von der durchschnittlichen Menge an erstellten/gelöschten/bearbeiteten Dateien. Zudem prüft es separat die Veränderung eines Canaries. Das Script ist nur als Proof-of-Concept eines dateiorientierten, Host-basierten, sowie Anomalie-basierten Intrusion Detection Systems zu verstehen.

#!/usr/bin/php
<?php
  // user-defined values
  define("CHECKFOLDER", "/testpit/");
  define("CHECKCANARY", CHECKFOLDER . "data/do-not-edit.txt");
  define("STATUSFILE",  CHECKFOLDER . "status/status");

  // deviation of user behaviour from previously collected behaviour
  define("DEVIATIONVALUE", 0.5); // default deviation of 50% is allowed

  // generated values
  define("CHECKDATE", date("Ymd-His"));

  // concatenated actions
  define("ADDREMOVECMD", "hg addremove -R \"" . CHECKFOLDER . "\" -X \"" . CHECKCANARY . "\"");
  define("COMMITCMD",    "hg commit -R \"" . CHECKFOLDER . "\" -X \"" . CHECKCANARY . "\" -m \"" . CHECKDATE . "\"");
  define("STATUSCMD",    "hg status -R \"" . CHECKFOLDER . "\"");

  // static definitions
  define("ADDEDHINT",     "A");
  define("MISSINGHINT",   "!");
  define("MODIFIEDHINT",  "M");
  define("NOTTRACKEDHINT","?");
  define("REMOVEDHINT",   "R");

  define("HINTDELIMITER",       " ");
  define("STATISTICSDELIMITER", ":");

  function check_filename($line, $filename) {
    $result = false;

    $parts = explode(HINTDELIMITER, $line, 2);
    if ((false !== $parts) && (2 === count($parts))) {
      $result = (0 == strcasecmp(CHECKFOLDER . $parts[1], $filename));
    }

    return $result;
  }

  function check_hint($line, $hint) {
    $result = false;

    $parts = explode(HINTDELIMITER, $line, 2);
    if ((false !== $parts) && (2 === count($parts))) {
      $result = (0 == strcasecmp($parts[0], $hint));
    }

    return $result;
  }

  function get_statistics_text($additions, $deletions, $modifications) {
    return (CHECKDATE . STATISTICSDELIMITER . ADDEDHINT . STATISTICSDELIMITER . $additions .
                        STATISTICSDELIMITER . MODIFIEDHINT . STATISTICSDELIMITER . $modifications .
                        STATISTICSDELIMITER . REMOVEDHINT . STATISTICSDELIMITER . $deletions);
  }

  function check_statistics($additions, $deletions, $modifications) {
    $result = true;

    // with any modification there's nothing to check
    if (0 < ($additions + $deletions + $modifications)) {
      // read statistics and execute statistics checkvg_additions_count     = 0;
      $avg_additions_count     = 0;
      $avg_additions_value     = 0;
      $avg_deletions_count     = 0;
      $avg_deletions_value     = 0;
      $avg_modifications_count = 0;
      $avg_modifications_value = 0;

      if (is_file(STATUSFILE)) {
        $statistics = file(STATUSFILE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        if ((false !== $statistics) && (0 < count($statistics))) {
          // calculate average additions, deletions and modifications from statistics data
          foreach ($statistics as $line) {
            $parts = explode(STATISTICSDELIMITER, $line, 7);
            if ((false !== $parts) && (7 === count($parts))) {
              // check if value is integer and bigger than 0
              if (is_numeric($parts[2]) && (0 < $parts[2])) {
                $avg_additions_value += $parts[2];
                $avg_additions_count++;
              }
              if (is_numeric($parts[6]) && (0 < $parts[6])) {
                $avg_deletions_value += $parts[6];
                $avg_deletions_count++;
              }
              if (is_numeric($parts[4]) && (0 < $parts[4])) {
                $avg_modifications_value += $parts[4];
                $avg_modifications_count++;
              }
            }
          }
        }
      }

      // there's nothing wrong when nothing happened
      if (0 < $additions) {
        // when actions has never been seen then that's a deviation
        if (0 === $avg_additions_count) {
          $result = false;
        } else {
          // more additions than expected
          if (((1.0 + DEVIATIONVALUE) * ($avg_additions_value / $avg_additions_count)) < $additions) {
            $result = false;
          }
        }
      }

      // there's nothing wrong when nothing happened
      if (0 < $deletions) {
        // when actions has never been seen then that's a deviation
        if (0 === $avg_deletions_count) {
          $result = false;
        } else {
          // more deletions than expected
          if (((1 + DEVIATIONVALUE) * ($avg_deletions_value / $avg_deletions_count)) < $deletions) {
            $result = false;
          }
        }
      }

      // there's nothing wrong when nothing happened
      if (0 < $modifications) {
        // when actions has never been seen then that's a deviation
        if (0 === $avg_modifications_count) {
          $result = false;
        } else {
          // more modifications than expected
          if (((1 + DEVIATIONVALUE) * ($avg_modifications_value / $avg_modifications_count)) < $modifications) {
            $result = false;
          }
        }
      }
    }

    // add new result to statistics
    file_put_contents(STATUSFILE,
                      get_statistics_text($additions, $deletions, $modifications) . "\n",
                      FILE_APPEND | LOCK_EX);

    return $result;
  }

  function main() {
    $additions     = 0;
    $deletions     = 0;
    $modifications = 0;

    $canary_found = false;

    // retrieve information about file changes
    exec(STATUSCMD, $output);

    // accept file changes right away
    exec(ADDREMOVECMD);
    exec(COMMITCMD);

    // iterate through file changes
    foreach ($output as $line) {
      // check if the canary file is part of the modifications
      if (check_filename($line, CHECKCANARY)) {
        $canary_found = true;
      } else {
        // check if a file has been added
        if (check_hint($line, ADDEDHINT) || check_hint($line, NOTTRACKEDHINT)) {
          $additions++;
        } else {
          // check if a file has been deleted
          if (check_hint($line, MISSINGHINT) || check_hint($line, REMOVEDHINT)) {
            $deletions++;
          } else {
            // check if a file has been modified
            if (check_hint($line, MODIFIEDHINT)) {
              $modifications++;
            }
          }
        }
      }
    }

    if (0 < ($additions + $deletions + $modifications)) {
      // accept file changes
      exec(ADDREMOVECMD);
      exec(COMMITCMD);
    }

    // print result
    print(get_statistics_text($additions, $deletions, $modifications) . "\n");

    // the canary has been modified
    if ($canary_found) {
      //!!! do something
      print("ALERT! CANARY HAS BEEN MODIFIED!\n");
    }

    // check if the modifications do not match the statistics
    if (!check_statistics($additions, $deletions, $modifications)) {
      //!!! do something
      print("ALERT! BEHAVIOUR DOES NOT MATCH STATISTICS!\n");
    }
  }

  // execute application
  main();

?>

Bei jedem Aufruf ermittelt das Script mit Hilfe von Mercurial, welche Dateien in einem Repository/Ordner hinzugefügt, entfernt oder bearbeitet wurden. Sollte sich darunter die Canary-Datei befinden, wird Alarm geschlagen. Zudem wird eine statistische Analyse durchgeführt. In diesem einfachen Beispiel gilt als Abweichung, wenn mehr als 150% der durchschnittlichen Dateioperationen erkannt wurden. Wird solch eine Abweichung erkannt, wird ebenfalls Alarm geschlagen. Durch die Verwendung von Mercurial ließen sich zudem zu jeder Zeit alle bearbeiteten Dateien rekonstruieren.

In einem realen Umfeld könnte solch eine Analyse natürlich noch viel tiefergreifend sein. So könnten beispielsweise folgende Prüfungen mit einfließen, um Anomalien besser erkennen zu können:

  • Es könnte die Uhrzeit der Dateibearbeitung mit in die Analyse einfließen. In Kombination mit der Auswertung von Arbeitsplänen und/oder Anwesenheitszeiten ließen sich bessere Modelle erstellen. So sollte es seltener der Fall sein, dass Dateien eines Mitarbeiters bearbeitet werden, der gar nicht anwesend ist.
  • Es könnte die Relation der Dateibearbeitungen untereinander betrachtet werden. Beispielswiese werden Büromitarbeiter wesentlich mehr Dateien erstellen und bearbeiten als löschen, da Arbeitsergebnisse selten wieder vernichtet werden.
  • Es könnte das ursprüngliche Dateidatum mit berücksichtigt werden. Beispielsweise ist es eher unüblich, dass Dateien ab einem bestimmten Alter noch einmal bearbeitet werden. Stattdessen werden sie eher als Referenz vorgehalten, anstatt als aktives Arbeitsdokument zu fungieren.

Je besser das erstellte Modell ist, mit dem das Verhalten der Systemnutzer abgeglichen wird, desto schneller erkennt man in Ausnahmesituationen einen potentiellen Angreifer. Nicht immer müssen das externe Angreifer sein. Auch interne Mitarbeiter, die ein ungewöhnliches Verhalten an den Tag legen, können auf diese Weise unter Umständen identifiziert werden. Es muss nicht einmal zwingend eine böse Absicht hinter diesem Verhalten stecken, evtl. stellt ein Mitarbeiter einfach eine Ausnahme zur üblichen Regel dar.

Generell sollte man sich bei solch einer Angriffserkennung auf Basis von Abweichungsermittlungen daran gewöhnen, auch False Positives zu erhalten. Diese sind durchaus wünschenswert, da sie einerseits zeigen, dass die durchgeführten Analysen tatsächlich einen Effekt haben und einem andererseits Verbesserungspotentiale in den erstellten Anomaliemodellen aufzeigen.


Search

Links

RSS feed

Categories

administration (40)
arduino (12)
calcpw (2)
code (33)
hardware (16)
java (2)
legacy (113)
linux (27)
publicity (6)
review (2)
security (58)
thoughts (21)
windows (17)
wordpress (19)