forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand_mapper.rb
137 lines (109 loc) · 4.77 KB
/
command_mapper.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# -*- coding: binary -*-
require 'rex/post/meterpreter/extension_mapper'
require 'rex/post/meterpreter/core_ids'
require 'rex/post/meterpreter/client_core'
module Rex
module Post
module Meterpreter
class CommandMapper
@@cached_tlv_types = {}
# Get the numeric command ID for the specified command name.
#
# @param [String] name The name of the command to retrieve the ID for. This
# parameter is case insensitive.
# @return [Integer, nil] The command ID or nil if the name does not exist.
def self.get_command_id(name)
name = name.downcase
return nil unless name.include?('_')
mod_name, cmd_name = name.split('_', 2)
if mod_name == 'core'
mod = Rex::Post::Meterpreter
else
mod = Rex::Post::Meterpreter::ExtensionMapper.get_extension_module(mod_name)
end
return nil unless mod
const_name = "COMMAND_ID_#{mod_name.upcase}_#{cmd_name.upcase}"
return nil unless mod.const_defined?(const_name)
mod.const_get(const_name)
end
# Get the string command name for the specified command ID.
#
# @param [Integer] id The ID of the command to retrieve the name for.
# @return [String, nil] The command name or nil if the ID does not exist.
def self.get_command_name(id)
extension_id = id - (id % COMMAND_ID_RANGE)
if extension_id == Rex::Post::Meterpreter::ClientCore.extension_id # this is the meterpreter core which is not exactly an extension.
mod = Rex::Post::Meterpreter
else
mod_name = Rex::Post::Meterpreter::ExtensionMapper.get_extension_name(extension_id)
mod = Rex::Post::Meterpreter::ExtensionMapper.get_extension_module(mod_name)
end
return nil unless mod
command_name = mod.constants.select { |c| c.to_s.start_with?('COMMAND_ID_') }.find { |c| id == mod.const_get(c) }
return nil unless command_name
command_name.to_s.delete_prefix('COMMAND_ID_').downcase
end
# Get all of the string command names for the specified extensions.
#
# @param [Array<String>] extensions The names of the extensions to retrieve
# all of the command names for. The extension names are case insensitive. If
# no extensions are specified, all extensions will be enumerated.
# @return [Array<String>] An array of all of the enumerated command names.
def self.get_command_names(*extensions)
self.get_commands(*extensions).keys
end
# Get a hash of all command name strings mapped to their numeric IDs.
#
# @param [Array<String>] extensions The names of the extensions to retrieve
# all of the commands for. The extension names are case insensitive. If
# no extensions are specified, all extensions will be enumerated.
# @return [Hash<String, Integer>] An hash of all of the enumerated commands.
def self.get_commands(*extensions)
extensions = ['core'] + Rex::Post::Meterpreter::ExtensionMapper.get_extension_names if extensions.empty?
commands = {}
extensions.each do |mod_name|
mod_name = mod_name.downcase
if mod_name == 'core'
mod = Rex::Post::Meterpreter
else
begin
mod = Rex::Post::Meterpreter::ExtensionMapper.get_extension_module(mod_name)
rescue RuntimeError
next
end
end
constants = mod.constants.select { |name| name.to_s.start_with?("COMMAND_ID_#{mod_name.upcase}") }
commands.merge!(constants.map { |name| [name.to_s.delete_prefix('COMMAND_ID_').downcase, mod.const_get(name)] }.to_h)
end
commands
end
# Get the TLV Type symbols that are defined with the value
# Potential return values are [], [:TLV_TYPE_A], and [:TLV_TYPE_A, :PACKET_TYPE_B]
#
# Returning an array is a solution to having multiple TLV types having the same value, as documented here:
# https://github.com/rapid7/metasploit-framework/issues/16267
#
# @param Integer value The value of the TLV type to retrieve the TLV type names for.
# @return [Array<Symbol>] An array of symbols of all TLV types that are defined with the value. Can be empty.
def self.get_tlv_names(value)
return @@cached_tlv_types[value] unless @@cached_tlv_types[value].nil? || @@cached_tlv_types[value].empty?
# Default to arrays that contain TLV Types, so that we only deal with one data type
@@cached_tlv_types = Hash.new { |h, k| h[k] = Set.new }
available_modules = [
::Rex::Post::Meterpreter,
*::Rex::Post::Meterpreter::ExtensionMapper.get_extension_klasses,
# Railgun is a special case that defines extra TLV_TYPES inside an extension
Rex::Post::Meterpreter::Extensions::Stdapi::Railgun
].uniq
available_modules.each do |mod|
mod.constants.each do |const|
next unless const.to_s.start_with?('TLV_TYPE_') || const.to_s.start_with?('PACKET_')
@@cached_tlv_types[mod.const_get(const)] << const
end
end
@@cached_tlv_types[value]
end
end
end
end
end