Skip to content

Commit

Permalink
Handle edge case in command shell when input contains backslash-quote…
Browse files Browse the repository at this point in the history
… combination already
  • Loading branch information
smashery committed Oct 15, 2024
1 parent bdfa1f3 commit 205adfe
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/msf/base/sessions/command_shell.rb
Original file line number Diff line number Diff line change
Expand Up @@ -763,14 +763,14 @@ def self._glue_cmdline_escape(arg, quote_requiring, unquotable_char, escaped_unq
next
elsif quote_requiring.include?(char)
# Oh, it turns out we should have been inside quotes for this token.
# Let's note that, so that when we actually append the token
# Let's note that, for when we actually append the token
in_quotes = true
end
current_token += char
end

if in_quotes
# This token has been in an inside-quote context, so let's properly wrap that before continuing
# The final token has been in an inside-quote context, so let's properly wrap that before continuing
current_token = "#{quote_char}#{current_token}#{quote_char}"
end
result += current_token
Expand Down
5 changes: 3 additions & 2 deletions lib/msf/base/sessions/command_shell_windows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ def self.to_cmd(cmd_and_args)
quote_requiring = ['"', '^', ' ', "\t", "\v", '&', '<', '>', '|']

escaped_cmd_and_args = cmd_and_args.map do |arg|
# Double-up all quote chars
arg = arg.gsub('"', '""')
# Escape quote chars by doubling them up, except those preceeded by a backslash (which are already effectively escaped, and handled below)
arg = arg.gsub(/([^\\])"/, '\\1""')
arg = arg.gsub(/^"/, '""')

result = CommandShell._glue_cmdline_escape(arg, quote_requiring, '%', '^%', '"')

Expand Down
2 changes: 2 additions & 0 deletions spec/lib/msf/base/sessions/command_shell_windows_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
expect(described_class.to_cmd(['test.exe'] + ['quote\\\\"'])).to eq('test.exe "quote\\\\\\\\"""')
expect(described_class.to_cmd(['test.exe'] + ['will be quoted\\\\'])).to eq('test.exe "will be quoted\\\\\\\\"')
expect(described_class.to_cmd(['test.exe'] + ['will be quoted\\\\ '])).to eq('test.exe "will be quoted\\\\ "') # Should not be doubled up
expect(described_class.to_cmd(['test.exe'] + ['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])).to eq('test.exe """test""" "test\\\\"" "test\\\\\\\\"" "test words\\\\\\\\\\\\\\\\" "test words\\\\\\\\\\\\" \\\\')
end

it 'should handle combinations of quoting and percent-escaping' do
Expand Down Expand Up @@ -76,6 +77,7 @@
it 'should handle the weird backslash escaping behaviour in front of quotes' do
expect(described_class.argv_to_commandline(['\\\\"'])).to eq('\\\\\\\\\\"')
expect(described_class.argv_to_commandline(['space \\\\'])).to eq('"space \\\\\\\\"')
expect(described_class.argv_to_commandline(['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])).to eq('\"test\" test\\\\\\" test\\\\\\\\\\" "test words\\\\\\\\\\\\\\\\" "test words\\\\\\\\\\\\" \\\\')
end

it 'should handle empty args' do
Expand Down
8 changes: 4 additions & 4 deletions test/modules/post/test/cmd_exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ def test_create_process
end

it 'should deal with weird windows edge cases' do
output = create_process(show_args_binary[:cmd], args: ['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\ ', 'test words\\\\\\ ', '\\\\'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\ ', 'test words\\\\\\ ', '\\\\'])
output = create_process(show_args_binary[:cmd], args: ['"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '"test"', 'test\\"', 'test\\\\"', 'test words\\\\\\\\', 'test words\\\\\\', '\\\\'])
end

it 'should accept special characters and return the create_process output' do
output = create_process(show_args_binary[:cmd], args: ['~!@#$%^&*(){`1234567890[]",.\'<>'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '~!@#$%^&*(){`1234567890[]",.\'<>'])
output = create_process(show_args_binary[:cmd], args: ['~!@#$%^&*(){`1234567890[]",.\'<>\\'])
valid_show_args_response?(output, expected: [show_args_binary[:upload_path], '~!@#$%^&*(){`1234567890[]",.\'<>\\'])
end

it 'should accept command line commands and return the create_process output' do
Expand Down

0 comments on commit 205adfe

Please sign in to comment.