Skip to content

Dokumentation Honeygrove

Florian Wilkens edited this page Mar 12, 2019 · 3 revisions

Honeygrove

Einleitung

Honeygrove ist ein vielseitig einsetzbarer Honeypot und bildet das Kernstück des Projekts. Er bietet verschiedene Services, die Angreifer anlocken und ihre Angriffsstrategien protokollieren. Es sind bewusst Schwachstellen in den Services eingebaut, die zur Ausnutzung durch den Angreifer verleiten. Über die Management-Konsole ist Honeygrove durch einen Benutzer dynamisch konfigurierbar. So können einzelne Services an bestimmten Ports gestartet oder gestoppt werden. Auch einzelne Settings können im laufenden Betrieb über die Management-Konsole verändert werden. Die erfassten Angriffsdaten werden von Honeygrove in einem festgelegten Format zum Incident-Monitoring weitergeleitet und dort ausgewertet.

Folgende Services umfasst Honeygrove:

SSH

Das SSH-Protokoll wird komplett implementiert und durch eine selbstgeschriebene Pseudo-Shell ergänzt. Auf Wunsch können die Befehle auch auf der echten Shell ausgeführt werden.

HTTP

Der HTTP-Service verwendet kein ganz vollständiges HTTP-Protokoll zur Kommunikation. Die gängigen GET und POST Befehle werden unterstützt.

FTP

Der FTP-Service simuliert fast vollständig das Verhalten eines FTP-Servers. Alle gängigen FTP-Befehle werden unterstützt.

ListenService

Der ListenService lauscht auf einer Menge von Ports und erfasst alle eingehenden Daten.

TCPFlagSniffer

Der TCPFlagSniffer lauscht auf half-open TCP-Connections und kann so SYN-Floods und Portscans erkennen.

Ressourcen:

Pakete:

  • Twisted 17.5.0
  • Broker (pybroker /mfischer/broker-multihop)

Prerequisites

  • Python 3 oder höher

Betriebssystem

  • Ubuntu (getestet ab Version 16.4 mit allen aktuellen Paketen)
  • Debian (getestet ab Version 9.1 mit allen aktuellen Paketen)

Hardware

CPU: ca. 1,4GHz Quad-Core RAM: min. 1 GB RAM Disk: ca. 10 MB

Installation

  • Ordner "honeygrove" an gewünschtes Verzeichnis kopieren
  • honeygrove_install ausführen

Pybroker

Konfiguration

config.py

Alles, was in Honeygrove konfigurierbar ist, wird in der Datei config.py festgelegt.

  • HPID - Eindeutige ID für den Honeypot

  • machine_name - Gerätename, der in den Services verwendet werden soll

  • hp_description - Beschreibung des Honeypots wie z.B. Standort

  • resources - Pfad zum Ressourcenordner

  • logpath - Pfad, an dem die lokale Logdatei abgelegt wird

  • listenServicePorts - Liste von Ports, auf denen der ListenService laufen soll

  • listenServiceName - Name, den der ListenService nutzen soll

  • tcpFlagSnifferName - Name, den der TCPFLagSniffer nutzen soll

  • httpResponseHeader - Header, der bei der HTTP Response gesendet wird

  • httpHTMLDictionary - Dict mit den unterstützten HTTP-Seiten. Kann durch Nutzung des HTMLLoader vereinfacht werden

  • httpResources - Pfad zu den Ressourcen für den HTTPService

  • httpPort - Port, auf dem der HTTPService laufen soll

  • httpName - Name, den der HTTPService nutzen soll

  • sshPort - Port, auf dem der SSHService laufen soll

  • sshName - Name, den der SSHService nutzen soll

  • ssh_real_shell - Gibt an, ob die Anfragen an den SSHService an die echte Shell weitergereicht werden sollen. Bietet dadurch mehr Möglichkeiten das Verhalten mitzuschneiden, öffnet das echte System jedoch komplett nach außen.

  • ftpPort - Port, auf dem der FTPService laufen soll

  • ftpName - Name, den der FTPService nutzen soll

  • path_to_filesys - Pfad zu dem XML-Dateisystem, das alle Services für ihre FilesystemParser nutzen

  • tokendir - Pfad zu den Dateien, die im vorgetäuschten Dateisystem auffindbar sein sollen

  • tokenDatabase - Pfad zu der Datei mit den Login-Daten

  • honeytokendbGenerating - Dict mit Services, welche Honeytoken generieren können

  • honeytokendbProbabilities - Dict mit Wahrscheinlichkeiten zur Honeytoken-Generierung

  • sshAcceptsFiles - Gibt an, ob der SSHService Dateien speichern darf (z.B. wget)

  • ftpAcceptsFiles - Gibt an, ob der FTPService Dateien speichern darf (z.B. put)

  • quarantineDir - Pfad zum Verzeichnis, in dem empfangene Dateien gespeichert werden sollen

  • startupList - Liste mit den Namen der Services, die beim Start von Honeygrove automatisch gestartet werden

  • noPortSpecificService - Liste mit den Namen der Services, die auf mehr als einem Port laufen dürfen

  • tcpTimeout - Zeit, nach der nach eine Antwort auf ACK-SYN erfolgen soll

  • BrokerComIP - IP auf der wir lauschen für Broker peerings

  • BrokerComPort - Port auf dem wir lauschen für Broker peerings

  • honeygrove_start - 'active' Service werden beim Start des Honeypots mit gestartet. 'passive' services bleiben ausgeschaltet

Änderungen treten erst nach einem Neustart von Honeygrove in Kraft. Einige Einstellungen lassen sich über die Management-Konsole jedoch auch im laufenden Betrieb ändern.

Run

  • Ausführen von honeygrove.sh startet Honeygrove
  • Wenn bei der Installation die Links angewählt wurden einfach im Terminal als Befehl honeygrove.

Test

Es gibt verschiedene Möglichkeiten die Funktionalitäten von Honeygrove zu testen oder auszuprobieren.

Manuelles Testen der Services

Nach dem Starten des Honeypots im 'active'-Mode (config.honeygrove_start = 'active'), laufen alle Services an den in der config festgelegten Ports. Alle Services können also über diese Ports manuell angesprochen werden.

Valide Login-Credentials für SSH, HTTP und FTP finden sich in config.tokenDatabase. Dort können auch manuell Login-Credentials eingetragen werden.

SSH

Es kann sich regulär über SSH verbunden werden, also über das Terminal z.B. mit ssh root@localhost -p 12222. Nach der Authentifizierung kann auf üblichem Wege über SSH mit dem SSH-Service kommuniziert werden.

HTTP

Beim gestarteten HTTPService, können die unterstützten Seiten über den Browser ausprobiert werden. Im Browser muss localhost:port/seiten_url eingegeben werden. Beispiel für Port 8080 (HTTP Standart):

  • localhost:8080/
    • Fritzbox Seite
  • localhost:8080/wp-admin
    • Wordpress Login
  • localhost:8080/ghost
    • Ghost Login
  • localhost:8080/phpmyadmin
    • phpMyAdmin Login

Bei allen default.Seiten, wird man bei einem erfolgreichen Login-Versuch auf eine Dashboard-Seite weitergeleitet.

FTP

Es kann sich regulär über FTP verbunden werden, z.B. mit dem Terminal ftp und dann open localhost 4646. Nach der Authentifizierung kann über die gängigen FTP-Befehle mit dem Service kommuniziert werden.

TCPFlagSniffer

Um den TCPFlagSniffer manuell zu testen erzeugt man eine half-open TCP-Connection zum entsprechenden Port. Dazu muss ein TCP Packet mit SYN gesendet werden, dieses wird dann geloggt (Achtung! Es darf kein TCP Packet mit ACK hinterhergeschickt werden).

ListenService

Um den ListenService zu testen, einfach einen Port an dem der ListenService lauscht mit irgendeinem Protokoll (z.B. SSH) ansprechen. Die Anfrage wird dann geloggt.

Unittests

In honeygrove.tests befinden sich die Unittests des Projekts. Es gibt Unittests für jede Komponente in honeygrove.core und honeygrove.services. Die TestCases sind wie die Dateien die sie testen und Suffix '_Test' benannt und daher leicht zuzuordnen.

Architektur

Honeygrove UML Klassendiagramm

Die Architektur von Honeygrove basiert auf verschiedenen Services, die vom ServiceControllerverwaltet werden. Alle Services implementieren das ServiceBaseModel, daher muss der ServiceController nur dieses kennen.

