Fix mkdir post API to behave consistently across session types#20944
Fix mkdir post API to behave consistently across session types#20944Nayeraneru wants to merge 2 commits intorapid7:masterfrom
Conversation
|
This looks a bit overengineered compared to a simple |
Thanks for the feedback. I agree that the iterative approach is simpler and more straightforward in many cases. For paths like C:\Temp\A\B\C (where C:\Temp exists but A is missing), the loop version might fail if it doesn’t handle C: and separators correctly, or it would require manual parent checking. The recursive version automatically creates all missing directories (A, B, C). For Unix-style paths like /tmp/A/B/C, the loop version works only if the parent directories already exist; otherwise, it fails unless extra checks are added. The recursive version works regardless of which intermediate directories exist. So while iteration is simpler and easier to read, recursion mirrors mkdir -p behavior and handles missing parents naturally, providing safer and more consistent behavior in all scenarios. |
|
What's wrong with something like his: directories = directory.s.split(s.fs.file.separator)
if session.platform == 'windows'
current_dir = directories.pop() # to get the drive letter
end
current_dir = ''
directories do | dir |
current_dir += s.fs.file.separator + dir
session.fs.dir.mkdir(current_dir) unless directory?(current_dir)
end |
Thanks for the suggestion and for sharing the example, It is very helpful. I’ve updated the code to use the same iterative approach you described. One small change I made was around Windows drive handling: instead of deriving the drive from the split path, I detect the drive root ( Does this look reasonable to you, or would you suggest any further tweaks? def meterpreter_mkdir_p(path)
return nil if directory?(path)
separator = session.fs.file.separator
normalized = path.tr('\\/', separator)
directories = normalized.split(separator)
current_path = ''
if normalized.match?(/\A[a-zA-Z]:#{Regexp.escape(separator)}?/)
current_path = "#{directories.shift}#{separator}"
elsif normalized.start_with?(separator)
current_path = separator
end
directories.each do |dir|
next if dir.empty?
current_path =
if current_path.end_with?(separator) || current_path.empty?
"#{current_path}#{dir}"
else
"#{current_path}#{separator}#{dir}"
end
session.fs.dir.mkdir(current_path) unless directory?(current_path)
end
nil
endnote: meterpreter_parent_directory function is removed from the code |
There was a problem hiding this comment.
The issue should be probably addressed on Meterpreter side, to avoid overhead of sending data for each path level. The specs should be kept though.
Summary
This PR fixes #20697
Currently,
powershell, Windows shell, and Unix (mkdir -p) automatically create intermediate directories. However, Windows Meterpreter relies onCreateDirectoryW, which fails if parent directories do not exist. This leads to inconsistent behavior depending on the session type.Change
This PR introduces a recursive helper method
meterpreter_mkdir_pandmeterpreter_parent_directoryto emulatemkdir -pbehavior for Meterpreter sessions.The implementation:
C:\).