For an introduction to the reasons and goals for external modules, [see our 2017 HaXmas post on the subject](https://blog.rapid7.com/2017/12/28/regifting-python-in-metasploit). 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](https://spacetelescope.github.io/understanding-json-schema). Work still needs to be done enumerating valid types and codes for the messages. Describe -------- **Request** ```javascript { "$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** ```javascript { "$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** ```javascript { "$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** ```javascript { "$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 ```javascript { "$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"} } } } } ```