Proftpd Bugfix macht Login unmöglich

Die späte Rache ereilte vermutlich die Entwickler vom allseits beliebten FTP-Server Proftpd. Um das Problem zu verstehen muß man etwas ausholen und in die Vergangenheit des Servers zurückgehen:

Spätestens im Jahr 1999 wurde mit der Version 1.2.0pre9 die Funktion eingebaut, daß FTP-Benutzer die einloggen, in einer Chroot gefangen werden, damit sie nur auf ihr Homeverzeichnis zugreifen können. Die Option hies „DefaultRoot“. In der Doku zu der Option findet sich folgender Hinweis:

When the specified chroot directory is a symlink this will be resolved to it’s parent
first before setting up the chroot. This can have unwanted side effects. For example if
a user has write access to the symlink he could modify it so that it points to ‚/‘

Meint auf Deutsch in Kurzform, daß wenn das Homeverzeichnis eigentlich ein Symlink ist, diesem gefolgt wird und das, wo der rauskommt, das neue „/“ von der Chroot ist.

Im Klartext: wenn  /home/testuser ein Symlink auf  „/“  ist, dann ist der User nicht in /home/testuser gefangen, sondern kann sich frei im normalen „/“ Verzeichnis rumtreiben. Ein Sicherheitsloch, daß locker mal 20 Jahre existiert hat.

Die FAQ von Proftpd meint zu dem Thema Chroot, daß man als Admin gefälligst dafür Sorgen soll, daß User das nicht anlegen/ändern können und halt kein Sicherheitsloch entstehen soll. Die schoben die Verantwortung also an die Admins weiter, was zu einem bestimmten grad ok war, aber dann darf man andere Sachen gar icht erst erlauben.

Mein Teil an der Story

In 2012 habe ich den Entwicklern von Proftpd einen Patch für proftpd geschickt, der genau dies Problem adressiert hat und keine Nebenwirkungen hatte. Der Patch prüft bei jedem Zugriff, ob sich in dem Pfad ein Symlink eingenistet hatte. So konnte es keine RACE Condition geben, bei der der Benutzer durch schnelles löschen und SymLink anlegen, die Sicherungsmaßnahmen umgehen konnte. Kurzfassung: Der Patch wurde mit : „Nicht unser Problem, siehe FAQ “ abgelehnt. Was sich jetzt als tragisch herausstellt. Besonders tragisch, da für den 29C3 in 2012 ein Vortrag zu dem Thema von mir eingereicht wurde.

Das Jahr 2016

In 2016 hat es dann endlich jemand geschafft, die Entwickler zu einer Option zum Checken von Symlinks im Pfad zu nötigen. Herzlichen Dank dafür, keine Ahnung wie Du das geschafft hast! Klasse!

Das Jahr 2017

Nun konnte ja nicht sein, was nicht sein durfte, in der Routine zum Checken der Symlinks wurde ein Sicherheitsloch entdeckt ( Hämischer Kommentar: Told you so ! ) und diesem wurde die CVE-2017-7418 zugeteilt.

Nun gabs es dieser Tage den Patch zu dieser Lücke im Server und damit das obligatorische Update auf den Produktivsystemen. Keine große Sache, sollte man denken. Tja, wer hat es geraten ? Auch diese Routine failed. Die hat das Sicherheitsproblem auf einer völlig neuen Ebene gelöst: Es kann sich kein Virtueller FTP-User mehr einloggen 😀

Ursache ist das hier:

[pid 32571] setresgid(-1, 99, -1)       = 0
[pid 32571] setresuid(-1, 99, -1)       = 0
[pid 32571] setresuid(-1, 0, -1)        = 0
[pid 32571] setresgid(-1, 1001, -1)     = 0
[pid 32571] setresuid(-1, 1000, -1)     = 0
[pid 32571] lstat("/", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
[pid 32571] lstat("/opt", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 32571] lstat("/opt/root", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 32571] lstat("/opt/root/home", {st_mode=S_IFDIR|0755, st_size=20480, ...}) = 0
[pid 32571] lstat("/opt/root/home/testuser", {st_mode=S_IFDIR|0750, st_size=4096, ...}) = 0
[pid 32571] lstat("/opt/root/home/testuser/public_html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
...
[pid 32571] geteuid()                   = 1000
[pid 32571] setresuid(-1, 0, -1)        = 0
[pid 32571] setresgid(-1, 99, -1)       = 0
[pid 32571] setresuid(-1, 99, -1)       = 0
[pid 32571] setresuid(-1, 0, -1)        = 0
[pid 32571] setresgid(-1, 0, -1)        = 0
[pid 32571] setgid(1001)                = 0
[pid 32571] geteuid()                   = 0
[pid 32571] setresgid(-1, 99, -1)       = 0
[pid 32571] setresuid(-1, 99, -1)       = 0
[pid 32571] lstat("/opt/root/home/testuser/public_html", 0x7ffee3d84dd0) = -1 EACCES (Permission denied)

Für die Laien unter Euch, das ist der Auszug eines STRACE Logfiles. Darin finden wir alle Befehle die der Prozess ausgeführt hat ( API-Calls , nicht Bashkommandos 😉 ) . Man sieht deutlich das im ersten Block mit einer UID/GID von 1000/1001 auf das Homeverzeichnis des Benutzers zugegriffen wird, weil der Prozess entsprechend seine UID/GID ändert. Das ist RICHTIG so.

Was falsch ist, daß er das nicht auch beim zweiten Block tut. Hier ist die UID des Prozesses (proftpd) statt 1000, nur 99, was dem User NOBODY entspricht. Das ist der User, zu dem Prozesse werden sollen um Ihre Rechte zu verlieren um im Falle eines Sicherheitsbruches den Schaden zu begrenzen. (@Team: Der Teil hat 1a funktionert. Ohne Logins keine Bedrohung mehr) . Natürlich müßte auch hier die UID/GID auf 1000/1001 gesetzt werden, damit man an seine Dateien rankommt, denn normalerweise haben Verzeichnisse wie „/home/testuser“ einen chmod von 700, damit nur der User drankommt.

20 Jahre bis Problem akzeptiert. 4 Jahre bis zum Fix und nur 6 Monate bis zum Totalausfall der Server. Eine Glanzleistung sonders gleichen. Hätte man meinen Patch in 2012 nicht todgeredet, wäre uns das erspart geblieben 🙂 Da der Vortrag abgelehnt wurde, ging das Thema am 29C3 leider unter und so könnten die Jungs und Mädels vom CCC unabsichtlich auch dran beteiligt gewesen sein 😉  Tja, so ist das Leben.

Kleiner Disclaimer:

Es hängt ein bisschen von der Serverkonfiguration ab. Wer keine Datenbank benutzt, sondern nur reale User, der hat das Problem den bisherigen Infos nach nicht. Wer „AllowChrootSymlinks on“ aktiviert hat ( was der Default ist) hat auch kein Problem mit dem Login, wohl aber mit dem Umstand, daß er/sie ein angreifbares System hat ( siehe oben ) das ganz schnell gehackt werden kann.