Samba: Mount.cifs-Patch im zweiten Anlauf

Samba erlaubt den einfachen Zugriff auf die in der Microsoft-Welt üblichen SMB-/CIFS-Dienste und enthält das mount.cifs-Tool womit sich CIFS-Shares bequem unter Linux einbinden lassen. Der Patch für eine vor einem Jahr entdeckte Sicherheitslücke hat sich kürzlich als fehlerhaft herausgestellt, wodurch ein lokaler Angreifer Denial-of-Service-Attacken gegen neuere Samba-Versionen durchführen kann.
Das Mount.cifs-Tool wird gewöhnlich indirekt als “mount -t cifs” aufgerufen und benötigt einen Kernel, der das Common Internet File System (CIFS)-Dateisystem über VFS unterstützt. CIFS ist der 1996 von Microsoft ins Leben gerufene Nachfolger des Server Message Block (SMB) Protokolls, der auf NetBIOS over TCP/IP und SMB basiert und zusätzlich zu den von SMB bekannten Diensten wie Dateifreigabe auch RPC- und NT-Domändienste bereitstellt. Wie andere Mount-Tools auch kann für mount.cifs das SetUID-Bit gesetzt werden, so dass lokale Nicht-Root-Anwender ebenfalls CIFS-Shares einhängen können.
Im September 2010 wurde bekannt, dass mount.cifs in Samba 3.4.5 die Gerätenamen- und Mountpoint-Strings nicht korrekt überprüft. Durch das Einfügen von Newline-, Tab- oder Backshlash-Zeichen war es damit für einen Angreifer möglich, die dynamisch modifizierte mtab-Datei zu manipulieren falls das SetUID-Bit für mount.cifs gesetzt ist. So konnte etwa durch Newline-Zeichen einfach in die nächste Zeile von /etc/mtab geschrieben werden, was dann als neuer Mtab-Eintrag interpretiert wurde und einem lokalen Angreifer damit verschiedene Denial-of-Service-Attacken ermöglichte. Als Reaktion auf diese Sicherheitslücke wurden einige Kontrollfunktionen in der “mount_cifs.c”-Datei hinzugefügt, die solche schädlichen Strings vermeiden sollten.
Für das Newline-Zeichen-Problem handelte es sich dabei um die Funktionen “check_newline()”, die von den fuse-utils übernommen wurde, und um die “check_mtab()”-Funktion:

static int check_newline(const char *progname, const char *name)
{ char *s; for (s = "\n"; *s; s++) { if (strchr(name, *s)) { fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n", progname, *s); return EX_USAGE; } } return 0;
}
static int check_mtab(const char *progname, const char *devname, const char *dir)
{ if (check_newline(progname, devname) == -1 || check_newline(progname, dir) == -1) return EX_USAGE; return 0;
}
Die EX_USAGE-Konstante wird in mount.h zusammen mit weiteren Exitcodes definiert:
#define EX_USAGE 1
Bevor nun die eigentliche Mount-Operation und der mtab-Eintrag vorgenommen wird, muss sowohl der Gerätename (devname) als auch der Mountpoint (dir) den Newline-Test in check_newline()-Test passieren. Dazu wurde in der main()-Funktion der mount_cifs.c-Datei direkt am Anfang check_mtab() aufgerufen:
int main(int argc, char ** argv)
... rc = check_mtab(thisprogram, dev_name, mountpoint); if (rc) goto mount_exit;

und falls der return code (rc) nicht “0” ist der Mount-Vorgang mit dem goto-Sprung abgebrochen.
Ein aufmerksamer Leser wird jedoch beim Betrachten des C-Codes schon festgestellt haben, dass dieser Mount.cifs-Patch nicht korrekt auf Newline-Zeichen reagiert und die Attacke immer noch möglich ist. Denn sollte der String (entweder devname oder dir) tatsächlich ein Newline-Zeichen enthalten, so liefert “check_newline()” “EX_USAGE”, das heißt 1 zurück. Die “check_mtab()”-Funktion liefert allerdings nur dann einen Returncode ungleich Null zurück, falls “check_newline() -1” zurückgeliefert hat. In dieser Form ist der Newline-Filter also nicht funktionsfähig und der Mount-Vorgang wird trotz kritischer Newline-Zeichen nicht abgebrochen, was Denial-of-Service-Attacken weiter ermöglicht. Dies ist ein Beispiel dafür wie eine vermeintlich simple Sicherheitslücke durch einen schlampig eingeführten Patch nicht ordentlich korrigiert wird. Der Patch für den Patch besteht natürlich einfach darin nicht auf -1 sondern auf ungleich 0 zu prüfen:

static int check_mtab(const char *progname, const char *devname, const char *dir)
{ if (check_newline(progname, devname) || check_newline(progname, dir)) return EX_USAGE; return 0;
}

Damit wird dann korrekt auf Newline-Zeichen gefiltert und die Attacken sind nicht mehr möglich. Betroffen von diesem Problem sind die Linux CIFS Utils Version 5.0.

Nach oben