Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand environment variables on Linux #15862

Merged
merged 5 commits into from Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 31 additions & 11 deletions lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb
Expand Up @@ -123,28 +123,48 @@ def File.basename(*a)

#
# Expands a file path, substituting all environment variables, such as
# %TEMP%.
# %TEMP% on Windows or $HOME on Unix
#
# Examples:
# client.fs.file.expand_path("%appdata%")
# # => "C:\\Documents and Settings\\user\\Application Data"
# client.fs.file.expand_path("~")
# # => "/home/user"
# client.fs.file.expand_path("$HOME/dir")
# # => "/home/user/dir"
# client.fs.file.expand_path("asdf")
# # => "asdf"
#
# NOTE: This method is fairly specific to Windows. It has next to no relation
# to the ::File.expand_path method! In particular, it does *not* do ~
# expansion or environment variable expansion on non-Windows systems. For
# these reasons, this method may be deprecated in the future. Use it with
# caution.
#
def File.expand_path(path)
request = Packet.create_request(COMMAND_ID_STDAPI_FS_FILE_EXPAND_PATH)
if client.platform == 'windows'
request = Packet.create_request(COMMAND_ID_STDAPI_FS_FILE_EXPAND_PATH)

request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( path ))
request.add_tlv(TLV_TYPE_FILE_PATH, client.unicode_filter_decode( path ))

response = client.send_request(request)
response = client.send_request(request)

return client.unicode_filter_encode(response.get_tlv_value(TLV_TYPE_FILE_PATH))
else
# For unix-based systems, do some of the work here
# First check for ~
gwillcox-r7 marked this conversation as resolved.
Show resolved Hide resolved
path_components = path.split(separator)
if path_components.length > 0 && path_components[0] == '~'
path_components[0] = '$HOME'
path = path_components.join(separator)
end

# Now find the environment variables we'll need from the client
env_regex = /\$(?:([A-Za-z0-9_]+)|\{([A-Za-z0-9_.]+)\})/
smashery marked this conversation as resolved.
Show resolved Hide resolved
matches = path.to_enum(:scan, env_regex).map { Regexp.last_match }
env_vars = matches.map { |match| (match[1] || match[2]).to_s }.uniq

return client.unicode_filter_encode(response.get_tlv_value(TLV_TYPE_FILE_PATH))
# Retrieve them
env_vals = client.sys.config.getenvs(*env_vars)

# Now fill them in
path = path.gsub(env_regex) { |z| envvar = $1; envvar = $2 if envvar == nil; env_vals[envvar] }
smashery marked this conversation as resolved.
Show resolved Hide resolved
path
end
end


Expand Down
32 changes: 19 additions & 13 deletions lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb
Expand Up @@ -23,8 +23,14 @@ class Console::CommandDispatcher::Stdapi::Fs

CHECKSUM_ALGORITHMS = %w{ md5 sha1 }
private_constant :CHECKSUM_ALGORITHMS
PATH_EXPAND_REGEX = /\%(\w*)\%/
private_constant :PATH_EXPAND_REGEX

def path_expand_regex
smashery marked this conversation as resolved.
Show resolved Hide resolved
if client.platform == 'windows'
/\%(\w*)\%/
else
/\$(([A-Za-z0-9_]+)|\{([A-Za-z0-9_.]+)\})|^~/
end
smashery marked this conversation as resolved.
Show resolved Hide resolved
end

#
# Options for the download command.
Expand Down Expand Up @@ -303,8 +309,8 @@ def cmd_cd(*args)
print_line("Usage: cd directory")
return true
end
if args[0] =~ PATH_EXPAND_REGEX
client.fs.dir.chdir(client.fs.file.expand_path(args[0].upcase))
if args[0] =~ path_expand_regex
client.fs.dir.chdir(client.fs.file.expand_path(args[0]))
else
client.fs.dir.chdir(args[0])
end
Expand Down Expand Up @@ -380,7 +386,7 @@ def cmd_rm(*args)
end

