Link Search Menu Expand Document

For an introduction to the reasons and goals for external modules, see our 2017 HaXmas post on the subject.

Request Flow

Each time Metasploit wants an external module to do something (ex. describe itself or run with a certain configuration), it runs the module in a new process and talks to it over stdin/stdout.

To get the metadata from a module (which includes options), the call sequence looks a bit like:

+------------+
| Metasploit |
|            |  Describe yourself  +-------------------+
|            +-------------------> |  some_module.py   |
|            |                     |                   |
|            |                     |                   |
|            |   Some metadata     |                   |
|            | <-------------------+                   |
|            |                     |                   |
|            |                     +-------------------+
|            |
|            |
+------------+

A module run might look like:

+------------+
| Metasploit |  Do a thing with
|            |   these options     +-------------------+
|            +-------------------> |  some_module.py   |
|            |                     |                   |
|            |                     |                   |
|            |   A bit of status   |                   |
|            | <-------------------+                   |
|            |                     |                   |
|            |  Moar status        |                   |
|            | <-------------------+                   |
|            |                     |                   |
|            |  I found a thing    |                   |
|            | <-------------------+                   |
|            |                     |                   |
|            |                     +-------------------+
|            |
+------------+

When a module meant for a single host is run against a range of hosts, Metasploit will start a new process for each host. If the THREADS datastore option is set and it is an auxiliary module, that many processes will be run at the same time.

JSON-RPC API

External modules communicate with Metasploit over stdin/stdout. The methods a module must implement are describe and run; additional methods can be advertised in the capabilities array, for now assumed to use a subset of the options used for run. Metasploit implements message and will implement report in the near future. The specs for each method are written below using JSON-schema. Work still needs to be done enumerating valid types and codes for the messages.

Describe

Request

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "required": ["params", "method", "jsonrpc", "id"],
  "properties": {
    "jsonrpc": {"enum": ["2.0"]},
    "id": {"type": "string"},
    "method": {"enum": ["describe"]},
    "params": {"type": "object"}
  }
}

Response

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "required": ["jsonrpc", "result", "id"],
  "properties": {
    "jsonrpc": {"enum": ["2.0"]},
    "id": {"type": "string"},
    "result": {
      "type": "object",
      "required": ["name", "description", "authors", "type", "options", "capabilities"],
      "properties": {
        "name": {"type": "string"},
        "description": {"type": "string"},
        "authors": {"type": "array", "items": {"type": "string"}},
        "date": {"type": "string"},
        "references": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["type", "ref"],
            "properties": {
              "type": {"type": "string"},
              "ref": {"type": "string"}
            }
          }
        },
        "type": {"enum": ["remote_exploit.cmd_stager.wget"]},
        "privileged": {"type": "boolean"},
        "targets": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["platform", "arch"],
            "properties": {
              "platform": {"type": "string"},
              "arch": {"type": "string"}
            }
          }
        },
        "options": {
          "type": "object",
          "additionalProperties": false,
          "patternProperties": {
            "^[^=]*$": {
              "type": "object",
              "required": ["type", "description", "required", "default"],
              "properties": {
                "required": {"type": "boolean"},
                "default": {"type": ["null", "string", "number", "boolean", "object", "array"]},
                "description": {"type": "string"},
                "type": {"type": "string"}
              }
            }
          }
        },
        "capabilities": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    }
  }
}

Run

Request

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "required": ["params", "method", "jsonrpc", "id"],
  "properties": {
    "jsonrpc": {"enum": ["2.0"]},
    "id": {"type": "string"},
    "method": {"enum": ["run"]},
    "params": {
      "type": "object"
      "additionalProperties": false,
      "patternProperties": {
        "^[^=]*$": {
          "type": "object",
          "required": ["type", "description", "required", "default"],
          "properties": {
            "required": {"type": "boolean"},
            "default": {"type": ["null", "string", "number", "boolean", "object", "array"]},
            "description": {"type": "string"},
            "type": {"type": "string"}
          }
        }
      }
    }
  }
}

Response

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "required": ["jsonrpc", "id"],
  "properties": {
    "jsonrpc": {"enum": ["2.0"]},
    "id": {"type": "string"},
    "result": {
      "type": "object",
      "required": ["message"]
      "properties": {
        "message": {"type": "string"},
        "return": {"type": "string"}
      }
    },
    "error": {
      "type": "object",
      "required": ["message", "code"],
      "properties": {
        "message": {"type": "string"},
        "code": {"type": "number"},
        "data": {"type": "object"}
      }
    }
  }
}

Message

Notification - no response

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "required": ["params", "method", "jsonrpc"],
  "properties": {
    "jsonrpc": {"enum": ["2.0"]},
    "method": {"enum": ["message"]},
    "params": {
      "type": "object",
      "required": ["level", "message"],
      "properties": {
        "level": {"enum": ["error", "good", "warning", "info", "debug"]},
        "message": {"type": "string"}
      }
    }
  }
}