Malware-Coding für IT-ler, Teil 1: FUD (Fully Undetected) Malware selbst programmieren

Im Großen und Ganzen unterscheidet man drei verschiedene Kategorien von Angreifern:

  • „Skids“ oder Script Kiddies – inzwischen ist damit jeder Hacker-Anfänger gemeint, der mit bereits existierendem Code und vorhandenen Tools experimentiert, um für seine eigenen Zwecke geeignete, eher einfach strukturierte Malware zu programmieren.
  • „Käufer“ – darunter versteht man beispielsweise „Hackerpreneure“, jugendliche Hacker oder einfach Leute, die nach einem Kick suchen und die für in der Cloud angebotene Coding-Dienste bezahlen. Man bekommt dann zum Beispiel eine Malware, die in der Lage ist, PII-Daten sammelt, also die Daten, durch die sich eine Person eindeutig identifizieren lässt. Ziel kann es sein die erbeuteten Informationen selbst auf dem Schwarzmarkt im Dark Web zum Verkauf anzubieten.
  • „Blackhat Coder“ – sie sind die eigentlichen Zauberer in der Malware-Szene, die vielfältige und teils sehr aufwendig programmierte Malware-Varianten mit einem hohen Schadenspotenzial entwickeln und anbieten.

Kann also jeder mit einigermaßen guten Programmier- und Software-Kenntnissen das Level eines Blackhat Coders erreichen? Das wahrscheinlich nicht. Andererseits sollte es für jemanden, der in der IT-Sicherheit tätig ist, nicht allzu schwierig sein, sich mit einigen der Malware-Programmierungskonzepte ausreichend vertraut zu machen. Vor allem gilt „kenne Deinen Feind“. Sprich, manchmal hilft es, zu denken wie es ein Hacker tun würde, um einen potenziellen Angreifer aufzuhalten. Wenn man ein Mal verstanden hat, wie vergleichsweise einfach es ist Malware zu programmieren (auch solche, die nicht aufzudecken ist) wird man das gesamte Thema Informationssicherheit aus einem anderen Blickwinkel betrachten.

Um dem Stoff einer Hacking 101-Lehrstunde zu folgen, sollte man Programmier-kenntnisse in C# und Java haben und über ein Grundverständnis von Windows verfügen. . Zur Erinnerung: Die weitaus meisten Ransomware-Varianten sind in C/C+++/Delphi programmiert, um die Abhängigkeit eines .NET Framework zu umgehen. Das schöne an C# ist, dass es sich wie eine Geschichte lesen lässt, sogar dann, wenn jemand nicht im Detail mit der zugrunde liegenden Syntax vertraut ist.

Keylogger für IT-ler

Ein Keylogger ist ein Stückchen Hard- oder Software, das Tastaturanschläge auf einem kompromittierten Rechner mitlesen, abfangen und aufzeichnen kann. Das funktioniert wie eine Art digitaler Falle, die sich jeden einzelnen Tastaturanschlag schnappt. Solche Keylogger-Funktionen sind nicht selten Bestandteil einer Malware. So kommen sie beispielsweise in RATS (Remote Access Trojans) vor und erlauben es einem Hacker, die Tastaturanschläge auf einem angemeldeten Keyboard an den Angreifer zu übermitteln. Es existieren auch Hardware/Firmware Keylogger, aber sie sind weit weniger verbreitet, weil man dazu physischen Zugriff auf einen Rechner braucht.

Grundsätzlich ist es nicht besonders schwierig einen Keylogger zu programmieren. Um juristisch auf der sicheren Seite zu sein, wenn Sie das Ganze selbst in ihrem Unternehmensumfeld ausprobieren wollen, sollten Sie sich eine Genehmigung einholen oder in einer separaten VM-Umgebung testen. Die folgenden Beispiele funktionieren nicht eigenständig. Es sind lediglich die Stückchen Code, die eine gewünschte Aktion hervorrufen. Es ist nicht unbedingt der eleganteste und beste Weg um ans Ziel zu kommen. Damit wir uns hier nicht zu sehr auf der dunklen Seite der Macht einrichten, zeigen wir bewusst nicht wie man einen Keylogger so programmiert, dass er auch mehrere Reboots überlebt oder so, dass er in der Lage ist, Sicherheitstools, die eigentlich zu seiner Aufdeckung gedacht sind, zu umgehen. Durch spezielle Codierungstechniken ist das natürlich möglich. Und selbst wenn es sich wie in unserem Beispiel um eine Malware handelt, die sich grundsätzlich aufdecken ließe, meistens reichen solche Varianten tatsächlich aus. Und sind längst nicht so leicht zu entfernen wie es scheint.

Und jetzt wenden wir uns dem eigentlichen Programmieren zu.
Um sich Zugriff auf die betreffende Tastatur zu verschaffen, braucht man genau zwei Zeile in C# programmierten Code:

[DllImport("user32.dll")]

public static extern int GetAsyncKeyState(Int32 i);

Unter diesem Link finden Sie weitere Informationen zur GetAsyncKeyState-API von MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx.

Diese beiden Codezeilen lassen sich in einem Satz zusammenfassen: Sie erlauben es festzustellen, ob eine Taste gedrückt oder nicht gedrückt ist, während diese Funktion aufgerufen wird und ebenfalls, ob die Taste nach einem vorherigen GetAsyncKeyState-Abruf gedrückt wurde. Um die gewünschten Tastaturdaten abzufangen, muss die Funktion kontinuierlich aktiviert sein. Die entspreche Codeabfolge sieht dann so aus:

while (true)
            {
                Thread.Sleep(100);
                for (Int32 i = 0; i < 255; i++)
                {
                    int state = GetAsyncKeyState(i);
                    if (state == 1 || state == -32767)
                    {
                        Console.WriteLine((Keys)i);

                    }
                }
            }

Was genau passiert dann? Mithilfe dieser Schleife wird die Tastatur alle 100 Millisekunden abgefragt, um den Status jeder einzelnen Taste zu ermitteln. Ist eine Taste gedrückt oder gedrückt worden, wird das innerhalb der Konsole angezeigt. In einem echten Keylogger werden die Tastaturanschläge gepuffert und geradewegs an den Hacker zurückgemeldet.

Der etwas intelligentere Keylogger

Aber sollte man sich nicht vielleicht besser darauf konzentrieren, den Strom der Tastaturanschläge in einer App zusammenzufassen? Der oben beschriebene Code zieht sich die kompletten Rohdaten aller Tastaturanschläge, unabhängig davon, welches Fenster gerade geöffnet ist oder welche Inhalte gerade im Fokus des Benutzers sind.

Wenn es unser Ziel wäre, sensible Daten wie Passwörter oder Kreditkarteninformationen abzufischen, die sich später wieder zu Geld machen oder für weitere Angriffe nutzen lassen, dann ist dieser Ansatz nicht besonders effizient. Wenn der betreffende Keylogger dann noch auf Tausenden von Rechnern läuft (was durchaus vorkommt), macht das die Sache nicht unbedingt besser. Nicht zu vergessen die Tatsache, dass sämtliche der aufgezeichneten Daten wieder zurück an den Hacker in das betreffende Command Center geschickt werden müssen. Diesen Datenstrom so zu zergliedern, dass der Angreifer die wirklich wichtigen und sensiblen Informationen findet, ist nicht ganz trivial.

Um das Ganze ein bisschen anschaulicher zu machen, stellen wir uns vor, dass wir tatsächlich etwas stehlen wollen, nämlich die Anmeldedaten eines Facebook- oder Gmail-Kontos. Diese Daten sollen dann später genutzt werden, um „Likes“ zu verkaufen.
Die Idee: die Keylogger-Methode nur dann anwenden, wenn erstens der Browser aktiviert ist und zweitens der Name der jeweiligen Webseite „Facebook“ oder „Gmail“ lautet. Indem man die Zahl der zu erfassenden Daten begrenzt, steigert man gleichzeitig seine eigenen Chancen Benutzernamen und Passwörter abzugreifen.

Version 2 des betreffenden Codes sieht dann so aus:

while (true)  
            {

              IntPtr handle = GetForegroundWindow();

              if (GetWindowText(handle, buff, chars) > 0)

              {

                string line = buff.ToString();

                if (line.Contains("Gmail")|| line.Contains("Facebook - Log In or Sign Up "))

                {

                   //Check keyboard

                }

              }

              Thread.Sleep(100);

            }


Dieser Codeausschnitt untersucht das aktive Fenster alle 100 Millisekunden. Die wesentliche Arbeit leistet dabei die Zeile GetForegroundWindow. Der Titel des jeweiligen Fensters wird dabei an die Buffer-Variable zurückgesandt und der Scanning-Code für die Tastatur aktiviert, wenn die Namen „Facebook“ oder „Gmail“ vorkommen.

Mehr zu dieser API finden Sie auch bei Microsoft direkt unter MSDN. Mit dieser Aktion ist sichergestellt, dass die Tastaturdaten nur dann abgefangen werden, wenn der Nutzer im Internet surft und er sich entweder auf der Facebook- oder der Gmail-Login-Seite befindet.

Und der noch ein bisschen intelligentere Keylogger

Nehmen wir an, ein Hacker hat mit einem ähnlichen Code und mithilfe eines Keyloggers die Daten in der beschriebenen Art und Weise abgezogen. Gehen wir zusätzlich davon aus, dass es sich um einen ehrgeizigen Hacker handelt, der es bereits geschafft hat zehn- oder sogar hunderttausend Laptops erfolgreich zu infizieren. Das Resultat: eine riesige Datei mit Megabytes an Text. Ein Datenwust, in dem sich die interessanten Details verstecken wie beispielsweise E-Mail-Adressen und Passwörter. Ein guter Zeitpunkt die Bekanntschaft von „Regulären Ausdrücken“, kurz „Regex“, zu machen. Sie dienen wie eine Minisprache dazu, Zeichenmuster zu finden und zu bearbeiten. Mit ihrer Hilfe ist man in der Lage bestimmte gefundene Muster mit denen abzugleichen, die man zuvor definiert hat. Mehr zum Thema reguläre Ausdrücke findet man unter anderem im Wikipedia-Artikel.

Hier sehen Sie ein Beispiel von zwei regulären Ausdrücken, die in der Lage sind Benutzernamen und Passwörter aus dem Text heraus zu arbeiten:

//Identify Email
^[\w!#$%&'*+\-/=?\^_`{|}~]+(\.[\w!#$%&'*+\-/=?\^_`{|}~]+)*@((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$


//Identify Password
(?=^.{6,}$)(?=.*\d)(?=.*[a-zA-Z])

Das sind nur zwei Beispiele, um Ihnen einen kleinen Vorgeschmack zu geben, was sich alles mithilfe von regulären Ausdrücken anstellen lässt. Praktisch alles, was ein wiedererkennbares Muster aufweist, lässt sich mit Regex identifizieren. Seien es Sozialversicherungsnummern, Namen, Passwörter und so weiter. Regex sind so etwas wie der beste Freund des Programmierers, auch wenn sie sich nicht so leicht lesen lassen. Sprachen wie Java, C#, JavaSript und andere verfügen über integrierte Regex-Funktionen. Damit lassen sich Ausdrücke einfügen, die das gewünschte Muster repräsentieren (wie den obigen kryptischen Code) und auf den Text anwenden, der potenziell diese Muster enthält.

In C# sieht der Regex dann so aus:

Regex re = new Regex(@"^[\w!#$%&amp;'*+\-/=?\^_`{|}~]+(\.[\w!#$%&amp;'*+\-/=?\^_`{|}~]+)*@((([\-\w]+\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\.){3}[0-9]{1,3}))$");

Regex re2 = new Regex(@"(?=^.{6,}$)(?=.*\d)(?=.*[a-zA-Z])");

string email = "Oded.awask@gmail.com";

string pass = "abcde3FG";

Match result = re.Match(email);

Match result2 = re2.Match(pass);

Der erste Regex (re) sucht nach Übereinstimmungen mit den im Text enthaltenen E-Mail-Adressen und der zweite nach Übereinstimmungen mit allen Passwörtern, die mehr als sechs Zeichen enthalten.

FUD frei Haus

Nutzt man etwa Visual Studio mit einer bevorzugten IDE lässt sich ein böswilliger Keylogger in weniger als 30 Minuten programmieren. Ein echter Hacker würde seine bevorzugten Ziele definieren (Bankenseiten, Seiten von sozialen Medien etc.) und den Code entsprechend seinen persönlichen Bedürfnissen anpassen. Dazu kommt die entsprechende E-Mail Phishing-Kampagne, die eine .exe-Datei in einem harmlos erscheinen Dokument wie einer Rechnung oder ähnlichem ans Ziel bringt.

Dann ist eigentlich nur noch eine Frage offen: Ist die Malware Fully Undetectable (FUD)? Um das herauszufinden kann man Virustotal nutzen. Das Webtool kalkuliert den Hashwert der exe-Datei und vergleicht ihn innerhalb der zugrundeliegenden Datenbank mit den Hashwerten bekannter Viren. Unter diesen Bedingungen ist es wenig überraschend, dass Virustotal keine Übereinstimmungen gefunden hat.

virustool

Und genau das ist der Punkt. Es ist für Hacker kein Problem, den verwendeten Code kontinuierlich weiterzuentwickeln und zu verändern. Und damit Scannern zuverlässig ein paar Schritte voraus zu sein. Mit einer eigenen Programmierung ist die Wahrscheinlichkeit groß, „FUD“ zu sein.

Im zweiten Teil unserer Serie befassen wir uns mit Ransomware und zeigen wie erschreckend einfach es ist eine FUD-Ransomware zu programmieren.