args.each do |file_path|
file_path = client.fs.file.expand_path(file_path) if file_path =~ PATH_EXPAND_REGEX
file_path = client.fs.file.expand_path(file_path) if file_path =~ path_expand_regex
client.fs.file.rm(file_path)
end

Expand All @@ -400,9 +406,9 @@ def cmd_mv(*args)
return true
end
old_path = args[0]
old_path = client.fs.file.expand_path(old_path) if old_path =~ PATH_EXPAND_REGEX
old_path = client.fs.file.expand_path(old_path) if old_path =~ path_expand_regex
new_path = args[1]
new_path = client.fs.file.expand_path(new_path) if new_path =~ PATH_EXPAND_REGEX
new_path = client.fs.file.expand_path(new_path) if new_path =~ path_expand_regex
client.fs.file.mv(old_path, new_path)
return true
end
Expand All @@ -423,9 +429,9 @@ def cmd_cp(*args)
return true
end
old_path = args[0]
old_path = client.fs.file.expand_path(old_path) if old_path =~ PATH_EXPAND_REGEX
old_path = client.fs.file.expand_path(old_path) if old_path =~ path_expand_regex
new_path = args[1]
new_path = client.fs.file.expand_path(new_path) if new_path =~ PATH_EXPAND_REGEX
new_path = client.fs.file.expand_path(new_path) if new_path =~ path_expand_regex
client.fs.file.cp(old_path, new_path)
return true
end
Expand All @@ -443,7 +449,7 @@ def cmd_chmod(*args)
return true
end
file_path = args[1]
file_path = client.fs.file.expand_path(file_path) if file_path =~ PATH_EXPAND_REGEX
file_path = client.fs.file.expand_path(file_path) if file_path =~ path_expand_regex
client.fs.file.chmod(file_path, args[0].to_i(8))
return true
end
Expand Down Expand Up @@ -746,7 +752,7 @@ def cmd_ls(*args)
return 0
when nil
path = val
path = client.fs.file.expand_path(path) if path =~ PATH_EXPAND_REGEX
path = client.fs.file.expand_path(path) if path =~ path_expand_regex
end
}

Expand Down Expand Up @@ -923,7 +929,7 @@ def cmd_mkdir(*args)
end

args.each { |dir_path|
dir_path = client.fs.file.expand_path(dir_path) if dir_path =~ PATH_EXPAND_REGEX
dir_path = client.fs.file.expand_path(dir_path) if dir_path =~ path_expand_regex
print_line("Creating directory: #{dir_path}")
client.fs.dir.mkdir(dir_path)
}
Expand Down Expand Up @@ -952,7 +958,7 @@ def cmd_rmdir(*args)
end

args.each { |dir_path|
dir_path = client.fs.file.expand_path(dir_path) if dir_path =~ PATH_EXPAND_REGEX
dir_path = client.fs.file.expand_path(dir_path) if dir_path =~ path_expand_regex
print_line("Removing directory: #{dir_path}")
client.fs.dir.rmdir(dir_path)
}
Expand Down
36 changes: 36 additions & 0 deletions test/modules/post/test/file.rb
Expand Up @@ -185,6 +185,42 @@ def test_binary_files
end
end

def test_path_expansion_nix
unless session.platform =~ /win/i
it "should expand home" do
home1 = expand_path('~')
home2 = expand_path('$HOME')
home1 == home2 && home1.length > 0
end

it "non-isolated tilde should not expand" do
s = '~a'
result = expand_path(s)
s == result
end

it "mid-string tilde should not expand" do
s = '/home/~'
result = expand_path(s)
s == result
end

it "no env vars should not expand" do
smashery marked this conversation as resolved.
Show resolved Hide resolved
s = 'no environment $ variables /here'
result = expand_path(s)
s == result
end

it "should expand multiple variables" do
result = expand_path('/blah/$HOME/test/$USER')
home = expand_path('$HOME')
user = expand_path('$USER')
expected = "/blah/#{home}/test/#{user}"
result == expected
end
end
end

def cleanup
vprint_status("Cleanup: changing working directory back to #{@old_pwd}")
cd(@old_pwd)
Expand Down