Die Steuerung von außen ist durch den HoneyAdapter realisiert, welcher über den BrokerEndpoint Nachrichten von der Management-Konsole empfängt und daraufhin entsprechende Methoden am ServiceController aufruft. Der BrokerEndpoint ist ebenfalls für das Senden von z.B. Logdateien an Management-Konsole und Incident-Monitoring zuständig.

Die Service-basierte Architektur ermöglicht einen hohen Grad an Modularität, d.h. neue Services können einfach hinzugefügt werden. Hierfür muss dieser ebenfalls im Modul services angelegt werden und das ServiceBaseModel ìmplementieren.


Das Honeygrove-Projekt teilt sich in die Module broker, core, services, logging, resources und tests.

broker

BrokerEndpoint.py

Der BrokerEndpoint ist für die Annahme und das Versenden von Broker Nachrichten zuständig. Diese Nachrichten enthalten Befehle von und Antworten an die Management-Konsole, logs und Dateien. Zusätzlich enthält diese Klasse die Funktionalität sich zu anderen Endpunkten zu peeren. Wichtig ist das der BrokerEndpoint nicht für die Bearbeitung zuständig ist, sondern nur für die Übermittlung.

core

FilesystemParser.py

Die Klasse FilesystemParser.py ist für die unmittelbare Verwaltung des simulierten Dateisystems zuständig. Sowohl FTP als auch der SSH Service benutzen den Filesystem Parser (FSP), um Operationen wie das Navigieren durch ein Dateisystem oder Erzeugen neuer Ordnerstrukturen zu ermöglichen. Dem FSP liegt ein XML Dokument zugrunde, das als ElementTree eingelesen wird und die Struktur des Dateisystems repräsentiert. Beim Erzeugen einer Instanz des FSP (in den jeweiligen Service Klassen) kann der Pfad zu diesem Dokument als Parameter übergeben werden. Wird kein Pfad angegeben, wird standardgemäß der path_to_filesys aus der Konfigurationsdatei des Honeypots (config.py) genommen, hinter dem eine Unix ähnliche Ordnerstruktur als XML Dokument zu finden ist (unix.xml).

Aufbau des XML Dokuments

Der FSP erwartet einen ähnlichen Aufbau aller XML Dateien, die als Ordnerstruktur dienen sollen. In der ersten Zeile kann in einem XML Kommentar angegeben werden, welcher Ordner als das home Verzeichnis des Benutzers ausgewählt werden soll, um z.B. in SSH künftig als ~ (Tilde) angezeigt werden zu können. Die Syntax der ersten Zeile ist dabei wie folgt: <!--a, b, c, ..., z--> Wobei die Buchstaben als Liste von Zahlen verstanden werden können und jeweils durch die Positionen in der XML Hierarchie ersetzt werden müssen. ######## Beispiel:

<!--1, 0-->
<dir name="/">
    <dir name="bin"/>
    <dir name="home">
        <dir name="root">
            <file name="hello_world.py"/>
        </dir>
        <dir name="asdf"/>
    </dir>
</dir>

Der äußerste bzw. oberste Ordner (in diesem Beispiel /) wird standardmäßig ignoriert und ist das home Verzeichnis falls in der ersten Zeile kein entsprechender Kommentar vorhanden ist. Die 1 zeigt somit auf den Ordner home (da wir bei 0 anfangen zu zählen) und die 0 danach auf das erste Unterverzeichnis in home nämlich root. Wird also ein Service gestartet, dem dieses XML Dokument zugrunde liegt, würde ein ls Befehl zum Anzeigen aller Dateien im aktuellen Verzeichnis die Datei hello_world.py liefern. Möchte man stattdessen das home Verzeichnis nicht in root haben sondern in asdf, müsste der Kommentar in der ersten Zeile zu <!--1, 1--> geändert werden, um auf das zweite Unterverzeichnis von home (nämlich asdf ) zu zeigen. Darüberhinaus ist zu beachten, dass nur zwei XML-Tags gültig sind: dir für Ordner und file für Dateien gefolgt vom Attribut name, das den Namen des jeweiligen Ordners / Datei enthält.

HoneyAdapter.py

Die Klasse HoneyAdapter reagiert auf Befehle der Management-Konsole an den Honeygrove. Die Befehle empfängt der Honeyadapter im JSON-Format über den BrokerEndpoint. Sie werden in der Methode handleMessages geparst und auf Validität überprüft. Im Anschluss werden je nach eingegangenem Befehl die entsprechenden Funktionen am Honeygrove-System aufgerufen oder Änderungen vorgenommen. Dazu verfügt der Honeyadapter über einen ServiceController.

HoneytokenDB.py

Die HoneytokenDB ist zuständig für das Verwalten von Login-Versuchen. Dazu implementiert sie den twisted.cred.checkers.ICredentialsChecker. Jeder Service verfügt über eine Instanz der HoneytokenDB, die er bei seiner Initialisierung an sein twisted.cred.portal.Portal übergibt. Wird dann am vom jeweiligen Service verwendeten Protokoll ein Login durchgeführt, ist die entsprechende Instanz von HoneytokenDB für die Überprüfung der Validität der Credentials zuständig. Alle HoneytokenDB-Instanzen greifen auf die gleiche Datei zu, deren Pfad in der config unter tokenDatabasezu finden ist. Dort werden gültige Login-Daten im Format Serv1,Serv2:Username:Passwort:Key eingetragen. Durch diese zentrale Aufzeichnung ist es der HoneytokenDB möglich, dynamische Honeytoken zu generieren, d.h. einen Login-Versuch zufällig für gültig zu erklären, die damit verbundenen Anmeldedaten in die Datei zu schreiben und diese so auch für andere Services gültig zu machen. Welcher Service auf diese Art Login-Credentials für welche anderen Services generieren darf ist in config.honeytokendbGenerating im Format {Von: [Für, Für], Von: [Für]} festgelegt. Mit welcher Wahrscheinlichkeit Honeytoken generiert werden, steht unter config.honeytokendbProbabilities im Format Service: Wahrscheinlichkeit, Service: Wahrscheinlichkeit. Um Konflikte (IOError) beim lesen bzw. verändern der Datei durch mehrere Services zu vermeiden, verfügt jede HoneytokenDB-Instanz zusätzlich über eine Arbeitskopie der gemeinsamen Datei, die genutzt wird, wenn die gemeinsame Datei blockiert ist.

ServiceController.py

Der ServiceController ist die Schnittstelle zwischen den Servicen, dem rest vom Honeygrove und ist für die Plugin Funktion der Service zuständig. Er findet automatisch alle Subklassen vom ServiceBaseModel und erstellt eine dann Instanz dieses Services. Er ist außerdem dazu da, Service zu starten, stoppen und die Synchronisation mit dem ListenService aufrechtzuerhalten. Laufende service werden in einen Dict gehalten und können über den jeweiligen Namen angesprochen werden. Durch diese vorgehensweiße, ist es einfach einen neuen Service in Honeygrove zu implementieren.

  1. Die neue Service-Klasse muss vom ServiceBaseModel erben und deren abstrakte Funktionen implementieren.
  2. Die Service-Klasse muss im Service Ordner sein

Der Entwickler muss keine weitere Kenntnis über den Rest des Projektes haben, außer er möchte über die Funktionen hinausgehen, die das ServiceBaseModel bietet.

logging

log.py

Das log Modul wird von überall im Projekt aufgerufen, um zu loggen und auf die Konsole auszugeben. Es hat verschiedene Methoden, die zu bestimmten Anlässen aufgerufen werden sollten. Manche Methoden sind nur für das Ausgeben und Schreiben zuständig, andere benutzen den BrokerEndpoint um die Meldungen an bspw. CIM oder Management-Konsole zu senden.

services

ServiceBaseModel.py

Das ServiceBaseModel bildet ein Interface, das von allen Services implementiert werden muss. Möchte man einen neuen Service zum Honeygrove hinzufügen, muss auch dieser ServiceBaseModel implementieren und in honeygrove.services platziert werden.

SSHService.py

Der SSHService nutzt für die Realisierung der Verbindung die SSH-Komponenten von Twisted. Er nutzt dafür die SSHFactory, setzt ihr jedoch mit groveUserauthein eigenes ssh-userauth um das Logging von Anmeldeversuchen zu ermöglichen. Ferner wird das Portal mit einem eigenen Realm und Avatargesetzt. Als "credentials checker" wird dem Portal die HoneytokenDBübergeben. Bei einem Login-Versuch wird nun die HoneytokenDB aufgerufen, bei Erfolg erzeugt dann das SSHRealmeinen SSHAvatar. Je nachdem, welchen Service der Angreifer fordert, gibt die SSHSession ihm bei der direkten Ausführung von Befehlen eine Meldung zurück. Bei der Forderung einer Shell wird der Angreifer mir unserem SSHProtocolverbunden.

Das SSHProtocol täuscht dem Angreifer ein Terminal vor. Es erbt dazu von HistoricRecvLine um das "Erinnern" und Scrollen der letzten Befehle zu ermöglichen. Bei der ersten Verbindung wird connectionMadeaufgerufen, hier werden Session-spezifische Attribute gesetzt. Jedes mal, wenn der Angreifer einen Befehl abschickt, wird lineReceivedaufgerufen. Wenn in der config die Option ssh_real_shellaktiv ist, werden die Befehle direkt auf der echten Maschine ausgeführt. Ansonsten wird die Zeile analysiert wobei das erste Wort dem Befehl und alle weiteren den Argumenten entsprechen. Es wird dann die jeweilige Funktion ssh_BEFEHLSNAMEaufgerufen und die Argumente als Parameter übergeben. Neue Befehle können hier einfach ergänzt werden.

HTTPService.py

Der HTTPService ermöglicht anhand von einigen twisted Komponenten einem Angreifer, sich über einen Port zu verbinden und eine HTTP Request zu schicken. Es wird ein eigenes, HTTP-ähnliches Protokoll, namens protokoll erstellt, welches von twisted.internet.protocol.Protocol erbt. Die ankommenden Requests werden von dem protokoll als String ausgelesen. Wenn eine gültige URL angefragt wird, wird die dementsprechende HTML-Seite per HTTP Response versendet. Bei den folgenden Login-Versuchen, wird immer ein HTTPAvatar erstellt. Diesem Avatar werden die Login Daten übergeben und er wird an die HoneytokenDB weitergereicht. Die HoneytokenDB dient als "credentials checker" dieses Services. Je nachdem ob die HoneytokenDB die Login Daten als gültig oder ungültig deklariert, wird die dementsprechende Response rausgeschickt. Bei gültigen Daten, kann eine 'Dashboard' Seite zugefügt werden.

Hinzufügen neuer default Seiten

Eine neue Html Seite kann über die Management Konsole hinzugefügt werden. Dies geht über den Befehl add_html. Der benötigt als Parameter einmal die URL unter welcher die Seite erreichbar sein soll und die eigentliche Html Dateien als String. Eine Login-Seite ist verbindlich, diese kann allerdings durch eine optionale Dashboard-Seite ergänzt werden, auf die man weitergeleitet wird, wenn der Login-Versuch erfolgreich war.

Bei den HTML Dateien sind folgende Punkte sehr wichtig und sollten angepasst werden, wenn noch nicht geschehen:

  • Alle Bilder, oder Files, die für den Aufbau der Website benötigt werden, sollten in Base64 encoded und direkt in die HTML geschrieben werden. Ansonsten werden die Requests für diese Dateien mit 404-NotFound beantwortet und nicht in die Website geladen!
  • In der Login-Page müssen die Login-Felder für Benutzername/Login und Passwort angepasst werden. Das Feld für den Benutzername muss 'name="log"' und das Passwort Feld muss 'name="pwd"' als Attribut bekommen oder dementsprechend umbenannt werden. Ansonsten werden die Credentials nicht erkannt.
  • Sämtliches CSS muss in Style-Tags innerhalb der HTML stehen und kann nicht von außen geladen werden.
Konfiguration

Der HTTPService holt sich Name, Port, HTTP-Response-Header und URLS für die Seiten direkt aus der config.py.

FTPService.py

Der FTPService nutzt, um eine Verbindung zu einem Angreifer zu ermöglichen, einige twisted Komponenten. Er erstellt eine twisted.protocols.ftp.FTPFactory. An dieser registriert er ein twisted.cred.portal.Portal, an das wiederum eine Instanz der HoneytokenDB als twisted.cred.checkers.ICredentialsChecker und das FTPProtocol als Protokoll übergeben wird. Verbindet sich nun ein Angreifer an den Port, an dem die FTPFactory lauscht, wird für je einen Angreifer eine Instanz des FTPProtocol erzeugt, die auf die Befehle des Angreifers reagiert. Erhält das FTPProtocol im Zuge der erhaltenen Befehle Login-Credentials vom Angreifer, werden diese mit Hilfe der HoneytokenDB-Instanz auf ihre Validität überprüft.

Das FTPProtocol erbt von twisted.protocols.ftp.FTP. Dieses Protokoll implementiert alle Funktionen eines FTP-Servers vollständig. Da unser Protokoll sich nicht wie ein wirklicher FTP-Server verhalten soll, sind die Funktionen von FTP, die auf Befehle eines Angreifers reagieren, zu einem Großteil überschrieben. Um über FTP zu kommunizieren verbinden sich Client und Server nicht nur über einen Port zur Kommunikation. Es wird zusätzlich ein DTP-Channel zwischen Client und Server geöffnet um eine Datenübertragung zu ermöglichen. Um diese Funktionalitäten nicht implementieren zu müssen, erbt FTPProtocol von FTP. FTPProtocol kann auf alle gängigen FTP-Befehle sinnvoll reagieren. Es täuscht dem Angreifer ein Dateisystem und dessen Modifikation vor. Dazu verfügt es über eine Instanz von FileSystemParser. Auch Datentransfers sind über den geerbten DTP-Kanal möglich. So kann ein Angreifer eine Datei hochladen und scheinbar im Dateisystem platzieren. Genauso kann ein Angreifer den Inhalt von Dateien über den DTP-Kanal herunterladen. Hochgeladene Dateien werden im Quarantäne-Ordner unter config.quarantineDir gespeichert. Es können nur Dateien heruntergeladen werden, die auch wirklich existieren und im Ordner unter config.tokendir liegen.

ListenService.py

Der ListenService ist ein spezieller Service, der vom ServiceController auf allen (in der config eingetragenen) Ports ausgeführt wird, auf denen kein anderer Service läuft. Er nimmt jegliche Art von Verbindung an und loggt die empfangenen Daten über log, sendet dabei jedoch keine Antwort.

TCPFlagSniffer.py

Im TCPFlagSniffer.py sind die Klassen TCPDataStruct und TCPFlagSniffer enthalten. TCPDataStruct ist eine Klasse, welche die für uns relevanten Informationen eines TCP/IP Paketes speichert. TCPFLagSniffer ist die eigentliche Service-Klasse. Es wird ein RAW Socket erstellet, der den gesamten TCP/IP Verkehr auf des Systems mitliest. Es wird nach Paketen mit einem SYN Flag Ausschau gehalten. Die relevanten Daten (IP, Port, Ankunftszeit) werden in einem Dict von TCPDataStruct Objekten gespeichert. Falls ein Paket von der selben IP und Zielport, mit einem ACK Flag reinkommt, wird der entsprechende Eintrag im Dict gelöscht. Ein Thread Scannt in einen bestimmten Zeitraum die Liste und schickt eine Nachricht (Titel SYN) raus, wenn zwischen Ankunftszeit des Paketes und Scanzeit ein bestimmter Zeitraum vergangen ist (Standard sind 5 Sekunden).

resources

honeytokendb
  • database.txt - Standardpfad für die Logins in der HoneytokenDB. In der Datei befinden sich bereits einige Beispiele für Login-Credentials.
honeytokenfiles

Standardpfad für "auffindbare Dateien" also Dateien, die durch den Filesystemparser ins vorgetäuschte Dateisystem übernommen werden und vom Angreifer erbeutet werden könnnen. (Das Beispiel-Schlüsselpaar ist in der beispielhaften database.txt bereits verzeichnet.)

  • id_rsa - Ein Beispiel für einen RSA Private Key
  • id_rsa.pub - Ein Beispiel für einen RSA Public Key
http_resources

