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:
parent
1e1d7c534d
commit
cccbdf9fab
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue