rapid7 / ruby_smb

A native Ruby implementation of the SMB Protocol Family
Other
79 stars 82 forks source link

Add the Virtual Disk share provider #213

Closed zeroSteiner closed 2 years ago

zeroSteiner commented 2 years ago

As it's name implies the Virtual Disk share provider allows the server to host files with contents that don't exist on disk. Files are divided into three types depending on if they're static, dynamically generated or mapped. Static files are pretty self explanatory. Dynamic files, are generated by a block when the share is opened. The block is passed the server client and session that the open request is associated with. This allows content specific to the session to be easily generated as well as by dynamically sized. Sizing is tricky because clients will often request information about the file including it's size before reading it. Dynamic files can be used in the future to do interesting things like generate payloads or simply display a message that a file was opened. Mapped files expose real entries on the file system. They provide a memory efficient way to host a large file without reading all of its contents into memory.

That vast majority of this works by defining a VirtualPathname class that emulates Ruby's builtin Pathname object for which the existing Disk share provider is currently using. It's also necessary to have a VirtualStat object that describes the fake file which closely emulates Ruby's Stat object. The current implementation requires that the described object either must not exist or it needs to be either a file or a directory. Nothing fancy like block devices or sockets is currently supported. The disk share also requires that real objects are directories and files anyways so that limitation won't change anything. A couple of files under the existing Disk processor were updated, mostly to ensure that files are opened exactly once per Create request. This fixes some implications with dynamic files.

Example

There is a Virtual file server example. It uses a subset of the existing file server example's command line options. It hosts the following 3 files:

Demo

Demo shows file reads for SMB 1-3 and then the dynamic file that changes each time.

  : ruby_smb:feat/server/virtual-disk17:49:08 ruby_smb ruby examples/read_file.rb --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home greeting
SMB3 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
Hello World!
  : ruby_smb:feat/server/virtual-disk17:49:23 ruby_smb ruby examples/read_file.rb --no-smbv3 --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home greeting
SMB2 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
Hello World!
  : ruby_smb:feat/server/virtual-disk17:49:32 ruby_smb ruby examples/read_file.rb --no-smbv2 --no-smbv3 --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home greeting
SMB1 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
Hello World!
  : ruby_smb:feat/server/virtual-disk17:49:40 ruby_smb ruby examples/read_file.rb --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home magic_8_ball 
SMB3 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
As I see it, yes.
  : ruby_smb:feat/server/virtual-disk17:49:51 ruby_smb ruby examples/read_file.rb --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home magic_8_ball
SMB3 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
Without a doubt.
  : ruby_smb:feat/server/virtual-disk17:49:53 ruby_smb ruby examples/read_file.rb --username MSFLAB\\smcintyre --password Password1! 192.168.159.128 home magic_8_ball
SMB3 : (0x00000000) STATUS_SUCCESS: The operation completed successfully.
Connected to \\192.168.159.128\home successfully!
Most likely.
  : ruby_smb:feat/server/virtual-disk17:49:56 ruby_smb 
cdelafuente-r7 commented 2 years ago

Thanks for updating this @zeroSteiner ! It looks good to me. I tested from multiple Windows and SMB versions. It works as expected. I'll go ahead and land it.

Example output

require 'bundler/setup' ... C:\Users\adminuser>type \192.168.1.33\public\self\mapped

!/usr/bin/ruby

require 'bundler/setup' ... C:\Users\adminuser>type \192.168.1.33\public\magic_8_ball Outlook good.

- Testing the `static` type from command line:

ruby examples/virtual_file_server.rb --no-smbv1 --no-smbv2 --username \smbtest --password 123456 --share public --virtual-name test --virtual-type static --virtual-content 'My content'

C:\Users\n00tmeg>type \192.168.1.33\public\test My content

- Testing the `mapped` type from command line:

ruby examples/virtual_file_server.rb --no-smbv1 --no-smbv2 --username \smbtest --password 123456 --share public --virtual-name test --virtual-type mapped --virtual-content /tmp/tmp.txt

C:\Users\n00tmeg>type \192.168.1.33\public\test testtttt

- Testing the `dynamic` type from command line:

ruby examples/virtual_file_server.rb --no-smbv1 --no-smbv2 --username \smbtest --password 123456 --share public --virtual-name test --virtual-type dynamic --virtual-content /tmp/tmp.txt

C:\Users\n00tmeg>type \192.168.1.33\public\test testtttt