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.
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.
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: |
|---|
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 & 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"> </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 |
|---|
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.
Mutmaßungen
Natürlich habe ich einige so gefundene Paketnummern im Onlinesystem von DHL manuell überprüft und dabei festgestellt, dass auch diese Pakete alle zuerst im Paketzentrum 21 bearbeitet wurden. Den DHL-Kunden ist offenbar je ein bestimmter Block von Paketnummern zugeordnet, der sich in den letzten Stellen unterscheidet. Vermutlich verwendet der Kunde die Nummer von vorne, sobald er seinen Block aufgebraucht hat.
Der vordere Teil der Nummer könnte einer Kundennummer entsprechen. Daher habe ich anschließend die ersten Ziffern variiert. Und siehe da – DHL lieferte eine neue Fehlermeldung, wenn die Prüfsumme stimmte: »Zugriff auf diese Sendung verweigert.« Diese scheint mit der Session-ID zusammenzuhängen, denn die URL, mit der ich sie extrahiert habe, enthält einen Nutzernamen und das Passwort »PUBLIC«.
Von Kollegen ließ ich mir Paketnummern von deren Lieferungen geben und versuchte über meinen Zugang deren Trackingstatus zu erfahren. Das führte zu genau der gleichen Fehlermeldung, ein Indiz dafür, dass meine Vermutung stimmt. Seiten, die augenscheinlich zu einem anderen Versender gehören, filtert daher der zweite Grep-Aufruf in Listing 2 heraus (Zeile 12). Wer möchte, könnte die Paketnummern speichern und später unter einem anderen Zugang überprüfen. Immerhin stimmt die Prüfsumme schon. Da HTML-Quelltexte lesen eklig ist, stellt »lynx –dump« die Seiten anschließend noch menschenlesbar dar. Ein Adressenjäger würde stattdessen eine Funktion basteln, die alle Adressen extrahiert und in eine Datenbank schreibt.
Alles drin
Mein kurzes Shellskript kann offenbar alle Kunden meines USB-Gewächshaus-Versenders der letzten eineinhalb Jahre ermitteln. Wäre das nicht ein gefundenes Fressen für einen Konkurrenten? Oder für eine Werbefirma – zielgruppengerecht aufbereitet?
Mich wurmte dann der verweigerte Zugriff. Der Nutzername ist nach dem »ZT« numerisch, vielleicht auch in aufsteigender Reihenfolge vergeben? Das peinliche Passwort »PUBLIC« jedenfalls scheint eine Standardeinstellung zu sein. Und tatsächlich, ein paar manuelle Versuche zeigten: Es gibt andere Nutzer mit demselben Passwort. Das kleine Skript in Listing 3 probiert – für die Proof of Concept – nur ganz schlicht alle Zahlen zwischen 20 000 und 30 000 durch.
Seine Arbeitsergebnisse landen in »counter.tmp« (Zeile 9), dort stehen dann URLs, die zu einem gültigen Login führen. Diese Datei könnte als Eingabe für ein weiteres Skript dienen, das die zugehörige Session-ID extrahiert und mit ihr alle Paketnummern durchprobiert, die der Code in Listing 1 bereits als gültig ausweist. Mit etwas Kreativität lassen sich dann die Paketnummernblöcke der einzelnen Versender ermitteln und so relativ interessante Verhaltensdaten der Nutzer gewinnen – Daten, die Organisationen wie Payback oder Happydigits auf (legalem) Weg mit erheblich höherem Aufwand zu erheben versuchen.
|
Listing 3: Raten leicht |
|---|
01 #!/bin/bash 02 COUNT="20000" 03 rm counter.tmp 04 while [ $COUNT -lt 30000 ] 05 do 06 wget --no-check-certificate "https://nolb.dhl.de/nolb-easylog/directsst.do?v_benutzer=ZT$COUNT&v_passwort=PUBLIC" -O tmp.html 07 if [ `grep -c "Anmeldung fehlgeschlagen" tmp.html` -eq 0 ] 08 then 09 echo "https://nolb.dhl.de/nolb-easylog/directsst.do?v_benutzer=ZT$COUNT&v_passwort=PUBLIC" >> counter.tmp 10 fi 11 COUNT=`expr $COUNT + 1` 12 done 13 rm tmp.html |
Identifikationsnummer
Nach dieser hemdsärmeligen Recherche gaben mir der Logistiker des Linux-Magazins sowie Google den entscheidenden Tipp: Eine Webseite [2] dokumentiert den Aufbau des Code und beschreibt, wie sich die Prüfziffer berechnet. Demnach sind die ersten beiden Stellen ein Code für das “Abgangsfrachtpostzentrum” (was für ein Name), danach folgen ein bis fünf Stellen mit einer Kundennummer, der Rest ist die Einlieferungsnummer. Der Prüfalgorithmus für die letzte Stelle passt zu meinen Paketnummern.
Mit diesen Kenntnissen ist ein systematischer Angriff deutlich leichter und effizienter – das war aber gar nicht mein Ziel. Der Gipfel wäre nun noch, wenn die Benutzerkennung im Online-Trackingsystem algorithmisch mit der Kundennummer im Identcode zusammenhinge, aber als Benutzer-“Name” schlicht eine Nummer zu verwenden ist auch schon ausreichend fahrlässig.
Nichts gelernt
Aus Sicherheitssicht ist es ein Eigentor, vorhersagbare Nutzernamen zu vergeben. Besser wären zufällige, mindestens gleich lange Buchstabenkombinationen. Schlechter zu merken als eine Zahlenkombination sind sie auch nicht, das Argument der Nutzerfreundlichkeit zählt also nicht. Zudem ist es äußerst ungeschickt, für alle unterschiedlichen Accounts ein und dasselbe Passwort zu verwenden, auch wenn es mutmaßlich nur für den öffentlichen Zugang dient. Das öffnet Brute-Force-Angriffen wie dem hier beschrieben Tür und Tor. Besser wären zufällige aufgebaute Passwörter.
Auch sollte eine Session-ID nicht so lange gültig sein wie in der aktuellen Implementierung. Zwar verhindert eine nur einmal gültige Session-ID keinen Brute-Force-Angriff, aber sie treibt den Aufwand in die Höhe. Der Programmierer müsste sich immer wieder neue IDs besorgen und dafür Rechenzeit und Bandbreite investieren. Sinnvoll wäre es auch, Paketnummern nur einmal zu vergeben oder – wenn das nicht möglich ist – bei Doppelungen immer nur die jüngste Aktivität anzuzeigen.
Das Beispiel zeigt, wie einfache und vermeidbare Programmierfehler erhebliche Sicherheitslücken reißen. Wer jedoch die Methoden der Angreifer – in diesem Fall recht simple Brute-Force-Angriffe – kennt, der kann seine Anwendung auch so gestalten, dass diese Szenarien nicht funktionieren. Dabei ist die aktuelle Lücke kein Einzelfall: Bereits im Jahr 2003 kritisierte der Bundesbeauftragte für den Datenschutz ein Datenleck im Track & Trace [3], das DHL damals angeblich behoben hat. Auch die Packstationen (siehe Kasten “Paketverteiler”) sind übertrieben freigiebig. Höchste Zeit für DHL, aus alten Fehlern zu lernen und keine Daten zu verschenken. (fjl)
|
Paketverteiler |
|---|
|
Schon bei Einführung der Packstationen (Abbildung 3) sind mir einige Probleme mit deren Sicherheit aufgefallen. Auf meine E-Mail reagierte DHL mit allgemeinen Textbausteinen, das Problem lösten sie jedoch nicht: Beim Abholen eines Pakets an der Packstation findet keine Authentifizierung des Empfängers statt. Es genügt allein die grüne Abholkarte, die jeder aus einem fremden Briefkasten fischen kann. Besonderes Geschick ist nicht nötig, um die kleinen Karten zu klauen. Der Name des Empfängers muss lediglich zwei Zeichen lang sein, ob das “XX” oder der wirkliche Name ist, interessiert das System nicht. Auch reicht als Unterschrift ein Querstrich oder ein sonstiges Zeichen, das ein Paketdieb auf den Touchscreen kritzelt. Jeder, der Zugang zu einem fremden Briefkasten hat, kann also ohne Identifizierung Pakete abholen. Auf diese Weise könnten Kreditkartenbetrüger ihre Identität bei Warenbestellungen verschleiern. Zum Vergleich: Wenn ich ein Paket am Postschalter abholen will, muss ich meinen Ausweis vorlegen. Der Postmitarbeiter protokolliert die Ausweisnummer und meinen Namen. Ein erhebliches Sicherheitsplus. Technisch wäre es kein Problem, an der Packstation einen Ausweisleser anzubringen – etliche Airlines führen das bei ihren Selbst-Check-in-Terminals an Flughäfen vor. Bei meinen schlechten Erfahrungen mit der Datensicherheit bei der DHL bin ich aber beinahe schon froh, dass die Packstation nicht auch noch meine Ausweisnummer erfährt. |
|
Infos |
|---|
|
[1] DHL-Sendungsverfolgung: [http://www.dhl.de/dhl?xmlFile=40315] [2] Identcode: [http://www.pruefziffernberechnung.de/I/Identcode.shtml] [3] Bundesbeauftragter für Datenschutz und Informationsfreiheit, “Track & Trace: Wer verfolgt wen?”: [http://www.bfdi.bund.de/cln_007/nn_533554/DE/Themen/WirtschaftUndFinanzen/Post/Artikel/TrackUndTrace-WerVerfolgtWen.html] |
|
Der Autor |
|---|
|
Dr. Tobias Eggendorfer ist in München als freiberuflicher IT-Berater und Dozent tätig. An der Universität der Bundeswehr forscht er im Bereich IT-Sicherheit und gibt sein Wissen an Studenten der Fernuniversität in Hagen und der Munich Business School weiter. Als Geek freut er sich über jedes unsinnige Gadget. |






