Skip to content

Add Support for Windows .writable? in Post Mixin#21573

Open
jheysel-r7 wants to merge 4 commits into
rapid7:masterfrom
jheysel-r7:feat/lib/post_windows_writable
Open

Add Support for Windows .writable? in Post Mixin#21573
jheysel-r7 wants to merge 4 commits into
rapid7:masterfrom
jheysel-r7:feat/lib/post_windows_writable

Conversation

@jheysel-r7

@jheysel-r7 jheysel-r7 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Description

This adds support to the Post Mixin for Windows sessions to run the .writable? method.

  • Meterpreter sessions will try to open a write handle to the file via session.fs.file.new(path, 'wb')

  • Shell sessions will try to append to the file via type nul >> path

    • This checks for FILE_APPEND_DATA and not GENERIC_WRITE. A file with append-but-not-write ACE (exotic, but possible) would return a false positive

Reviewer Notes

Create two separates files to test. As a low privilege user, create the files in your home directory - avoid creating the files elsewhere like C:\users\public or C:\ which will inherit unwanted privileges which will affected the test.

Create writable.txt:

C:\Users\lowboi>echo test > writable.txt

Create not_writable.txt:

C:\Users\lowboi>echo test > not_writable.txt

Take away write privileges from your user by setting (R) read privs only:

C:\Users\lowboi>icacls not_writable.txt /inheritance:r /grant:r "DESKTOP-0OPTL76\lowboi:(R)" "SYSTEM:(F)" "Administrators:(F)"
processed file: not_writable.txt
Successfully processed 1 files; Failed processing 0 files

Double check everything looks good:

C:\Users\lowboi>icacls not_writable.txt
not_writable.txt BUILTIN\Administrators:(F)
                 NT AUTHORITY\SYSTEM:(F)
                 DESKTOP-0OPTL76\lowboi:(R)

From the GUI you should see:
Screenshot 2026-06-15 at 12 37 48 PM

Verification Steps

  • Establish a meterpreter session on the target
  • Load any module that loads the Post::File mixin
  • Drop into IRB
  • test like so:
msf exploit(windows/local/adobe_sandbox_adobecollabsync) > sessions -l

Active sessions
===============

  Id  Name  Type                     Information                               Connection
  --  ----  ----                     -----------                               ----------
  6         meterpreter x64/windows  DESKTOP-0OPTL76\lowboi @ DESKTOP-0OPTL76  192.168.1.68:4444 -> 192.168.1.150:50514 (192.168.1.150)

msf exploit(windows/local/adobe_sandbox_adobecollabsync) > irb
[*] Starting IRB shell...
[*] You are in exploit/windows/local/adobe_sandbox_adobecollabsync

>> writable?('c:\users\lowboi\not_writable.txt')
=> false
>> writable?('c:\users\lowboi\writable.txt')
=> true
  • Establish a shell session on the target
  • Load any module that loads the Post::File mixin
  • Drop into IRB
  • test like so:
msf exploit(windows/local/adobe_sandbox_adobecollabsync) > sessions -l

Active sessions
===============

  Id  Name  Type               Information                                                      Connection
  --  ----  ----               -----------                                                      ----------
  5         shell cmd/windows  Shell Banner: Microsoft Windows [Version 10.0.19045.6466] -----  192.168.1.68:4444 -> 192.168.1.150:50370 (192.168.1.150)

msf exploit(windows/local/adobe_sandbox_adobecollabsync) > irb
[*] Starting IRB shell...
[*] You are in exploit/windows/local/adobe_sandbox_adobecollabsync

>> writable?('c:\users\lowboi\writable.txt')
=> true
>> writable?('c:\users\lowboi\not_writable.txt')
=> false

Test Evidence

Evidence included in the verification steps. See the rspec output below:

➜  metasploit-framework git:(feat/lib/post_windows_writable) ✗ bundle exec rspec spec/lib/msf/core/post/file_spec.rb
.Overriding user environment variable 'OPENSSL_CONF' to enable legacy functions.
Run options:
  include {:focus=>true}
  exclude {:acceptance=>true}

All examples were filtered out; ignoring {:focus=>true}

Randomized with seed 16757
Msf::Post::File ........................................
Acceptance::DatastoreFormatting .......

Top 10 slowest examples (2.05 seconds, 19.0% of total time):
  Msf::Post::File#writable? on a Windows shell session returns false when the file is not writable
    0.2817 seconds ./spec/lib/msf/core/post/file_spec.rb:196
  Msf::Post::File#find_writable_directories on Unix returns an empty array when no directories are found
    0.26119 seconds ./spec/lib/msf/core/post/file_spec.rb:115
  Msf::Post::File#writable? on a Windows shell session returns true when the file is writable
    0.20451 seconds ./spec/lib/msf/core/post/file_spec.rb:190
  Msf::Post::File#find_writable_directories on Unix passes a custom timeout to cmd_exec
    0.19586 seconds ./spec/lib/msf/core/post/file_spec.rb:125
  Msf::Post::File#writable? on a Windows meterpreter session returns true when the file is writable
    0.19576 seconds ./spec/lib/msf/core/post/file_spec.rb:238
  Msf::Post::File#find_writable_directories raises an error for relative paths
    0.19185 seconds ./spec/lib/msf/core/post/file_spec.rb:95
  Msf::Post::File#_can_echo? should return false for "hello \"world\""
    0.19021 seconds ./spec/lib/msf/core/post/file_spec.rb:62
  Msf::Post::File#mkdir registers the directory for cleanup by default
    0.1872 seconds ./spec/lib/msf/core/post/file_spec.rb:34
  Msf::Post::File#writable? on a Windows PowerShell session returns true when the file is writable
    0.17541 seconds ./spec/lib/msf/core/post/file_spec.rb:269
  Msf::Post::File#find_writable_directories on Unix filters out non-absolute paths and error lines
    0.16756 seconds ./spec/lib/msf/core/post/file_spec.rb:110

Top 2 slowest example groups:
  Acceptance::DatastoreFormatting
    0.27547 seconds average (1.93 seconds / 7 examples) ./spec/support/acceptance/datastore_formatting_spec.rb:6
  Msf::Post::File
    0.22051 seconds average (8.82 seconds / 40 examples) ./spec/lib/msf/core/post/file_spec.rb:4

Finished in 10.82 seconds (files took 58.86 seconds to load)
47 examples, 0 failures

Randomized with seed 16757
Coverage report generated for RSpec to /Users/jheysel/rapid7/metasploit-framework/coverage.
Line Coverage: 18.55% (2510 / 13532)

Environment

Field Details
Operating System Windows 10 10.0.19045 N/A Build 19045
Ruby Version ruby 3.3.8 (2025-04-09 revision b200bad6cd) [x86_64-darwin24]
Target Software/Hardware Windows

AI Usage Disclosure

Claude wrote the tests

Pre-Submission Checklist

  • Ran rubocop on new files with no new offenses (net new files only)
  • Ran msftidy on changed module files with no new offenses (modules only)
  • Ran msftidy_docs on changed documentation files with no new offenses (documentation files only)
  • Included a corresponding documentation markdown file in documentation/modules (new modules only)
  • No sensitive information (IP addresses, credentials, API keys, hashes) in code or documentation
  • Tested on the target environment specified in the Environment section above
  • Included RSpec tests for library changes (encouraged for lib/ changes)
  • Read the CONTRIBUTING.md and module acceptance guidelines

Comment thread lib/msf/core/post/file.rb Outdated
Comment thread lib/msf/core/post/file.rb Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

4 participants