Go to English page

ViaThinkSoft CodeLib

Dieser Artikel befindet sich in der Kategorie:
CodeLibHowTosSonstiges

Szenario: Eine Anwendung oder App baut eine verschlüsselte Verbindung zu einem Webserver auf. Aufgrund der Verschlüsselung können Sie nicht mittels herkömmlichen Tools wie z.B. Wireshark die Daten mitlesen. Diese Anleitung zeigt, wie Sie mittels eines Linux-Systems (z.B. einem Raspberry Pi) die verschlüsselten Daten aufzeichnen können.

Dies funktioniert jedoch NUR unter folgenden Bedingungen:

1. Die Zielanwendung muss im selben Netzwerk wie die Linux-Maschine laufen. Eine Überwachung über das Internet ist nicht möglich.

2. Die Zielanwendung muss über eine bestimmte Schwachstelle verfügen. Sie muss SSL-Zertifikate akzeptieren, die von einer nicht-vertrauenswürdigen Zertifizierungsstelle (CA) ausgestellt wurden, bzw. es muss eine Möglichkeit geben, eine Zertifikatswarnung zu ignorieren und mit dem Programmablauf fortzufahren, oder dem Zertifikat durch das Hinzufügen in den Stammzertifikatsspeicher explizit zu vertrauen.

3. Die Zielanwendung darf keine zusätzlichen Sicherheitsmaßnahmen wie z.B. Public Key Pinning oder feste IP-Adressen verwenden.

Diese Anleitung ist gerichtet an technisch versierte Personen, die z.B. eine Schadware oder ein auffälliges Programm analysieren möchten. Die Analyse von verschlüsselten Verbindungen ermöglicht es z.B. Sicherheitsforschern, das Verhalten von Schadware zu analysieren. Es ist auch sinnvoll, Programme, die ungewöhnlich häufig Verbindungen zum Internet aufbauen, zu analysieren, um zu prüfen, welche Daten gesendet werden und ob z.B. ein Verstoß gegen den Datenschutz vorliegt.

Achtung: Diese Anleitung darf nicht dazu verwendet werden, um Daten von fremden Personen ohne deren Erlaubnis auszuspähen, oder Dinge wie z.B. einen Kopierschutz auszuhebeln. Die Verwendung erfolgt auf eigene Gefahr; ViaThinkSoft haftet nicht für entstandene Schäden.


Schritt 1: Bestimmung der Ziel-Domain

Im ersten Schritt müssen Sie bestimmen, welche Domain Sie überwachen möchten.

Es gibt verschiedene Möglichkeiten, z.B. können Sie Wireshark verwenden, um die DNS-Anfragen auszulesen.

Eine andere Möglichkeit ist es, in Windows den DNS-Cache zu leeren (ipconfig /flushdns), danach die Zielanwendung zu starten, und gleich danach den DNS Cache abzufragen (ipconfig /displaydns).

In unserem Beispiel möchten wir die Domain www.example.com analysieren.


Schritt 2: Erstellen eines Sicherheits-Zertifikats

Auf der Linux-Maschine erstellen Sie ein Verzeichnis, z.B. /daten/example

Dort geben Sie ein:

openssl req -x509 -newkey rsa:4096 -keyout private.key -out cert.crt -days 365 -nodes -subj '/CN=www.example.com'


Schritt 3: Apache auf der Linux-Maschine einrichten

Erstellen Sie /etc/apache2/sites-available/001-example.conf mit folgendem Inhalt:

<VirtualHost *:443>
        SSLEngine on
        SSLCertificateFile "/daten/example/cert.crt"
        SSLCertificateKeyFile "/daten/example/private.key"
        SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
        ServerName www.example.com
        DocumentRoot /daten/example
</VirtualHost>

<VirtualHost *:80>
        ServerName www.example.com
        DocumentRoot /daten/example
</VirtualHost>


Erstellen Sie einen Symlink

/etc/apache2/sites-available/001-example.conf -&gt; /etc/apache2/sites-enabled/001-example.conf

Starten Sie Apache dann neu:

service apache2 restart


Schritt 4: Überwachungs-Script einrichten

Erstellen Sie das Script /daten/example/proxy.php mit folgendem Inhalt:

<?php

$site = 'https://'.$_SERVER['http_host'];
$remoteDomain = $_SERVER['http_host'];
$proxyDomain = $_SERVER['http_host'];

# ----------------------------------------------------------------

error_reporting(E_ALL);
ini_set('display_errors', 1);

$request = $_SERVER['request_uri'];

$ch = curl_init();

/* If there was a POST request, then forward that as well.*/
if ($_SERVER['request_method'] == 'POST')
{
        curl_setopt($ch, CURLOPT_POST, TRUE);

        $postvars = array();
        foreach ($_POST as $key => $val) {
                $postvars[] = urlencode($key).'='.urlencode($val);
        }
        $postvars = implode('&', $postvars);
        curl_setopt ($ch, CURLOPT_POSTFIELDS, $postvars);
}


//$url = 'http://whois.viathinksoft.de/req';
$url = $site . $request;

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_HEADER, TRUE);

$headers = getallheaders();

/* Translate some headers to make the remote party think we actually browsing that site. */
$extraHeaders = array();
if (isset($headers['referer'])) {
        $extraHeaders[] = 'Referer: '. str_replace($proxyDomain, $remoteDomain, $headers['referer']);
}
if (isset($headers['origin'])) {
        $extraHeaders[] = 'Origin: '. str_replace($proxyDomain, $remoteDomain, $headers['origin']);
}

/* Forward cookie as it came.  */
curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
if (isset($headers['cookie']))
{
        curl_setopt($ch, CURLOPT_COOKIE, $headers['cookie']);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
$response = curl_exec($ch);

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);

$headerArray = explode(PHP_EOL, $headers);

/* Process response headers. */
$xx = '';
foreach($headerArray as $header) {
        $colonPos = strpos($header, ':');
        if ($colonPos !== FALSE) {
                $headerName = substr($header, 0, $colonPos);

                /* Ignore content headers, let the webserver decide how to deal with the content. */
                if (trim($headerName) == 'Content-Encoding') continue;
                if (trim($headerName) == 'Content-Length') continue;
                if (trim($headerName) == 'Transfer-Encoding') continue;
                /* -- */
                /* Change cookie domain for the proxy */
                if (trim($headerName) == 'Set-Cookie') {
                        $header = str_replace('domain='.$remoteDomain, 'domain='.$proxyDomain, $header);
                }
                /* -- */
        }
        header($header, FALSE);
}

echo $body;

curl_close($ch);

// ----------------- Logging

if (substr($body,0,1) == '{') {
        $body = json_encode(json_decode($body), JSON_PRETTY_PRINT);
}

if (isBinary($body)) {
        $body = "(Binary data)";
}

$logcontent = $_SERVER['request_method']." ".$_SERVER['request_scheme'].'://'.$_SERVER['server_name'].':'.$_SERVER['server_port'].$_SERVER['request_uri']."\n";
$logcontent .= "\n";
$logcontent .= "REQUEST HEADERS:\n".print_r(getRequestHeaders(),true);
if ($_SERVER['request_method'] == 'GET') $logcontent .= "GET FIELDS:\n" . print_r($_GET,true);
if ($_SERVER['request_method'] == 'POST') $logcontent .= "POST FIELDS:\n" . print_r($_POST,true);
$logcontent .= "\n";
$logcontent .= "RESPONSE HEADERS:\n".print_r($headerArray,true);
$logcontent .= "RESPONSE BODY:\n$body\n";
$logcontent .= "\n\n\n---------\n\n";

$logcontent = str_replace("\n", "\r\n", $logcontent);
file_put_contents("log.txt", $logcontent, FILE_APPEND);

// ----------------- Functions

function isBinary($str) {
        return preg_match('~[^\x20-\x7e\t\r\n]~', $str) > 0;
}

function getRequestHeaders() {
        // https://stackoverflow.com/questions/541430/how-do-i-read-any-request-header-in-php
    $headers = array();
    foreach($_SERVER as $key => $value) {
        if (substr($key, 0, 5) <> 'HTTP_') {
            continue;
        }
        $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
        $headers[$header] = $value;
    }
    return $headers;
}


Erstellen Sie /daten/example/.htaccess mit folgendem Inhalt:

RewriteEngine on
RewriteRule ^(.*)$ proxy.php [qsa,l]


Stellen Sie sicher, dass mod_rewrite aktiviert ist:

a2enmod rewrite

Erstellen Sie /daten/example/log.txt mit allen Berechtigungen:

touch /daten/example/log.txt

chmod 777 /daten/example/log.txt



Schritt 5: DNS-Eintrag umlenken

Auf dem Windows PC öffnen Sie die Eingabeaufforderung mit Administrator-Rechten. Dort eingeben:

notepad.exe drivers\etc\hosts

In dieser Datei fügen Sie folgende Zeile hinzu:

1.2.3.4    www.example.com

wobei Sie 1.2.3.4 mit der IP-Adresse Ihres Linux-Systems austauschen.

Alternativ können Sie den DNS-Eintrag auch für andere Geräte im Netzwerk umleiten, wenn Sie einen eigenen DNS-Server (z.B. mittels pihole/dnsmasq) besitzen. In diesem Falle können Sie dann auch Verbindungen von Apps aus Mobilgeräten im Netzwerk überwachen.

Starten Sie nun die Anwendung. Es sollte nun auf der Linux-Maschine die Datei log.txt mit den übertragenen Daten gefüllt werden. Die Anwendung müsste normal funktionieren, da die Daten durch das Proxy-Script ganz normal weitergericht werden ("Man in the middle").


Schritt 6: Hinzufügen des Zertifikats in den Stammzertifikatsspeicher

Sollte die Anwendung nicht funktionieren, kann es daran liegen, dass diese prüft, ob das Zertifikat von einer vertrauenswürdigen Stelle signiert wurde.

Sofern die Anwendung kein Public Key Pinning verwendet, können Sie versuchen, das selbst ausgestellte Zertifikat in dem Stammzertifikats-Speicher Ihres Betriebssystems oder Browsers hinzuzfügen.

Achtung: Dieses Vorgehen ist riskant. Da diese Anleitung keine besonderen Maßnahmen zur Sicherung des privaten Schlüssels (private.key) beschreibt, besteht die Gefahr, dass dieser private Schlüssel dazu verwendet wird, SIE auszuspionieren oder Verbindungen Ihres Computers zu kompomittieren. Sie sollten daher nachdem Sie Ihre Analyse abgeschlossen haben, das Zertifikat wieder aus Ihrem Stammzertifikatsspeicher entfernen.

Unter Windows fügen Sie das Zertifikat wie folgt hinzu:
- Öffnen Sie inetcpl.cpl
- Gehen Sie auf den Reiter Inhalte und dann auf Zertifikate.
- Klicken Sie auf "Importieren", dann auf Weiter.
- Wählen Sie die Datei cert.crt aus und klicken Sie auf Weiter.
- Wählen Sie den Speicher "Vertrauenswürdige Stammzertifizierungsstellen". Klicken Sie dann auf Weiter und Fertig stellen.
Daniel Marschall
ViaThinkSoft Mitbegründer