Standardpfad für die Ressourcen des HTTPService. Hier finden sich bereits einige aufbereitete und einsatzbereite Seiten.

  • 404_login.html - Eine standard 404-Seite
  • \_content.html - Eine FRITZ!Box 6490 Dashboard-Seite
  • \_login.html - Eine FRITZ!Box Login-Seite
  • ghost_content.html - Eine Management-Seite der Blogging-Plattform Ghost
  • ghost_login.html - Eine Login-Seite der Blogging-Plattform Ghost
  • HTMLDictionary.pkl - Abgespeicherter Zustand des httpHTMLDictionary in der config.py
  • HTMLLoader.py - Hilfsskript um HTML-Seiten dynamisch in die conig.py zu laden und aus dieser zu sichern
  • phpmyadmin_content.html - Eine phpMyAdmin Dashboard-Seite
  • phpmyadmin_login.html - Eine phpMyAdmin Login-Sete
  • wp-admin_content.html - Eine Wordpress Dashboard-Seite
  • wp-admin_login.html - Eine Wordpress Login-Seite
ssh_resources:
  • gnuhelp - Standard Hilfetext von GNU Bash. Wird vom SSHService genutzt.
  • helptexts - Datei mit den Hilfetexten für die Befehle im SSHService. Hier können eigene Texte für weitere Befehle ergänzt werden, die dann im SSHService entsprechend ausgegeben werden.
parser_resources
  • dir_sys.xml - Ein Beispiel für eine XML-Datei, die ein Windows-Dateisystem repräsentiert.
  • unix.xml - Ein Beispiel für eine XML-Datei, die ein UNIX-Dateisystem repräsentiert. In der config.py als Standard eingetragen.
quarantine

Standardpfad zum Abspeichern von empfangenen Dateien. Diese werden hier zur weiteren Verarbeitung verwahrt.

Schnittstellen:

broker

BrokerEndpoint.py

Dependencies

pybroker
base64

Felder

  • BrokerEndpoint.listenEndpoint: Broker Endpunkt über den die Nachrichtenübermittlung geschieht
  • BrokerEndpoint.commandsQueue: Nachrichten Queue die alle Nachrichten an dieses Topic in einer Queue speichert
  • BrokerEndpoint.peerings: Enthält ein peering Objekt des Honeypots. Wird gebraucht um sich von diesen Objekt zu unpeeren

API

class BrokerEndpoint.BrokerEndpoint()

getCommandMessage()

Holt das erste Element der commandsQueue und gibt es zurück

Returns:

-- Broker.Message


startListening()

Startet das lauschen auf den in der config definierten IP/Port


sendLogs(jsonString)

Sendet den jsonString als Broker.Message an das logging topic

Parameter:

-- jsonString: Ein String in JSON-Format.


peerTo(ip, port)

Peert den Honeypot zu der angegebenen ip, port. Setzt peerings auf die Ip, Port und peering Objekt

Parameter:

-- ip: (str) IP zu der gepeert werden soll

-- port: (int) Port auf den gepeert werden soll


unpeer(peeringObj=None)

Unpeert den Honeypot. Wenn kein peeringObj gesetzt ist, wird das erste der peerings liste genommen

Parameter:

-- peeringObj: Peering Objekt. Die jeweilige zugehörige Verbindung wird getrennt.


sendMessageToTopic(topic, msg)

Sendet an ein bestimmtes topic eine Nachricht

Parameter:

-- topic: (str) Topic an das gesendet werden soll

-- msg: (str, int, float, double) Nachricht die gesendet werden soll


sendFile(filepath)

Sendet eine Datei an das files topic.

Parameter:

-- filepath: (str) Pfad zur Datei


core

FileSystemParser.py

Dependencies

os
re
xml.etree.ElementTree

Felder

  • FilesystemParser.xml_path: Pfad zu XML-Datei
  • FilesystemParser.tree: Aus Datei in self.xml_path eingelesener ElementTree
  • FilesystemParser.root: Root-Element von self.tree
  • FilesystemParser.current_pos: Aktuelle Position in self.tree
  • FilesystemParser.honeytoken_directory: Pfad zu den Honeytokenfiles, aus config.py
  • FilesystemParser.cd_pattern: Regex für cd-Befehle
  • FilesystemParser.mkdir_pattern: Regex für mkdir-Befehle
  • FilesystemParser.touch_pattern: Regex für touch-Befehle
  • FilesystemParser.ls_pattern: Regex für ls-Befehle
  • FilesystemParser.user_path: Pfad zur User-Directory
  • FilesystemParser.mode: Je nach verwendetem XML 'DOS' oder 'UNIX'

API

class FileSystemParser.FileSystemParser()

get_position(path)

Gibt die Position im self.tree am Pfad path zurück.

Parameter:

-- path: Pfad (str)

Returns:

-- Position (list)


get_path(position)

Gibt den Pfad für eine Position im self.tree.

Parameter:

-- position: Position (list)

Returns:

-- path: Pfad (str)


get_element(position)

Gibt Element des self.tree an der Position position.

Parameter:

-- position: Position (list)

Returns:

-- Element (xml.etree.Element)


get_absolute_path(rel_path)

Konvertiert einen absoluten oder relativen Pfad zu einem absoluten Pfad.

Parameter:

-- rel_path: Pfad (str)

Returns:

-- Pfad (str)


tree_contains(file_name)

Überprüft ob file_name irgendwo im self.tree existiert.

Parameter:

-- file_name: Dateiname/Ordnername (str)

Returns:

-- True/False (bool)


add_honeytoken_files()

Fügt die Dateien aus self.honeytoken_directory zum self.tree hinzu, wenn dort noch kein gleichnamiges Element enhalten ist.


get_current_path()

Gibt den aktuellen Standort im self.tree als String.

Returns:

-- Pfad (str)


get_formatted_path()

Gibt den aktuellen Standort im self.tree als formatierten String (platform adjusted).

Returns:

-- Pfad (str)


mkdir(path)

Erstellt ein neues 'dir'- Element im self.tree an der Position path.

Parameter:

-- path: Pfad (str)


touch(path)

Erstellt ein neues 'file'- Element im self.tree an der Position path.

Parameter:

-- path: Pfad (str)


create(path, tag)

Hilfsfunktion für touch(path) und mkdir(path). Erstellt einen neues Element-Knoten im self.tree an der Position path mit Tag tag.

Parameter:

-- path: Pfad (str)

-- tag: Tag (str)


ls(path='')

Gibt die Namen aller Kindknoten im self.tree von self.current_pos aus als String.

Parameter:

-- path: Pfad (str)

Returns:

-- Namen aller Kindknoten, getrennt mit '\n' (str)


cd(path)

Ändert self.current_pos im self.tree zum Pfad path.

Parameter:

-- path: Pfad (str)

Returns:

-- Im Falle dass path nicht existiert: Fehlermeldungs-String (str)


valid_directory(path)

Überprüft ob path von self.current_pos aus zu einem Element mit 'dir' als Tag führt.

Parameter:

-- path: Pfad (str)

-- tag: Tag (str)

Returns:

-- True/False (bool)


valid_file(path)

Überprüft ob path von self.current_pos aus zu einem Element mit 'file' als Tag führt.

Parameter:

-- path: Pfad (str)

Returns:

-- True/False (bool)


valid_path(path, tag)

Hilfsfunktion für valid_directory und valid_file. Überprüft ob path von self.current_pos aus zu einem Element mit tag als Tag führt.

Parameter:

-- path: Pfad (str)

-- tag: Tag (str)

Returns:

-- True/False (bool)


delete(path)

Sucht nach einem Element von self.current_pos aus und löscht es wenn es existiert.

Parameter:

-- path: Pfad (str)


move(sourcepath, targetpath)

Bewegt das Element im self.tree, das unter sourcepath liegt, an die Position targetpath.

Parameter:

-- sourcepath: Pfad des Elements davor (str)

-- targetpath: Pfad des Elements danach (str)

Returns:

-- Im Falle dass Pfade nicht valide: Fehlermeldungs-String (str)


rename(from_path, to_name)

Ändert den Namen eines Elements von from_path zu to_name. Verwendet dazu move.

Parameter:

-- from_path: Pfad (str)

-- to_name: Tag (str)

Returns:

-- Im Falle dass Pfade nicht valide: Fehlermeldungs-String (str)


cat(path)

Gibt es an der Position path im self.tree ein Element dessen Namen auch der Name einer Datei in self.honeytoken_directory ist, wird der Inhalt dieser Datei als String zurückgegeben.

Parameter:

-- path: Pfad zum Element (str)

Returns:

-- Inhalt der entsprechenden Datei (str)

HoneyAdapter.py

Dependencies

threading
time
json
os
os.path.isfile
os.path.join
xml.etree.ElementTree

Felder

  • HoneyAdapter.controller: Instanz von ServiceController
  • HoneyAdapter.start: 'active' wenn Honeygrove inkl. aller Services gestartet werden soll (aus config.py)
  • HoneyAdapter.lock: Instanz von threading.Lock

API

class HoneyAdapter.HoneyAdapter()

Lauscht auf eingehende Nachrichten am BrokerEndpoint. Wertet die Nachrichten aus und nimmt am Honeygrove die entsprechenden Änderungen vor.

command_message_loop()

Die Methode startet eine Schleife, in der der Honeyadapter alle 0.1 Sekunden am BrokerEndpoint nach neuen Messages fragt. Erhält der Honeyadapter so eine Message wird diese an handle_messages weitergereicht.


hearbeat()

Die Methode startet eine Schleife, in der der Honeyadapter alle 60 Sekunden einen Heartbeat loggt.


handle_messages(msgs)

In dieser Methode wertet der Honeyadapter die erhaltenen Befehle aus. Je nach Befehl ruft er die entsprechenden Methoden an self.controller auf, verändert Dateien in resources-Modul oder updated config.py.

Parameter:

-- msgs: Zweifach geschachtelte Liste mit Broker-Message (list)

HoneytokenDB.py

Dependencies

os
tempfile
shututil
random
zope.interface.implementer
twisted.cred.error
twisted.cred.credentials
twisted.cred.checkers.ICredentialsChecker
twisted.conch.error
twisted.conch.ssh.keys
twisted.internet.defer.Deferred
twisted.python.failure

Felder

  • HoneytokenDataBase.filepath: Pfad zur Datei mit den validen Credentials
  • HoneytokenDataBase.temp_copy_path: Pfad zur Arbeitskopie der Datei bei self.filepath
  • HoneytokenDataBase.sep: Separator im Credentials-Format
  • HoneytokenDataBase.scopeField: Position des Scope-Strings im Credentials-Format
  • HoneytokenDataBase.usernameField: Position des Usernames im Credentials-Format
  • HoneytokenDataBase.passwordField: Position des Passworts im Credentials-Format
  • HoneytokenDataBase.publicKeyField: Position des PublicKeys im Credentials-Format
  • HoneytokenDataBase.allServices: Liste aller Service-Namen
  • HoneytokenDataBase.credentialInterfaces: Liste aller unterstützten Credential-Interfaces
  • HoneytokenDataBase.servicename: Name des Services, der diese Instanz der HDB verwendet
  • HoneytokenDataBase.randomAcceptProbability: Aus config.py, sonst standardmäßig 0.1

API

class HoneytokenDB.HoneytokenDataBase()

Implementiert twisted.cred.checkers.ICredentialsChecker. Überprüft Login-Credentials auf ihre Validität.

create_temporary_copy(path)

Erstellt eine Kopie der Datei path als temp-File.

Parameter:

-- path: Pfad zur zu kopierenden Datei (str)

Returns:

-- Pfad zur temporären Datei (str)


getActual(user, pw, isKey=False)

Gibt eine Liste der Services, für die user und pw valide Login-Credentials sind.

Parameter:

-- user: Username (str)

-- pw: Passwort (str)

-- isKey: True wenn pw ein SSH-Key ist (bool)

Returns:

-- Liste von Servicenamen (list)


load_credentials()

Lädt die Credentials aus der Datei mit validen Credentials (self.filepath). Ist diese in Benutzung, dann aus der Arbeitskopie(self.temp_copy_path).

Returns:

-- Liste aus Tupeln valider Credentials (list)


readLinesFromFile(file)

Hilfsfunktion für load_credentials(). Liest ein File-Objekt, das Credentials enthält, aus.

Parameter:

-- file: Auszulesendes File-Objekt(file)

Returns:

-- Liste aus Tupeln valider Credentials (list)


writeToDatabase(user, pw, services)

Schreibt die übergebenen Credentials in die Credentials-Datei(self.filepath).

Parameter:

-- user: Username der Credentials (str)

-- pw: Passwort der Credentials (str)

-- services: Services für die die Credentials valide sind. (str)


getUser(username)

Gibt Username, Passwort und Key für einen Usernamen zurück, wenn es Credentials mit Usernamen username gibt, die für self.servicename valide sind.

Parameter:

-- username: Username (str)

Returns:

-- u, p, k: Username, Passwort, Key ((str), (str), (str))


password_match(matched, username)

Wenn matched == True gibt die Funktion username zurück. Wird als Callback-Funktion von requestAvatarId() an ein twisted.internet.defer.Deferred übergeben.

Parameter:

-- matched: True wenn die vom Angreifer übergebenen Credentials valide waren. (bool)

-- username: Username (str)

Returns:

-- username: Username (str)


requestAvatarId(c)

Hauptmethode der HoneytokenDataBase. Diese Methode wird vom twisted.cred.portal.Portal aufgerufen sobald dieses Credentials von einem Angreifer erhalten hat. Die Methode überprüft die Credentials auf ihre Validität und liefert je nach Ergebnis der Überprüfung ein entsprechendes twisted.internet.defer.Deferred-Objekt.

Parameter:

-- c: Credentials (ICredentials)

Returns:

-- deferred: Deferred-Objekt mit Ergebnis des Cred-Checks (twisted.internet.defer.Deferred)

ServiceController.py

Dependencies

twisted.internet.reactor
threading

Felder

  • ServiceController.serviceList: Liste der instanziierten Subklassen von ServiceBaseModel
  • ServiceController.serviceDict: Dict, in dem der Name eines Services der Key und die jeweilige Instanz der Wert ist
  • ServiceController.listen: Instanz vom Listen Service für schnelleren Zugriff
  • ServiceController.runnigServicesDict: Dict, in dem Name des Services der Key und die die Instanz der Wert ist. Enthält nur die Services, die auch gestartet wurden.

API

class ServiceController.ServiceController() Sucht alle Unterklassen von ServiceBaseModel und erstellt jeweils eine Instanz. Erstellt aus der Liste von Instanzen ein Dictionary.

startService(name)

Startet den Service wenn möglich. Stoppt den ListenService automatisch auf den Port wo der neue Service starten will.

Parameter

-- name: Name des Services (str)

Returns:

-- True wenn der Service gestartet werden konnte. False wenn nicht. (boolean)

-- stopService(name)

Stoppt den Service wenn möglich. Startet den ListenService automatisch auf den Port wo der neue Service stoppt.

Parameter

-- name: Name des Services (str)

Returns:

-- True wenn der Service gestoppt werden konnte. False wenn nicht. (boolean)

logging

log.py

Dependencies

json
datetime

API

write(message)

Hilfsmethode zum Schreiben in die Logdatei.

Parameter:

-- message: Die zu schreibende Nachricht (str)


info(message)

Methode zum Loggen von administrativen und informativen Meldungen.

Parameter:

-- message: Die zu loggende Nachricht (str)


err(message)

Methode zum Loggen von Fehlermeldungen.

Parameter:

-- message: Die zu loggende Fehlermeldung (str)


*defer_login(result, args)

Wrapper um login als Callback für Deferred Nutzen zu können.

Parameter:

-- result: Ergebnis des vorherigen Callbacks

-- args: Argumente für login

Returns:

-- Reicht result einfach weiter


login(service, ip, port, successful, user, key=None, actual=None)

Methode zum Loggen von Login-Versuchen.

Parameter:

-- service: Name des Services, an dem der Versuch stattfand (str)

-- ip: IP des Angreifers (str)

-- port: Port, auf dem der Service läuft (str)

-- successful: Ob der Versuch Erfolgreich war (bool)

-- user: Username des Versuchs (str)

-- key: Passwort oder Key des Versuchs (str)

-- actual: Services, für welche der Login gültig gewesen wäre. Nützlich um die Verwendung eines Honeytoken an verschiedenen Services zu ermitteln. (list)


request(service, ip, port, request, user=None, request_type=None)

Methode zum Loggen von Anfragen.

Parameter:

-- service: Name des Services, an den die Anfrage gesendet wurde (str)

-- ip: IP des Angreifers (str)

-- port: Port, auf dem der Service läuft (str)

-- request: Inhalt der Anfrage (str)

-- user: Username (str)

-- request_type: HTTP GET oder POST (str)


response(service, ip, port, request, user=None, statusCode=None)

