- Mitglied seit
- 10 Mai 2006
- Beiträge
- 15,278
- Punkte für Reaktionen
- 1,753
- Punkte
- 113
Immer wieder stehen FRITZ!Box-Besitzer aus den verschiedensten Gründen vor dem Problem, aus ihrem Gerät irgendwelche Daten extrahieren zu müssen, die von AVM dort (vorbildlicherweise, wenn es um das "ob" geht, zum "wie" und ein paar Nachlässigkeiten dabei kommen wir gleich) nur in verschlüsselter Form gespeichert werden und auch beim Export der Einstellungen sind diese Daten normalerweise verschlüsselt.
Es gibt aber durchaus gute und legitime Gründe für das Ansinnen, auch auf solche Daten Zugriff zu erhalten. Eine kleine Liste von Beispielen (ohne jeden Anspruch auf Vollständigkeit) wäre z.B. die folgende:
Einem "bad guy" (unter "bad girl" versteht sicherlich jeder etwas anderes) hat man damit also nur ein paar Kiesel in den Weg gelegt ... aber der "Gelegenheitsnutzer" aus den o.a. Beispielen steht dabei (in aller Regel, solange er das nicht ständig machen muß) vor entsprechenden Problemen. Das ist in meinen Augen aber der Falsche, der hier von Sanktionen betroffen ist ... daher halte ich es für geboten, diesem legitimen Benutzer auch die passenden Werkzeuge in die Hand zu geben. Das habe ich lange und reiflich überlegt - ein entscheidender Punkt war auch der Wegfall des Routerzwangs und damit entfällt für mich zu einem großen Teil auch das "Schutzbedürfnis", das man früher für Einstellungen vom Provider in den FRITZ!Boxen noch unterstellen und geltenlassen konnte, die dem Provider gehören. Seitdem die Kunden aber die Zugangsdaten ohnehin vom Provider erhalten müssen, entfällt auch dieser Punkt der "contra"-Liste.
Das führt dann im Ergebnis zu der Einstellung, daß diese "security by obscurity" eigentlich nur einem wirklich schadet: dem berechtigten Benutzer. Alle anderen finden auch ohne mich und die folgenden Informationen immer wieder einen Weg, an diese Daten zu gelangen. AVM hilft also mit dieser Geheimniskrämerei eher den Bösen und ich sehe nicht einen einzigen Punkt, wo eine Beschreibung meinerseits die Sicherheit eines FRITZ!Box-Besitzers tatsächlich aushöhlen würde - ganz im Gegenteil ... wie im Beispiel oben angeführt, kann es dem Besitzer sogar helfen, über Merkwürdigkeiten in den Einstellungen auf einen Angriff zu schließen.
Das war's dann jetzt auch mit der Präambel und nun geht es "in medias res".
-Schaut man sich die verschlüsselten Daten in irgendeiner AVM-Datei einmal an, stellt man ja schnell fest, daß diese immer mit vier Dollarzeichen beginnen und danach dann nur die Großbuchstaben A bis Z und Ziffern 1 bis 6 folgen. AVM muß also irgendwie die verschlüsselten Daten aus der binären Form (das Ergebnis der eigentlichen Verschlüsselung sind alle denkbaren Werte von 0 bis 255 in mehreren Bytes - das ist dann die "binäre Form", so wie die Daten im Speicher liegen) in eine andere transformieren, die mit insgesamt 32 Zeichen (26 Buchstaben, 6 Ziffern) auskommt.
Das kennt aber praktisch jeder aus der Mathematik und der Schule ... es ist am Ende nichts anderes als eine andere Zahlenbasis, die da zum Einsatz kommt. Da, wo das Binärsystem mit den Zeichen 0 und 1 auskommt, braucht das Oktalsystem dann schon acht (0 bis 7), das Dezimalsystem zehn (0 bis 9) und auch vom Hexadezimalsystem (mit 0 bis 9 und den Buchstaben A bis F für die Werte 10 bis 15) sollte man schon mal etwas gehört haben (wenn nicht, wäre hier der richtige Zeitpunkt, sich das z.B. in der Wikipedia anzusehen).
AVM verwendet hier also 32 verschiedene "Ziffern" und damit ist das offenbar ein Zahlensystem mit der Basis 32 ... daher nennt man diese Kodierung dann auch folgerichtig: Base32. Die gibt es auch an anderen Stellen (die Base64-Kodierung zur Darstellung beliebiger Inhalte nur mit ASCII-Zeichen ist aber bekannter), aber AVM verwendet hier wohl ein eigenes "Alphabet", denn die meisten anderen arbeiten mit 0 bis 5 für die zusätzlich benötigten 6 Werte. Warum AVM hier überhaupt auf Base32 zurückgreift, kann man auch nur vermuten ... die zusätzlichen 32 "Zeichen" für Base64 sind sicherlich nicht das Problem; notfalls ersetzt man die zwei Sonderzeichen im Zeichenvorrat (das sind das Plus und der Schrägstrich) durch andere, wenn man diese Zeichen für eigene Zwecke braucht.
Also rate ich mal hinsichtlich der Beweggründe und tippe auf: Verschleierung (für Laien) - auf Kosten zusätzlicher "Längen" bei der Kodierung, denn im Gegensatz zum Base64 (mit einem Verhältnis von 4 Zeichen für 3 Byte Binärdaten) braucht Base32 da mehr und bietet ungünstigere Bedingungen (8 Zeichen für 5 Byte Binärdaten) "aus Computersicht" bei den binären Daten (es müssen Vielfache von 5 sein bei der Länge der zu kodierenden Daten).
Kommen wir darauf zurück, wie das "AVM-Alphabet" wohl genutzt wird ... irgendwo in der Firmware gibt es bestimmt passende Zeichenketten. Das naheliegendste ist zunächst mal der Blick in die "libar7cfg.so", diese ist für die Be- und Verarbeitung der "Hauptdatei" (ar7.cfg) zuständig:
Da ist also unser Zeichenvorrat und wie man sehen kann, steht die "1" dann für den Wert 26 und die "6" für 31 - das "A" ist dann die Null in diesem "Zahlensystem".
Mit dieser Erkenntnis ausgerüstet, ist es jetzt recht simpel, aus der Base32-Form die binäre Darstellung zu gewinnen. Das habe ich im Laufe der Jahre in mehreren Formen realisiert ... von Python über Shell bis C.
Aber mit diesen Daten kann man jetzt auch noch nicht so richtig viel anfangen ... was wir zunächst einmal brauchen, ist ein bekannter Klartext und das dazugehörige Chiffrat. Das ist schnell erledigt ... auf einer 7412 habe ich mir einen Benutzer "PeterPawn" mit dem Kennwort "PeterPawn" angelegt und das Ergebnis war dann das Folgende:
Hier sehen wir also schon mal zwei verschiedene Kodierungen, die eigentlich für denselben Wert stehen sollen ... offensichtlich gibt es neben dem Klartext und einem (bisher unbekannten) Schlüssel auch noch einen weiteren zufälligen Wert, der in das Chiffrat eingeht und damit dafür sorgt, daß sich jedesmal eine andere Darstellung ergibt. Egal, ob es sich dabei nun um das "Salz in der Suppe" (salt) handelt oder um einen "initialization vector" (IV) für eine Block-Chiffre, dieser zufällige Wert muß natürlich zusammen mit dem Chiffrat gespeichert werden, damit bei einer Entschlüsselung genau wieder dieser Wert verwendet werden kann.
Was wir auch schon aus der Erfahrung wissen (entsprechende Berichte gibt es seit Jahren) ... es gibt bei der Verschlüsselung für die interne Speicherung auch noch eine gerätespezifische Komponente, denn eine Datei von der einen FRITZ!Box läßt sich nicht ohne weiteres auf einer anderen FRITZ!Box entschlüsseln - das ging schon zu Zeiten von "allcfgconv -c" nicht. Wenn man sich ein wenig mit dem Aufbau einer FRITZ!Box befaßt, kommt man auch schnell dahinter, daß diese "Geräteeigenschaften" für die Verschlüsselung eigentlich nur im sogenannten "Urlader-Environment" gespeichert sein können ... das sind ein paar Eckdaten einer Box (inkl. variabler Daten, die auch bei zwei Geräten desselben Modells bei der Finalisierung der Boxen ab Werk unterschiedlich sind) und - da die Firmware an sich für alle Geräte eines Modells dieselbe ist - praktisch die einzige (maschinenlesbare) Stelle, wo das FRITZ!OS auf (dauerhaft existierende, denn diese Daten werden weder bei Recovery noch bei Werkseinstellungen gelöscht) Daten eines Gerätes zugreifen kann.
Wenn es also variable Größen gibt, dann können die praktisch nur dort drin stehen und wenn man dann etwas mit den Werten im Environment und einem (bekanntermaßen funktionierenden) Programm zum Dekodieren von verschlüsselten Daten experimentiert, stellt man recht schnell auch fest, daß diese variablen Daten offenbar aus dem Wert bei "maca" und "wlan_key" bestehen, die in praktisch jeder FRITZ!Box vorhanden sind. Zusätzlich kommt noch ein weiterer Wert hinzu, der aber nicht bei allen Boxen vorhanden ist und deshalb auf den ersten Blick nicht auffällt ... das ist "tr069_passphrase", was nur bei den Boxen mit konfiguriertem CWMP-Account (also einer TR-069-"Identität") vorhanden ist.
Es geht auch noch ein vierter Wert in diese gerätespezifischen Daten ein ... aber auch der fiel bisher eher nicht auf, weil es praktisch nur Geräte gab, in denen er immer denselben Wert hatte. Es handelt sich hierbei um "SerialNumber" und die meisten FRITZ!Boxen haben dort lediglich 16 Nullen (als Zeichen, also 0x30) stehen ... erst bei einigen neueren Modellen wird da jetzt tatsächlich die Seriennummer hinterlegt. Dieser Umstand (und der damit verbundene Ausfall meiner bisherigen Lösungen, weil ich diese 16 Nullen auch fest verdrahtet hatte) war es auch, der mich zur erneuten Beschäftigung mit dem Thema "Verschlüsselung im FRITZ!OS" zwang und im Zuge dessen kam dann der Entschluß, das nun doch zu veröffentlichen.
[ Die 16 fest verdrahteten Nullen waren das Ergebnis von früheren Untersuchungen mit einer Library, die über "LD_PRELOAD" eine Funktion von AVM ersetzte (HASH_Update - wie man die findet, kommt gleich) und deren Aufrufe protokollierte. Das machte es auch leichter, die korrekte "Reihenfolge" der gerätespezifischen Daten zu ermitteln, obwohl da die denkbaren Permutationen mit 8 Variablen (jeder Wert einmal mit und einmal ohne "newline" am Ende) auch begrenzt wären und rein experimentell ermittelt werden könnten. ]
Wir haben also experimentell dann vier Werte ermittelt, die für diese "Identität" einer FRITZ!Box eine Rolle spielen und für die weitere Betrachtung brauchen wir dann auch die zu den oben gezeigten Chiffraten passenden Werte aus der Box:
Die Box hier hat also keinen CWMP-Account, damit gibt es nur drei Werte. Wie diese nun zu einer Variablen verknüpft werden, die als variable Größe in die Verschlüsselung eingehen kann (normalerweise als "key", aber denkbar wäre auch als "iv"), wissen wir aber damit noch lange nicht.
Zunächst einmal müssen wir irgendwie feststellen, welche (hoffentlich standardisierten) Algorithmen von AVM an dieser Stelle überhaupt verwendet werden. Dazu schauen wir uns mal ein paar Dateien aus der AVM-Firmware etwas genauer an und versuchen, die Abhängigkeiten zwischen den Bibliotheken dort zu ermitteln. Beginnen wir mit der "libar7cfg.so", die muß ja irgendwie in der Lage sein, so etwas zu ver- und entschlüsseln - wenn das nicht helfen sollte, bleibt uns immer noch ein altes "webdavcfginfo" ... schon anhand der Größe der Datei ist es relativ unwahrscheinlich, daß diese die gesamte Unterstützung der Verschlüsselung direkt enthält.
Das sieht ja schon sehr nach dem aus, was wir eigentlich suchen ... die "libar7cfg.so" braucht also für ihre Arbeit (wir sehen ja nur die importierten Funktionen) auch die rot markierten aus anderen Bibliotheken (man kriegt auch noch heraus, welche Bibliotheken das wären) und dabei taucht sowohl ein "MD5_Environ" als auch ein "AES256_Environ" auf - es spricht einiges dafür, daß wir hier sowohl eine Digest- als auch eine Cipher-Funktion gefunden haben.
Eine Digest-Funktion macht aus Daten variabler Länge einen eindeutigen Wert mit fester Länge, der z.B. als "key" oder als "iv" (der muß der Blockgröße eines Cipher-Algorithmus entsprechen von der Größe) für eine Verschlüsselung verwendet werden kann oder als "Prüfsumme", ob Daten in verschlüsselter oder Klartext-Form korrekt (sprich: unverändert bzw. erfolgreich entschlüsselt) wurden.
Eine Cipher-Funktion (hier das symmetrische AES mit einer Schlüssellänge von 256 Bits, wobei auch das eine Blocklänge von 16 Byte (128 Bits) verwendet) kann dann als "Block-Chiffre" auch dazu verwendet werden, einen Datenstrom (reversibel) zu verschlüsseln, der aus mehr als einem Block (16 Byte sind etwas wenig) besteht. Die gebräuchlichste Variante (und m.W. auch die älteste) ist dabei "Cipher Block Chaining" (CBC) und das ist auch das Erste, was man bei einer Untersuchung hier probieren würde.
Wir haben also die chiffrierten Daten (nach Base32-Dekodierung) und eine Vorstellung, was da von AVM wohl verwendet wird. Mit diesem Wissen bewaffnet, kann man sich jetzt ans Experimentieren machen ... ob man dazu jetzt das OpenSSL-Kommandozeilen-Tool, irgendeine höhere Sprache mit Crypto-Unterstützung oder direkt C-Programmierung mit OpenSSL-Funktionen verwendet, bleibt den eigenen Vorlieben überlassen. Als (nachvollziehbare) Demonstration bietet sich aber wieder die Linux-Kommandozeile an und so benutzen wir hier auch diese erst einmal:
Das ist also schon mal der binäre Inhalt der verschlüsselten Daten und damit wir den nicht jedesmal neu dekodieren müssen, speichern wir das Ergebnis einfach jeweils in einer Datei:
Für eine AES-Verschlüsselung brauchen wir einen "key" und einen "iv" ... normalerweise würde der IV zufällig gewählt (der muß auch nicht geheim sein und wird damit unverschlüsselt übermittelt/gespeichert) und der Key mit einer passenden Funktion aus einem Kennwort generiert - z.B. mit PBKDF2 als standardisiertem Weg, wo auch noch ein "salt" (das man entweder im Klartext oder selbst noch einmal verschlüsselt speichern muß oder man verwendet einen festen Wert) eingearbeitet werden kann, damit das Ergebnis für dasselbe Kennwort variiert und nicht beim System A mit demselben Kennwort auch derselbe Wert aus der PBKDF (Password Based Key Derivation Function) herauskommt wie beim System B (das nimmt dann eben einen anderen "salt"-Wert).
Gehen wir davon aus, daß auch AVM den IV irgendwo speichern wird ... da ist dann die Speicherung am Beginn der Daten (diese können ja eine variable Länge haben) logischer, als wenn das irgendwo am Ende steht (auch wenn das ebenfalls machbar wäre). Nun wissen wir ja (MD5 und AES256 nehmen wir mal als gesicherte Erkenntnis, auch wenn es ganz am Beginn natürlich nur eine Hypothese ist, die man mal bestätigen muß), daß wir für AES256 auch einen IV mit 16 Byte Länge brauchen. Das wäre dann der oben grün markierte Teil des jeweiligen Chiffrats ... damit beginnen die Daten vermutlich doch eher erst bei Byte 16 einer unserer Dateien "cipher_x.bin". Das müssen wir zunächst auch mal splitten ... ansonsten wird das später zu unhandlich beim "Probieren".
Nun stehen wir also vor der Aufgabe, uns irgendwie einen Key aus den vorhandenen Daten der Box zu generieren ... wir bräuchten hier aber einen Key mit 256 Bits (also 32 Bytes). Merkwürdigerweise gibt es bei AVM aber in den Beziehungen zwischen den Bibliotheken keinen Hinweis auf eine PBKDF-Funktion oder irgendeine Hash-Funktion (bzw. eine Digest-Funktion, das ist im Prinzip dasselbe), die uns diese 32 Bytes als Hash-Wert liefern würde (z.B. käme hier SHA-256 in Frage).
Wir haben also eigentlich nur unsere MD5-Implementierung, um aus den variablen Daten einer FRITZ!Box irgendeinen (spezifischen) Wert mit fester Länge zu berechnen ... und auch dafür sind die Möglichkeiten jetzt nicht allzu üppig. Wir greifen hier aber mal nur zwei davon heraus (eine richtige und eine falsche) und generieren uns dafür einen MD5-Hash:
Ich will das jetzt nicht weiter auswalzen und ich habe die korrekte Reihenfolge für das Berechnen des Hash-Wertes auch auf anderem Weg ermittelt (s.o.), aber man kann sich natürlich auch mit den vier Variablen (mit und ohne "\n" sind es dann acht) die jeweiligen Kombinationen automatisch berechnen lassen - das sprengt aber den Rahmen. Der grüne Wert ist der korrekte "Geräteschlüssel" für meine 7412 und der rote dient uns nachher nur zur Demonstration, was bei der Entschlüsselung mit einem falschen Schlüssel passiert.
Wir "wissen" ja auch, daß als Verschlüsselung AES-256 verwendet wird ... damit sähe dann ein Versuch des Entschlüsselns z.B. so aus:
Weil unsere Schlüssellänge nicht so richtig passend erscheint, habe ich erst einmal die Daten anzeigen lassen (-P), wie sie mit diesem Aufruf verwendet würden. Wir sehen also, daß der Schlüssel einfach mit Nullen auf die benötigte Länge aufgefüllt wird. Gehen wir jetzt mit dem falschen Schlüssel an unseren ersten Versuch, sieht das Ergebnis so aus:
Das Ergebnis sieht zwar mit den roten Zeilen recht entmutigend aus, aber da das Kommandozeilen-Tool von OpenSSL auch einen speziellen Aufbau der Datei erwartet, ist das ein Fehler, den man hier "aushalten" muß ... wenn man das mal mit einer OpenSSL-Version macht, die mit allen Schikanen erstellt wurde, sieht man auch, daß der Fehler erst beim "Finalisieren" des letzten Blocks auftritt:
Solange wir dafür sorgen, daß unsere Daten immer mit einer Länge vorliegen, daß der letzte Block nicht genau "gefüllt" ist, können wir den Fehler ignorieren (wir haben ja auch keinen "envelope", der da stimmen könnte) - und AVM tut uns hier mit der Base32-Kodierung und deren "krummen Längen" auch noch den Gefallen, daß es nur selten Probleme gibt ... aber wir hängen einfach mal vorsichtshalber an unsere Daten noch ein paar binäre Nullen an:
Wir haben jetzt also mindestens den letzten Block komplett und unsere binäre Null an Position 49 (0x31) stellt sicher, daß die Finalisierung erst für den nächsten Block stattfindet und die Daten davor noch komplett bearbeitet wurden ... allerdings rettet uns das auch nicht vor dem Fehler und wir werden diesen Fehler einfach ignorieren müssen:
Aber das ist ja auch nur die Entschlüsselung mit einem der denkbaren Keys (kennt man die richtige Reihenfolge beim Hash-Berechnen nicht, muß man halt alle ausprobieren) und wenn wir das jetzt mit dem richtigen Key angehen, sieht es schon viel besser aus:
Na das sieht doch schon wieder ganz anders aus ... wenn da im Klartext "PeterPawn" auftaucht, war die Entschlüsselung offenbar erfolgreich und dann stellt sich jetzt die Frage, was da eigentlich verschlüsselt wurde. Schon vor langer Zeit hatte ich entsprechende Tests zu den "Grenzen" der AVM-Daten gemacht und ermittelt, welche Länge der Klartext-Daten zu welcher Länge der verschlüsselten Daten führt ... das Ergebnis kann man u.a. hier sehen (habe ich irgendwann mal versehentlich veröffentlicht). Der graue Text ist ohnehin "garbage" und resultiert nur aus unserer "Verlängerung" der Daten.
Für die ersten 22 Bytes Klartext braucht AVM also 50 Bytes Chiffrat, wobei das beim verwendeten Cipher-Algorithmus ja auf ein Vielfaches der Blockgröße zu reduzieren ist und die 2 Bytes "Overhead" nur der Tatsache geschuldet sind, daß die Base32-Kodierung immer in Fünfer-Gruppen erfolgt. Bleiben also 48 Bytes Daten übrig und davon gehen die ersten 16 Bytes auch noch für den IV ab. Aber die verbleibenden 32 Bytes sind ja immer noch deutlich mehr als der reine Klartext und damit wird da wohl noch etwas anderes mitverschlüsselt.
Und richtig ... vor den Klartextdaten stehen oben ja noch weitere 8 Bytes, wobei die Bedeutung der vier ab Offset 4 wohl augenfällig ist. Das ist einfach die Länge der Klartextdaten (hier mit einer binären Null als Ende einer Zeichenkette in C) als 32-Bit-Wert in "big endian"-Speicherung. Da bei AVM (fast) alles Zeichenketten sind, was da verschlüsselt wird, ist die Längenangabe halt immer um eins höher als der eigentliche Wert, damit braucht AVM also eigentlich diese 48 Bytes Chiffrat für 23 Zeichen Klartext, denn das "end of string" ist ja Bestandteil des Klartextes.
Aber was könnte das "4e 2b d5 d3" in den ersten vier Bytes denn sein? Da kommen wir wieder auf die eingangs mal erläuterte Bedeutung eines "Markers" für die richtige Entschlüsselung (mithin das richtige Kennwort) zurück ... hat man so eine Validierung vorgesehen, kann man anhand dieses Wertes sehen, ob die Entschlüsselung erfolgreich war oder nicht. Nun kann man einerseits hingehen und dafür eine "Signatur" verwenden, die immer aus denselben Zeichen besteht ... das hat zwar andere Nachteile (bei denkbaren Angriffen auf die Verschlüsselung), aber wir können ja auch leicht überprüfen, ob das eine Signatur ist oder nicht - wir nehmen einfach den nächsten Wert und lassen uns den entschlüsseln:
Die Entschlüsselung funktioniert also auch hier (nicht vergessen, den IV ebenfalls passend anzugeben) und wir sehen, daß die "relevanten" Inhalte der Daten (die Längenangabe und die Daten an sich, bis Offset 0x12) tatsächlich dieselben sind ... nur der "Müll" beim Auffüllen auf die Blockgröße ist ein anderer und auch der Inhalt der ersten vier Bytes.
Sollten diese jetzt tatsächlich so ein Marker sein, dann müssen sie aber (da sie sich ja unterscheiden für die beiden Klartext-Angaben) mehr als nur die Längenangabe und die Daten an sich absichern (also mehr als 14 Bytes ab Offset 4), ansonsten wären die Werte ja wieder identisch. Was liegt jetzt näher als das Einbeziehen des "Schmutzes" hinter den Daten (bis zur nächsten Blockgröße der Verschlüsselung) ... wären das wieder alles Nullen, ergäbe sich auch immer wieder derselbe "Prüfwert" am Beginn und daß es sich offenbar um zufälligen Inhalt handelt (egal, wie der erzeugt wurde), sieht man wieder im Vergleich der beiden Klartext-Puffer.
Bleibt also die Frage, wie man so etwas realisieren könnte ... wir hätten hier in unserem konkreten Fall 32 Byte (2 Blöcke) abzgl. der 4 Bytes für den Prüfwert, da der natürlich nicht selbst eingehen kann in die Berechnung und entweder als Nullen interpretiert wird (das haben wir beim Signieren der Firmware ja auch für die Signatur-Datei so gesehen) oder die Berechnung erfolgt erst ab Offset 4.
Trotzdem stellt sich immer noch die Frage, wie man da nun 32-Bit-Werte zur Prüfung erzeugen könnte und da wäre der erste Kandidat eine CRC32-Prüfsumme mit einem der bekannten Polynome. Das habe ich damals auch tatsächlich als erstes treudoof ausprobiert (schließlich hat AVM auch an einer Export-Datei einen solchen Wert zur Prüfung), aber irgendwann fiel mir dann doch auf, daß die libar7cfg.so (die das ja offenbar auch kann) per se gar nichts mit Im- oder Export zu tun hat ... also müßte diese Sicherung vielleicht doch mit irgendeiner Funktion erfolgen, die auch von der Library importiert wird.
Da blieb dann wieder schnell nur noch MD5 übrig ... allerdings erzeugt diese Funktion eben 16 Bytes. Nach ein wenig Probieren (auch mit längeren Werten, die nicht mehr in zwei Blöcke (das Minimum) paßten) stellte sich dann heraus, daß hier tatsächlich erneut MD5 als Digest verwendet wird - es werden aber nur die ersten vier Bytes des Hash-Wertes gespeichert und das mit der Länge hat AVM dann so gelöst, daß diese vier Bytes von der Länge der Daten abgezogen werden (also von den Vielfachen der vollen Blockgröße).
Das ergibt dann 28 Bytes für zwei Blöcke, 44 Bytes für drei Blöcke, usw. - jeweils eben mit dem "Müll", der da gerade im Buffer steht (ich glaube nicht, daß das initialisiert wird mit Zufallsdaten, weiß es aber nicht sicher, schlau wäre es aber in jedem Falle) und damit dafür sorgt, daß dieselben Daten nicht einmal als Hash-Wert dasselbe Ergebnis liefern. Stimmt dann nach dem Dechiffrieren der noch einmal berechnete Hash-Wert (auch wenn es nur die ersten vier Bytes sind, ist die Wahrscheinlichkeit für einen Zufallstreffer gering - geringer als bei CRC-Prüfsummen, wo man das gezielt herbeiführen kann mit dem richtigen "filler"), dann stimmte offensichtlich auch der Key und man kann den entschlüsselten Wert verwenden. Ansonsten nimmt AVM i.d.R. die verschlüsselten Daten genau so, wie sie kommen ... das ergibt dann beim Restore von Freetz-Sicherungen auf anderen Geräten diese lustigen Werte, wie man sie desöfteren in Freetz-Tickets findet.
Das war dann auch schon "das Geheimnis" der AVM-Verschlüsselung (zumindest in Kurzform) ... das gilt es nun nachzubauen.
Wobei AVM da m.E. ohnehin selbst noch einen "off by one" macht, der mich fast wahnsinnig gemacht hat, als ich begonnen hatte, das mit der Verschlüsselung an sich zu untersuchen:
Bei einer Länge der Klartextdaten von 24 (inkl. "end of string", also 23 "reine" Zeichen) würden die Daten genau in zwei Blöcke passen (24 Bytes + 4 Bytes Längenangaben (man sieht auch das 0x18 dort) + 4 Bytes Hash-Beginn) ... aber AVM beschickt die Verschlüsselung hier offenbar mit einem Byte mehr und das ergibt bereits bei 23 Zeichen Eingabe dann einen zusätzlichen Block bei der Verschlüsselung und einen Sprung um 15 Byte in der Länge der verschlüsselten Daten (oder 20, wenn kein "garbage" dabei war). Das war dann die wirkungsvollste Verschleierung - bis ich da eine Systematik entdeckt hatte, brauchte es eine Weile.
Auch heute noch machen einige meiner Lösungen Probleme, wenn es zu diesen Grenzfällen bei der Länge und bei deren Berechnung kommt - einfach weil der "Sprung" dafür auch bei der Berechnung des Hash-Wertes in den ersten vier Bytes des Klartextes erfolgt und das dann genauso zu implementieren ist, wie es AVM (meiner Ansicht nach ist das tatsächlich auch ein Fehler und keine Absicht) macht. Die einzige "vernünftige" Erklärung wäre es halt, daß ohne irgendwelche Zufallsdaten am Ende auch bei der Berechnung des Hash-Wertes (über das Längenfeld und den Inhalt) immer derselbe Hash-Wert entstehen würde - vielleicht möchte man das vermeiden. Das finde ich dann angesichts von einfachen MD5-Hashes als Key aber schon weit vorausgedacht und es paßt für mich nicht wirklich zum Rest (komme ich gleich noch drauf).
Parallel dazu gibt es noch den Spezialfall einer Export-Datei ... hier können ja für den Key offensichtlich nicht die Eigenschaften des Gerätes herangezogen werden ... dann ließe sich die Datei ja nicht auf einem anderen Gerät entschlüsseln und importieren. Also muß AVM hier etwas anders machen ... und das fällt einem auch ins Auge, wenn man mal einen Blick in so eine Export-Datei wirft. Dort steht im Header der Datei (i.d.R. vor der Firmware-Version) ein Eintrag mit dem Namen "Password", offensichtlich gefolgt von einem verschlüsselten Wert, wie er auch an anderen Stellen auftritt.
Da wir inzwischen ja schon wissen, wie die Daten aussehen sollten nach der Entschlüsselung (und mit dem Hash-Wert auch selbst prüfen können, ob unser Kennwort stimmt), ist es dann wieder nur eine Fingerübung, diesen Wert solange mit wechselnden Keys zu traktieren, bis wir den passenden gefunden haben (ich hatte mir dafür entsprechende Hilfsprogramme geschrieben). Es gibt ja mindestens zwei Möglichkeiten, denn wir kennen Export-Dateien mit einem benutzerspezifizierten Kennwort und solche, die sich nur auf demselben Gerät wiederherstellen lassen (also wohl wieder den Geräteschlüssel benutzen).
Für die Variante mit dem Kennwort kommt man dann relativ schnell dahinter, daß es sich hier lediglich um den simplen MD5-Hash des Kennwortes handelt (ohne "newline" dahinter) und auch für die Variante ohne, wird man schnell fündig - nachdem man erst einmal verwirrt wurde, daß es sich dabei nicht um denselben Key handelt, wie er für die interne Speicherung verwendet wird. Auch hier ist halt "fröhliches Probieren" angesagt, aber die Permutationen sind wieder nicht so zahlreich - am Ende landet man bei der Seriennummer (bzw. für mich waren das immer irgendwelche Nullen und der Zusammenhang war mir bis vor kurzem gar nicht klar, weil die eben auf fast allen Geräten identisch war) und der MAC-Adresse, jeweils gefolgt von einmal "newline" (0x0A).
Zur Untersuchung brauchen wir erst einmal irgendwelche Daten, wir lassen einfach auf der 7412 mal die Konfiguration mit einem bekannten Kennwort exportieren und suchen uns das Kennwort am Beginn und das "PeterPawn" im Benutzernamen
Mit dem Wissen um dieses Kennwort können wir jetzt (auch außerhalb der 7412) die ersten Daten entschlüsseln ... dabei setze ich jetzt gleich zwei der Dateien ein, die ich später noch beschreiben werde:
Da der Hash-Wert stimmt, ist die Entschlüsselung offenbar geglückt und die letzte Zeile enthält (hier hexadezimal angezeigt) einen 256-Bit-Wert, der ja durchaus als Schlüssel für unser AES-256 in Frage käme. Schaut man noch einmal genauer hin, ist das aber lediglich eine Doppelung der ersten 16 Bytes (es würde mich nicht wundern, wenn das ein verdoppelter MD5-Hash irgendeines Zufallswertes ist) und dadurch wird der Wert auf 32 Bytes aufgeblasen (inkl. Hash und der bezieht auch die "garbage" am Ende mit ein (8 Bytes).
Versucht man sich jetzt mit diesem 256-Bit-Key an der Entschlüsselung der einzelnen Einstellungen in der Export-Datei, beißt man aber auf Granit:
Das war also offensichtlich schon mal nicht der richtige Key ... aber mit etwas Probieren stellt man dann schnell fest, daß da auch wieder nur der halbe Key verwendet wird (die "Güte" ist dank Doppelung ja ohnehin nicht wirklich besser als bei 128-Bit):
Wie man sieht, lassen sich auch beide Werte aus den Tiefen der Export-Datei mit demselben Key dechiffrieren - es ist halt nur ein zweistufiges Verfahren zur Gewinnung des richtigen Schlüssels bei einer Export-Datei.
Damit wäre die Beschreibung jetzt tatsächlich durch ... bleibt noch so etwas wie ein Zwischenfazit. Auch wenn die AVM-Verschlüsselung mit einem 256-Bit-Key protzt, ist es am Ende in Wirklichkeit alles nur die Sicherheit, die sich aus AES mit 128-Bit-Schlüsseln ergibt - wenn jeweils die Hälfte der 256 Bits schon vorher bekannt ist (hier sind es eben immer Nullen), dann ist AES-256 ein wenig Augenwischerei, jedenfalls wenn es um den "Schlüsselraum" geht. Ob MD5-Hashes tatsächlich das Mittel der Wahl sind (erst recht bei der einfachsten Variante mit dem Export-Kennwort), muß jeder selbst beurteilen. So, wie es zur Zeit aussieht, verwendet AVM wohl tatsächlich auch eine eigene Implementierung des "Rijndael-Algorithmus" (der später als Standard dann in "Advanced Encryption Standard" (AES) umbenannt wurde) und begeht damit ggf. schon den ersten Fehler. Selbst wenn das vielleicht früher mal erforderlich war, gibt es lange genug auch AES-256 in OpenSSL und es wäre längst an der Zeit gewesen, die eigene Implementierung:
in einen Wrapper für ein Standard-Paket umzuwandeln. Daß es sich nicht um einen solchen handelt, kann man an den importierten Funktionen sehen.
Auch ist es eigentlich verpönt, irgendwelche Keys ganz simpel von einem Hash-Wert (wie beim Export-Kennwort) abzuleiten ... das ist anfällig für Attacken und die üblichen Funktionen zur Ableitung eines Keys von einem Kennwort (PBKDF2 hatte ich oben schon erwähnt) fügen diesem Vorgang der Kennwort-Generierung (auch ohne "salt", wenn also aus einem identischen Kennwort auch ein identischer Key werden soll) einiges an Komplexität hinzu, um genau solche Angreifer passend zu verlangsamen. Mit vorausberechneten MD5-Hashes (wenn sich das überhaupt lohnt) ist das jedenfalls relativ(!) leicht angreifbar - es macht bloß niemand, weil sich der Aufwand vermutlich nicht lohnt. Aber "sicher" ist eben etwas anderes ... zwischen einem "ausgezeichnet" und einem "genügend" können da Welten liegen.
-Seit einiger Zeit gibt es bei AVM auch den "Dateityp" CRYPTEDBINFILE in einer export-Datei. Bisher habe ich das nur für die "dvb.cfg" bei den Geräten gesehen, die eine TV-Funktion (für DVB-C) unterstützen.
Daher steht man (ohne 6490, 6590 oder einen DVB-C-Repeater) erst einmal vor der Aufgabe, sich sein Material für eine genauere Untersuchung zu beschaffen und dann stellt man schnell fest, daß es dem Export ziemlich egal ist, ob es eine Datei "/var/flash/dvb.cfg" gibt oder nicht bzw. ob der Node 219 im TFFS Daten enthält oder nicht. Es muß also noch irgendeinen anderen Auslöser geben, wenn die Box sich zum Export der "dvb.cfg" entschließt und da liegt natürlich die hervorstechendste Eigenschaft am nächsten ... und das wäre die Variable "CONFIG_LINEARTV=y". Diese beeinflußt nicht nur die Anzeige des DVB-C-Menüs bei den DOCSIS-Boxen, sie regelt auch, ob "tr069fwupdate configexport" die "dvb.cfg" berücksichtigt oder nicht.
Das läßt sich ja recht einfach testen und so entstand das folgende Shell-Skript, das man auf seiner FRITZ!Box ausführen kann, um sich den Inhalt einer solchen CRYPTEDBINFILE-Datei ausgeben zu lassen:
Das gibt es auch im "decode_passwords"-Repository, man muß es also nicht abtippen.
Das erzeugt also eine eigene "dvb.cfg" (eine existierende sollte unverändert bleiben und nach einem Neustart wieder zur Verfügung stehen - außerdem braucht man keine großen Datenmengen bei einer Analyse, das macht es nur unhandlicher), exportiert die Einstellungen mit oder ohne ein Kennwort (das müßte man beim Aufruf des Skripts als ersten Parameter angeben) und sucht sich dann aus der Datei nur den Inhalt heraus, der wirklich diese "dvb.cfg" darstellt - der ist einerseits verschlüsselt und andererseits - wie alle BINFILE-Einträge - in hexadezimaler Kodierung gespeichert.
Ruft man das also auf der Box auf (ich nehme eine 7490), ergibt das folgende Ausgabe:
Wer sich mit solchen Themen befaßt, entwickelt irgendwann auch einen Blick für hexadezimale Darstellungen und damit fällt dann auch schnell auf, daß die erzeugte Ausgabe sich eigentlich nur in den ersten 32 Hex-Ziffern (also 128 Bits) wirklich unterscheidet und das bleibt auch so (vorausgesetz, man nimmt dasselbe Kennwort), egal wie oft man das probiert.
[ Kleiner Einschub zwischendurch ... es sieht für mich fast so aus, als hätte AVM (absichtlich oder versehentlich will ich nicht beurteilen) mit der Einführung der 2FA auch die Möglichkeit gekillt (im GUI war das durch Abfragen ohnehin schon verhindert), die export-Datei auch ohne Kennwort zu erzeugen. Das macht dann ein paar von mir kritisierte Zeichenketten in der TR-069-Implementierung noch rätselhafter ... wenn dort (zumindest dem Text nach, ob es wirklich ausgelöst wird bei einem "Upload()"-Call vom ACS muß ich erst mal wieder probieren) die Datei ohne Kennwort per "tr069fwupdate" exportiert und per "ftpput" auf einen Server geladen werden soll, funktioniert das ggf. nicht mehr. Bei mir hängt sich jedenfalls ein Aufruf von "tr069fwupdate configexport" irgendwo kurz vor dem Ende der Datei auf - auf einer 7490, einer 7412 und einer 6490, jeweils mit 06.83 und unabhängig davon, ob 2FA aktiviert ist oder nicht. Daher funktionierte der Export dieser CRYPTEDBINFILE-Zeilen oben bei mir auch nur mit Angabe eines Kennworts. ]
Zurück zur Analyse von dem, was wir da in den Daten dieser verschlüsselten "dvb.cfg" sehen ... dieses Verhalten ist viel "verräterischer", als man auf den ersten Blick vermuten würde. Wenn nämlich mehrmaliger Export immer dieselben Daten erzeugt (die ersten 16 Byte lassen wir mal aus bei der Betrachtung) und so eine Export-Datei ansonsten aber mit einem Zufallswert (der im Kopf in "Password" gespeichert wird) verschlüsselt wird (und das ist mal sicher), dann kann für die Verschlüsselung dieses CRYPTEDBINFILE ja nicht der zufällige Schlüssel verwendet werden ... das ergäbe ein anderes Chiffrat bei jedem Export. Probiert man dann noch einen Export mit einem anderen Passwort aus und sieht, daß sich die Daten dabei zwar ändern, aber auch für dieses Passwort wieder mehrfach dieselben Daten als Chiffrat erzeugt werden, dann darf man schon mal annehmen, daß hier genau derselbe Key verwendet wird, wie für die Verschlüsselung des Inhalts im "Password"-Feld.
Dieses Bild - identisches Chiffrat bei identischem Key - ist typisch für zwei Sachen ... erstens für das Arbeiten ohne einen zufälligen IV (was das ist und ob man das auch in grün bestellen kann, bitte bei Google nachschlagen) und zweiten für das Verwenden eines recht einfachen Verschlüsselungsverfahrens, wo jeder Block immer wieder mit denselben Daten verschlüsselt wird. Das nennt sich dann "Electronic Codebook Mode" (ECB) und welche Auswirkungen solche Algorithmen haben bzw. wie man diesen entgegenwirkt, zeigt die englische Seite der Wikipedia zu den "block modes" recht gut (die deutsche Seite kann ihr nicht das Wasser reichen): https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
[ Das Fehlen eines IV als zusätzliche variable Komponente ist am Ende damit gleichzusetzen, daß dort lauter binäre Nullen verwendet werden ... da diese Algorithmen in der Regel mit einem logischen XOR arbeiten (dabei wird jedes Bit des einen Wertes, für das im zweiten ein Bit gesetzt ist, negiert), ist das für ein XOR eine Maske, die gar nichts am Ausgangswert ändert. Zudem verwendet der ECB-Mode ohnehin keinen IV, aber für eine einfachere Parametrierung der Skript-Dateien habe ich da wenig geändert und setze halt einen IV von 0, worüber sich "openssl" ggf. beschwert, was man aber ignorieren kann. ]
Ausgerüstet mit diesem Wissen, können wir nun mal versuchen, die Daten aus so einer verschlüsselten Datei zu dechiffrieren. Dazu wandeln wir erst einmal das Chiffrat in binäre Daten um und speichern es ab, damit wir nicht immer mit wechselnden Werten in den ersten 16 Bytes konfrontiert werden:
Der Aufbau stimmt ... lediglich die Dateilänge (0x370) könnte problematisch werden, wenn AVM hier auch einen AES-256-Algorithmus verwendet (dann stimmt das Padding im letzten Block nicht). Aber bisher ist das alles graue Theorie, also schauen wir es uns mal mit "openssl" an:
Das war ja schon fast zu einfach ... dabei hat uns aber der Fehler mit dem ECB (und das halte ich absolut für einen, darauf komme ich gleich) dann schon sehr geholfen. Zumindest hat er uns (wenn man dabei etwas nachdenkt) die denkbaren Möglichkeiten stark eingeschränkt und einiges an vergeblichen Versuchen erspart.
Das Ende der Datei ist auch nicht schwer zu interpretieren ... da wird offensichtlich der eigentliche Inhalt der Datei (zzgl. 4 Byte am Beginn) auf die nächste 16-Bytes-Grenze mit Nullen aufgefüllt und am Ende ein weiterer Block mit "AVM", 2x (Int32)-Null und der Länge der eigentlichen Daten hinzugefügt. Damit hat man wieder den Marker, ob die Entschlüsselung möglich war und gleichzeitig die originale Dateilänge. Bleibt noch die Frage, wofür die ersten vier Bytes wohl gut sein sollen ... die sind ja jedesmal anders und das ergibt auch den ständig abweichenden ersten Block im Chiffrat. Wenn das wirklich ein zufälliger Wert ist, dann würde der ja auch dafür sorgen, daß das Chiffrat jedesmal unterschiedlich ist, wenn - ja, wenn - man denn einen anderen Mode als ECB verwenden würde.
Genau aus diesem Grund (es gibt ansonsten keine logisch begründbare Notwendigkeit für diese Zufallsdaten und es müssen auch zufällige Daten sein und keine CRC-Prüfsumme oder gar wieder ein Hash-Wert, der wäre ja bei ansonsten identischem Inhalt auch immer wieder derselbe) halte ich das auch für einen Anfängerfehler, den da jemand bei AVM begangen hat. Ich frage mich nur, warum dieses Problem nicht anhand des Chiffrates oder bei einer Kontrolle des Codes durch einen zweiten Mitarbeiter aufgefallen ist. So, wie man das hier gemacht hat, hätte man dieses CRYPTEDBINFILE auch gleich ganz weglassen können, denn das zu "knacken", ist eigentlich wieder sehr einfach. Bleibt als Erklärung also nur die Vermutung, daß es nur darum ging, das irgendwie zu verschleiern, was da drin steht.
Ich hoffe mal, daß AVM da trotzdem nachbessert (mit einem CRYPTEDBINFILE2, damit alte Dateien weiterhin gültig bleiben) ... auch wenn es bei AES noch(?) keine "known plaintext attacks" (KPA) gibt. Aber der Inhalt des zweiten Blocks (oben grün) ist auch als Klartext bereits bekannt, der variable Teil mit dem Datum kommt erst nach Offset 32. Aber das betrifft ja alles ohnehin nur DOCSIS-Boxen und den DVB-C-Repeater ...
-Wenn es jedenfalls um das Nachbauen geht, so habe ich seit drei Jahren da die verschiedensten Lösungen am Start gehabt ... je nachdem, worum es dabei jeweils ging und wenn irgendetwas Neues gebraucht wurde, habe ich auch eher etwas Vorhandenes genommen, geändert und dann parallel zur "Vorlage" verwendet, anstatt das in eine "gemeinsame" Code-Basis zu integrieren. So ein "refactoring" ist eben ein erheblicher Aufwand und mich juckte es eher nicht, wenn ich denselben Code immer wieder verwendet habe ... es gab einfach keine Notwendigkeit, die Sachen irgendwie zusammenzufassen.
Das war jetzt für die Veröffentlichung dann wieder etwas anderes und so bin ich (wohl oder übel) hingegangen und habe einiges "from scratch" neu gemacht ... zwar mit älteren Dateien als Vorlage, aber im Prinzip ist wirklich alles neu (das war der Mai).
-Inzwischen (Stand 08.06.2017) sind die Shell-Skripte im Prinzip fertig und auch das C-Programm funktioniert schon recht gut. Bei letzterem will ich noch einige Funktionen nach und nach ergänzen und auch die Unterstützung für "help" auf der Kommandozeile mit der Option "-h" oder "--help" ist praktisch nicht vorhanden, was die Benutzung natürlich schwer macht, weil man die Parameter nur beim Blick in den Quelltext erahnen kann.
Dafür sind die Shell-Skripte sowohl unter 32-bittigem Linux (z.B. auf FRITZ!Boxen selbst), 64-Bit-Linux (openSuSE und (in Grenzen) Ubuntu 14.04 LTS - also auch auf Systemen mit der "dash" als Shell) und auch in der "bash" unter Windows 10/x64 getestet ... bei mir arbeiten sie unter diesen Umgebungen ohne Probleme (ggf. im Windows noch ein passendes OpenSSL installieren).
Das C-Programm läßt sich sowohl in der Freetz-Toolchain als auch auf so ziemlich jedem anderen Linux-System übersetzen und wenn man sich das fertige x64-Binary in seine Windows-"bash" kopiert und dort OpenSSL installiert ist, läuft das Programm auch dort (allerdings schnarchlangsam im Vergleich und das liegt nicht an einem zu schwachen System).
Es gibt also noch ein wenig zu tun am C-Programm und auch ein oder zwei andere Shell-Skripte kann man dem Programm vermutlich noch zur Seite stellen ... z.B. zum Erzeugen eines Environment-Files aus den Support-Daten einer Box mit einem TFFS-Dump (in den "normalen" Support-Daten ist ja leider der WLAN-Key überschrieben). Auch ein kleines Shell-Skript als CGI-Wrapper, damit man auch mit einer HTML-Seite eine Export-Datei entschlüsseln lassen kann, könnte ich mir noch vorstellen.
Es gibt aber durchaus gute und legitime Gründe für das Ansinnen, auch auf solche Daten Zugriff zu erhalten. Eine kleine Liste von Beispielen (ohne jeden Anspruch auf Vollständigkeit) wäre z.B. die folgende:
- Jemand möchte seine FRITZ!Box mit zusätzlichen Programmen erweitern, die Kenntnis von solchen, verschlüsselt gespeicherten, Einstellungen benötigen. In diesem Falle ist es sicherlich keine allzu gute Idee, dieselben Datei noch einmal irgendwoanders zu verwalten und das vielleicht noch unverschlüsselt ... es gibt ja i.d.R. einen Grund dafür, warum so eine Einstellung von AVM verschlüsselt wird und nur wenige dieser Werte vom FRITZ!OS dann wieder in der Klartext-Version bereitgestellt werden (zumindest auf Wegen, die mit überschaubarem Aufwand verbunden sind).
- Jemand hat nur eine ältere Sicherungsdatei auf einer früheren Box (mit oder ohne Kennwort für die Sicherungsdatei), braucht aber ganz dringend noch irgendeine uralte Einstellung oder irgendwelche Zugangsdaten, die nur in dieser einen Datei noch vorhanden sind und ein (teilweiser) Import kommt als Lösung nicht in Frage.
- Als aktuelles Problem: Jemand hat eine aktuelle Sicherungsdatei erstellt, weil er verdächtige Aktivitäten in seiner FRITZ!Box bemerkt hat und bevor er alle Spuren vernichtet durch das Laden der Werkseinstellungen samt Neukonfiguration, war er so schlau, noch eine Sicherung der aktuellen Einstellungen zu machen. Die nutzt ihm aber nichts, weil er die in dieser Sicherung enthaltenen Benutzerkonten gar nicht wirklich "untersuchen" kann, denn man sieht einem Account in einer Sicherungsdatei nicht mehr an, für welchen Benutzer der nun erzeugt wurde (es gibt ja auch eine Möglichkeit, Benutzer zu verstecken vor dem GUI) und welches Kennwort dort ggf. von einem Angreifer überschrieben wurde, so daß sich der Besitzer selbst nicht mehr anmelden konnte. Hier hilft es natürlich unheimlich, wenn man (bei Kenntnis des Export-Kennworts, es geht hier nicht um das Brechen der Verschlüsselung einer unbekannten Export-Datei) die Sicherungsdatei dann einfach als Klartext anzeigen lassen kann.
Einem "bad guy" (unter "bad girl" versteht sicherlich jeder etwas anderes) hat man damit also nur ein paar Kiesel in den Weg gelegt ... aber der "Gelegenheitsnutzer" aus den o.a. Beispielen steht dabei (in aller Regel, solange er das nicht ständig machen muß) vor entsprechenden Problemen. Das ist in meinen Augen aber der Falsche, der hier von Sanktionen betroffen ist ... daher halte ich es für geboten, diesem legitimen Benutzer auch die passenden Werkzeuge in die Hand zu geben. Das habe ich lange und reiflich überlegt - ein entscheidender Punkt war auch der Wegfall des Routerzwangs und damit entfällt für mich zu einem großen Teil auch das "Schutzbedürfnis", das man früher für Einstellungen vom Provider in den FRITZ!Boxen noch unterstellen und geltenlassen konnte, die dem Provider gehören. Seitdem die Kunden aber die Zugangsdaten ohnehin vom Provider erhalten müssen, entfällt auch dieser Punkt der "contra"-Liste.
Das führt dann im Ergebnis zu der Einstellung, daß diese "security by obscurity" eigentlich nur einem wirklich schadet: dem berechtigten Benutzer. Alle anderen finden auch ohne mich und die folgenden Informationen immer wieder einen Weg, an diese Daten zu gelangen. AVM hilft also mit dieser Geheimniskrämerei eher den Bösen und ich sehe nicht einen einzigen Punkt, wo eine Beschreibung meinerseits die Sicherheit eines FRITZ!Box-Besitzers tatsächlich aushöhlen würde - ganz im Gegenteil ... wie im Beispiel oben angeführt, kann es dem Besitzer sogar helfen, über Merkwürdigkeiten in den Einstellungen auf einen Angriff zu schließen.
Das war's dann jetzt auch mit der Präambel und nun geht es "in medias res".
-Schaut man sich die verschlüsselten Daten in irgendeiner AVM-Datei einmal an, stellt man ja schnell fest, daß diese immer mit vier Dollarzeichen beginnen und danach dann nur die Großbuchstaben A bis Z und Ziffern 1 bis 6 folgen. AVM muß also irgendwie die verschlüsselten Daten aus der binären Form (das Ergebnis der eigentlichen Verschlüsselung sind alle denkbaren Werte von 0 bis 255 in mehreren Bytes - das ist dann die "binäre Form", so wie die Daten im Speicher liegen) in eine andere transformieren, die mit insgesamt 32 Zeichen (26 Buchstaben, 6 Ziffern) auskommt.
Das kennt aber praktisch jeder aus der Mathematik und der Schule ... es ist am Ende nichts anderes als eine andere Zahlenbasis, die da zum Einsatz kommt. Da, wo das Binärsystem mit den Zeichen 0 und 1 auskommt, braucht das Oktalsystem dann schon acht (0 bis 7), das Dezimalsystem zehn (0 bis 9) und auch vom Hexadezimalsystem (mit 0 bis 9 und den Buchstaben A bis F für die Werte 10 bis 15) sollte man schon mal etwas gehört haben (wenn nicht, wäre hier der richtige Zeitpunkt, sich das z.B. in der Wikipedia anzusehen).
AVM verwendet hier also 32 verschiedene "Ziffern" und damit ist das offenbar ein Zahlensystem mit der Basis 32 ... daher nennt man diese Kodierung dann auch folgerichtig: Base32. Die gibt es auch an anderen Stellen (die Base64-Kodierung zur Darstellung beliebiger Inhalte nur mit ASCII-Zeichen ist aber bekannter), aber AVM verwendet hier wohl ein eigenes "Alphabet", denn die meisten anderen arbeiten mit 0 bis 5 für die zusätzlich benötigten 6 Werte. Warum AVM hier überhaupt auf Base32 zurückgreift, kann man auch nur vermuten ... die zusätzlichen 32 "Zeichen" für Base64 sind sicherlich nicht das Problem; notfalls ersetzt man die zwei Sonderzeichen im Zeichenvorrat (das sind das Plus und der Schrägstrich) durch andere, wenn man diese Zeichen für eigene Zwecke braucht.
Also rate ich mal hinsichtlich der Beweggründe und tippe auf: Verschleierung (für Laien) - auf Kosten zusätzlicher "Längen" bei der Kodierung, denn im Gegensatz zum Base64 (mit einem Verhältnis von 4 Zeichen für 3 Byte Binärdaten) braucht Base32 da mehr und bietet ungünstigere Bedingungen (8 Zeichen für 5 Byte Binärdaten) "aus Computersicht" bei den binären Daten (es müssen Vielfache von 5 sein bei der Länge der zu kodierenden Daten).
Kommen wir darauf zurück, wie das "AVM-Alphabet" wohl genutzt wird ... irgendwo in der Firmware gibt es bestimmt passende Zeichenketten. Das naheliegendste ist zunächst mal der Blick in die "libar7cfg.so", diese ist für die Be- und Verarbeitung der "Hauptdatei" (ar7.cfg) zuständig:
Code:
root@FB7490:~ $ [COLOR="#0000FF"][B]strings /lib/libar7cfg.so | grep "ABCDEFGHIJKLMNOPQRSTUVWXYZ\|123456"[/B][/COLOR]
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
[COLOR="#FF0000"]ABCDEFGHIJKLMNOPQRSTUVWXYZ123456[/COLOR]
Mit dieser Erkenntnis ausgerüstet, ist es jetzt recht simpel, aus der Base32-Form die binäre Darstellung zu gewinnen. Das habe ich im Laufe der Jahre in mehreren Formen realisiert ... von Python über Shell bis C.
Aber mit diesen Daten kann man jetzt auch noch nicht so richtig viel anfangen ... was wir zunächst einmal brauchen, ist ein bekannter Klartext und das dazugehörige Chiffrat. Das ist schnell erledigt ... auf einer 7412 habe ich mir einen Benutzer "PeterPawn" mit dem Kennwort "PeterPawn" angelegt und das Ergebnis war dann das Folgende:
Code:
# [COLOR="#0000FF"][B]sed -n -e "/^boxusers/,/^}/p" /var/flash/ar7.cfg[/B][/COLOR]
boxusers {
users {
enabled = yes;
id = 11;
name = "$$$$[COLOR="#FF0000"]EWOYB6UU4CXNGTRIIFPBKROUTTMBZ53XATBLWTXHOFXRTO2UVC3I32RS132MAAC3BXGSM6HGYS51S4W1[/COLOR]";
email = "";
password = "$$$$[COLOR="#FF0000"]J4U52P1Y3JBDZWIXNCVQRVG2B63N4TJLJO456FTQNNOEUGJEQWXEXWHIOZBNYDTVI51X3CNLNF15W4W1[/COLOR]";
vpn_access = no;
box_admin_rights = secobj_access_rights_readwrite_from_homenetwork_only;
nas_rights = secobj_access_rights_none;
phone_rights = secobj_access_rights_readwrite_from_homenetwork_only;
homeauto_rights = secobj_access_rights_readwrite_from_homenetwork_only;
[...]
}
remote_access_id = 0;
version = 1;
two_factor_auth_enabled = yes;
}
Was wir auch schon aus der Erfahrung wissen (entsprechende Berichte gibt es seit Jahren) ... es gibt bei der Verschlüsselung für die interne Speicherung auch noch eine gerätespezifische Komponente, denn eine Datei von der einen FRITZ!Box läßt sich nicht ohne weiteres auf einer anderen FRITZ!Box entschlüsseln - das ging schon zu Zeiten von "allcfgconv -c" nicht. Wenn man sich ein wenig mit dem Aufbau einer FRITZ!Box befaßt, kommt man auch schnell dahinter, daß diese "Geräteeigenschaften" für die Verschlüsselung eigentlich nur im sogenannten "Urlader-Environment" gespeichert sein können ... das sind ein paar Eckdaten einer Box (inkl. variabler Daten, die auch bei zwei Geräten desselben Modells bei der Finalisierung der Boxen ab Werk unterschiedlich sind) und - da die Firmware an sich für alle Geräte eines Modells dieselbe ist - praktisch die einzige (maschinenlesbare) Stelle, wo das FRITZ!OS auf (dauerhaft existierende, denn diese Daten werden weder bei Recovery noch bei Werkseinstellungen gelöscht) Daten eines Gerätes zugreifen kann.
Wenn es also variable Größen gibt, dann können die praktisch nur dort drin stehen und wenn man dann etwas mit den Werten im Environment und einem (bekanntermaßen funktionierenden) Programm zum Dekodieren von verschlüsselten Daten experimentiert, stellt man recht schnell auch fest, daß diese variablen Daten offenbar aus dem Wert bei "maca" und "wlan_key" bestehen, die in praktisch jeder FRITZ!Box vorhanden sind. Zusätzlich kommt noch ein weiterer Wert hinzu, der aber nicht bei allen Boxen vorhanden ist und deshalb auf den ersten Blick nicht auffällt ... das ist "tr069_passphrase", was nur bei den Boxen mit konfiguriertem CWMP-Account (also einer TR-069-"Identität") vorhanden ist.
Es geht auch noch ein vierter Wert in diese gerätespezifischen Daten ein ... aber auch der fiel bisher eher nicht auf, weil es praktisch nur Geräte gab, in denen er immer denselben Wert hatte. Es handelt sich hierbei um "SerialNumber" und die meisten FRITZ!Boxen haben dort lediglich 16 Nullen (als Zeichen, also 0x30) stehen ... erst bei einigen neueren Modellen wird da jetzt tatsächlich die Seriennummer hinterlegt. Dieser Umstand (und der damit verbundene Ausfall meiner bisherigen Lösungen, weil ich diese 16 Nullen auch fest verdrahtet hatte) war es auch, der mich zur erneuten Beschäftigung mit dem Thema "Verschlüsselung im FRITZ!OS" zwang und im Zuge dessen kam dann der Entschluß, das nun doch zu veröffentlichen.
[ Die 16 fest verdrahteten Nullen waren das Ergebnis von früheren Untersuchungen mit einer Library, die über "LD_PRELOAD" eine Funktion von AVM ersetzte (HASH_Update - wie man die findet, kommt gleich) und deren Aufrufe protokollierte. Das machte es auch leichter, die korrekte "Reihenfolge" der gerätespezifischen Daten zu ermitteln, obwohl da die denkbaren Permutationen mit 8 Variablen (jeder Wert einmal mit und einmal ohne "newline" am Ende) auch begrenzt wären und rein experimentell ermittelt werden könnten. ]
Wir haben also experimentell dann vier Werte ermittelt, die für diese "Identität" einer FRITZ!Box eine Rolle spielen und für die weitere Betrachtung brauchen wir dann auch die zu den oben gezeigten Chiffraten passenden Werte aus der Box:
Code:
# [COLOR="#0000FF"][B]sed -n -e "/^SerialNumber/p" -e "/^maca/p" -e "/^tr069_passphrase/p" -e "/^wlan_key/p" /proc/sys/urlader/environment[/B][/COLOR]
SerialNumber 0000000000000000
maca 5C:49:79:57:47:5A
wlan_key 25083886372223913969
Zunächst einmal müssen wir irgendwie feststellen, welche (hoffentlich standardisierten) Algorithmen von AVM an dieser Stelle überhaupt verwendet werden. Dazu schauen wir uns mal ein paar Dateien aus der AVM-Firmware etwas genauer an und versuchen, die Abhängigkeiten zwischen den Bibliotheken dort zu ermitteln. Beginnen wir mit der "libar7cfg.so", die muß ja irgendwie in der Lage sein, so etwas zu ver- und entschlüsseln - wenn das nicht helfen sollte, bleibt uns immer noch ein altes "webdavcfginfo" ... schon anhand der Größe der Datei ist es relativ unwahrscheinlich, daß diese die gesamte Unterstützung der Verschlüsselung direkt enthält.
Code:
# [COLOR="#0000FF"][B]/var/bintools/usr/bin/nm -D -B /lib/libar7cfg.so | grep " U "[/B][/COLOR]
U [COLOR="#FF0000"]AES256_Environ[/COLOR]
U [COLOR="#FF0000"]CIPHER_Cleanup[/COLOR]
U [COLOR="#FF0000"]CIPHER_Init[/COLOR]
U [COLOR="#FF0000"]CIPHER_Update[/COLOR]
U ConvertEmailAddrFromUTF8ToIDNA_WithAlloc
U Event_Add
U [COLOR="#FF0000"]HASH_Final[/COLOR]
U [COLOR="#FF0000"]HASH_Init[/COLOR]
U [COLOR="#FF0000"]HASH_Update[/COLOR]
U [COLOR="#FF0000"]MD5Final[/COLOR]
U [COLOR="#FF0000"]MD5Init[/COLOR]
U [COLOR="#FF0000"]MD5Update[/COLOR]
U [COLOR="#FF0000"]MD5_Environ[/COLOR]
U __ctype_b_loc
U _strlwr
U access
U atoi
U boxenv_boxnumber
U boxenv_config_is
U boxenv_hwrevision
U boxenv_is_release_firmware
U boxenv_serial
U boxenv_shortversion
U bugmsg
U close
U config_allocstruct
U config_freestruct
U config_loaderr2str
U config_memberbymagic
U config_set_pwfuncs
U config_setbstyle
U config_varfree
U config_varinit
U config_varload
U config_varload_merge
U config_varload_overwrite
U config_varsave
U createpathto
U crwmmap_mapmem
U crwmmap_unmap
U crwmmap_writerlock
U crwmmap_writerunlock
U csock_addr2str
U csock_isaddr6_zero
U debug_gethandle
U emailaddress_parse
U errmsg
U fclose
U fgets
U fopen
U fread
U get_major_of
U getenv
U getpid
U if_exists
U ipaccess_optim_rulestruct
U ipaccess_parse
U ipmasqfwrule_parse
U ipmasqfwruleex_parse
U is_eth_switch_installed
U localtime_r
U memblock_set
U memcmp
U memcpy
U memset
U mknod
U open
U read
U slab_cbcontext_free
U slab_dcalloc
U slab_dmalloc
U slab_dstrdup
U snprintf
U sprintf
U srand
U sscanf
U strcasecmp
U strcasestr
U strchr
U strcmp
U strcmp_safe
U strcpy
U stringlist_append_string
U stringlist_append_string_caseunique
U stringlist_append_string_unique
U stringlist_free
U stringlist_in
U stringlist_len
U stringlist_prepend_string
U stringlist_remove_string
U stringlist_split
U strlen
U strncasecmp
U strncmp
U strncpy
U strrchr
U strstr
U strtoul
U time
U timercb_elapsed
U unlink
U urlader_getenv
U urlader_getmac
U utillib_random
U write
Eine Digest-Funktion macht aus Daten variabler Länge einen eindeutigen Wert mit fester Länge, der z.B. als "key" oder als "iv" (der muß der Blockgröße eines Cipher-Algorithmus entsprechen von der Größe) für eine Verschlüsselung verwendet werden kann oder als "Prüfsumme", ob Daten in verschlüsselter oder Klartext-Form korrekt (sprich: unverändert bzw. erfolgreich entschlüsselt) wurden.
Eine Cipher-Funktion (hier das symmetrische AES mit einer Schlüssellänge von 256 Bits, wobei auch das eine Blocklänge von 16 Byte (128 Bits) verwendet) kann dann als "Block-Chiffre" auch dazu verwendet werden, einen Datenstrom (reversibel) zu verschlüsseln, der aus mehr als einem Block (16 Byte sind etwas wenig) besteht. Die gebräuchlichste Variante (und m.W. auch die älteste) ist dabei "Cipher Block Chaining" (CBC) und das ist auch das Erste, was man bei einer Untersuchung hier probieren würde.
Wir haben also die chiffrierten Daten (nach Base32-Dekodierung) und eine Vorstellung, was da von AVM wohl verwendet wird. Mit diesem Wissen bewaffnet, kann man sich jetzt ans Experimentieren machen ... ob man dazu jetzt das OpenSSL-Kommandozeilen-Tool, irgendeine höhere Sprache mit Crypto-Unterstützung oder direkt C-Programmierung mit OpenSSL-Funktionen verwendet, bleibt den eigenen Vorlieben überlassen. Als (nachvollziehbare) Demonstration bietet sich aber wieder die Linux-Kommandozeile an und so benutzen wir hier auch diese erst einmal:
Code:
$ [COLOR="#0000FF"][B]printf "%s" "EWOYB6UU4CXNGTRIIFPBKROUTTMBZ53XATBLWTXHOFXRTO2UVC3I32RS132MAAC3BXGSM6HGYS51S4W1" | decoder b32dec | hd[/B][/COLOR]
00000000 [COLOR="#008000"]25 9d 80 fe 94 e8 ae d3 4e 28 41 5e 15 45 d4 9c[/COLOR] |%.......N(A^.E..|
00000010 d8 1c fb 97 04 c2 bb 4e e7 71 6f 19 bb 74 a8 b8 |.......N.qo..t..|
00000020 8e 6e 32 d7 36 c0 00 5c 0d cd 26 7c e6 c4 bd a9 |.n2.6..\..&|....|
00000030 76 da |v.|
00000032
$ [COLOR="#0000FF"][B]printf "%s" "J4U52P1Y3JBDZWIXNCVQRVG2B63N4TJLJO456FTQNNOEUGJEQWXEXWHIOZBNYDTVI51X3CNLNF15W4W1" | decoder b32dec | hd[/B][/COLOR]
00000000 [COLOR="#008000"]4f 69 ed bf 58 e2 42 3c d9 17 68 ab 08 d4 db 0f[/COLOR] |Oi..X.B<..h.....|
00000010 f8 de cd 2b 4b bb ef 96 70 6b 5c 4a 19 24 85 ae |...+K...pk\J.$..|
00000020 4b d8 e8 76 42 dc 0e 75 47 b5 7e 09 ab 69 75 eb |K..vB..uG.~..iu.|
00000030 76 da |v.|
00000032
Code:
$ printf "%s" "EWOYB6UU4CXNGTRIIFPBKROUTTMBZ53XATBLWTXHOFXRTO2UVC3I32RS132MAAC3BXGSM6HGYS51S4W1" | decoder b32dec >cipher_1.bin
$ printf "%s" "J4U52P1Y3JBDZWIXNCVQRVG2B63N4TJLJO456FTQNNOEUGJEQWXEXWHIOZBNYDTVI51X3CNLNF15W4W1" | decoder b32dec >cipher_2.bin
Gehen wir davon aus, daß auch AVM den IV irgendwo speichern wird ... da ist dann die Speicherung am Beginn der Daten (diese können ja eine variable Länge haben) logischer, als wenn das irgendwo am Ende steht (auch wenn das ebenfalls machbar wäre). Nun wissen wir ja (MD5 und AES256 nehmen wir mal als gesicherte Erkenntnis, auch wenn es ganz am Beginn natürlich nur eine Hypothese ist, die man mal bestätigen muß), daß wir für AES256 auch einen IV mit 16 Byte Länge brauchen. Das wäre dann der oben grün markierte Teil des jeweiligen Chiffrats ... damit beginnen die Daten vermutlich doch eher erst bei Byte 16 einer unserer Dateien "cipher_x.bin". Das müssen wir zunächst auch mal splitten ... ansonsten wird das später zu unhandlich beim "Probieren".
Code:
$ [COLOR="#0000FF"]dd if=cipher_1.bin of=iv_1.bin bs=16 count=1[/COLOR]
1+0 records in
1+0 records out
16 bytes (16B) copied, 0.002797 seconds, 5.6KB/s
$ [COLOR="#0000FF"]dd if=cipher_2.bin of=iv_2.bin bs=16 count=1[/COLOR]
1+0 records in
1+0 records out
16 bytes (16B) copied, 0.002744 seconds, 5.7KB/s
$ [COLOR="#0000FF"]dd if=cipher_1.bin of=data_1.bin bs=16 skip=1[/COLOR]
2+1 records in
2+1 records out
34 bytes (34B) copied, 0.004771 seconds, 7.0KB/s
$ [COLOR="#0000FF"]dd if=cipher_2.bin of=data_2.bin bs=16 skip=1[/COLOR]
2+1 records in
2+1 records out
34 bytes (34B) copied, 0.004724 seconds, 7.0KB/s
$ [COLOR="#0000FF"]hd iv_1.bin[/COLOR]
00000000 25 9d 80 fe 94 e8 ae d3 4e 28 41 5e 15 45 d4 9c |%.......N(A^.E..|
00000010
$ [COLOR="#0000FF"]hd data_1.bin[/COLOR]
00000000 d8 1c fb 97 04 c2 bb 4e e7 71 6f 19 bb 74 a8 b8 |.......N.qo..t..|
00000010 8e 6e 32 d7 36 c0 00 5c 0d cd 26 7c e6 c4 bd a9 |.n2.6..\..&|....|
00000020 76 da |v.|
00000022
$ [COLOR="#0000FF"]hd iv_2.bin[/COLOR]
00000000 4f 69 ed bf 58 e2 42 3c d9 17 68 ab 08 d4 db 0f |Oi..X.B<..h.....|
00000010
$ [COLOR="#0000FF"]hd data_2.bin[/COLOR]
00000000 f8 de cd 2b 4b bb ef 96 70 6b 5c 4a 19 24 85 ae |...+K...pk\J.$..|
00000010 4b d8 e8 76 42 dc 0e 75 47 b5 7e 09 ab 69 75 eb |K..vB..uG.~..iu.|
00000020 76 da |v.|
00000022
Wir haben also eigentlich nur unsere MD5-Implementierung, um aus den variablen Daten einer FRITZ!Box irgendeinen (spezifischen) Wert mit fester Länge zu berechnen ... und auch dafür sind die Möglichkeiten jetzt nicht allzu üppig. Wir greifen hier aber mal nur zwei davon heraus (eine richtige und eine falsche) und generieren uns dafür einen MD5-Hash:
Code:
$ [COLOR="#0000FF"][B]printf "5C:49:79:57:47:5A\n25083886372223913969\n0000000000000000" | openssl dgst -md5[/B][/COLOR]
(stdin)= [COLOR="#FF0000"]42e6943e51d3a9ae8209dd2d6c3534c8[/COLOR]
$ [COLOR="#0000FF"][B]printf "0000000000000000\n5C:49:79:57:47:5A\n25083886372223913969" | openssl dgst -md5[/B][/COLOR]
(stdin)= [COLOR="#008000"]a41d7248990bc5a36ff6cc85547cb363[/COLOR]
Wir "wissen" ja auch, daß als Verschlüsselung AES-256 verwendet wird ... damit sähe dann ein Versuch des Entschlüsselns z.B. so aus:
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K 42e6943e51d3a9ae8209dd2d6c3534c8 -iv 259d80fe94e8aed34e28415e1545d49c -P[/B][/COLOR]
salt=00530C4C77506108
key=[COLOR="#FF0000"]42E6943E51D3A9AE8209DD2D6C3534C800000000000000000000000000000000[/COLOR]
iv =259D80FE94E8AED34E28415E1545D49C
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K 42e6943e51d3a9ae8209dd2d6c3534c8 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | hd[/B][/COLOR]
[COLOR="#FF0000"]bad decrypt
2001658984:error:0606506D:lib(6):func(101):reason(109):NA:0:[/COLOR]
00000000 6d 76 6e 4b 7f 41 3c 0f cf fc b4 64 1c 06 d0 f1 |mvnK.A<....d....|
00000010 f8 3f dc 04 82 61 87 a4 b7 33 54 2b 43 1b 51 16 |.?...a...3T+C.Q.|
00000020
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K 42e6943e51d3a9ae8209dd2d6c3534c8 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | hd[/B][/COLOR]
bad decrypt
139794545268368:error:0606506D:[COLOR="#FF0000"]digital envelope routines:EVP_DecryptFinal_ex:wrong final block length[/COLOR]:evp_enc.c:589:
00000000 6d 76 6e 4b 7f 41 3c 0f cf fc b4 64 1c 06 d0 f1 |mvnK.A<....d....|
00000010 f8 3f dc 04 82 61 87 a4 b7 33 54 2b 43 1b 51 16 |.?...a...3T+C.Q.|
00000020
Code:
$ [COLOR="#0000FF"][B]dd if=/dev/zero bs=1 count=15 >> data_1.bin[/B][/COLOR]
15+0 records in
15+0 records out
15 bytes (15B) copied, 0.014798 seconds, 946B/s
$ [COLOR="#0000FF"][B]dd if=/dev/zero bs=1 count=15 >> data_2.bin[/B][/COLOR]
15+0 records in
15+0 records out
15 bytes (15B) copied, 0.014798 seconds, 946B/s
$ [COLOR="#0000FF"][B]hd data_1.bin[/B][/COLOR]
00000000 d8 1c fb 97 04 c2 bb 4e e7 71 6f 19 bb 74 a8 b8 |.......N.qo..t..|
00000010 8e 6e 32 d7 36 c0 00 5c 0d cd 26 7c e6 c4 bd a9 |.n2.6..\..&|....|
00000020 76 da 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |v...............|
00000030 00 |.|
00000031
$ [COLOR="#0000FF"][B]hd data_2.bin[/B][/COLOR]
00000000 f8 de cd 2b 4b bb ef 96 70 6b 5c 4a 19 24 85 ae |...+K...pk\J.$..|
00000010 4b d8 e8 76 42 dc 0e 75 47 b5 7e 09 ab 69 75 eb |K..vB..uG.~..iu.|
00000020 76 da 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |v...............|
00000030 00 |.|
00000031
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K 42e6943e51d3a9ae8209dd2d6c3534c8 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | hd[/B][/COLOR]
bad decrypt
2006570088:error:0606506D:lib(6):func(101):reason(109):NA:0:
00000000 6d 76 6e 4b 7f 41 3c 0f cf fc b4 64 1c 06 d0 f1 |mvnK.A<....d....|
00000010 f8 3f dc 04 82 61 87 a4 b7 33 54 2b 43 1b 51 16 |.?...a...3T+C.Q.|
00000020 7e 92 95 c2 5d 36 5e 06 d4 e9 6b ba ec 80 a5 6e |~...]6^...k....n|
00000030
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K a41d7248990bc5a36ff6cc85547cb363 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | hd[/B][/COLOR]
bad decrypt
1998218344:error:0606506D:lib(6):func(101):reason(109):NA:0:
00000000 [COLOR="#FFA500"]4e 2b d5 d3[/COLOR] [COLOR="#008000"]00 00 00 0a[/COLOR] [COLOR="#FF0000"]50 65 74 65 72 50 61 77[/COLOR] |N+......[COLOR="#FF0000"]PeterPaw[/COLOR]|
00000010 [COLOR="#FF0000"]6e 00[/COLOR] 00 a3 95 b5 f8 5d fe 79 34 e1 bc 2c d6 eb |[COLOR="#FF0000"]n[/COLOR]......].y4..,..|
00000020 af fd [COLOR="#A9A9A9"]a7 2a b6 2b e4 d7 fe 1b 3c ce 07 27 55 89[/COLOR] |...*.+....<..'U.|
00000030
Für die ersten 22 Bytes Klartext braucht AVM also 50 Bytes Chiffrat, wobei das beim verwendeten Cipher-Algorithmus ja auf ein Vielfaches der Blockgröße zu reduzieren ist und die 2 Bytes "Overhead" nur der Tatsache geschuldet sind, daß die Base32-Kodierung immer in Fünfer-Gruppen erfolgt. Bleiben also 48 Bytes Daten übrig und davon gehen die ersten 16 Bytes auch noch für den IV ab. Aber die verbleibenden 32 Bytes sind ja immer noch deutlich mehr als der reine Klartext und damit wird da wohl noch etwas anderes mitverschlüsselt.
Und richtig ... vor den Klartextdaten stehen oben ja noch weitere 8 Bytes, wobei die Bedeutung der vier ab Offset 4 wohl augenfällig ist. Das ist einfach die Länge der Klartextdaten (hier mit einer binären Null als Ende einer Zeichenkette in C) als 32-Bit-Wert in "big endian"-Speicherung. Da bei AVM (fast) alles Zeichenketten sind, was da verschlüsselt wird, ist die Längenangabe halt immer um eins höher als der eigentliche Wert, damit braucht AVM also eigentlich diese 48 Bytes Chiffrat für 23 Zeichen Klartext, denn das "end of string" ist ja Bestandteil des Klartextes.
Aber was könnte das "4e 2b d5 d3" in den ersten vier Bytes denn sein? Da kommen wir wieder auf die eingangs mal erläuterte Bedeutung eines "Markers" für die richtige Entschlüsselung (mithin das richtige Kennwort) zurück ... hat man so eine Validierung vorgesehen, kann man anhand dieses Wertes sehen, ob die Entschlüsselung erfolgreich war oder nicht. Nun kann man einerseits hingehen und dafür eine "Signatur" verwenden, die immer aus denselben Zeichen besteht ... das hat zwar andere Nachteile (bei denkbaren Angriffen auf die Verschlüsselung), aber wir können ja auch leicht überprüfen, ob das eine Signatur ist oder nicht - wir nehmen einfach den nächsten Wert und lassen uns den entschlüsseln:
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K a41d7248990bc5a36ff6cc85547cb363 -iv 4f69edbf58e2423cd91768ab08d4db0f -in data_2.bin | hd[/B][/COLOR]
bad decrypt
2008532072:error:0606506D:lib(6):func(101):reason(109):NA:0:
00000000 [COLOR="#FFA500"]0c bf be b1[/COLOR] 00 00 00 0a 50 65 74 65 72 50 61 77 |........PeterPaw|
00000010 6e 00 50 c9 42 4a e0 ce 81 a7 05 02 f1 89 9a 3c |n.P.BJ.........<|
00000020 6a 4b 7d 8b c2 37 ea fe b4 63 64 bb 4a 8a 9d cb |jK}..7...cd.J...|
00000030
Sollten diese jetzt tatsächlich so ein Marker sein, dann müssen sie aber (da sie sich ja unterscheiden für die beiden Klartext-Angaben) mehr als nur die Längenangabe und die Daten an sich absichern (also mehr als 14 Bytes ab Offset 4), ansonsten wären die Werte ja wieder identisch. Was liegt jetzt näher als das Einbeziehen des "Schmutzes" hinter den Daten (bis zur nächsten Blockgröße der Verschlüsselung) ... wären das wieder alles Nullen, ergäbe sich auch immer wieder derselbe "Prüfwert" am Beginn und daß es sich offenbar um zufälligen Inhalt handelt (egal, wie der erzeugt wurde), sieht man wieder im Vergleich der beiden Klartext-Puffer.
Bleibt also die Frage, wie man so etwas realisieren könnte ... wir hätten hier in unserem konkreten Fall 32 Byte (2 Blöcke) abzgl. der 4 Bytes für den Prüfwert, da der natürlich nicht selbst eingehen kann in die Berechnung und entweder als Nullen interpretiert wird (das haben wir beim Signieren der Firmware ja auch für die Signatur-Datei so gesehen) oder die Berechnung erfolgt erst ab Offset 4.
Trotzdem stellt sich immer noch die Frage, wie man da nun 32-Bit-Werte zur Prüfung erzeugen könnte und da wäre der erste Kandidat eine CRC32-Prüfsumme mit einem der bekannten Polynome. Das habe ich damals auch tatsächlich als erstes treudoof ausprobiert (schließlich hat AVM auch an einer Export-Datei einen solchen Wert zur Prüfung), aber irgendwann fiel mir dann doch auf, daß die libar7cfg.so (die das ja offenbar auch kann) per se gar nichts mit Im- oder Export zu tun hat ... also müßte diese Sicherung vielleicht doch mit irgendeiner Funktion erfolgen, die auch von der Library importiert wird.
Da blieb dann wieder schnell nur noch MD5 übrig ... allerdings erzeugt diese Funktion eben 16 Bytes. Nach ein wenig Probieren (auch mit längeren Werten, die nicht mehr in zwei Blöcke (das Minimum) paßten) stellte sich dann heraus, daß hier tatsächlich erneut MD5 als Digest verwendet wird - es werden aber nur die ersten vier Bytes des Hash-Wertes gespeichert und das mit der Länge hat AVM dann so gelöst, daß diese vier Bytes von der Länge der Daten abgezogen werden (also von den Vielfachen der vollen Blockgröße).
Das ergibt dann 28 Bytes für zwei Blöcke, 44 Bytes für drei Blöcke, usw. - jeweils eben mit dem "Müll", der da gerade im Buffer steht (ich glaube nicht, daß das initialisiert wird mit Zufallsdaten, weiß es aber nicht sicher, schlau wäre es aber in jedem Falle) und damit dafür sorgt, daß dieselben Daten nicht einmal als Hash-Wert dasselbe Ergebnis liefern. Stimmt dann nach dem Dechiffrieren der noch einmal berechnete Hash-Wert (auch wenn es nur die ersten vier Bytes sind, ist die Wahrscheinlichkeit für einen Zufallstreffer gering - geringer als bei CRC-Prüfsummen, wo man das gezielt herbeiführen kann mit dem richtigen "filler"), dann stimmte offensichtlich auch der Key und man kann den entschlüsselten Wert verwenden. Ansonsten nimmt AVM i.d.R. die verschlüsselten Daten genau so, wie sie kommen ... das ergibt dann beim Restore von Freetz-Sicherungen auf anderen Geräten diese lustigen Werte, wie man sie desöfteren in Freetz-Tickets findet.
Code:
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K a41d7248990bc5a36ff6cc85547cb363 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | hd[/B][/COLOR]
bad decrypt
2009859176:error:0606506D:lib(6):func(101):reason(109):NA:0:
00000000 [COLOR="#008000"]4e 2b d5 d3[/COLOR] 00 00 00 0a 50 65 74 65 72 50 61 77 |N+......PeterPaw|
00000010 6e 00 00 a3 95 b5 f8 5d fe 79 34 e1 bc 2c d6 eb |n......].y4..,..|
00000020 af fd a7 2a b6 2b e4 d7 fe 1b 3c ce 07 27 55 89 |...*.+....<..'U.|
00000030
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-cbc -K a41d7248990bc5a36ff6cc85547cb363 -iv 259d80fe94e8aed34e28415e1545d49c -in data_1.bin | dd bs=1 skip=4 count=28 | openssl dgst -md5[/B][/COLOR]
bad decrypt
2006807656:error:0606506D:lib(6):func(101):reason(109):NA:0:
28+0 records in
28+0 records out
28 bytes (28B) copied, 0.009273 seconds, 2.9KB/s
(stdin)= [COLOR="#008000"]4e2bd5d3[/COLOR]52c4acbce309247ad9572032
Wobei AVM da m.E. ohnehin selbst noch einen "off by one" macht, der mich fast wahnsinnig gemacht hat, als ich begonnen hatte, das mit der Verschlüsselung an sich zu untersuchen:
Code:
$ [COLOR="#0000FF"][B]printf 42337a07b84fb9dcff9248a44f5663b3471818d10d9ae7148fcb7a8109d9687eb3d55b184fceb681ca927d969db6b03acb | decoder hexdec | openssl enc -d -aes256 -K a41d7248990bc5a36ff6cc85547cb363 -iv 2dc7a98e732e1dfe8f1ae15530323835 | hd[/B][/COLOR]
bad decrypt
140071090394768:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:evp_enc.c:589:
00000000 e2 30 77 5f [COLOR="#FF0000"]00 00 00 18[/COLOR] [COLOR="#008000"]61 62 63 64 65 66 67 68[/COLOR] |.0w_....abcdefgh|
00000010 [COLOR="#008000"]69 6a 6b 6c 6d 6e 6f 40 71 72 73 2e 63 6f 6d 00 [/COLOR] |[email protected].|
00000020 [COLOR="#AFEEEE"]4f 44 c7 84 1c e9 ae 95 5a a7 2b e7 e9 f8 07 cd[/COLOR] |OD......Z.+.....|
00000030
Auch heute noch machen einige meiner Lösungen Probleme, wenn es zu diesen Grenzfällen bei der Länge und bei deren Berechnung kommt - einfach weil der "Sprung" dafür auch bei der Berechnung des Hash-Wertes in den ersten vier Bytes des Klartextes erfolgt und das dann genauso zu implementieren ist, wie es AVM (meiner Ansicht nach ist das tatsächlich auch ein Fehler und keine Absicht) macht. Die einzige "vernünftige" Erklärung wäre es halt, daß ohne irgendwelche Zufallsdaten am Ende auch bei der Berechnung des Hash-Wertes (über das Längenfeld und den Inhalt) immer derselbe Hash-Wert entstehen würde - vielleicht möchte man das vermeiden. Das finde ich dann angesichts von einfachen MD5-Hashes als Key aber schon weit vorausgedacht und es paßt für mich nicht wirklich zum Rest (komme ich gleich noch drauf).
Parallel dazu gibt es noch den Spezialfall einer Export-Datei ... hier können ja für den Key offensichtlich nicht die Eigenschaften des Gerätes herangezogen werden ... dann ließe sich die Datei ja nicht auf einem anderen Gerät entschlüsseln und importieren. Also muß AVM hier etwas anders machen ... und das fällt einem auch ins Auge, wenn man mal einen Blick in so eine Export-Datei wirft. Dort steht im Header der Datei (i.d.R. vor der Firmware-Version) ein Eintrag mit dem Namen "Password", offensichtlich gefolgt von einem verschlüsselten Wert, wie er auch an anderen Stellen auftritt.
Da wir inzwischen ja schon wissen, wie die Daten aussehen sollten nach der Entschlüsselung (und mit dem Hash-Wert auch selbst prüfen können, ob unser Kennwort stimmt), ist es dann wieder nur eine Fingerübung, diesen Wert solange mit wechselnden Keys zu traktieren, bis wir den passenden gefunden haben (ich hatte mir dafür entsprechende Hilfsprogramme geschrieben). Es gibt ja mindestens zwei Möglichkeiten, denn wir kennen Export-Dateien mit einem benutzerspezifizierten Kennwort und solche, die sich nur auf demselben Gerät wiederherstellen lassen (also wohl wieder den Geräteschlüssel benutzen).
Für die Variante mit dem Kennwort kommt man dann relativ schnell dahinter, daß es sich hier lediglich um den simplen MD5-Hash des Kennwortes handelt (ohne "newline" dahinter) und auch für die Variante ohne, wird man schnell fündig - nachdem man erst einmal verwirrt wurde, daß es sich dabei nicht um denselben Key handelt, wie er für die interne Speicherung verwendet wird. Auch hier ist halt "fröhliches Probieren" angesagt, aber die Permutationen sind wieder nicht so zahlreich - am Ende landet man bei der Seriennummer (bzw. für mich waren das immer irgendwelche Nullen und der Zusammenhang war mir bis vor kurzem gar nicht klar, weil die eben auf fast allen Geräten identisch war) und der MAC-Adresse, jeweils gefolgt von einmal "newline" (0x0A).
Zur Untersuchung brauchen wir erst einmal irgendwelche Daten, wir lassen einfach auf der 7412 mal die Konfiguration mit einem bekannten Kennwort exportieren und suchen uns das Kennwort am Beginn und das "PeterPawn" im Benutzernamen
Code:
# tr069fwupdate configexport YourFritz | sed -n -e '/\$\$\$\$/p'
Password=$$$$[COLOR="#008000"]Q1PR24A6GC6BSRJSYRSWQCUZRFGFZR2QBAK6K6X166VPT16CYAXYN6XS63XRFM4IQP66VM52SEZ5YMJSIXEZNUTOE5OKV2EEJMFDQWLX[/COLOR]
[...]
name = "$$$$[COLOR="#FF0000"]2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46[/COLOR]";
password = "$$$$[COLOR="#FF0000"]6LIY5G1S1PQJNYX1EU5OHSNJJDQYBXHIJI2AFBLCWY3OJP4XV5SVL2SLEHHPAFJP3UAKQ43ECFWR2I46[/COLOR]";
[...]
Code:
# [COLOR="#0000FF"][B]user_password YourFritz | hd[/B][/COLOR]
00000000 [COLOR="#FF0000"]ed 19 b0 84 62 9d 98 fc 45 5f 54 3d 7c 71 1c 47[/COLOR] |....b...E_T=|q.G|
00000010
# [COLOR="#0000FF"][B]decode_secret -D Q1PR24A6GC6BSRJSYRSWQCUZRFGFZR2QBAK6K6X166VPT16CYAXYN6XS63XRFM4IQP66VM52SEZ5YMJSIXEZNUTOE5OKV2EEJMFDQWLX ed19b084629d98fc455f543d7c711c47[/B][/COLOR]
key : (016) 0xed19b084629d98fc455f543d7c711c47
base32 : (104) Q1PR24A6GC6BSRJSYRSWQCUZRFGFZR2QBAK6K6X166VPT16CYAXYN6XS63XRFM4IQP66VM52SEZ5YMJSIXEZNUTOE5OKV2EEJMFDQWLX
input : (065) 0x869f1df41f30be194532c465680a99894c5cc7700815f57efaffeaf9ebe2c02f86fef2ff2f12b3a883fffab3db9133ec313245c996d26e279caaec844b0a385977
iv : (016) 0x869f1df41f30be194532c465680a9989
enc'd : (049) 0x4c5cc7700815f57efaffeaf9ebe2c02f86fef2ff2f12b3a883fffab3db9133ec313245c996d26e279caaec844b0a385977
dec'd : (048) 0x322b877800000020ab908ef57cadde611b8a8919caa632e1ab908ef57cadde611b8a8919caa632e17fa916daab1d9dfc
size : 32
string : no
value : (032) 0x[COLOR="#FF0000"]ab908ef57cadde611b8a8919caa632e1[/COLOR][COLOR="#FFA500"]ab908ef57cadde611b8a8919caa632e1[/COLOR]
Versucht man sich jetzt mit diesem 256-Bit-Key an der Entschlüsselung der einzelnen Einstellungen in der Export-Datei, beißt man aber auf Granit:
Code:
# [COLOR="#0000FF"][B]decode_secret -d 2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46 ab908ef57cadde611b8a8919caa632e1ab908ef57cadde611b8a8919caa632e1[/B][/COLOR]
key : (032) 0xab908ef57cadde611b8a8919caa632e1ab908ef57cadde611b8a8919caa632e1
base32 : (080) 2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46
input : (050) 0xde5e6cc2d6ead1c6b354a27808cd422ef74b4c6d03e1b23f3877ab4039794e6c4639a57e050c6c01a03ce9087df9da37a3bf
iv : (016) 0xde5e6cc2d6ead1c6b354a27808cd422e
enc'd : (034) 0xf74b4c6d03e1b23f3877ab4039794e6c4639a57e050c6c01a03ce9087df9da37a3bf
dec'd : (032) 0x84997cbc4458a4e4b9493f0446ebbfba5b07c84db84a8314070c4fa33e4e7c7d
size : 1146660068
[COLOR="#FF0000"]decode_secret: Error decoding value with the specified key.[/COLOR]
Code:
# [COLOR="#0000FF"][B]decode_secret -D 2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46 ab908ef57cadde611b8a8919caa632e1[/B][/COLOR]
key : (016) 0xab908ef57cadde611b8a8919caa632e1
base32 : (080) 2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46
input : (050) 0xde5e6cc2d6ead1c6b354a27808cd422ef74b4c6d03e1b23f3877ab4039794e6c4639a57e050c6c01a03ce9087df9da37a3bf
iv : (016) 0xde5e6cc2d6ead1c6b354a27808cd422e
enc'd : (034) 0xf74b4c6d03e1b23f3877ab4039794e6c4639a57e050c6c01a03ce9087df9da37a3bf
dec'd : (032) 0x70710d340000000a50657465725061776e000093496a7cad303b716668c09e16
size : 10
string : yes
value : (009) PeterPawn
# [COLOR="#0000FF"][B]decode_secret 2ZPGZQWW4LI3NM1UUJ3ARTKCF22UWTDNAPQ2EPZYO5VUAOLZJZWEMONFPYCQY2ABUA5OSCD46HNDPI46 ab908ef57cadde611b8a8919caa632e1[/B][/COLOR]
[COLOR="#FF0000"]PeterPawn[/COLOR]
# [COLOR="#0000FF"][B]decode_secret 6LIY5G1S1PQJNYX1EU5OHSNJJDQYBXHIJI2AFBLCWY3OJP4XV5SVL2SLEHHPAFJP3UAKQ43ECFWR2I46 ab908ef57cadde611b8a8919caa632e1[/B][/COLOR]
[COLOR="#FF0000"]PeterPawn[/COLOR]
Damit wäre die Beschreibung jetzt tatsächlich durch ... bleibt noch so etwas wie ein Zwischenfazit. Auch wenn die AVM-Verschlüsselung mit einem 256-Bit-Key protzt, ist es am Ende in Wirklichkeit alles nur die Sicherheit, die sich aus AES mit 128-Bit-Schlüsseln ergibt - wenn jeweils die Hälfte der 256 Bits schon vorher bekannt ist (hier sind es eben immer Nullen), dann ist AES-256 ein wenig Augenwischerei, jedenfalls wenn es um den "Schlüsselraum" geht. Ob MD5-Hashes tatsächlich das Mittel der Wahl sind (erst recht bei der einfachsten Variante mit dem Export-Kennwort), muß jeder selbst beurteilen. So, wie es zur Zeit aussieht, verwendet AVM wohl tatsächlich auch eine eigene Implementierung des "Rijndael-Algorithmus" (der später als Standard dann in "Advanced Encryption Standard" (AES) umbenannt wurde) und begeht damit ggf. schon den ersten Fehler. Selbst wenn das vielleicht früher mal erforderlich war, gibt es lange genug auch AES-256 in OpenSSL und es wäre längst an der Zeit gewesen, die eigene Implementierung:
Code:
$ [COLOR="#0000FF"][B]/var/bintools/usr/bin/nm -D -B /lib/libavmcipher.so[/B][/COLOR]
0000153c T AES128_Environ
00001554 T AES192_Environ
0000156c T AES256_Environ
000013a4 T CIPHER_Cleanup
000011b8 T CIPHER_Final
00000f64 T CIPHER_Init
00001054 T CIPHER_Update
00001410 T CIPHER_keylen
00003e0c T DES3_Environ
00003cc8 T DES_Environ
00003bc4 T NULL_Environ
00009428 R S
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0001a8fc B __bss_start
w __cxa_finalize
w __deregister_frame_info
w __register_frame_info
0001a8fc G _edata
0001a930 B _end
0001a8fc B _fbss
0001a710 D _fdata
00006260 T _fini
00000b70 T _ftext
00000aec T _init
00009ef0 R des_SPtrans
0001a920 B des_check_key
00005c20 T des_check_key_parity
00004c98 T des_decrypt3
000060e0 T des_ecb_encrypt
00005518 T des_ede3_cbc_encrypt
00003e30 T des_encrypt
0000450c T des_encrypt2
00004ac4 T des_encrypt3
000060bc T des_fixup_key_parity
00005c70 T des_is_weak_key
000060a4 T des_key_sched
00004e70 T des_ncbc_encrypt
00006054 T des_set_key
00005fcc T des_set_key_checked
00005d04 T des_set_key_unchecked
00005be0 T des_set_odd_parity
U memcmp
U memcpy
U memset
00001944 T rijndaelKeyEncToDec
00001590 T rijndaelKeySched
00001fbc T rijndael_Decrypt
00001aa0 T rijndael_Encrypt
000030a4 T rijndael_blockDecrypt
000026b0 T rijndael_blockEncrypt
00002604 T rijndael_cipherInit
000024a0 T rijndael_makeKey
00003740 T rijndael_padDecrypt
00002d64 T rijndael_padEncrypt
Auch ist es eigentlich verpönt, irgendwelche Keys ganz simpel von einem Hash-Wert (wie beim Export-Kennwort) abzuleiten ... das ist anfällig für Attacken und die üblichen Funktionen zur Ableitung eines Keys von einem Kennwort (PBKDF2 hatte ich oben schon erwähnt) fügen diesem Vorgang der Kennwort-Generierung (auch ohne "salt", wenn also aus einem identischen Kennwort auch ein identischer Key werden soll) einiges an Komplexität hinzu, um genau solche Angreifer passend zu verlangsamen. Mit vorausberechneten MD5-Hashes (wenn sich das überhaupt lohnt) ist das jedenfalls relativ(!) leicht angreifbar - es macht bloß niemand, weil sich der Aufwand vermutlich nicht lohnt. Aber "sicher" ist eben etwas anderes ... zwischen einem "ausgezeichnet" und einem "genügend" können da Welten liegen.
-Seit einiger Zeit gibt es bei AVM auch den "Dateityp" CRYPTEDBINFILE in einer export-Datei. Bisher habe ich das nur für die "dvb.cfg" bei den Geräten gesehen, die eine TV-Funktion (für DVB-C) unterstützen.
Daher steht man (ohne 6490, 6590 oder einen DVB-C-Repeater) erst einmal vor der Aufgabe, sich sein Material für eine genauere Untersuchung zu beschaffen und dann stellt man schnell fest, daß es dem Export ziemlich egal ist, ob es eine Datei "/var/flash/dvb.cfg" gibt oder nicht bzw. ob der Node 219 im TFFS Daten enthält oder nicht. Es muß also noch irgendeinen anderen Auslöser geben, wenn die Box sich zum Export der "dvb.cfg" entschließt und da liegt natürlich die hervorstechendste Eigenschaft am nächsten ... und das wäre die Variable "CONFIG_LINEARTV=y". Diese beeinflußt nicht nur die Anzeige des DVB-C-Menüs bei den DOCSIS-Boxen, sie regelt auch, ob "tr069fwupdate configexport" die "dvb.cfg" berücksichtigt oder nicht.
Das läßt sich ja recht einfach testen und so entstand das folgende Shell-Skript, das man auf seiner FRITZ!Box ausführen kann, um sich den Inhalt einer solchen CRYPTEDBINFILE-Datei ausgeben zu lassen:
Code:
1 #! /bin/sh
2 #
3 # create an export file with a CRYPTEDBINFILE section
4 #
5 # MUST BE EXECUTED ON A FRITZ!OS DEVICE
6 #
7 # remove the character device for an existing dvb.cfg file
8 #
9 rm /var/flash/dvb.cfg 2>/dev/null
10 #
11 # create our own file
12 #
13 cat >/var/flash/dvb.cfg <<'EOT'
14 /*
15 * /var/flash/dvb.cfg
16 * Sun May 14 20:57:35 2017
17 */
18
19 meta { encoding = "utf-8"; }
20
21 version_dvb {
22 revision = "$Revision: 1.0 $";
23 creatversion = "1.00.00";
24 }
25
26
27 dvbcfg {
28 nit_pid = 16;
29 network_id = 61444;
30 network_name = "Kabel Deutschland";
31 bouquets = 32;
32 tv_services = 101;
33 radio_services = 67;
34 other_services = 0;
35 channels {
36 sid = 53019;
37 tsid = 10008;
38 frequency = 442000000;
39 lcn_nordig = 0;
40 lcn_eacem = 0;
41 flags = 32;
42 url = 239.2.1.1;
43 provider = "";
44 name = "53019";
45 type = 0;
46 ca_mode = 0;
47 pid_pmt = 220;
48 pid_pcr = 0;
49 pid_cnt = 0;
50 }
51 }
52
53
54 // EOF
55 EOT
56 #
57 # declare TV functions active
58 #
59 export CONFIG_LINEARTV=y
60 #
61 # export the data with or without password
62 #
63 # ATTENTION:
64 #
65 # It looks like AVM disabled (accident or not, that's the question) the ability
66 # to export data without a password, since 2FA was added to the firmware.
67 # Exporting a file without password is not functioning on any of my 06.83 devices.
68 #
69 # We strip off all lines around the encrypted content.
70 #
71 tr069fwupdate configexport $1 | sed -n -e "/\*\*\*\* CRYPTEDBINFILE/,/\*\*\*\* END OF FILE/p" | sed -e "1d;\$d"
72 #
73 # data should be visible on STDOUT now
74 #
Das erzeugt also eine eigene "dvb.cfg" (eine existierende sollte unverändert bleiben und nach einem Neustart wieder zur Verfügung stehen - außerdem braucht man keine großen Datenmengen bei einer Analyse, das macht es nur unhandlicher), exportiert die Einstellungen mit oder ohne ein Kennwort (das müßte man beim Aufruf des Skripts als ersten Parameter angeben) und sucht sich dann aus der Datei nur den Inhalt heraus, der wirklich diese "dvb.cfg" darstellt - der ist einerseits verschlüsselt und andererseits - wie alle BINFILE-Einträge - in hexadezimaler Kodierung gespeichert.
Ruft man das also auf der Box auf (ich nehme eine 7490), ergibt das folgende Ausgabe:
Code:
$ [B]cryptedbin.sh YourFritz[/B]
[COLOR="#FF0000"]3824070A9E395A36B5B21810A59CA905[/COLOR]10C340D708811AFD63C01F1E46937C216D1C0EAEED681953
BD5D4AB181BD6CE5A7D36BE4D1F13A018A892A6B7CB4E6C243DE33DD8F1AAF23786BE0FFA8C589F7
534037A5257A173213CE6D0D8FF2624219429C4088F3D136235C17D86C3E8661FCE26DC638788F08
AFAA543981633FC14B6C4EF17DDBD14CA35E2083AA2B44AC035887DB1F1798D59D4D8B8D329AAD13
13D477C36A25DE00232B21D24F243765C53CE9BB8FE6E42B1B985ED1DC3247DC8FC848973C34BEF9
A0DCC1F8DF847256B19BECCDB3BD988028FC61DE36DB5947E4E527F8B6B2C4F6611BF81C4FF2EC2E
2A15036E895917B7E1B480356E54268C744B314BC8EA09E6B9B25E6491EBDBADA69F8352EC99D6F2
2012740D083E2F1C0ADDC7BD0ACB861663973FA6A699CD6D0F6C44107D23A751A54A41EF60DE6848
6A6D18C3B956DE3665CCBCB96BD713A5D1E22A7CE5B846B4BBEE669AC80C5519AA29BBF02AEFE395
8FEC20CE31BA5CE65FC80A2C000433E563299AE339A8E90BDFBD22CD4C0D5F1DA12D9C915437B6B1
4C8D8A8E4F4801877C9502688A067085C8C0C83F661F90575C5C1F7AA970EBA20B35B988075FDF9E
F574D6FD40C9A4D38FDD501D1C0EA2E2B0EF73CDA5AE9C4ABF99999532E5E7B54CA2D83819E5C33B
6E793E80CF8656EC5CA5161264A206B055218660A36BE5466E0AC66B713B74902D3EB447E09280BC
3C147F9B6FCE422D7FC7C5AB9648B6DEAAD681DCAD0A5EE52D3EB447E09280BC3C147F9B6FCE422D
B17CE824483BF1B6908702CDC2F629C7B48BDD03331BAB2A3A757E66B1E6A9C88A5F15162B95A189
23E3B802AD9AD17D47667B548E72127A2CB0C689A0E8EDB82C37D19AA98E6D08B286B1B5A486E615
370AE33FF1AC6FCBB47BEA8B9E464DE8A27700898CD719F92F16766F307761884FEDF8FF5A760097
B63F20F99567396CE0C8AA07E79F40A097244659275F06BD37C66FD0DC4DCF5E47E7B0A4CB1D9CDB
1E8B1BDBFF6331A4B29D905AD75E837753F1E198715A600FA1209427F6E0D0F4CE9979CE58752F6B
FE5A1FC8FC145826D290AE1095FC9BB50D3BBEF493C46EAEE3BED1ABE12C35A0FA2CB9373BD74D09
64649C720317E55A18B8AF13C354974419ACECA1091ABED474C10E7C5B2B1B51F18687FBB6D71124
47642643B8B56D8B8A4C9A787B3CC63C603088C7E81F948C5A7A6BB42D625B5EDBB1B1F102A0F035
4C8A464D7278993F20C327EA468AB46A
$ [COLOR="#0000FF"][B]cryptedbin.sh YourFritz[/B][/COLOR]
[COLOR="#FF0000"]9C41FB65730CE1E69CB93314218B[/COLOR]10EB10C340D708811AFD63C01F1E46937C216D1C0EAEED681953
BD5D4AB181BD6CE5A7D36BE4D1F13A018A892A6B7CB4E6C243DE33DD8F1AAF23786BE0FFA8C589F7
534037A5257A173213CE6D0D8FF2624219429C4088F3D136235C17D86C3E8661FCE26DC638788F08
AFAA543981633FC14B6C4EF17DDBD14CA35E2083AA2B44AC035887DB1F1798D59D4D8B8D329AAD13
13D477C36A25DE00232B21D24F243765C53CE9BB8FE6E42B1B985ED1DC3247DC8FC848973C34BEF9
A0DCC1F8DF847256B19BECCDB3BD988028FC61DE36DB5947E4E527F8B6B2C4F6611BF81C4FF2EC2E
2A15036E895917B7E1B480356E54268C744B314BC8EA09E6B9B25E6491EBDBADA69F8352EC99D6F2
2012740D083E2F1C0ADDC7BD0ACB861663973FA6A699CD6D0F6C44107D23A751A54A41EF60DE6848
6A6D18C3B956DE3665CCBCB96BD713A5D1E22A7CE5B846B4BBEE669AC80C5519AA29BBF02AEFE395
8FEC20CE31BA5CE65FC80A2C000433E563299AE339A8E90BDFBD22CD4C0D5F1DA12D9C915437B6B1
4C8D8A8E4F4801877C9502688A067085C8C0C83F661F90575C5C1F7AA970EBA20B35B988075FDF9E
F574D6FD40C9A4D38FDD501D1C0EA2E2B0EF73CDA5AE9C4ABF99999532E5E7B54CA2D83819E5C33B
6E793E80CF8656EC5CA5161264A206B055218660A36BE5466E0AC66B713B74902D3EB447E09280BC
3C147F9B6FCE422D7FC7C5AB9648B6DEAAD681DCAD0A5EE52D3EB447E09280BC3C147F9B6FCE422D
B17CE824483BF1B6908702CDC2F629C7B48BDD03331BAB2A3A757E66B1E6A9C88A5F15162B95A189
23E3B802AD9AD17D47667B548E72127A2CB0C689A0E8EDB82C37D19AA98E6D08B286B1B5A486E615
370AE33FF1AC6FCBB47BEA8B9E464DE8A27700898CD719F92F16766F307761884FEDF8FF5A760097
B63F20F99567396CE0C8AA07E79F40A097244659275F06BD37C66FD0DC4DCF5E47E7B0A4CB1D9CDB
1E8B1BDBFF6331A4B29D905AD75E837753F1E198715A600FA1209427F6E0D0F4CE9979CE58752F6B
FE5A1FC8FC145826D290AE1095FC9BB50D3BBEF493C46EAEE3BED1ABE12C35A0FA2CB9373BD74D09
64649C720317E55A18B8AF13C354974419ACECA1091ABED474C10E7C5B2B1B51F18687FBB6D71124
47642643B8B56D8B8A4C9A787B3CC63C603088C7E81F948C5A7A6BB42D625B5EDBB1B1F102A0F035
4C8A464D7278993F20C327EA468AB46A
$ [COLOR="#0000FF"][B]cryptedbin.sh YourFritz[/B][/COLOR]
[COLOR="#FF0000"]9702F180ABE634297AC4DE61977D289E[/COLOR]10C340D708811AFD63C01F1E46937C216D1C0EAEED681953
BD5D4AB181BD6CE5A7D36BE4D1F13A018A892A6B7CB4E6C243DE33DD8F1AAF23786BE0FFA8C589F7
534037A5257A173213CE6D0D8FF2624219429C4088F3D136235C17D86C3E8661FCE26DC638788F08
AFAA543981633FC14B6C4EF17DDBD14CA35E2083AA2B44AC035887DB1F1798D59D4D8B8D329AAD13
13D477C36A25DE00232B21D24F243765C53CE9BB8FE6E42B1B985ED1DC3247DC8FC848973C34BEF9
A0DCC1F8DF847256B19BECCDB3BD988028FC61DE36DB5947E4E527F8B6B2C4F6611BF81C4FF2EC2E
2A15036E895917B7E1B480356E54268C744B314BC8EA09E6B9B25E6491EBDBADA69F8352EC99D6F2
2012740D083E2F1C0ADDC7BD0ACB861663973FA6A699CD6D0F6C44107D23A751A54A41EF60DE6848
6A6D18C3B956DE3665CCBCB96BD713A5D1E22A7CE5B846B4BBEE669AC80C5519AA29BBF02AEFE395
8FEC20CE31BA5CE65FC80A2C000433E563299AE339A8E90BDFBD22CD4C0D5F1DA12D9C915437B6B1
4C8D8A8E4F4801877C9502688A067085C8C0C83F661F90575C5C1F7AA970EBA20B35B988075FDF9E
F574D6FD40C9A4D38FDD501D1C0EA2E2B0EF73CDA5AE9C4ABF99999532E5E7B54CA2D83819E5C33B
6E793E80CF8656EC5CA5161264A206B055218660A36BE5466E0AC66B713B74902D3EB447E09280BC
3C147F9B6FCE422D7FC7C5AB9648B6DEAAD681DCAD0A5EE52D3EB447E09280BC3C147F9B6FCE422D
B17CE824483BF1B6908702CDC2F629C7B48BDD03331BAB2A3A757E66B1E6A9C88A5F15162B95A189
23E3B802AD9AD17D47667B548E72127A2CB0C689A0E8EDB82C37D19AA98E6D08B286B1B5A486E615
370AE33FF1AC6FCBB47BEA8B9E464DE8A27700898CD719F92F16766F307761884FEDF8FF5A760097
B63F20F99567396CE0C8AA07E79F40A097244659275F06BD37C66FD0DC4DCF5E47E7B0A4CB1D9CDB
1E8B1BDBFF6331A4B29D905AD75E837753F1E198715A600FA1209427F6E0D0F4CE9979CE58752F6B
FE5A1FC8FC145826D290AE1095FC9BB50D3BBEF493C46EAEE3BED1ABE12C35A0FA2CB9373BD74D09
64649C720317E55A18B8AF13C354974419ACECA1091ABED474C10E7C5B2B1B51F18687FBB6D71124
47642643B8B56D8B8A4C9A787B3CC63C603088C7E81F948C5A7A6BB42D625B5EDBB1B1F102A0F035
4C8A464D7278993F20C327EA468AB46A
[ Kleiner Einschub zwischendurch ... es sieht für mich fast so aus, als hätte AVM (absichtlich oder versehentlich will ich nicht beurteilen) mit der Einführung der 2FA auch die Möglichkeit gekillt (im GUI war das durch Abfragen ohnehin schon verhindert), die export-Datei auch ohne Kennwort zu erzeugen. Das macht dann ein paar von mir kritisierte Zeichenketten in der TR-069-Implementierung noch rätselhafter ... wenn dort (zumindest dem Text nach, ob es wirklich ausgelöst wird bei einem "Upload()"-Call vom ACS muß ich erst mal wieder probieren) die Datei ohne Kennwort per "tr069fwupdate" exportiert und per "ftpput" auf einen Server geladen werden soll, funktioniert das ggf. nicht mehr. Bei mir hängt sich jedenfalls ein Aufruf von "tr069fwupdate configexport" irgendwo kurz vor dem Ende der Datei auf - auf einer 7490, einer 7412 und einer 6490, jeweils mit 06.83 und unabhängig davon, ob 2FA aktiviert ist oder nicht. Daher funktionierte der Export dieser CRYPTEDBINFILE-Zeilen oben bei mir auch nur mit Angabe eines Kennworts. ]
Zurück zur Analyse von dem, was wir da in den Daten dieser verschlüsselten "dvb.cfg" sehen ... dieses Verhalten ist viel "verräterischer", als man auf den ersten Blick vermuten würde. Wenn nämlich mehrmaliger Export immer dieselben Daten erzeugt (die ersten 16 Byte lassen wir mal aus bei der Betrachtung) und so eine Export-Datei ansonsten aber mit einem Zufallswert (der im Kopf in "Password" gespeichert wird) verschlüsselt wird (und das ist mal sicher), dann kann für die Verschlüsselung dieses CRYPTEDBINFILE ja nicht der zufällige Schlüssel verwendet werden ... das ergäbe ein anderes Chiffrat bei jedem Export. Probiert man dann noch einen Export mit einem anderen Passwort aus und sieht, daß sich die Daten dabei zwar ändern, aber auch für dieses Passwort wieder mehrfach dieselben Daten als Chiffrat erzeugt werden, dann darf man schon mal annehmen, daß hier genau derselbe Key verwendet wird, wie für die Verschlüsselung des Inhalts im "Password"-Feld.
Dieses Bild - identisches Chiffrat bei identischem Key - ist typisch für zwei Sachen ... erstens für das Arbeiten ohne einen zufälligen IV (was das ist und ob man das auch in grün bestellen kann, bitte bei Google nachschlagen) und zweiten für das Verwenden eines recht einfachen Verschlüsselungsverfahrens, wo jeder Block immer wieder mit denselben Daten verschlüsselt wird. Das nennt sich dann "Electronic Codebook Mode" (ECB) und welche Auswirkungen solche Algorithmen haben bzw. wie man diesen entgegenwirkt, zeigt die englische Seite der Wikipedia zu den "block modes" recht gut (die deutsche Seite kann ihr nicht das Wasser reichen): https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
[ Das Fehlen eines IV als zusätzliche variable Komponente ist am Ende damit gleichzusetzen, daß dort lauter binäre Nullen verwendet werden ... da diese Algorithmen in der Regel mit einem logischen XOR arbeiten (dabei wird jedes Bit des einen Wertes, für das im zweiten ein Bit gesetzt ist, negiert), ist das für ein XOR eine Maske, die gar nichts am Ausgangswert ändert. Zudem verwendet der ECB-Mode ohnehin keinen IV, aber für eine einfachere Parametrierung der Skript-Dateien habe ich da wenig geändert und setze halt einen IV von 0, worüber sich "openssl" ggf. beschwert, was man aber ignorieren kann. ]
Ausgerüstet mit diesem Wissen, können wir nun mal versuchen, die Daten aus so einer verschlüsselten Datei zu dechiffrieren. Dazu wandeln wir erst einmal das Chiffrat in binäre Daten um und speichern es ab, damit wir nicht immer mit wechselnden Werten in den ersten 16 Bytes konfrontiert werden:
Code:
$ [COLOR="#0000FF"][B]cryptedbin.sh YourFritz | yf_hex2bin > crypted.bin[/B][/COLOR]
$ [COLOR="#0000FF"][B]hd crypted.bin[/B][/COLOR]
00000000 [COLOR="#FF0000"]43 0c 73 1d c1 69 ee 2d 47 8e 0b 59 e5 bf fa 83[/COLOR] |C.s..i.-G..Y....|
00000010 10 c3 40 d7 08 81 1a fd 63 c0 1f 1e 46 93 7c 21 |[email protected].|!|
00000020 6d 1c 0e ae ed 68 19 53 bd 5d 4a b1 81 bd 6c e5 |m....h.S.]J...l.|
00000030 a7 d3 6b e4 d1 f1 3a 01 8a 89 2a 6b 7c b4 e6 c2 |..k...:...*k|...|
00000040 43 de 33 dd 8f 1a af 23 78 6b e0 ff a8 c5 89 f7 |C.3....#xk......|
00000050 53 40 37 a5 25 7a 17 32 13 ce 6d 0d 8f f2 62 42 |S@7.%z.2..m...bB|
00000060 19 42 9c 40 88 f3 d1 36 23 5c 17 d8 6c 3e 86 61 |[email protected]#\..l>.a|
00000070 fc e2 6d c6 38 78 8f 08 af aa 54 39 81 63 3f c1 |..m.8x....T9.c?.|
00000080 4b 6c 4e f1 7d db d1 4c a3 5e 20 83 aa 2b 44 ac |KlN.}..L.^ ..+D.|
00000090 03 58 87 db 1f 17 98 d5 9d 4d 8b 8d 32 9a ad 13 |.X.......M..2...|
000000a0 13 d4 77 c3 6a 25 de 00 23 2b 21 d2 4f 24 37 65 |..w.j%..#+!.O$7e|
000000b0 c5 3c e9 bb 8f e6 e4 2b 1b 98 5e d1 dc 32 47 dc |.<.....+..^..2G.|
000000c0 8f c8 48 97 3c 34 be f9 a0 dc c1 f8 df 84 72 56 |..H.<4........rV|
000000d0 b1 9b ec cd b3 bd 98 80 28 fc 61 de 36 db 59 47 |........(.a.6.YG|
000000e0 e4 e5 27 f8 b6 b2 c4 f6 61 1b f8 1c 4f f2 ec 2e |..'.....a...O...|
000000f0 2a 15 03 6e 89 59 17 b7 e1 b4 80 35 6e 54 26 8c |*..n.Y.....5nT&.|
00000100 74 4b 31 4b c8 ea 09 e6 b9 b2 5e 64 91 eb db ad |tK1K......^d....|
00000110 a6 9f 83 52 ec 99 d6 f2 20 12 74 0d 08 3e 2f 1c |...R.... .t..>/.|
00000120 0a dd c7 bd 0a cb 86 16 63 97 3f a6 a6 99 cd 6d |........c.?....m|
00000130 0f 6c 44 10 7d 23 a7 51 a5 4a 41 ef 60 de 68 48 |.lD.}#.Q.JA.`.hH|
00000140 6a 6d 18 c3 b9 56 de 36 65 cc bc b9 6b d7 13 a5 |jm...V.6e...k...|
00000150 d1 e2 2a 7c e5 b8 46 b4 bb ee 66 9a c8 0c 55 19 |..*|..F...f...U.|
00000160 aa 29 bb f0 2a ef e3 95 8f ec 20 ce 31 ba 5c e6 |.)..*..... .1.\.|
00000170 5f c8 0a 2c 00 04 33 e5 63 29 9a e3 39 a8 e9 0b |_..,..3.c)..9...|
00000180 df bd 22 cd 4c 0d 5f 1d a1 2d 9c 91 54 37 b6 b1 |..".L._..-..T7..|
00000190 4c 8d 8a 8e 4f 48 01 87 7c 95 02 68 8a 06 70 85 |L...OH..|..h..p.|
000001a0 c8 c0 c8 3f 66 1f 90 57 5c 5c 1f 7a a9 70 eb a2 |...?f..W\\.z.p..|
000001b0 0b 35 b9 88 07 5f df 9e f5 74 d6 fd 40 c9 a4 d3 |.5..._...t..@...|
000001c0 8f dd 50 1d 1c 0e a2 e2 b0 ef 73 cd a5 ae 9c 4a |..P.......s....J|
000001d0 bf 99 99 95 32 e5 e7 b5 4c a2 d8 38 19 e5 c3 3b |....2...L..8...;|
000001e0 6e 79 3e 80 cf 86 56 ec 5c a5 16 12 64 a2 06 b0 |ny>...V.\...d...|
000001f0 55 21 86 60 a3 6b e5 46 6e 0a c6 6b 71 3b 74 90 |U!.`.k.Fn..kq;t.|
00000200 2d 3e b4 47 e0 92 80 bc 3c 14 7f 9b 6f ce 42 2d |->.G....<...o.B-|
00000210 7f c7 c5 ab 96 48 b6 de aa d6 81 dc ad 0a 5e e5 |.....H........^.|
00000220 2d 3e b4 47 e0 92 80 bc 3c 14 7f 9b 6f ce 42 2d |->.G....<...o.B-|
00000230 b1 7c e8 24 48 3b f1 b6 90 87 02 cd c2 f6 29 c7 |.|.$H;........).|
00000240 b4 8b dd 03 33 1b ab 2a 3a 75 7e 66 b1 e6 a9 c8 |....3..*:u~f....|
00000250 8a 5f 15 16 2b 95 a1 89 23 e3 b8 02 ad 9a d1 7d |._..+...#......}|
00000260 47 66 7b 54 8e 72 12 7a 2c b0 c6 89 a0 e8 ed b8 |Gf{T.r.z,.......|
00000270 2c 37 d1 9a a9 8e 6d 08 b2 86 b1 b5 a4 86 e6 15 |,7....m.........|
00000280 37 0a e3 3f f1 ac 6f cb b4 7b ea 8b 9e 46 4d e8 |7..?..o..{...FM.|
00000290 a2 77 00 89 8c d7 19 f9 2f 16 76 6f 30 77 61 88 |.w....../.vo0wa.|
000002a0 4f ed f8 ff 5a 76 00 97 b6 3f 20 f9 95 67 39 6c |O...Zv...? ..g9l|
000002b0 e0 c8 aa 07 e7 9f 40 a0 97 24 46 59 27 5f 06 bd |......@..$FY'_..|
000002c0 37 c6 6f d0 dc 4d cf 5e 47 e7 b0 a4 cb 1d 9c db |7.o..M.^G.......|
000002d0 1e 8b 1b db ff 63 31 a4 b2 9d 90 5a d7 5e 83 77 |.....c1....Z.^.w|
000002e0 53 f1 e1 98 71 5a 60 0f a1 20 94 27 f6 e0 d0 f4 |S...qZ`.. .'....|
000002f0 ce 99 79 ce 58 75 2f 6b fe 5a 1f c8 fc 14 58 26 |..y.Xu/k.Z....X&|
00000300 d2 90 ae 10 95 fc 9b b5 0d 3b be f4 93 c4 6e ae |.........;....n.|
00000310 e3 be d1 ab e1 2c 35 a0 fa 2c b9 37 3b d7 4d 09 |.....,5..,.7;.M.|
00000320 64 64 9c 72 03 17 e5 5a 18 b8 af 13 c3 54 97 44 |dd.r...Z.....T.D|
00000330 19 ac ec a1 09 1a be d4 74 c1 0e 7c 5b 2b 1b 51 |........t..|[+.Q|
00000340 f1 86 87 fb b6 d7 11 24 47 64 26 43 b8 b5 6d 8b |.......$Gd&C..m.|
00000350 8a 4c 9a 78 7b 3c c6 3c 60 30 88 c7 e8 1f 94 8c |.L.x{<.<`0......|
00000360 5a 7a 6b b4 2d 62 5b 5e db b1 b1 f1 02 a0 f0 35 |Zzk.-b[^.......5|
00000370 4c 8a 46 4d 72 78 99 3f 20 c3 27 ea 46 8a b4 6a |L.FMrx.? .'.F..j|
Code:
$ [COLOR="#0000FF"][B]user_password YourFritz | hd[/B][/COLOR]
00000000 [COLOR="#008000"]ed 19 b0 84 62 9d 98 fc 45 5f 54 3d 7c 71 1c 47[/COLOR] |....b...E_T=|q.G|
00000010
$ [COLOR="#0000FF"][B]openssl enc -d -aes-256-ecb -K ed19b084629d98fc455f543d7c711c47 -in crypted.bin | hd[/B][/COLOR]
00000000 [COLOR="#FF0000"]1b e1 8d 70[/COLOR] 2f 2a 0a 20 2a 20 2f 76 61 72 2f 66 |...p/*. * /var/f|
00000010 [COLOR="#008000"][B]6c 61 73 68 2f 64 76 62 2e 63 66 67 0a 20 2a 20[/B][/COLOR] |lash/dvb.cfg. * |
00000020 53 75 6e 20 4d 61 79 20 31 34 20 32 30 3a 35 37 |Sun May 14 20:57|
00000030 3a 33 35 20 32 30 31 37 0a 20 2a 2f 0a 0a 6d 65 |:35 2017. */..me|
00000040 74 61 20 7b 20 65 6e 63 6f 64 69 6e 67 20 3d 20 |ta { encoding = |
00000050 22 75 74 66 2d 38 22 3b 20 7d 0a 0a 76 65 72 73 |"utf-8"; }..vers|
00000060 69 6f 6e 5f 64 76 62 20 7b 0a 20 20 20 20 20 20 |ion_dvb {. |
00000070 20 20 72 65 76 69 73 69 6f 6e 20 3d 20 22 24 52 | revision = "$R|
00000080 65 76 69 73 69 6f 6e 3a 20 31 2e 30 20 24 22 3b |evision: 1.0 $";|
00000090 0a 20 20 20 20 20 20 20 20 63 72 65 61 74 76 65 |. creatve|
000000a0 72 73 69 6f 6e 20 3d 20 22 31 2e 30 30 2e 30 30 |rsion = "1.00.00|
000000b0 22 3b 0a 7d 0a 0a 0a 64 76 62 63 66 67 20 7b 0a |";.}...dvbcfg {.|
000000c0 20 20 20 20 20 20 20 20 6e 69 74 5f 70 69 64 20 | nit_pid |
000000d0 3d 20 31 36 3b 0a 20 20 20 20 20 20 20 20 6e 65 |= 16;. ne|
000000e0 74 77 6f 72 6b 5f 69 64 20 3d 20 36 31 34 34 34 |twork_id = 61444|
000000f0 3b 0a 20 20 20 20 20 20 20 20 6e 65 74 77 6f 72 |;. networ|
00000100 6b 5f 6e 61 6d 65 20 3d 20 22 4b 61 62 65 6c 20 |k_name = "Kabel |
00000110 44 65 75 74 73 63 68 6c 61 6e 64 22 3b 0a 20 20 |Deutschland";. |
00000120 20 20 20 20 20 20 62 6f 75 71 75 65 74 73 20 3d | bouquets =|
00000130 20 33 32 3b 0a 20 20 20 20 20 20 20 20 74 76 5f | 32;. tv_|
00000140 73 65 72 76 69 63 65 73 20 3d 20 31 30 31 3b 0a |services = 101;.|
00000150 20 20 20 20 20 20 20 20 72 61 64 69 6f 5f 73 65 | radio_se|
00000160 72 76 69 63 65 73 20 3d 20 36 37 3b 0a 20 20 20 |rvices = 67;. |
00000170 20 20 20 20 20 6f 74 68 65 72 5f 73 65 72 76 69 | other_servi|
00000180 63 65 73 20 3d 20 30 3b 0a 20 20 20 20 20 20 20 |ces = 0;. |
00000190 20 63 68 61 6e 6e 65 6c 73 20 7b 0a 20 20 20 20 | channels {. |
000001a0 20 20 20 20 20 20 20 20 20 20 20 20 73 69 64 20 | sid |
000001b0 3d 20 35 33 30 31 39 3b 0a 20 20 20 20 20 20 20 |= 53019;. |
000001c0 20 20 20 20 20 20 20 20 20 74 73 69 64 20 3d 20 | tsid = |
000001d0 31 30 30 30 38 3b 0a 20 20 20 20 20 20 20 20 20 |10008;. |
000001e0 20 20 20 20 20 20 20 66 72 65 71 75 65 6e 63 79 | frequency|
000001f0 20 3d 20 34 34 32 30 30 30 30 30 30 3b 0a 20 20 | = 442000000;. |
00000200 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 63 | lc|
00000210 6e 5f 6e 6f 72 64 69 67 20 3d 20 30 3b 0a 20 20 |n_nordig = 0;. |
00000220 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 63 | lc|
00000230 6e 5f 65 61 63 65 6d 20 3d 20 30 3b 0a 20 20 20 |n_eacem = 0;. |
00000240 20 20 20 20 20 20 20 20 20 20 20 20 20 66 6c 61 | fla|
00000250 67 73 20 3d 20 33 32 3b 0a 20 20 20 20 20 20 20 |gs = 32;. |
00000260 20 20 20 20 20 20 20 20 20 75 72 6c 20 3d 20 32 | url = 2|
00000270 33 39 2e 32 2e 31 2e 31 3b 0a 20 20 20 20 20 20 |39.2.1.1;. |
00000280 20 20 20 20 20 20 20 20 20 20 70 72 6f 76 69 64 | provid|
00000290 65 72 20 3d 20 22 22 3b 0a 20 20 20 20 20 20 20 |er = "";. |
000002a0 20 20 20 20 20 20 20 20 20 6e 61 6d 65 20 3d 20 | name = |
000002b0 22 35 33 30 31 39 22 3b 0a 20 20 20 20 20 20 20 |"53019";. |
000002c0 20 20 20 20 20 20 20 20 20 74 79 70 65 20 3d 20 | type = |
000002d0 30 3b 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 |0;. |
000002e0 20 20 20 63 61 5f 6d 6f 64 65 20 3d 20 30 3b 0a | ca_mode = 0;.|
000002f0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | |
00000300 70 69 64 5f 70 6d 74 20 3d 20 32 32 30 3b 0a 20 |pid_pmt = 220;. |
00000310 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 70 | p|
00000320 69 64 5f 70 63 72 20 3d 20 30 3b 0a 20 20 20 20 |id_pcr = 0;. |
00000330 20 20 20 20 20 20 20 20 20 20 20 20 70 69 64 5f | pid_|
00000340 63 6e 74 20 3d 20 30 3b 0a 20 20 20 20 20 20 20 |cnt = 0;. |
00000350 7d 0a 7d 0a 0a 0a 2f 2f 20 45 4f 46 0a [COLOR="#00FF00"][B]00 00 00[/B][/COLOR] |}.}...// EOF....|
00000360 [COLOR="#FF0000"][B]41 56 4d 00 00 00 00 00 00 00 00 00 00 00 03 59[/B][/COLOR] |AVM............Y|
Das Ende der Datei ist auch nicht schwer zu interpretieren ... da wird offensichtlich der eigentliche Inhalt der Datei (zzgl. 4 Byte am Beginn) auf die nächste 16-Bytes-Grenze mit Nullen aufgefüllt und am Ende ein weiterer Block mit "AVM", 2x (Int32)-Null und der Länge der eigentlichen Daten hinzugefügt. Damit hat man wieder den Marker, ob die Entschlüsselung möglich war und gleichzeitig die originale Dateilänge. Bleibt noch die Frage, wofür die ersten vier Bytes wohl gut sein sollen ... die sind ja jedesmal anders und das ergibt auch den ständig abweichenden ersten Block im Chiffrat. Wenn das wirklich ein zufälliger Wert ist, dann würde der ja auch dafür sorgen, daß das Chiffrat jedesmal unterschiedlich ist, wenn - ja, wenn - man denn einen anderen Mode als ECB verwenden würde.
Genau aus diesem Grund (es gibt ansonsten keine logisch begründbare Notwendigkeit für diese Zufallsdaten und es müssen auch zufällige Daten sein und keine CRC-Prüfsumme oder gar wieder ein Hash-Wert, der wäre ja bei ansonsten identischem Inhalt auch immer wieder derselbe) halte ich das auch für einen Anfängerfehler, den da jemand bei AVM begangen hat. Ich frage mich nur, warum dieses Problem nicht anhand des Chiffrates oder bei einer Kontrolle des Codes durch einen zweiten Mitarbeiter aufgefallen ist. So, wie man das hier gemacht hat, hätte man dieses CRYPTEDBINFILE auch gleich ganz weglassen können, denn das zu "knacken", ist eigentlich wieder sehr einfach. Bleibt als Erklärung also nur die Vermutung, daß es nur darum ging, das irgendwie zu verschleiern, was da drin steht.
Ich hoffe mal, daß AVM da trotzdem nachbessert (mit einem CRYPTEDBINFILE2, damit alte Dateien weiterhin gültig bleiben) ... auch wenn es bei AES noch(?) keine "known plaintext attacks" (KPA) gibt. Aber der Inhalt des zweiten Blocks (oben grün) ist auch als Klartext bereits bekannt, der variable Teil mit dem Datum kommt erst nach Offset 32. Aber das betrifft ja alles ohnehin nur DOCSIS-Boxen und den DVB-C-Repeater ...
-Wenn es jedenfalls um das Nachbauen geht, so habe ich seit drei Jahren da die verschiedensten Lösungen am Start gehabt ... je nachdem, worum es dabei jeweils ging und wenn irgendetwas Neues gebraucht wurde, habe ich auch eher etwas Vorhandenes genommen, geändert und dann parallel zur "Vorlage" verwendet, anstatt das in eine "gemeinsame" Code-Basis zu integrieren. So ein "refactoring" ist eben ein erheblicher Aufwand und mich juckte es eher nicht, wenn ich denselben Code immer wieder verwendet habe ... es gab einfach keine Notwendigkeit, die Sachen irgendwie zusammenzufassen.
Das war jetzt für die Veröffentlichung dann wieder etwas anderes und so bin ich (wohl oder übel) hingegangen und habe einiges "from scratch" neu gemacht ... zwar mit älteren Dateien als Vorlage, aber im Prinzip ist wirklich alles neu (das war der Mai).
-Inzwischen (Stand 08.06.2017) sind die Shell-Skripte im Prinzip fertig und auch das C-Programm funktioniert schon recht gut. Bei letzterem will ich noch einige Funktionen nach und nach ergänzen und auch die Unterstützung für "help" auf der Kommandozeile mit der Option "-h" oder "--help" ist praktisch nicht vorhanden, was die Benutzung natürlich schwer macht, weil man die Parameter nur beim Blick in den Quelltext erahnen kann.
Dafür sind die Shell-Skripte sowohl unter 32-bittigem Linux (z.B. auf FRITZ!Boxen selbst), 64-Bit-Linux (openSuSE und (in Grenzen) Ubuntu 14.04 LTS - also auch auf Systemen mit der "dash" als Shell) und auch in der "bash" unter Windows 10/x64 getestet ... bei mir arbeiten sie unter diesen Umgebungen ohne Probleme (ggf. im Windows noch ein passendes OpenSSL installieren).
Das C-Programm läßt sich sowohl in der Freetz-Toolchain als auch auf so ziemlich jedem anderen Linux-System übersetzen und wenn man sich das fertige x64-Binary in seine Windows-"bash" kopiert und dort OpenSSL installiert ist, läuft das Programm auch dort (allerdings schnarchlangsam im Vergleich und das liegt nicht an einem zu schwachen System).
Es gibt also noch ein wenig zu tun am C-Programm und auch ein oder zwei andere Shell-Skripte kann man dem Programm vermutlich noch zur Seite stellen ... z.B. zum Erzeugen eines Environment-Files aus den Support-Daten einer Box mit einem TFFS-Dump (in den "normalen" Support-Daten ist ja leider der WLAN-Key überschrieben). Auch ein kleines Shell-Skript als CGI-Wrapper, damit man auch mit einer HTML-Seite eine Export-Datei entschlüsseln lassen kann, könnte ich mir noch vorstellen.
Zuletzt bearbeitet: