RealVNC vs. TightVNC - Wer hat bei wem abgeschrieben?

17.12.2010 yahe

Wisst ihr noch? Vor ein paar Tagen habe ich euch erklärt, dass man die Passworte von TightVNC ermitteln kann, wenn man Zugriff auf die Registry hat. Kurz darauf hatte ich euch gezeigt, wie ein entsprechendes Programm hierfür aussehen könnte.

Da ich hier Zuhause RealVNC einsetze, war das natürlich kein Problem. Trotzdem interessierte mich, wie das Problem wohl bei dieser Software gelöst ist. Da es sich jedoch um kommerzielle Software handelt, dachte ich nicht, dass ich darauf eine Antwort kriegen würde - bis ich letztens mal wieder den RealVNC-Viewer herunterladen musste. Da fiehl mir auf, dass ich vor dem Herunterladen der GPL-Lizenz zustimmen musste. Also dachte ich mir: "Hey! Dann müsste ich ja auch den Quelltext bekommen können!" Und tatsächlich steht dieser zum freien Download bereit.

Nach wenigen Sekunden versank ich auch schon im Quelltext. Interesse weckte zuerst die Datei "win\vncconfig\PasswordDialog.cxx", die mich zur "common\rfb\Password.cxx" weiterführte. An dieser Stelle war meine Suche bereits beendet. Und Ernüchterung machte sich breit. Nicht nur, dass RealVNC das Passwort ebenfalls DES-verschlüsselt in der Registry ablegt (im Wert "HKLM\SOFTWARE\RealVNC\WinVNC4\Password"). Nein! Für die DES-Verschlüsselung wird auch noch exakt derselbe Schlüssel wie bei TightVNC verwendet! Das letztens vorgestellte Programm funktioniert also auch für RealVNC!

Achja! Und an alle Nutzer von UltraVNC: Auch eure Software nutzt denselben Schlüssel. In der entsprechenden Datei ("rfb\vncauth.c") findet sich sogar noch der originale Copyright-Kommentar von RealVNC!

Cheers, Yahe


TightVNC-Passwörter entschlüsseln...

11.12.2010 yahe

Letztens hatte ich euch erklärt, dass es möglich ist, die Passwörter zu entschlüsseln, die das Tool TightVNC in der Registry ablegt. Heute möchte ich euch gerne anhand eines Quelltextes zeigen, wie das gemacht werden kann. Den Ansporn dazu hat mir Hannes Schurig mit seinem neuen Artikel zu TightVNC gegeben. Darin beschreibt er, wie man TightVNC für die Fernwartung mehrerer Rechner nutzen kann - inklusive automatisierter Konfiguration und allem drum und dran.

Leider ist mir bei der ganzen Sache aufgefallen, dass das Problem der Passwortwiederherstellung viel zu stiefmütterlich behandelt wurde. Ja, es wurde gesagt, dass die Wiederherstellung möglich ist. Allerdings wurde auch darauf verwiesen, dass dies nur mit viel Können und Forscherdrang möglich sei. Um diese Aussage zu widerlegen, habe ich nun kurzerhand das Tool "tvncpass" geschrieben, mit dem man die Passwörter verschlüsseln und auch wieder entschlüsseln kann.

#include <stdio.h>
#include <string.h>

#include "VncPassCrypt.h"

const char* HEX_CHARS = "0123456789ABCDEF";

#define APP_NAME     "tvncpass"
#define DECODE_PARAM "--decode"
#define ENCODE_PARAM "--encode"

void hexToDecimal(char* hexText, UINT8* decimalText, int decimalLength) {
    int index;

    if (decimalLength > 0) {
        // reset output
        memset(decimalText, 0, decimalLength);

        if ((strlen(hexText) <= decimalLength * 2) && ((strlen(hexText) % 2) == 0)) {
            // only proceed if string length is small enough
            for (index = 0; index < strlen(hexText); index += 2) {
                decimalText[index/2] = ((strchr(HEX_CHARS, hexText[index]) - HEX_CHARS) * strlen(HEX_CHARS)) + (strchr(HEX_CHARS, hexText[index+1]) - HEX_CHARS);
            }
        }
    }
}

void printHelp() {
    printf("Usage: %s (%s|%s) PASSWORD\n", APP_NAME, DECODE_PARAM, ENCODE_PARAM);
    printf("\n");
    printf("The password has to be provided in hexadecimal form.\n");
    printf("In addition to that the password must not be longer\n");
    printf("than 8 bytes and the hexadecimal representation must\n");
    printf("be in all uppercase.\n");
}

void printHex(UINT8* decimalText, int decimalLength) {
    for (int index = 0; index < decimalLength; index++) {
        if (decimalText[index] < strlen(HEX_CHARS)) {
            printf("0%X", decimalText[index]);
        } else {
            printf("%X", decimalText[index]);
        }
    }
    printf("\n");
}

