Wer kennt sie nicht, diese schöne Meldung auf der Startseite des Web-Interface?
In Ihrer FRITZBox wurden vom Hersteller nicht unterstützte Änderungen durchgeführt.
Was haben wir Böses gemacht, um diese Meldung zu verdienen? Da kommen i.a. zwei Dinge in Frage:
Für beide Arten der Manipulation schreibt die Box Flags persistent in
den Flash-Speicher, allerdings nicht in eine der unter /var/flash
sicht- und änderbaren Konfigurationsdateien.
Es gibt allerdings ein Werkzeug, um sich die gesetzten Flags anzeigen zu
lassen, wenn man auf der Box via Telnet oder SSH angemeldet ist:
/sbin/eventsdump
.
eventsdump -d | head -n 1
Eventsdump gibt eigentlich eine Ereignisliste auf die Konsole aus, wie
man sie auch über das Web-Interface zu sehen bekommmt. Der Parameter
-d führt dazu, dass eventuell gesetzte Manipulations-Flags mit
ausgegeben werden, und zwar direkt in der ersten Zeile. Die filtern wir
mit head
heraus. Mögliche Ausgaben sind
So sehen wir also, was wir alles Böses getan haben.
Wenn wir jetzt wissen wollen, woher eventsdump
seine Informationen
nimmt, müssen wir mit einem Werkzeug wie
strace
nachverfolgen, welche Systemaufrufe eventsdump
macht. Hier ist ein
Ausschnitt aus einem strace
-Log:
01 mkdir("/var", 0777) = -1 EEXIST (File exists)
02 mkdir("/var/flash", 0777) = -1 EEXIST (File exists)
03 unlink("/var/flash/fw_attrib") = -1 ENOENT (No such file or directory)
04 mknod("/var/flash/fw_attrib", S_IFCHR|0666, makedev(240, 87)) = 0
05 open("/var/flash/fw_attrib", O_RDONLY) = 3
06 ioctl(3, TIOCNXCL, 0x7fc22230) = -1 EOPNOTSUPP (Operation not supported)
07 read(3, "NOT_SIGNED,TELNET", 4096) = 17
08 write(1, "NOT_SIGNED,TELNET\n", 3) = 18
09 close(3) = 0
10 unlink("/var/flash/fw_attrib") = 0
Den Ausschnitt habe ich leicht umformatiert. Links steht statt der Zeilennummern normalerweise jeweils die PID des beobachteten Prozesses. Rechts nach dem Gleichheitszeichen steht übrigens immer der Rückgabewert des Aufrufs.
Was passiert hier im Einzelnen?
/var
wird angelegt, falls es noch nicht existiert./var/flash
wird angelegt, falls es noch nicht
existiert./var/flash/fw_attrib
wird gelöscht, falls vorhanden./var/flash/fw_attrib
wird als Character Device mit den
Major/Minor-Nummern 240/87 neu angelegt. Mehr dazu später./var/flash/fw_attrib
wird zum Lesen geöffnet. Der aufmerksame
Leser fragt sich: zum Lesen?! Der Node wurde doch gerade erst
angelegt.fw_attrib
zu initialisieren. Worin
dieses besteht, werden wir gleich sehen. Hintergründe zu ioctl
finden sich z.B. in Linux-Gerätetreiber, 2. Auflage
(OpenBook von
O’Reilly)
oder in der englischen
Wikipedia.fw_attrib
gelesen. 17 Zeichen werden gefunden, sie
enthalten den Text NOT_SIGNED,TELNET. Bingo!eventsdump -d
aufrufen.fw_attrib
wird wieder geschlossen.fw_attrib
wird gelöscht, genauer gesagt der Node entfernt. Die
Daten im Flash-Speicher überleben das, denn sie sind immer noch da,
wenn wir genau das gleiche Character Device mit der selben
Major/Minor-Kombination erneut öffnen.Wie versprochen, mehr zu Ziffer 4. Das Erzeugen des Character Device
Nodes kann man auch selbst nachvollziehen, indem man den Shell-Befehl
mknod
verwendet. Die Schritte 4 bis 8 sehen auf der Shell wie folgt
aus:
mknod /var/flash/fw_attrib c 240 87
cat /var/flash/fw_attrib
Ausgabe (ohne Zeilenvorschub):
NOT_SIGNED,TELNET
Vorsichtshalber sollte man aber die auf diesem Character Device
arbeitende Befehlssequenz mit vor- und nachherigem Löschen des Nodes
umschließen, wie im Trace zu sehen. Also einfach
rm -f /var/flash/fw_attrib
.
Offenbar ist nicht bei jeder Box bzw. jedem Firmware-Stand die Major Number dieselbe. Statt 240 kann also auch 250 oder etwas anderes als Major festgelegt sein. Darum wollen wir die Major Number allgemein feststellen können. Wie man in /etc/init.d/rc.S sehr schön sehen kann, wird beim Systemstart die Major fürs tffs so bestimmt:
major=$(grep tffs /proc/devices)
tffs_major=${major%%tffs}
Das können wir in unserem Code weiter verwenden, um ihn allgemeiner zu machen.
Anmerkung: Ob die Minor Number auch geräte- oder firmwareabhängig ist, ist momentan nicht bekannt. Im ersten Fall einer unterschiedlichen Major war die Minor gleich.
Interessantes Detail: Auch ohne manuelles Löschen der Datei wird diese
vom System alle paar Sekunden automatisch gelöscht, sofern das
Web-Interface im Browser geöffnet ist. Das liegt daran, daß sich die
Seite regelmäßig automatisch neu lädt, und dabei wird wegen des Aufrufs
von eventsdump -d
abgeräumt - security by obscurity. AVM möchte wohl
nicht, daß die Benutzer die Datei sehen und manipulieren. Deshalb müssen
wir den Node jedesmal wieder neu erzeugen. Aber das stört ja nicht, wenn
man es erst einmal weiß.
Um das Löschen zu verhindern, kann man der Datei auch einfach einen
anderen Namen geben, z.B. /var/tmp/fw_attrib
. Wichtig sind die Major
und Minor Number.
Wenn wir aus fw_attrib
lesen können, wieso dann nicht auch hinein
schreiben? Andere Prozesse tun es ja auch, wenn sie
“Klassenbucheinträge” vornehmen. Das geht so:
major=$(grep tffs /proc/devices)
tffs_major=${major%%tffs}
rm -f /var/flash/fw_attrib
mknod /var/flash/fw_attrib c $tffs_major 87
echo -n "" > /var/flash/fw_attrib
rm -f /var/flash/fw_attrib
Beachten Sie, daß echo -n
nichts, also auch keinen Zeilenvorschub in
die Datei schreibt. Das kommt einem Löschen des Inhalts gleich. Ein
Kontroll-Aufruf von eventsdump -d | head -n 1
bestätigt das, und wenn
man jetzt http://fritz.box
aufruft, ist auf der Übersichtsseite die Meldung verschwunden - das
Führungszeugnis ist sozusagen wieder sauber.
:-)
Aber freuen wir uns nicht zu früh, denn nach dem nächsten unautorisierten FW-Update bzw. dem folgenden Telnet-Login ist die Meldung wieder da. Was kann man also noch tun?
Obige Befehlssequenz kann man selbstverständlich auch
/var/flash/debug.cfg
ausführen lassen. Solange man sich nicht per
Telnet anmeldet, ist die Meldung damit weg, auch wenn man zuvor gerade
ein FW-Update eingespielt hat. Tip: Mit SSH zu arbeiten, stört die
FritzBox nicht, denn damit rechnet sie nicht und kreidet es uns somit
auch nicht als Manipulation an. Wer also ein Freetz mit
Dropbear hat, ist fein heraus.
Mit Freetz hat man auch die Möglichkeit, einen cron-Job nach dem Rechten sehen und aufräumen zu lassen. Selbst wenn man also Telnet benutzt, ist, je nach eingestellter Frequenz, nach ein paar Minuten wieder das Flag gelöscht.
Wenn wir uns ein wenig in den Eingeweiden der Firmware umschauen,
stellen wir fest, daß nicht telnetd
selbst das entsprechende Flag
setzt. Nein, es ist /sbin/ar7login
. telnetd
selbst wird ja wie folgt
aufgerufen, um eine Anmeldung zu ermöglichen:
telnetd -l /sbin/ar7login
Wer mit einem Hex-Editor (unter Linux z.B. hexedit aus dem
gleichnamigen Paket) ar7login
öffnet, findet schnell die Zeichenkette
“TELNET” in Großbuchstaben. Genau diese Zeichenkette schreibt das
Programm nach fw_attrib
. Ersetzt man den ersten Buchstaben durch ein
Null-Byte, entspricht das dem Ersetzen des Wortes durch eine
Zeichenkette der Länge null, Strings in C sind schließlich
null-terminiert. (Ziemlich oft das Wort “null”, Entschuldigung.)
Abspeichern, Firmware neu bauen, flashen - fürderhin bleiben wir
verschont von Klassenbucheinträgen für Telnet-Logins.
Vielleicht traut sich nicht jeder die Arbeit mit dem Hex-Editor zu. Es
geht auch ohne. Anstatt ar7login
binär zu manipulieren, wenden wir
einen Proxy-Ansatz an: Wir benennen /sbin/ar7login
um in z.B.
/sbin/ar7login-binary
und setzen an seine Stelle ein Shell-Skript
/sbin/ar7login
:
#!/bin/sh
/sbin/ar7login-binary $*
major=$(grep tffs /proc/devices)
tffs_major=${major%%tffs}
rm -f /var/flash/fw_attrib
mknod /var/flash/fw_attrib c $tffs_major 87
echo -n "" > /var/flash/fw_attrib
Wir reichen also einfach alle Parameter durch an ar7login
und löschen
danach umgehend wieder dessen Spuren im Klassenbuch ;-)
Anschließend gilt analog zu Variante 1: Firmware bauen, flashen,
glücklich sein.
Achtung: Das Flag wird erst gelöscht, nachdem die Telnet-Sitzung wieder beendet wird.
Wem das Firmware-Bauen zu umständlich ist, kann die Proxy-Methode auch
dynamisch zur Laufzeit einsetzen, indem folgende Sequenz in
/var/flash/debug.cfg
eingebaut wird:
cat << EOF > /var/tmp/ar7login-proxy
#!/bin/sh
/var/tmp/ar7login-binary \$*
major=\$(grep tffs /proc/devices)
tffs_major=\${major%%tffs}
rm -f /var/flash/fw_attrib
mknod /var/flash/fw_attrib c \$tffs_major 87
echo -n "" > /var/flash/fw_attrib
EOF
chmod +x /var/tmp/ar7login-proxy
cp /sbin/ar7login /var/tmp/ar7login-binary
mount -o bind /var/tmp/ar7login-proxy /sbin/ar7login
Wie man sieht, wird ar7login
zunächst nach /var/tmp/ar7login-binary
kopiert. Das dynamisch erzeugte Skript /var/tmp/ar7login-proxy
wird
ausführbar gemacht und überlagert durch mount - o bind
die Datei
/sbin/ar7login
, nur um als Proxy wiederum auf das kopierte Binary zu
verweisen und nach Ende der Sitzung dann wieder das Telnet-Flag zu
löschen.
Die beiden Proxy-Varianten haben den Nachteil, während der Dauer der
Telnet-Sitzung auf deren Beendigung zu warten und erst anschließend das
Flag zu löschen. Wenn wir stattdessen unseren Aufräum-Code ins globale
Shell-Profil /etc/profile
einbauen, wird er jeweils direkt nach dem
Login ausgeführt. Es gibt also keine signifikante Latenzzeit, in der die
Flags gesetzt sind, denn das Aufräumen erfolgt ja bereits zu Beginn der
Telnet-Sitzung.
# ... normaler Inhalt von /etc/profile ...
major=$(grep tffs /proc/devices)
tffs_major=${major%%tffs}
rm -f /var/flash/fw_attrib
mknod /var/flash/fw_attrib c $tffs_major 87
echo -n "" > /var/flash/fw_attrib
Ebenso wie bei der Proxy-Methode gilt auch hier: Das Profil kann auch
beim Booten aus /var/flash/debug.cfg
heraus umgeschrieben werden,
indem man es per mount
der Original-Datei überlagert:
cp /etc/profile /var/tmp/profile
cat << EOF >> /var/tmp/profile
major=\$(grep tffs /proc/devices)
tffs_major=\${major%%tffs}
rm -f /var/flash/fw_attrib
mknod /var/flash/fw_attrib c \$tffs_major 87
echo -n "" > /var/flash/fw_attrib
EOF
mount -o bind /var/tmp/profile /etc/profile
Man beachte, daß dieses Mal cat
keine Datei erzeugt, sondern seine
Ausgabe an die zuvor kopierte Originaldatei anhängt. Da wir auch nicht
irgendwelche komplizierten Proxy-Konstrukte haben, brauchen wir uns auch
nicht zu verrenken mit der Namensgebung der Shell-Profile.
Mit einem Patch für Freetz lässt sich der ganze obige Stress vermeiden, und die vermaledeite Meldung ist weg. Da unterstreicht das “Free” in “Freetz” doch gleich, was es heißt :-)
Man kann tffs-Dateien auch über /proc/tffs löschen. In diesem Fall ist der Befehl:
echo clear_id 87 > /proc/tffs
Wozu die vielen Varianten, wenn es mit dem Patch doch so einfach geht?
Ich dachte mir, ich erkläre mal die unterschiedlichen Ansätze, wie man
beim FritzBox-Modding grundsätzlich vorgehen kann - von minimal-invasiv
aus der debug.cfg
heraus über die Manipulation von Skripten in der
Firmware bis hin zum Patchen einer Binärdatei. Ich hoffe, meine
Anregungen helfen anderen Mitstreitern beim Entwickeln von Konzepten, um
die gute AVM-Firmware mit neuen Ideen noch ein bißchen besser, bequemer
oder einfach cooler zu machen - kurz: um zu erreichen, was auch AVM uns
nicht übel nehmen dürfte: optimale Ausnutzung der Hard- und Software,
die wir beim Hersteller oder einem seiner Vertriebspartner gekauft
haben.
Was bleibt bzgl. dieses Themas noch offen? Nun, da sind immer noch die digitalen Signaturen, mit denen die Firmware-Images versehen sind. Sie sind an sich nichts Schlechtes, im Gegenteil. AVM, T-Com und 1&1 tun gut daran, ihre jeweiligen Firmware-Versionen eindeutig als solche zu kennzeichnen und weisen mit Recht bei fehlerhafter Verifikation der Signaturen darauf hin, daß Support-Ansprüche für modifizierte Firmwares nicht mehr bestehen. Was ist aber, falls eines Tages der Hersteller oder einer seiner OEM-Partner beschließen sollten, die Boxen so zu konfigurieren, daß nicht korrekt signierte Firmware-Versionen nicht mehr zum Flashen angenommen würden? Das wäre eine Beschneidung der Benutzerrechte, für die es keinen triftigen Grund gäbe. Deswegen habe ich mir kürzlich die Signatur-Mechanismen angeschaut und auch hier Mittel und Wege gefunden, sie zu entschärfen. Mehr dazu gibt es ein anderes Mal.
Weiterhin happy modding wünscht Euch
Alexander Kriegisch (kriegaex) ###
Anmerkung: Ich habe eben in meiner neuen FBF 7170 (FW 29.4.32-7153) das
schreiben in /var/flash/fw_attrib
versucht. Zunächst lies dies die
Meldung im Web-Interface jedoch vollkommen unbeeindruckt. Erst als ich
mit
echo -n "\0\0\0\0\0\0" >/var/flash/fw_attrib
mein “TELNET” in dem fw_attrib überschrieben habe, verschwand die Meldung im Web-Interface! Kann es sein, daß es notwendig ist die betreffenden Daten zu überschreiben (mit binär 0 = Stringende)?
Harald Becker (ralda)