Methode zum Loggen von Antworten.

Parameter:

-- service: Name des Services, der die Antwort sendet (str)

-- ip: IP des Angreifers (str)

-- port: Port, auf dem der Service läuft (str)

-- response: Inhalt der Antwort (str)

-- user: Username (str)

-- statusCode: Der gesendete Statuscode (z.B. HTTP) (str)


file(service, ip, filename, filepath=None, user=None)

Methode zum Loggen von empfangenen Dateien. Sendet die Datei (falls gespeichert) zusätzlich zur Auswertung über BrokerEndpoint and das "files"-Topic.

Parameter:

-- service: Name des Services, an den die Datei gesendet wurde (str)

-- ip: IP des Angreifers (str)

-- filename: Name der empfangenen Datei (str)

-- filepath: Pfad zur empfangenen Datei, falls diese gespeichert wurde (str)

-- user: Username (str)


tcp_syn(ip, port)

Methode zum Loggen von einzelnen empfangenen SYN-Paketen (z.B. Portscan).

Parameter:

-- ip: IP des Angreifers (str)

-- port: Port, der das Paket empfangen hat (str)


heartbeat()

Methode zum Senden einer Heartbeat-Message über Broker.


services

ServiceBaseModel.py

Dependencies

abc.ABC
abc.AbstractMethod
twisted.internet.protocol.Factory

Felder

  • ServiceBaseModel._fService: Instanz von Factory
  • ServiceBaseModel._fService.clients: Leeres Python-Dict
  • ServiceBaseModel._port: None
  • ServiceBaseModel._stop: None
  • ServiceBaseModel._name: None
  • ServiceBaseModel._status: None
  • ServiceBaseModel._transport: None

API

class ServiceBaseModel.ServiceBaseModel

Prototyp aller Services. Wird von allen Services implementiert.

startService()

Abstrakte Methode. Wird von Subklassen implementiert.


stopService()

Abstrakte Methode. Wird von Subklassen implementiert.


changePort(port)

Ändert self.port zu port und startet den Service am neu gesetzten Port. Ist port bereits besetzt wird der Service nicht gestartet.

Parameter:

-- port: Ein Port oder eine List von Ports (int oder list)

SSHService.py

Dependencies

os
re
subprocess
time
datetime
os.path
random
urllib

cryptography.hazmat.backends
cryptography.hazmat.primitives
twisted.conch
twisted.conch.ssh
twisted.cred.portal
twisted.internet
twisted.python

Felder

  • SSHService._name: Name des Service (aus config.py)

  • SSHService._port: Port an dem der Service läuft bzw. nach dem Starten laufen soll (aus config.py)

  • SSHService._fService: Instanz von SSHFactory mit eigens gesetztem ssh-userauth Service

  • SSHProtocol.user: Instanz von SSHAvatar, die den angemeldeten User repräsentiert

  • SSHProtocol.userName: Username des angemeldeten Users

  • SSHProtocol.name: Name des Service (für Logging)

  • SSHProtocol.port: Port des Service (für Logging)

  • SSHProtocol._parser: Instanz von FilesystemParser

  • SSHProtocol.userIP: IP des angemeldeten Users

  • SSHProtocol.l: Referenz auf den Logger

  • SSHProtocol.current_dir: Das aktuelle Verzeichnis im echten System (für die ssh_real_shell Option)

API

class SSHService.SSHService()

Implementiert das ServiceBaseModel, managt also die Verfügbarkeit des SSHProtocol. Registriert eine SSHFactory beim Reactor.


class SSHService.SSHProtocol()

Erbt von twisted.conch.recvline.HistoricRecvLine und stellt damit ein Terminal dar. Ist verantwortlich für die Behandlung von Anfragen und die Generierung von Antworten.

connectionMade()

Initialisiert die Terminal-Session.


getCommandFunc(cmd)

Holt zu einem Empfangenen Befehl die passende "ssh_" Methode.

Parameter:

-- cmd: Der Empfangene Befehl (str)

Returns:

-- Die entsprechende Function (function)


get_help(cmd)

Holt aus den SSH-Ressourcen den Hilfetext zu einer Funktion.

Parameter:

-- cmd: Der Befehl, für den die Hilfe geholt werden soll (str)

Returns:

-- Den Hilfetext der Funktion (str)


handle_arguments(args)

Hilfsfunktion um Argumente der Form "pfad -optns" in den Pfad und eine Liste von Buchstaben zu zerlegen.

Parameter:

-- args: Pfad und Argumente (iterable)

Returns:

-- Tupel aus Pfad und Liste von Argumenten (str, list)


lineReceived(line)

Wird aufgerufen, wenn ein Befehl ankommt. Hier wird entschieden, ob der Befehl lokal oder "fake" ausgeführt wird.

Parameter:

-- line: Die Zeile, die bei uns ankommt (bytes)

Returns:

-- Pfad (str)

-- Argumente (list)


print(lines, log=None)

Schreibt eine Zeile oder eine Liste von Zeilen auf das Terminal und loggt dabei.

Parameter:

-- lines: Die zu schreibende(n) Zeile(n) (list), (str)

-- log: Wenn dieser Parameter übergeben wird, wird statt der eigentlich gesendeten Nachricht dieser Wert geloggt (str)


showPrompt()

Zeigt den Prompt im Terminal des Angreifers.


*ssh_cat(args)

Zeigt den Inhalt einer Datei im vorgetäuschten Dateisystem.

Parameter:

-- args: Argumente für cat (iterable)

Returns:

-- Antwort (Meldung oder Dateiinhalt) (str)


*ssh_cd(args)

Wechselt das Verzeichnis im vorgetäuschten Dateisystem.

Parameter:

-- args: Argumente für cd (iterable)

Returns:

-- Eventuell eine Meldung (str)


ssh_clear()

Leert das Terminal


*ssh_echo(args)

Gibt zurück was eingegeben wurde.

Parameter:

-- args: Argumente die zurückgegeben werden sollen (iterable)

Returns:

-- Alles was in args steht (str)


ssh_exit()

Stößt das beenden der Session an.


ssh_help(cmd='')

Gibt (wenn vorhanden) den Hilfetext für den Befehl, wenn kein Befehl angegeben wurde den allgemeinen Hilfetext.

Parameter:

-- cmd: Befehl für den die Hilfe gezeigt werden soll (str)

Returns:

-- Meldung, Hilfe zu cmd oder allgemeine Hilfe (str)

-- Wenn allgemeine Hilfe "Help text" um das Log zu entlasten (str)


*ssh_ll(args)

Alias (Wrapper) für ls -l.

Parameter:

-- args: Argumente für ls (iterable)

Returns:

-- Was von ls zurückgegeben wird (str)


*ssh_ls(args)

Gibt den Inhalt des aktuellen Verzeichnisses im vorgetäuschten Dateisystem aus.

Parameter:

-- args: Argumente für ls. Wenn "a" nicht dabei ist, werden Dateien und Ordner mit Präfix "." ignoriert. (iterable)

Returns:

-- Ordnerinhalt (list)

-- "ls Text" um log zu entlasten (str)


*ssh_mkdir(args)

Erstellt ein Verzeichnis im vorgetäuschten Dateisystem.

Parameter:

-- args: Argumente für mkdir (iterable)

Returns:

-- Eventuell Meldung von FilesystemParser (str)


*ssh_mv(args)

Verschiebt eine Datei im vorgetäuschten Dateisystem.

Parameter:

-- args: Argumente für mv, die ersten beiden werden als source und destination behandelt (iterable)

Returns:

-- Eventuell Meldung von FilesystemParser (str)


ssh_pwd()

Gibt den aktuellen Pfad im vorgetäuschten Dateisystem.

Returns:

-- Aktueller Pfad (str)


*ssh_rm(args)

Löscht etwas im vorgetäuschten Dateisystem. Wenn "r" und "f" als Argumente angegeben wurden und "/" der Pfad ist, wird die Verbindung beendet. Wenn ein Verzeichnis als Pfad angegeben wurde und "r" nicht in den Argumenten ist, wird eine Meldung ausgegeben.

Parameter:

-- args: Argumente für rm (iterable)

Returns:

-- Eventuell Meldung (str)


*ssh_touch(args)

Erstellt eine Datei im vorgetäuschten Dateisystem.

Parameter:

-- args: Argumente für touch, wird als Pfad behandelt (iterable)

Returns:

-- Eventuelle Meldung vom FilesystemParser (str)


*ssh_wget(args)

Lädt eine Datei herunter, versendet sie zur Analyse und speichert sie im Quarantäneverzeichnis. Die Datei wird außerdem im vorgetäuschten Dateisystem angezeigt.

Parameter:

-- args: Argumente für wget, wird als URL behandelt (iterable)


ssh_whoami()

Zeigt den Username des aktuellen Users an.

Returns:

-- Username (str)


class SSHService.SSHSession()

Erbt von twisted.conch.ssh.session.SSHSession und repräsentiert einen SSH Channel. Bestimmt, was als nächstes geschieht (Shell, Command Execution, ...)

execCommand(pp, cmd)

Wird aufgerufen, wenn ein Angreifer ohne Shell einen Befehl ausführen will. Loggt den Befehl und weist den Angreifer ab.

Parameter:

-- pp: das Transport Protocol (twisted.internet.protocol.ProcessProtocol) -- cmd: der gewünschte Befehl (bytes)


getPty(terminal, windowSize, attrs)

Wird aufgerufen, wenn der Angreifer ein Pseudo-Terminal fordert. Dies wird ignoriert.


openShell(transport)

Wird aufgerufen, wenn ein Angreifer eine Shell fordert. Verknüpft den transport mit einem SSHProtocol.

Parameter:

-- transport: der Transportchannel zum Angreifer (twisted.internet.protocol.ProcessProtocol)


*windowChanged(args)

Wird aufgerufen, wenn sich die Fenstergröße beim Angreifer ändert. Wird ignoriert, könnte aber für Formatierungszwecke genutzt werden.

Parameter:

-- args: die neue Fenstergröße (tuple)


class SSHService.SSHRealm()

Erbt von SSHService.SSHSession und ist das Twisted Realm für SSH, d.h. es ist für die Vergabe von Avataren zuständig.

*requestAvatar(avatarId, mind, interfaces)

Gibt einen SSHAvatar mit dem jeweiligen Username und Transport etc. Siehe Dokumentation von Twisted Cred.

Parameter:

-- avatarId: der Servcie, für den der Avatar gilt (bytes) -- mind: der Nutzername (bytes) -- *interfaces: Interfaces, die der Avatar implementieren soll

Returns:

-- Eines der Interfaces (zope.interface.interface) -- Exemplar eines SSHAvatar (SSHService.SSHAvatar) -- Funktion bei Logout (function)


class SSHService.SSHAvatar(username, service)

Erbt von twisted.conch.avatar.ConchUser und repräsentiert einen User für SSH. Siehe Dokumentation von Twisted Cred.

Parameter:

-- Username: Name des Users (bytes) -- service: Service, für den der User gilt (bytes)


class SSHService.groveUserauth()

Erbt von twisted.conch.ssh.userauth und ist damit ein Service für die SSHFactory, der Anmeldedaten überprüft. Nur notwendig, um Anmeldeversuche umfassend loggen zu können.

ssh_USERAUTH_REQUEST(packet)

Wird aufgerufen, wenn der Angreifer sich Authentifizieren möchte.

Parameter:

-- packet: das Empfangene Paket, welches den User, den gewünschten Service, die Authentifizierungsmethode und die Login-Daten beinhaltet (bytes)

Returns:

-- Ein Deferred, welcher entsprechende Callbacks für erfolgreiche oder abgelehnte Anmeldung gesetzt hat (twisted.internet.defer.Deferred)


HTTPService.py

Dependencies

time
builtins.print
datetime.datetime
wsgiref.handlers.format_date_time
twisted.conch.avatar
twisted.cred.error
twisted.internet.reactor
twisted.internet.defer.Deferred
twisted.internet.protocol.Protocol
twisted.python.failure
Felder
  • HTTPService.now: Hält die aktuelle Zeit
  • HTTPService.timeNow: Hält die aktuelle Zeit formatiert
  • HTTPService.responseHeadersOkStatus: Beinhaltet HTTP-Get response header
  • HTTPService.responseHeadersForbidden: Beinhaltet HTTP-Get response header
  • HTTPService.responseHeadersNotFound: Beinhaltet HTTP-Get response header
  • HTTPService.okStatus: Hält den HTTP-OK Status
  • HTTPService.forbiddenStatus: Hält den HTTP-Forbidden Status
  • HTTPService.notFoundStatus: Hält den HTTP-NotFoundStatus Status
  • HTTPService.htdb: Hält die HTTP Login Kombinationen
  • HTTPService.port: Hält den aktuellen Port
  • HTTPService.resourceLocation: Gibt den Pfad zu den HTML Dateien an
  • HTTPService.supportedSites: Gibt an welche HTML Seiten zu erreichen sind
  • protokoll.state: Gibt an in welchen Zustand sich das Protokoll befindet
  • protokoll.peerOfAttacker: Enthält Informationen über den Angreifer
  • protokoll.page: Gibt die aktuelle Seite an
  • protokoll.path: Gibt den aktuellen Pfad zu den Honeygrove Ressourcen an
  • protokoll.attackingSite: Hält Informationen zur login Seite
  • protokoll.loginSuccessfulSite: Hält Informationen zur dashboard Seite
  • protokoll.requestType: Gibt an Ob es sich um POST oder GET handelt
  • protokoll.supportedSites: Hält Informationen zu den erreichbaren Seiten an

API

Implementiert das ServiceBaseModel, managt also die Verfügbarkeit des protokoll.


class HTTPService.protokoll()

Erbt von twisted.internet.protocol.Protocol und implementiert ein eigenes, HTTP-ähnliches Protokoll. Empfängt Daten, interpretiert sie und antwortet.

connectionMade()

Wenn eine TCP Verbindung über den HTTP-Port erstellt wurde, wird die Aktuelle Verbindung zum Dict hinzugefügt.


dataReceived(data)

Wenn der Angreifer Daten sendet, werden diese Daten interpretiert. Durch die gesendeten Daten kann die Art der Anfrage des Angreifers ausgelesen werden. So kann z.B. zwischen GET und POST Anfragen unterschieden und darauf reagiert werden.

Parameter:

-- data: die empfangenen Daten (bytes)


connectionLost(reason)

Wenn die Verbindung unterbrochen/aufgegeben wird, wird hier der Grund ausgegeben

Parameter:

-- reason: Der grund des Verbindungsabbruches (str)


errorBack(f)

Bei einem Unauthorisierten Login-Versuch, wird die Error Message von der HoneytokenDB getraped und der Fehlerfall behandelt

Parameter:

-- f: failure zum trappen


class HTTPService.HTTPAvatar()

Erbt von twisted.conch.avatar.ConchUser und repräsentiert einen User für HTTP. Siehe Dokumentation von Twisted Cred.


checkPassword(password)

Überprüft ein Passwort mit der HoneytokenDB.

Parameter:

-- password: das eingegebene Passwort vom User

Returns:

-- True, wenn das Passwort richtig ist, ansonsten False


FTPService.py

Dependencies

random
datetime.datetime
twisted.protocols.ftp
twisted.cred.portal.Portal
Felder
  • FTPService._name: Name des FTP-Services (aus config.py)
  • FTPService._port: Port an dem der Service läuft bzw. nach dem Starten laufen soll.
  • FTPService._fService: Instanz von FTPFactory
  • FTPService.protocol: Instanz von FTPProtocol
  • FTPService.credchecker: Instanz von HoneytokenDB
  • FTPProtocol.overwritten_commands_whitelist: Liste aller vom Protokoll überschriebenen FTP-Funktionen
  • FTPProtocol.inherited_commands_whitelist: Liste aller FTP-Funktionen, die von twisted.protocols.ftp.FTP geerbt werden
  • FTPProtocol.inherited_responses: Dict unserer individuellen Antworten auf die geerbten FTP-Funktionen
  • FTPProtocol.'honeytokenDirectory: Dateipfad zum Ordner mit den Honeytoken-Dateien (aus config.py)
  • FTPProtocol.receivedDataDirectory: Pfad zum Ordner für erhaltene Dateien (aus config.py)
  • FTPProtocol.lastmodified: Zeit der Erstellung des Protokolls
  • FTPProtocol.user: Aktueller Name des Users
  • FTPProtocol._parser: Instanz von FileSystemParser
  • FTPProtocol.l: Instanz von log.py

API

class FTPService.FTPService()