int main(int argc, char** argv) {
    // define variables
    int   index;
    UINT8 input[8];
    bool  isEncode;
    UINT8 output[8];
    char* password;

    if (argc == 3) {
        isEncode = (strcmp(argv[1], ENCODE_PARAM) == 0);
        if (!isEncode) {
            if (strcmp(argv[1], DECODE_PARAM) != 0) {
                // exit if first param does not match
                printHelp();
                return 1;
            }
        }

        // this is our password
        password = argv[2];
        if ((strlen(password) <= 16) && ((strlen(password) % 2) == 0)) {
            // read password as decimal
            hexToDecimal(password, input, sizeof(input)/sizeof(UINT8));

            // encrypt or decrypt
            if (isEncode) {
                VncPassCrypt::getEncryptedPass(output, input);
            } else {
                VncPassCrypt::getPlainPass(output, input);
            }

            // print result as hex
            printHex(output, sizeof(output)/sizeof(UINT8));
        } else {
            // the password must not be longer than 8 bytes
            printHelp();
            return 1;
        }
    } else {
        // exit if wrong number of params
        printHelp();
        return 1;
    }

    return 0;
}

Da der Quelltext ziemlich quick-and-dirty geschrieben wurde, gibt es dieses Mal keine kompilierte Version des ganzen. Wenn ihr das Tool also selbst kompiliert haben solltet, könnt ihr es wie folgt aufrufen.

tvncpass (--decode|--encode) PASSWORD

Wenn ihr den "--decode" Modus nutzt, könnt ihr das Passwort entschlüsseln, wenn ihr den "--encode" Modus nutzt, könnt ihr es verschlüsseln. Das Passwort selbst muss dabei in Hexadezimalform und in Großbuchstaben übergeben werden - und es darf nicht länger als 16 Hexadezimal-Zeichen lang sein. Um also z.B. das Passwort "test" zu verschlüsseln, muss es als "74657374" an das Programm übergeben werden.

tvncpass --encode 74657374

Um daraus nun wieder das ursprüngliche Passwort zu erhalten, müsst ihr das Ergebnis der ersten Operation an das Programm übergeben.

tvncpass --decode 2F981DC548E09EC2

Cheers, Yahe


Passwörter von TightVNC ermitteln...

24.11.2010 yahe

Nachdem ich letztens nachgewiesen habe, wie unsicher eines der Lieblingstools von Hannes Schurig ist, hat dieser mich gestern angeschrieben und gefragt, ob ich mir nicht mal das OpenSource-Tool TightVNC angucken könnte.

Wie er mitbekommen hatte, speichert der TightVNC-Server in der Registry unter "HKCU\Software\TightVNC\Server" zwei Werte mit den Namen "Password" und "PasswordViewOnly". Seine Frage war nun, ob es möglich wäre, aus den kryptischen Werten die ursprünglichen Passworte für den "Remote Control"- und den "Remote View Only"-Zugang wiederherzustellen.

Da man von diesem Programm die Quelltexte erhält, habe ich mir diesen natürlich zuerst angeguckt und auch relativ schnell eine Antwort auf die Frage gefunden: Ja, man kann die ursprünglichen Passworte anhand der Werte in der Registry ermitteln!

Um das herauszufinden, habe ich am Quellcode entlang gehangelt. Begonnen habe ich in der Datei "ServerConfig.cpp". In dieser wird die Klasse ServerConfig definiert, die später anscheinend die gesamte Konfiguration vorhält. In dieser Klasse gibt es u.a. auch die beiden Methoden "setControlPassword()" und "setReadOnlyPassword()", die einen Rückschluss auf die verschiedenen Zugänge zulassen. Um zu sehen, was weiter geschieht, habe ich nachgesehen, wo die Methode setControlPassword() überall aufgerufen wird. Das wiederum ist u.a. in der Datei "ControlApplication.cpp" der Fall, in der sich die Methode "run()" befindet. In der Methode werden anscheinend Kommandozeilenparameter verarbeitet und wie es aussieht, kann man die Passwörter über die Kommandozeile setzen. Auffallend ist die Verwendung der Methode "getCryptedPassword()". Sie befindet sich in der gleichen Datei und enthält u.a. einen Aufruf der Form "VncPassCrypt::getEncryptedPass()". Diese Methode (die sich in der Datei "VncPassCrypt.cpp" befindet) enthält nun die eigentlich interessante Passage:

void VncPassCrypt::getEncryptedPass(UINT8 encryptedPass[8],
                                    const UINT8 plainPassword[8])
{
  DesCrypt desCrypt;
  desCrypt.encrypt(encryptedPass, plainPassword,
                   sizeof(encryptedPass), m_key);
}

Das Passwort, das oben eingekippt wird, wird unten DES-verschlüsselt wieder ausgegeben. Eine Entschlüsselungsmethode wird übrigens gleich mitgeliefert und selbst das Passwort liegt fest einprogrammiert im Quelltext vor:

const UINT8 VncPassCrypt::m_key[] = { 23, 82, 107, 6, 35, 78, 88, 7 };

Man sollte sich also dringend überlegen, wie man die Passwörter in der Registry absichert, wenn man vorhat, TightVNC zum Beispiel zur Fernwartung von Mitarbeiter-PCs zu nutzen. Die Leute könnten schneller an das Passwort kommen, als einem lieb sein dürfte.

Cheers, Yahe


Remotedesktopverbindung: Eine geht noch...

17.11.2010 yahe

Häufig muss ich es erleben, dass ich mich via RDP zur Administration auf einen Windows-Server verbinden muss, nur um dann die Meldung an den Kopf geworfen zu kriegen, dass "Die maximale Anzahl der Verbindungen [...] erreicht" ist. Eine Verbindung ist also nicht möglich, solange sich nicht mindestens ein Kollege von dem Server abmeldet.

Das denkt man zumindest! Denn das Standard-Tool mstsc (auch bekannt als "Remotedesktopverbindung") kennt einen Kommandozeilenparameter, mit dem man sich direkt mit der physikalischen Session des Servers verbinden kann. Mit folgendem Aufruf schafft man es meistens noch, eine Session zu ergattern, um seine Arbeiten zu erledigen:

mstsc /admin

Anschließend kann man dann mit qwinsta und rwinsta einen Kollegen aus seiner RDP-Session kicken und sich so eine eigene Session ergattern. (Achtung: Das ist natürlich nur ein Scherz!)

Cheers, Yahe


Aktuelle Sicherheit von Flattr

25.10.2010 yahe

Nachdem ich vor einiger Zeit einmal eine Schwachstelle bei Flattr aufgedeckt hatte, hat mich heute einmal interessiert, wie die Flattr-Links nun inzwischen abgesichert sind. Nach ein bisschen Graben habe ich nun die Antwort gefunden.

Erst einmal noch grundsätzlich dazu, wie Flattr überhaupt funktioniert: Damit ein "Thing" geflattred werden kann, muss man eingeloggt sein, Geld auf sein Flattr-Konto eingezahlt haben und einen Flattr-Button drücken. Dieser Flattr-Button ist grob gesehen nichts anderes als ein Link mit einer eindeutigen ID. Früher war es so, dass man einen eingeloggten Nutzer nur dazu bringen musste, diese URL mit dieser eindeutigen ID aufzurufen, um einen Flattr-Button-Click zu simulieren.

Inzwischen sieht das ganze ein wenig anders aus. Inzwischen ist es so, dass beim Login ein Wert mit dem Namen "f_rt" im Cookie von Flattr.com hinterlegt wird. Beim Aufruf einer Flattr-URL wird dieser Wert im Header-Eintrag "X_REQUEST_TOKEN" mitgegeben. Daneben werden zusätzlich noch die Header-Einträge "X_REQUESTED_WITH" (muss anscheinend "XMLHttpRequest" sein) und "Referer" (muss anscheinend mit "api.flattr.com" beginnen) abgeprüft. Dass die beiden statischen Werte abgeprüft werden, halte ich für ziemlich unnötig, da diese problemlos gefälscht werden können.

Die Idee mit dem Cookie und dem daraus abgeleiteten HTTP-Header-Eintrag finde ich ziemlich intelligent gelöst. Einfaches Klicken auf eine Flattr-Button-URL ist dadurch nicht mehr möglich und selbst trickreichere Angriffe laufen dadurch ins Leere, da es für fremde Seiten nicht möglich ist (zumindest laut Definition), die Cookie-Informationen einer fremden Seite auszulesen.

Nun kommt jedoch ein aber, das ich besonders betonen möchte: Die Cookies von Flattr haben ein massives Problem! Diese sind für ALLE SUBDOMAINS von Flattr.com gültig. Das bedeutet, dass sollte es an irgendeiner Stelle möglich sein, der Flattr-Plattform Schadcode unterzuschieben (JavaScript im Profil, JavaScript in einer Thing-Beschreibung, o.Ä.), dies genutzt werden kann, um die derzeitige Sicherheit von Flattr auszuhebeln. Schlimmer noch: Genau dieses Problem scheint im Flattr-Forum schon einmal ausgenutzt worden zu sein. Die Konsequenz, die draus gezogen wurde, ist, dass das Forum inzwischen unter "forum.flattr.net" statt unter "forum.flattr.com" erreichbar ist.

Neben der Sicherung der Flattr-Vorganges selber, wurde übrigens auch die Nachsorge verbessert! So findet man in seinem Dashboard unter "Things I have flattred" zu jedem Thing in der Liste einen "Report this click"-Link, den man nutzen kann, um Flatterings zu melden, die man selbst nicht vorgenommen hat. Dafür muss man jedoch natürlich regelmäßig dort in die Liste gucken.

Cheers, Yahe