This patch allows meterpreter to work with file paths and user names that are not of the US-ASCII character set.

git-svn-id: file:///home/svn/framework3/trunk@13200 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2011-07-17 17:32:52 +00:00
parent 1e1d7c534d
commit cccbdf9fab
9 changed files with 81 additions and 71 deletions

View File

@ -36,7 +36,7 @@ class File < Rex::Post::Meterpreter::Channels::Pool
[
{
'type' => Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_FILE_PATH,
'value' => name
'value' => Rex::Text.unicode_filter_decode( name )
},
{
'type' => Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_FILE_MODE,

View File

@ -56,14 +56,14 @@ class Dir < Rex::Post::Dir
request = Packet.create_request('stdapi_fs_ls')
files = []
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, name)
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, Rex::Text.unicode_filter_decode(name))
response = client.send_request(request)
response.each(TLV_TYPE_FILE_NAME) { |file_name|
files << file_name.value
files << Rex::Text.unicode_filter_encode( file_name.value )
}
return files
end
@ -74,7 +74,7 @@ class Dir < Rex::Post::Dir
request = Packet.create_request('stdapi_fs_ls')
files = []
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, name)
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, Rex::Text.unicode_filter_decode(name))
response = client.send_request(request)
@ -88,7 +88,7 @@ class Dir < Rex::Post::Dir
fname.each_with_index { |file_name, idx|
st = nil
if (sbuf[idx])
st = ::Rex::Post::FileStat.new
st.update(sbuf[idx].value)
@ -96,12 +96,12 @@ class Dir < Rex::Post::Dir
files <<
{
'FileName' => file_name.value,
'FilePath' => fpath[idx].value,
'FileName' => Rex::Text.unicode_filter_encode( file_name.value ),
'FilePath' => Rex::Text.unicode_filter_encode( fpath[idx].value ),
'StatBuf' => st,
}
}
return files
end
@ -117,20 +117,20 @@ class Dir < Rex::Post::Dir
def Dir.chdir(path)
request = Packet.create_request('stdapi_fs_chdir')
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, path)
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
return 0
end
#
# Creates a directory.
#
def Dir.mkdir(path)
request = Packet.create_request('stdapi_fs_mkdir')
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, path)
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
@ -145,7 +145,7 @@ class Dir < Rex::Post::Dir
response = client.send_request(request)
return response.get_tlv(TLV_TYPE_DIRECTORY_PATH).value
return Rex::Text.unicode_filter_encode( response.get_tlv(TLV_TYPE_DIRECTORY_PATH).value )
end
#
@ -161,7 +161,7 @@ class Dir < Rex::Post::Dir
def Dir.delete(path)
request = Packet.create_request('stdapi_fs_delete_dir')
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, path)
request.add_tlv(TLV_TYPE_DIRECTORY_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
@ -193,9 +193,10 @@ class Dir < Rex::Post::Dir
# local directory, optionally in a recursive fashion.
#
def Dir.download(dst, src, recursive = false, force = true, &stat)
self.entries(src).each { |src_sub|
dst_item = dst + ::File::SEPARATOR + src_sub
src_item = src + File::SEPARATOR + src_sub
dst_item = dst + ::File::SEPARATOR + Rex::Text.unicode_filter_encode( src_sub )
src_item = src + File::SEPARATOR + Rex::Text.unicode_filter_encode( src_sub )
if (src_sub == '.' or src_sub == '..')
next
@ -215,7 +216,7 @@ class Dir < Rex::Post::Dir
raise e
end
end
elsif (src_stat.directory?)
if (recursive == false)
next
@ -239,8 +240,8 @@ class Dir < Rex::Post::Dir
#
def Dir.upload(dst, src, recursive = false, &stat)
::Dir.entries(src).each { |src_sub|
dst_item = dst + File::SEPARATOR + src_sub
src_item = src + ::File::SEPARATOR + src_sub
dst_item = dst + File::SEPARATOR + Rex::Text.unicode_filter_encode( src_sub )
src_item = src + ::File::SEPARATOR + Rex::Text.unicode_filter_encode( src_sub )
if (src_sub == '.' or src_sub == '..')
next
@ -280,3 +281,4 @@ protected
end
end; end; end; end; end; end

View File

@ -44,6 +44,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
request = Packet.create_request( 'stdapi_fs_search' )
root = Rex::Text.unicode_filter_decode(root) if root
root = root.chomp( '\\' ) if root
request.add_tlv( TLV_TYPE_SEARCH_ROOT, root )
@ -56,8 +57,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
if( response.result == 0 )
response.each( TLV_TYPE_SEARCH_RESULTS ) do | results |
files << {
'path' => results.get_tlv_value( TLV_TYPE_FILE_PATH ).chomp( '\\' ),
'name' => results.get_tlv_value( TLV_TYPE_FILE_NAME ),
'path' => Rex::Text.unicode_filter_encode( results.get_tlv_value( TLV_TYPE_FILE_PATH ).chomp( '\\' ) ),
'name' => Rex::Text.unicode_filter_encode( results.get_tlv_value( TLV_TYPE_FILE_NAME ) ),
'size' => results.get_tlv_value( TLV_TYPE_FILE_SIZE )
}
end
@ -87,11 +88,11 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
def File.expand_path(path)
request = Packet.create_request('stdapi_fs_file_expand_path')
request.add_tlv(TLV_TYPE_FILE_PATH, path)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_FILE_PATH)
return Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_FILE_PATH) )
end
@ -101,10 +102,11 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
def File.md5(path)
request = Packet.create_request('stdapi_fs_md5')
request.add_tlv(TLV_TYPE_FILE_PATH, path)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
# This is not really a file name, but a raw hash in bytes
return response.get_tlv_value(TLV_TYPE_FILE_NAME)
end
@ -114,32 +116,19 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
def File.sha1(path)
request = Packet.create_request('stdapi_fs_sha1')
request.add_tlv(TLV_TYPE_FILE_PATH, path)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( path ))
response = client.send_request(request)
# This is not really a file name, but a raw hash in bytes
return response.get_tlv_value(TLV_TYPE_FILE_NAME)
end
#
# Expands a file path, substituting all environment variables, such as
# %TEMP%.
#
def File.expand_path(path)
request = Packet.create_request('stdapi_fs_file_expand_path')
request.add_tlv(TLV_TYPE_FILE_PATH, path)
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_FILE_PATH)
end
#
# Performs a stat on a file and returns a FileStat instance.
#
def File.stat(name)
return client.fs.filestat.new(name)
return client.fs.filestat.new( name )
end
#
@ -156,7 +145,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO
def File.rm(name)
request = Packet.create_request('stdapi_fs_delete_file')
request.add_tlv(TLV_TYPE_FILE_PATH,name)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( name ))
response = client.send_request(request)

View File

@ -88,7 +88,7 @@ protected
def stat(file)
request = Packet.create_request('stdapi_fs_stat')
request.add_tlv(TLV_TYPE_FILE_PATH, file)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( file ))
response = self.class.client.send_request(request)
stat_buf = response.get_tlv(TLV_TYPE_STAT_BUF).value
@ -101,3 +101,4 @@ protected
end
end; end; end; end; end; end

View File

@ -30,7 +30,7 @@ class Config
def getuid
request = Packet.create_request('stdapi_sys_config_getuid')
response = client.send_request(request)
return response.get_tlv_value(TLV_TYPE_USER_NAME)
return Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
@ -62,7 +62,7 @@ class Config
req = Packet.create_request('stdapi_sys_config_steal_token')
req.add_tlv(TLV_TYPE_PID, pid.to_i)
res = client.send_request(req)
return res.get_tlv_value(TLV_TYPE_USER_NAME)
return Rex::Text.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#
@ -71,7 +71,7 @@ class Config
def drop_token
req = Packet.create_request('stdapi_sys_config_drop_token')
res = client.send_request(req)
return res.get_tlv_value(TLV_TYPE_USER_NAME)
return Rex::Text.unicode_filter_encode( res.get_tlv_value(TLV_TYPE_USER_NAME) )
end
#

View File

@ -151,7 +151,7 @@ class Process < Rex::Post::Process
end
end
request.add_tlv(TLV_TYPE_PROCESS_PATH, path);
request.add_tlv(TLV_TYPE_PROCESS_PATH, Rex::Text.unicode_filter_decode( path ));
# If process arguments were supplied
if (arguments != nil)
@ -177,7 +177,7 @@ class Process < Rex::Post::Process
# Return a process instance
return self.new(pid, handle, channel)
end
#
# Kills one or more processes.
#
@ -223,7 +223,7 @@ class Process < Rex::Post::Process
response.each(TLV_TYPE_PROCESS_GROUP) { |p|
arch = ""
pa = p.get_tlv_value( TLV_TYPE_PROCESS_ARCH )
if( pa != nil )
if pa == 1 # PROCESS_ARCH_X86
@ -232,15 +232,15 @@ class Process < Rex::Post::Process
arch = ARCH_X86_64
end
end
processes <<
{
'pid' => p.get_tlv_value(TLV_TYPE_PID),
'parentid' => p.get_tlv_value(TLV_TYPE_PARENT_PID),
'name' => p.get_tlv_value(TLV_TYPE_PROCESS_NAME),
'path' => p.get_tlv_value(TLV_TYPE_PROCESS_PATH),
'name' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_NAME) ),
'path' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_PROCESS_PATH) ),
'session' => p.get_tlv_value(TLV_TYPE_PROCESS_SESSION),
'user' => p.get_tlv_value(TLV_TYPE_USER_NAME),
'user' => Rex::Text.unicode_filter_encode( p.get_tlv_value(TLV_TYPE_USER_NAME) ),
'arch' => arch
}
}
@ -291,7 +291,7 @@ class Process < Rex::Post::Process
def self.finalize(client,handle)
proc { self.close(client,handle) }
end
#
# Returns the executable name of the process.
#
@ -316,7 +316,7 @@ class Process < Rex::Post::Process
handle = nil;
return true
end
#
# Instance method
#
@ -358,8 +358,8 @@ protected
response = client.send_request(request)
# Populate the hash
info['name'] = response.get_tlv_value(TLV_TYPE_PROCESS_NAME)
info['path'] = response.get_tlv_value(TLV_TYPE_PROCESS_PATH)
info['name'] = Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_PROCESS_NAME) )
info['path'] = Rex::Text.unicode_filter_encode( response.get_tlv_value(TLV_TYPE_PROCESS_PATH) )
return info
end

View File

@ -44,8 +44,8 @@ class Registry
request = Packet.create_request('stdapi_registry_load_key')
request.add_tlv(TLV_TYPE_ROOT_KEY, root_key)
request.add_tlv(TLV_TYPE_BASE_KEY, base_key)
request.add_tlv(TLV_TYPE_FILE_PATH,hive_file)
request.add_tlv(TLV_TYPE_FILE_PATH, Rex::Text.unicode_filter_decode( hive_file ))
response = client.send_request(request)
return response.get_tlv(TLV_TYPE_RESULT).value
end
@ -95,7 +95,7 @@ class Registry
return Rex::Post::Meterpreter::Extensions::Stdapi::Sys::RegistrySubsystem::RemoteRegistryKey.new(
client, target_host, root_key, response.get_tlv(TLV_TYPE_HKEY).value)
end
#
# Creates the supplied registry key or opens it if it already exists.
#

View File

@ -113,7 +113,7 @@ class Tlv
def initialize(type, value = nil, compress=false)
@type = type
@compress = compress
if (value != nil)
if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
if (value.kind_of?(Fixnum))
@ -219,7 +219,7 @@ class Tlv
# Serializers
#
##
#
# Converts the TLV to raw.
#
@ -240,14 +240,14 @@ class Tlv
raw = [0].pack("c")
end
end
# check if the tlv is to be compressed...
if( @compress )
raw_uncompressed = raw
# compress the raw data
raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
# check we have actually made the raw data smaller...
# (small blobs often compress slightly larger then the origional)
# (small blobs often compress slightly larger then the origional)
# if the compressed data is not smaller, we dont use the compressed data
if( raw_compressed.length < raw_uncompressed.length )
# if so, set the TLV's type to indicate compression is used
@ -257,7 +257,7 @@ class Tlv
raw = [ raw_uncompressed.length ].pack("N") + raw_compressed
end
end
return [raw.length + 8, self.type].pack("NN") + raw
end
@ -273,7 +273,7 @@ class Tlv
if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED )
# set this TLV as using compression
@compress = true
# remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
# remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
# tlv type to its origional, allowing for transparent data compression.
self.type = self.type ^ TLV_META_TYPE_COMPRESSED
# decompress the compressed data (skipping the length and type DWORD's)
@ -283,7 +283,7 @@ class Tlv
# update the raw buffer with the new length, decompressed data and updated type.
raw = [length, self.type].pack("NN") + raw_decompressed
end
if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
if (raw.length > 0)
self.value = raw[8..length-2]
@ -293,7 +293,7 @@ class Tlv
elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
self.value = raw.unpack("NNN")[2]
elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
self.value = raw.unpack("NNQ")[2]
self.value = raw.unpack("NNQ")[2]
self.value = self.ntohq( self.value )
elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
self.value = raw.unpack("NNc")[2]
@ -309,9 +309,9 @@ class Tlv
return length;
end
protected
def htonq( value )
if( [1].pack( 's' ) == [1].pack( 'n' ) )
return value
@ -322,7 +322,7 @@ class Tlv
def ntohq( value )
return htonq( value )
end
end
###
@ -685,5 +685,6 @@ class Packet < GroupTlv
end
end
end; end; end

View File

@ -35,6 +35,7 @@ module Text
Alpha = UpperAlpha + LowerAlpha
AlphaNumeric = Alpha + Numerals
HighAscii = [*(0x80 .. 0xff)].pack("C*")
LowAscii = [*(0x00 .. 0x1f)].pack("C*")
DefaultWrap = 60
AllChars = [*(0x00 .. 0xff)].pack("C*")
@ -1122,7 +1123,23 @@ module Text
def self.pack_int64le(val)
[val & 0x00000000ffffffff, val >> 32].pack("V2")
end
#
# A custom unicode filter for dealing with multi-byte strings on a 8-bit console
# Punycode would have been more "standard", but it requires valid Unicode chars
#
def self.unicode_filter_encode(str)
if (str.unpack("C*") & ( LowAscii + HighAscii + "\x7f" ).unpack("C*")).length > 0
str = "$U$" + str.unpack("C*").select{|c| c < 0x7f and c > 0x1f and c != 0x2d}.pack("C*") + "-0x" + str.unpack("H*")[0]
else
str
end
end
def self.unicode_filter_decode(str)
str.gsub( /\$U\$([\x20-\x2c\x2e-\x7E]*)\-0x([A-Fa-f0-9]+)/ ){|m| [$2].pack("H*") }
end
protected