Implementiert das ServiceBaseModel, kennt das FTPProtocol und übergibt es an eine twisted.protocols.ftp.FTPFactory. Registriert die Factory beim Reactor.


class FTPService.FTPProtocol()

Erbt von twisted.protocols.ftp.FTP. Reagiert auf eingehende FTP-Befehle entsprechend mit der Modifikation eines simulierten Dateisystems. Generiert erwartete (Standard-)Antworten.

ftp_PWD()

Gibt die aktuelle Position im simulierten Dateisystem zurück.

Returns:

-- Entsprechende FTP-Antwort (tuple)


ftp_CWD(path)

Navigiert im simulierten Dateisystem zum angegebenen Pfad.

Parameter:

-- path: Pfad zu dem navigiert wird (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_DELE(path)

Ist path ein valider Pfad im simulierten Dateisystem, wird die Datei oder der Ordner mit dem Pfad path im simulierten Dateisystem entfernt.

Parameter:

-- path: Pfad der zu löschenden Datei. (str)

Returns:

-- Entsprechende FTP-Antwort (str), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_LIST(path)

Ist path ein valider Pfad zu einem Ordner im simulierten Dateisystem werden die Namen aller im Ordner enthaltenen Dateien über self.DTPInstance versendet.

Parameter:

-- path: Pfad des zu listenden Ordners. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_MDTM(path)

Ist path ein valider Pfad zu einer Datei im simulierten Dateisystem wird self.lastmodified zurückgegeben.

Parameter:

-- path: Pfad der Datei zu der der letzte Modifikationszeitpunkt gefragt ist. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_MKD(name)

Befindet sich im simulierten Dateisystem noch kein Ordner mit Namen name wird dieser hinzugefügt.

Parameter:

-- name: Pfad eines zu erstellen Ordners. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_RMD(path)

Ist path ein valider Pfad zu einem Ordner im simulierten Dateisystem wird dieser Ordner entfernt.

Parameter:

-- path: Pfad eines zu erstellen Ordners. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_RNTO(toName)

Über die geerbte Methode ftp_RNFR(fromName) wurde vor Aufruf dieser Methode eine Datei oder ein Ordner gewählt, die oder der umbenannt werden soll. In dieser Methode wird die entsprechende Datei oder der entsprechende Ordner zu toName umbenannt, sofern toName noch nicht vergeben und die gewählte Datei bzw. der gewählte Ordner valide im simulierten Dateisystem ist.

Parameter:

-- toName: Neuer Name der Datei/ des Ordners. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn toName valide ist

oder

-- (twisted.internet.defer.fail), wenn toName invalide ist


ftp_SIZE(path)

Ist path ein valider Pfad im simulierten Dateisystem gibt die Funktion in der Antwort eine zufällige Zahl zwischen 20000 und 5000000 für Ordner bzw zwischen 100 und 30000 für Dateien zurück.

Parameter:

-- path: Pfad des Ordners oder der Datei dessen/deren Größe gefragt ist. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

oder

-- (twisted.internet.defer.fail), wenn der Pfad invalide ist


ftp_STOR(path)

Die Funktion empfängt über den DTP-Channel eine Datei und speichert diese in self.receivedDataDirectory. Ist path noch kein valider Pfad im simulierten Dateisystem, wird dort eine Datei hinzugefügt.

Parameter:

-- path: Name der Datei die hochgeladen werden soll. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

(*1)


ftp_RETR(path)

Ist path ein valider Pfad zu einer Datei im simulierten Dateisystem und liegt eine Datei des gleichen Namens in .honeytokenDirectory, wird die Datei aus .honeytokenDirectory über den DTP-Channel versandt.

Parameter:

-- path: Name der Datei die heruntergeladen werden soll. (str)

Returns:

-- Entsprechende FTP-Antwort (tuple), wenn der Pfad valide ist

(*1)


processCommands(cmd, params)

Die Funktion wird aufgerufen sobald ein Befehl durch den Angreifer eingeht. Sie analysiert den Befehl und ruft die entsprechenden Funktionen an ihrer Klasse auf.

Parameter:

-- cmd: Übergebener FTP-Befehl (str)

-- params: Übergebene Parameter zu dem Befehl (str)

Returns:

-- Entsprechende FTP-Antwort

(*1)


*(1) Bei den hiermit markierten Funktionen sind große Stücke aus den gleichnamige Methoden aus der Superklasse twisted.protocols.ftp.FTP übernommen. Da aber doch Einiges in unserem System signifikant anders laufen muss, konnten sie nicht geerbt werden und es mussten auf diese Art kleinere aber notwendige Teile überschreiben.

ListenService.py

Dependencies

twisted.internet
twisted.internet.error
twisted.internet.protocol

Felder

  • ListenService._name: Name des Service (aus config.py)
  • ListenService._port: Ports an denen der Service läuft bzw. laufen darf (aus config.py)
  • ListenService._fService: Instanz von Factory
  • ListenService._transport: Dict zum Erfassen der transports
  • ListenService._stop: Gibt an, ob der Service gestoppt ist
  • ListenService._active: Gibt an, ob der Service aktiv ist

API

class ListenService.Listen()

Implementiert das ServiceBaseModel, kann sein Protokoll aber anders als andere Services auf viele verschiedene Ports gleichzeitig legen.

startService()

Startet den Service auf allen konfigurierten Ports. Ignoriert Ports, auf denen nicht gestartet werden kann. Fügt die transports in _transport ein.


startOnPort(port)

Startet den Service auf einem bestimmten Port. Ignoriert, wenn auf diesem nicht gestartet werden kann. Fügt den transport in _transport ein.

Parameter:

-- port Der Port auf dem gestartet werden soll (int)


stopOnPort(port)

Stoppt den Service auf einem bestimmten Port. Löscht den transport aus _transport.

Parameter:

-- port Der Port auf dem nicht mehr gelauscht werden soll (int)


stopService()

Stoppt den Service auf allen laufenden Ports.


class ListenService.ListenProtocol()

Erbt von twisted.internet.protocol und ist damit ein Verbindungsprotokol auf relativ niedriger Ebene. Seine Einzige Aufgabe ist das Aufzeichnen von allen Daten, die es empfängt.

dataReceived(data)

Wird aufgerufen wenn Daten empfangen werden. Loggt die Daten und macht weiter nichts.

Parameter:

-- data: Die empfangenen Daten (bytes)


TCPFlagSniffer.py

Dependencies

struct
socket
threading
time

Felder

  • TCPDataStruct.sourceIP Die IP woher das Packet kommt
  • TCPDataStruct.destPort Der Port wohin das Packer soll
  • TCPDataStruct.inTime Der Zeitpunkt der Ankunft des Pakets
  • TCPFlagSniffer.synConnections Das Dict welches die TCPDataStruct Instanzen hält
  • TCPFlagSniffer.synCpnnectionLock Eine Semaphore, die den Zugang zum SynConnections Dict regelt
  • TCPFlagSniffer.startThread Der Thread welcher den Service startet
  • TCPFlagSniffer.synScannThread Der Thread der in regelmäßigen Abständen das synConnection Dict nach den Eingangszeiten der Pakete scannt
  • TCPFlagSniffer.rSock Der RAW Socket welcher alle TCP/IP PAkete an das System abfängt

API

####class TCPFlagSnifer.TCPFlagSniffer()

Implementiert ServiceBaseModel. Überwacht alle eingehenden TCP/IP Pakete.


startService()

Startet den startThread nach einem root check.


stopService()

Stoppt den Service.


startTCPSniffer()

Diese Funktion wird im startThread ausgeführt wird. Empfängt TCP/IP Pakete und ruft getTCPPacketInformation auf.


reInstanceThreads()

Reinstanziiert die Threads.


getTCPPacketInformation(packet)

Parst ein TCP/IP Packet und extrahiert Informationen

Parameter:

-- packet: Das TCP/IP Packet welches geparst werden soll

returns:

-- flags: Die Flags des TCP/IP Paketes -- destPort: Den Zielport der TCP/IP Paketes -- sourceIP: Die Absender IP-Adresse


scanOpenSynConnections()

Wird im synScannThread ausgeführt. Durchsucht das synConnections Dict nach eingegangen TCP/IP Paketen mit einem SYN Flag, die älter als standardmäßig 5 Sekunden sind.

Home

User Guides:

Documentation:

  • Honeygrove documentation
  • Incident-Monitoring documentation
  • Management-Console documentation

Legacy:

Clone this wiki locally