Class: Msf::MCP::Metasploit::MessagePackClient

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/mcp/metasploit/messagepack_client.rb

Overview

MessagePack RPC client for Metasploit Framework Implements authentication and API calls using MessagePack serialization

Constant Summary collapse

DEFAULT_ENDPOINT =
'/api/'

Instance Method Summary collapse

Constructor Details

#initialize(host:, port:, endpoint: DEFAULT_ENDPOINT, ssl: true) ⇒ MessagePackClient

Initialize MessagePack client

Parameters:

  • host (String)

    Metasploit RPC host

  • port (Integer)

    Metasploit RPC port

  • endpoint (String) (defaults to: DEFAULT_ENDPOINT)

    API endpoint path (default: DEFAULT_ENDPOINT)

  • ssl (Boolean) (defaults to: true)

    Use SSL (default: true)



18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 18

def initialize(host:, port:, endpoint: DEFAULT_ENDPOINT, ssl: true)
  @host = host
  @port = port
  @endpoint = endpoint
  @token = nil
  @http = nil
  @user = nil
  @password = nil
  @retry_count = 0
  @max_retries = 2
  @ssl = ssl
end

Instance Method Details

#authenticate(user, password) ⇒ String

Authenticate with Metasploit RPC

Parameters:

  • user (String)

    Username

  • password (String)

    Password

Returns:

  • (String)

    The resulting token if authentication successful

Raises:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 36

def authenticate(user, password)
  # Store credentials for automatic re-authentication
  @user = user
  @password = password

  # Send authentication request directly (bypass retry logic)
  request_array = ['auth.login', user, password]
  response = send_request(request_array)

  # Real Metasploit API returns string keys
  if response['result'] == 'success' && response['token']
    @token = response['token']
  elsif response['error']
    raise AuthenticationError, response['error']
  else
    raise AuthenticationError, 'Authentication failed'
  end
end

#call_api(method, args = []) ⇒ Hash, Array

Call Metasploit RPC API method

Parameters:

  • method (String)

    API method name (e.g., ‘module.search’)

  • args (Array) (defaults to: [])

    Arguments to pass to the method (must be an array)

Returns:

  • (Hash, Array)

    API response

Raises:



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
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 63

def call_api(method, args = [])
  raise ArgumentError, "args must be an Array, got #{args.class}" unless args.is_a?(Array)

  begin
    raise AuthenticationError, 'Not authenticated' unless @token

    # Build request array: [method, token, *args]
    request_array = [method, @token, *args]

    # Send HTTP request
    send_request(request_array)

  rescue AuthenticationError => e
    # It is not possible to reauthenticate if we don't have credentials stored
    raise unless @user && @password
    # If reauthentication succeeded but the token is still invalid, we should not retry indefinitely
    raise unless @retry_count < @max_retries

    @retry_count += 1
    @token = nil

    begin
      wlog({ message: "#{method}': #{e.message}. Attempting to re-authenticate (#{@retry_count}/#{@max_retries})" },
          LOG_SOURCE, LOG_WARN)
      authenticate(@user, @password)
    rescue AuthenticationError => auth_e
      wlog({ message: "Re-authentication failed: #{auth_e.message}" },
          LOG_SOURCE, LOG_WARN)
      if @retry_count < @max_retries
        @retry_count += 1
        @token = nil
        retry
      end
      raise AuthenticationError, "Unable to authenticate after #{@retry_count} attempts: #{auth_e.message}"
    end

    # Retry the original request with new token
    retry
  end

rescue Msf::MCP::Error => e
  elog({ message: 'MessagePack API call error', context: { error: e.message } },
      LOG_SOURCE, LOG_ERROR)
  raise
ensure
  @retry_count = 0
end

#db_creds(options = {}) ⇒ Hash

Get credentials from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options

Returns:

  • (Hash)

    Response with ‘creds’ array



157
158
159
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 157

def db_creds(options = {})
  call_api('db.creds', [options])
end

#db_hosts(options = {}) ⇒ Hash

Get hosts from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options (workspace, limit, offset, etc.)

Returns:

  • (Hash)

    Response with ‘hosts’ array



129
130
131
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 129

def db_hosts(options = {})
  call_api('db.hosts', [options])
end

#db_loot(options = {}) ⇒ Hash

Get loot from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options

Returns:

  • (Hash)

    Response with ‘loots’ array



164
165
166
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 164

def db_loot(options = {})
  call_api('db.loots', [options])
end

#db_notes(options = {}) ⇒ Hash

Get notes from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options

Returns:

  • (Hash)

    Response with ‘notes’ array



150
151
152
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 150

def db_notes(options = {})
  call_api('db.notes', [options])
end

#db_services(options = {}) ⇒ Hash

Get services from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options

Returns:

  • (Hash)

    Response with ‘services’ array



136
137
138
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 136

def db_services(options = {})
  call_api('db.services', [options])
end

#db_vulns(options = {}) ⇒ Hash

Get vulnerabilities from database

Parameters:

  • options (Hash) (defaults to: {})

    Query options

Returns:

  • (Hash)

    Response with ‘vulns’ array



143
144
145
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 143

def db_vulns(options = {})
  call_api('db.vulns', [options])
end

#module_check(type, name, options = {}) ⇒ Hash

Run the check method of a Metasploit module

Parameters:

  • type (String)

    Module type (‘exploit’ or ‘auxiliary’)

  • name (String)

    Module name

  • options (Hash) (defaults to: {})

    Module datastore options

Returns:

  • (Hash)

    Response containing ‘job_id’ and ‘uuid’ keys



182
183
184
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 182

def module_check(type, name, options = {})
  call_api('module.check', [type, name, options])
end

#module_execute(type, name, options = {}) ⇒ Hash

Execute a Metasploit module

Parameters:

  • type (String)

    Module type (‘exploit’, ‘auxiliary’, ‘post’, ‘payload’, ‘evasion’)

  • name (String)

    Module name (e.g. ‘multi/handler’)

  • options (Hash) (defaults to: {})

    Module datastore options

Returns:

  • (Hash)

    Response containing ‘job_id’ and ‘uuid’ keys



173
174
175
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 173

def module_execute(type, name, options = {})
  call_api('module.execute', [type, name, options])
end

#module_info(type, name) ⇒ Hash

Get module information

Parameters:

  • type (String)

    Module type (‘exploit’, ‘auxiliary’, ‘post’, etc.)

  • name (String)

    Module name

Returns:

  • (Hash)

    Module information



122
123
124
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 122

def module_info(type, name)
  call_api('module.info', [type, name])
end

#module_results(uuid) ⇒ Hash

Get module execution results by UUID

Parameters:

  • uuid (String)

    Module run UUID returned by module_execute / module_check

Returns:

  • (Hash)

    Result hash with ‘status’ key (and ‘result’ / ‘error’ as applicable)



189
190
191
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 189

def module_results(uuid)
  call_api('module.results', [uuid])
end

#running_statsHash

Get currently running module stats (waiting / running / results)

Returns:

  • (Hash)

    Hash with ‘waiting’, ‘running’, ‘results’ arrays of UUIDs



195
196
197
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 195

def running_stats
  call_api('module.running_stats', [])
end

#search_modules(query) ⇒ Array<Hash>

Search for Metasploit modules

Parameters:

  • query (String)

    Search query

Returns:

  • (Array<Hash>)

    Module metadata



114
115
116
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 114

def search_modules(query)
  call_api('module.search', [query])
end

#session_listHash

List active sessions

Returns:

  • (Hash)

    Hash keyed by session ID with session info hashes as values



201
202
203
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 201

def session_list
  call_api('session.list', [])
end

#session_read(session_id) ⇒ Hash

Read buffered output from an interactive session (meterpreter, DB, SMB)

Parameters:

  • session_id (Integer)

    Session ID

Returns:

  • (Hash)

    Response with ‘data’ key containing the buffered output



215
216
217
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 215

def session_read(session_id)
  call_api('session.interactive_read', [session_id])
end

#session_stop(session_id) ⇒ Hash

Stop (kill) an active session

Parameters:

  • session_id (Integer)

    Session ID

Returns:

  • (Hash)

    Response with ‘result’ key set to ‘success’



208
209
210
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 208

def session_stop(session_id)
  call_api('session.stop', [session_id])
end

#session_write(session_id, data) ⇒ Hash

Send input to an interactive session

Parameters:

  • session_id (Integer)

    Session ID

  • data (String)

    Data to send to the session

Returns:

  • (Hash)

    Response with ‘result’ key



223
224
225
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 223

def session_write(session_id, data)
  call_api('session.interactive_write', [session_id, data])
end

#shutdownObject

Shutdown client and cleanup



228
229
230
231
232
233
234
# File 'lib/msf/core/mcp/metasploit/messagepack_client.rb', line 228

def shutdown
  @token = nil
  @user = nil
  @password = nil
  @http&.finish if @http&.started?
  @http = nil
end