Im Rahmen seiner jüngsten forensischen Analysen hat das Cylance Consulting Services Team eine neue RawPOS Malware identifiziert. Diese POS Malware Familie ist bereits seit 2008 aktiv und ausführlich dokumentiert.
Wir wollen keine alte Malware sozusagen wieder aufwärmen. Unsere Absicht ist es vielmehr zu diskutieren wie tragfähig ein Signatur-basierter Ansatz seiner Natur nach überhaupt sein kann. Anhand der technischen Details werden wir zeigen, warum schlecht programmierte Signaturen dazu führen sich in falscher Sicherheit zu wiegen. Ja, das Argument „Antivirus ist tot“ ist zugegebenermaßen nicht neu. Was bisher aber eher selten der Fall war ist, anhand technischer Details zu zeigen, warum das so ist.
In unserem Beispiel blieb eine Variante der besagten RawPOS-Malware für mehr als 30 Tage von der eingesetzten Antiviren-Lösung unentdeckt. Mittlerweile hat der Hersteller spezielle DAT-Dateien ausgebracht. Die einzigen Beispiele landeten im Quarantäne-Verzeichnis von CylancePROTECT. Glücklicherweise hatte der betreffende Kunde das Produkt schon im Einsatz und konnte verhindern, dass Daten heraus geschleust wurden.
Zum Schluss des Blogbeitrags stellen wir Ihnen das Update einer Yara-Datei zur Verfügung mit deren Hilfe Sie alle Varianten des RawPOS Dumper identifizieren können sowie einige SHA256-Hashes der neuen Variante.
RawPOS im Überblick
RawPOS gehört zu den Malware-Familien. Die von uns identifizierte Variante ist ein Update mit nur geringfügigen Änderungen gegenüber früheren Varianten. Bei unserer Analyse konzentrieren wir uns auf die Memory Dump-Komponente: 0ca08c10a79cddbb359354f59ba988e77892e16dce873b5ba8e20eb053af8a18.
Im Moment stehen drei OpenSource-Signaturen auf Github zur Verfügung:
https://raw.githubusercontent.com/mattulm/sfiles_yara/master/pos/rawpos_POS.yar
https://raw.githubusercontent.com/mattulm/sfiles_yara/master/pos/RawPOS2015_dumper_old.yar
https://github.com/mattulm/sfiles_yara/blob/master/pos/RawPOS2015_dumper.yar
Die obige Signatur basiert weitgehend auf Zeichenketten, die sich mit vergleichsweise geringem Aufwand umgehen lassen wie wir später noch sehen werden.
Diff-Analyse des Codes
Auf dieser Ebene der Analyse erforschen wir die funktionalen Unterschiede im Code selbst. Dabei betrachten wir insbesondere die Unterschiede zwischen zwei Varianten ein und desselben Speicherauszugs (Memory Dump). Eine von beiden ist im März 2015 aufgetreten und das Update dieser Variante im Januar 2017. Die Diff-Analyse fördert nur wenige funktionale Unterschiede zutage. Die neu aufgetretene Variante ist zu großen Teilen mit der aus dem Jahr 2015 identisch.
Innerhalb des Programms wurde das Benennungsschema geändert, das festlegt wo die Memory Dump- Dateien abgelegt werden sollen. Auch der ‘Help’-Text ist aus den Binaries entfernt worden. Zum aktuellen Zeitpunkt wurde die Datei vom Antiviren-Hersteller in der installierten Version nicht erkannt. Lassen Sie uns nun diese Version mit der 2015 dokumentierten (252C13FE7A7E4F1E9E9227678C7156630A9D15AA457ADD2FF8EA5BCDB3403CD4) vergleichen, um die Unterschiede fest zu machen.
Wir benutzen Binary Diffing, um herauszufinden welche Unterschiede es zwischen den beiden Varianten gibt und wie viel Entwicklungsanstrengungen der Autor in die aktuelle Variante investiert hat. Bei Malware-Updates handelt es sich oft nur um minimale Änderungen in der Programmierung entweder um neue Funktionen hinzuzufügen oder um bestehende Antiviren-Signaturen zu umgehen. Wir verwenden Diaphora, ein sehr gutes OpenSource-Tool. Diaphora nutzt dazu die IDA-Datenbank als Input und vergleicht sie anschließend mit der zweiten IDA-Datenbank um festzustellen welche Regionen des verwendeten Codes übereinstimmen und welche nicht. Wir haben zur Erläuterung der Analyse einige Screenshots der beiden betreffenden Hashes zusammengestellt.
Von den insgesamt 454 innerhalb der Binaries identifizierten Funktionen stimmen 445 100%ig mit denen der 2015-Variante überein (252C13FE7A7E4F1E9E9227678C7156630A9D15AA457ADD2FF8EA5BCDB3403CD4). Die verbleibenden neun Funktionen sind teilweise identisch.
Drei Funktionen tauchen ausschließlich in der älteren Variante auf:
Lediglich drei Funktionen stimmen nicht überein und fehlen in der neuen Variante. 0040146E ist die ursprüngliche Variante des Snapshot-Moduls, die entfernt worden ist (wie schon erwähnt).
004013EC ist in der neuen Variante im Sektor 004012C9 enthalten. Es gibt aber innerhalb der Binaries keinen Querverweis wie es die IDA-Datenbank vorzugeben scheint. 004013A0 ist innerhalb der neuen Version komplett entfernt worden, da es sich dabei um die Aufruffunktion für 004012C9 in der Version von 2015 handelt.
Es bleiben schließlich ganze zwei Funktionen übrig, die ausschließlich in der neuen Variante auftauchen:
Bei den beiden nicht übereinstimmenden Funktionen handelt es sich um ein statistisch gelinktes strcpy und eine Snapshot PID-Funktion in 00401A6C. Wie diese Funktion auseinandergenommen aussieht ist in der unten stehenden Abbildung zu sehen. Sie erlaubt es dem Memory Dumper einen Snapshot aufzunehmen, wenn ihm eine PID-Funktion bereitgestellt wird. Diese Funktion als solche war bereits unter 0x40146E in der 2015er-Variante enthalten. Demontiert man die Funktion sieht das so aus:
Zusammengefasst hat die Analyse ergeben, dass die neue Variante über so gut wie keine zusätzlichen Funktionen verfügt. Es sind sogar Funktionen entfernt worden. Das kommt einigermaßen selten vor, denn in aller Regel bemühen sich Programmierer eher Funktionen zu ergänzen denn zu entfernen. Es stellt sich also die große Frage, warum in aller Welt ein Malware-Entwickler Funktionen in einer neuen Variante entfernt? Aller Wahrscheinlichkeit nach handelt es sich dabei um den Versuch bestehende Signaturen zu umgehen. Das belegen die geänderten Code-Areale. Bei der nun folgenden Analyse des String-Layouts beider Varianten behalten wir das im Hinterkopf.
Diff-Analyse des String
Um die Unterschiede zwischen den beiden Variante dingfest zu machen, benutzen wir den folgenden Code-Schnipsel aus Python. Das erste und zweite Argument geht jeweils auf String-Tools zurück (hier wurden strings.exe Dateien aus Windows-Sysinternals als Input verwendet). Für die Differentialanalyse des Strings überführt man diesen String in eine Datei und benutzt dann jede dieser beiden Dateien als Kommandozeilenargument in besagtem Python-Skript:
import sys
with open(sys.argv[1], ‚r‘) as f:
rawpos_newvar_txt = f.readlines()
with open(sys.argv[2], ‚r‘) as f2:
rawpos_315_txt = f2.readlines()
#print(„Common strings\nF1:{}\nF2:{}:\n{}“.format(sys.argv[1], sys.argv[2], „“.join(set(rawpos_newvar_txt) & set(rawpos_315_txt))))
#print(„New Variant only strings\nF1:{}\nF2:{}:\n{}“.format(sys.argv[1], sys.argv[2], „“.join( set(rawpos_newvar_txt) – set(rawpos_315_txt))))
print(„Old Variant only strings\nF1:{}\nF2:{}:\n{}“.format(sys.argv[1], sys.argv[2], „“.join(set(rawpos_315_txt) – set(rawpos_newvar_txt) )))
Dadurch lässt sich der Strings-Output der beiden Binaries ermitteln und mithilfe von Python-Sets miteinander vergleichen. Vergleicht man nun Unterschiede/Übereinstimmungen zwischen den beiden Beispielen, sehen wir wie sich die Zusammenstellung der beiden Zeichenketten unterscheidet.
Anhand unserer Zusammenstellung ist ersichtlich, welche Zeichenketten in der alten und der neuen Variante übereinstimmen, welche Zeichenketten nur in der neuen Variante vorkommen und solche, die nur in der älteren Version zu finden sind. Vergleicht man jetzt den Output der für diese Malware veröffentlichten OpenSource-Signaturen, werden die folgenden Unterschiede offensichtlich:
Der Regex-Teil scheint sich – basierend auf den OpenSource-Signaturen – leicht verändert zu haben:
“((B(([0-9]{13,16})” (alt)
“(B(([0-9]{13,16})” (neu)
Die Zeichenkette für die Track-Daten hat sich geändert.
„Found track data at %s with PID %d“ (alt)
“Found some data at %s with process id %d!” (neu)
Die Eingabeaufforderung, welche PID gedumped werden soll hat sich verändert.
“Enter Process Id:” (alt)
“Enter PID:” (neu)
Die „How to“-Hilfe Zeichenkette wurde entfernt.
““ Dump private process memory by PID“ (alt)
Die zusätzlichen Informationen wurden ebenfalls entfernt. Diese Zeichenkette war im 004103A0-Code enthalten, der aber nicht mehr länger existiert.
“Dumping private memory for pid %s to %s.dmp…“ (alt )
Die „How to“-Hilfe Zeichenkette wurde entfernt.
“Full private dump of all running processes” (alt)
Die Namenskonvention des Memory Dump wurde geändert.
“memdump\\%s-%d.dmp” (alt)
“memdump\quota.prNam-%s-pID-%d.dmp” (neu)
Parallel dazu wurde die Kommandozeile verlängert um diese Signatur zu umgehen.
“mkdir memdump >NUL 2>NUL” (alt)
“mkdir memdump >NUL 2>NUL” (neu)
Und zu guter Letzt haben wir in der neuen Variante diese Zeichenkette entdeckt und sie ist überraschenderweise eine gute Nachricht für die Security Community.
iknowyouwatchingthisandilikeyou.exe
Um Signaturen zu umgehen, die auf solchen Zeichenketten basieren, bedarf es verhältnismäßig geringer Anstrengungen. Die Zahl der Auszeichnungen (Prints) in 40146E (alte Variante) zu ändern, das Hilfe-Banner zu entfernen und einige simple Manipulationen innerhalb der Zeichenkette reichten aus um diese Signaturen zu umgehen. Der zweiten OpenSource-Signatur liegt eine richtige Idee zugrunde. Nämlich $_main zu benutzen, um eine Funktion mit Time-Check zu erzeugen. Aber auch diese Idee verfehlt insofern ihr Ziel, als dass sich die Funktion geändert hat. Die Signatur muss also in jedem Fall so angepasst werden, dass sie auch die Version der Malware erkennt, die mit einem Time-Check versehen ist.
Schlussfolgerung
Die obige Analyse zeigt sehr deutlich wie wenig Aufwand man betreiben muss, um Signatur-basierte Technologien zu umgehen. Malware mit mehr oder weniger denselben Fähigkeiten wird nur geringfügig verändert um problemlos existierende Antiviren-Signaturen zu umgehen. Wenn man sich auf rein Signatur-basierende Mechanismen als Schlüsselkomponente bei der IT-Sicherheit verlässt, führt das zu einem höchst trügerischen Sicherheitsgefühl. Es wird aber lediglich für bekannte/bereits dokumentierte Varianten ein Alarm ausgelöst und nicht für eine möglicherweise nur minimal abweichende Signatur-Variante derselben Malware. Ein Autor muss, wie wir gezeigt haben, nicht allzu viele Entwicklungsanstrengungen auf sich nehmen um eine solche Signatur zu umgehen.
Yara-Datei:
rule RawPOS_dumper
{
meta:
author = „Cylance Inc.“
date = „2017-01-24“
description = „Used to detect all RawPOS RAM dumper(s)“
strings:
$time_func = { 55 8b ec 81 c4 ?? ?? ?? ?? 53 56 57 8b ?? ?? 8b ?? ?? 6a 00 e8 ?? ?? ?? ?? 59 a3 ?? ?? ?? ?? 6a 00 e8 ?? ?? ?? ?? 59 3d ?? ?? ?? ?? 7e ?? 33 c0 e9 ?? ?? ?? ??}
$enum_proc_func = { 55 8b ec 81 c4 ?? ?? ?? ?? 50 81 c4 ?? ?? ?? ?? 53 56 57 be c8 b9 42 00 8d ?? ?? ?? ?? ?? b9 41 00 00 00 f3 ?? 8d ?? ?? 50 68 a0 0f 00 00 8d ?? ?? ?? ?? ?? 52 e8 ?? ?? ?? ?? 85 c0 0f ?? ?? ?? ?? ??}
$open_proc_func = { 8b f0 85 f6 0f ?? ?? ?? ?? ?? 8d ?? ?? 50 6a 04 8d ?? ?? 52 56 e8 ?? ?? ?? ?? 85 c0 74 ?? 68 04 01 00 00 8d ?? ?? ?? ?? ?? 51 ff ?? ?? 56 e8 ?? ?? ?? ?? 56 e8 ?? ?? ?? ??}
condition:
$enum_proc_func or $time_func or $open_proc_func
}
SHA256’s der neuen Variante:
a2e720a2c538347144aee50ae85ebfdaf3fdffcfc731af732be5d3d82cd08b18
fe8637ef9be609951aa218942d46a535ba771236668a49a84512b18b02e9fbee
0ca08c10a79cddbb359354f59ba988e77892e16dce873b5ba8e20eb053af8a18
4bd1cc0a38117af7d268c29592ef754e51ce5674e26168c6bb613302f3c62fb8
967fcbc7abcb328afb1dbfd72d68636c478d7369e674d622799b8dfd66230112
Anmerkung: Die andere Funktion ist _strcpy, die in der neuen Variante statistisch gelinkt ist, während in der alten Version _strncpy verwendet wird. Warum tun die Malware-Autoren das? Wenn wir uns einige OpenSource-Signaturen für diese spezielle RawPOS-Variante ansehen, werden wir vermutlich die Antwort finden. Hier einige der derzeit verfügbaren Signaturen:
https://github.com/mattulm/sfiles_yara/blob/master/pos/rawpos_POS.yar (gut, aber trotzdem nicht ausreichend)
https://github.com/mattulm/sfiles_yara/blob/master/pos/RawPOS2015_dumper_old.yar (schlecht, online)