-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tomas Gonzalez Vivo
committed
Jul 29, 2017
0 parents
commit 1e8932c
Showing
9 changed files
with
599 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
FROM kalilinux/kali-linux-docker | ||
|
||
ENV DEBIAN_FRONTEND noninteractive | ||
|
||
RUN echo "deb http://http.kali.org/kali kali-rolling main contrib non-free" > /etc/apt/sources.list && \ | ||
echo "deb-src http://http.kali.org/kali kali-rolling main contrib non-free" >> /etc/apt/sources.list | ||
|
||
RUN apt-get -y update && apt-get -y dist-upgrade && apt-get clean | ||
|
||
RUN apt-get install -y curl apt-utils nmap python ruby ruby-dev postgresql | ||
RUN curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \ | ||
chmod 755 msfinstall && \ | ||
./msfinstall | ||
|
||
RUN service postgresql start && msfconsole | ||
|
||
EXPOSE 5432 | ||
EXPOSE 55553 | ||
|
||
ENV username msfUser | ||
ENV password 123456 | ||
|
||
CMD msfrpcd -U msfUser -P $password -n -f -a 0.0.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
 | ||
> The Metasploit RPC api for Node.js | ||
## Getting started | ||
|
||
### Installing | ||
|
||
This will install the cli in your system. | ||
```shell | ||
npm install -g msfrpc | ||
``` | ||
|
||
This will add the msfrpc module to your Node.js project. | ||
```shell | ||
npm install --save msfrpc | ||
``` | ||
|
||
### Using the cli | ||
|
||
```shell | ||
msfrpc-cli <URI> | ||
``` | ||
|
||
URI example: ```https://msfUser:123456@localhost:55553``` | ||
|
||
### Using the api | ||
|
||
All msfrpc methods are grouped in the following "method groups": | ||
* Auth | ||
* Base | ||
* Console | ||
* Core | ||
* Db | ||
* Job | ||
* Module | ||
* Plugin | ||
* Session | ||
|
||
To call a msfrpc, use the following pattern: | ||
``` | ||
msfrpc.<method group>.<method name (camel case)>([arguments]); | ||
``` | ||
|
||
All methods returns Promises. | ||
|
||
Please note that we don't pass tokens to the methods. | ||
Tokens are added automatically by MsfRpc. | ||
|
||
Here is an example: | ||
```js | ||
const MsfRpc = require('msfrpc'); | ||
|
||
const msfrpcUri = 'https://msfUser:123456@localhost:55553'; | ||
const msfrpc = new MsfRpc(msfrpcUri); | ||
|
||
console.log(`Connecting to ${msfrpcUri}`); | ||
msfrpc.connect().then(() => { | ||
return msfrpc.core.version().then((res) => { | ||
console.log(`Metasploit Framework version ${res.version}`); | ||
}).then(() => { | ||
const keyword = 'windows'; | ||
console.log(`Search modules containing "${keyword}". This may take a few seconds...`); | ||
return msfrpc.module.search(keyword).then((modules) => { | ||
console.log(`Found the ${modules.length} modules for "${keyword}":`); | ||
modules.forEach((module) => { | ||
console.log('=========', module.fullname); | ||
console.log(' Name', module.name); | ||
console.log(' Type', module.type); | ||
console.log(' Rank', module.rank); | ||
if(module.disclosuredate) { | ||
console.log(' Date', module.disclosuredate); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
In the example, we: | ||
* Connect to the msfrpc server | ||
* Obtain and print the Metasploit Version | ||
* Find and print all modules containing a given keyword | ||
|
||
### Api Reference | ||
|
||
For a list and documentation of all available methods, visit the following links. | ||
* http://www.nothink.org/metasploit/documentation/RemoteAPI_4.1.pdf | ||
* https://help.rapid7.com/metasploit/Content/api/rpc/overview.html | ||
* https://help.rapid7.com/metasploit/Content/api/rpc/standard-reference.html | ||
* https://rapid7.github.io/metasploit-framework/api/Msf/RPC.html | ||
|
||
Here are some examples of method calls: | ||
|
||
Get version information: | ||
```js | ||
msfrpc.core.version() | ||
``` | ||
|
||
Get module stats: | ||
```js | ||
msfrpc.core.moduleStats() | ||
``` | ||
|
||
Search for a module: | ||
```js | ||
msfrpc.module.search('keyword') | ||
``` | ||
|
||
List payloads: | ||
```js | ||
msfrpc.module.payloads() | ||
``` | ||
|
||
## Developing | ||
|
||
### Optional Prerequisites | ||
This project includes a ```Dockerfile``` (and ```docker-compose.yml```) so you dont have to build a testing environment yourself. | ||
To use docker, you need it installed in your system. | ||
For installation, follow the steps [here](https://docs.docker.com/compose/install/). | ||
|
||
### Setting up Dev | ||
|
||
Clone the repository and install dependencies. | ||
```shell | ||
git clone https://github.com/tomasgvivo/node-msfrpc.git | ||
cd node-msfrpc/ | ||
npm install | ||
``` | ||
|
||
## Licensing | ||
|
||
Copyright 2017 Tomas Gonzalez Vivo | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
version: "3.3" | ||
|
||
services: | ||
msfrpc: | ||
build: . | ||
network_mode: host |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
/** | ||
* Allow self-signed ssl sertificates. | ||
*/ | ||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; | ||
|
||
/** | ||
* Load dependencies. | ||
*/ | ||
const URL = require('url'); | ||
const decamelize = require('decamelize'); | ||
const request = require('request'); | ||
const MsgPack5 = require('msgpack5'); | ||
const Promise = require('bluebird'); | ||
|
||
/** | ||
* Instance MsgPack5. | ||
*/ | ||
const msgpack = MsgPack5(); | ||
|
||
/** | ||
* MsfRpc Class. | ||
* @constructor constructor(uri, options) | ||
* @constructor constructor(options) | ||
*/ | ||
module.exports = class MsfRpc { | ||
|
||
/** | ||
* MsfRpc constructor. | ||
* @param {string|object} uri - Url string with auth credentials, hostname and port. | ||
* @example 'https://msfUser:myPassword@msfrpchost:55553' | ||
* @param {object} options - MsfRpc options. | ||
* @property {string} options.user - MsfRpc username. | ||
* @property {string} options.pass - MsfRpc password. | ||
* @property {string} options.host - MsfRpc hostname. | ||
* @property {number} options.port - MsfRpc port. | ||
* @property {boolean} options.ssl - MsfRpc ssl - true: use https protocol. | ||
* @property {string} options.token - MsfRpc token. | ||
* @return {MsfRpc} | ||
*/ | ||
constructor(uri, options) { | ||
options = options || {}; | ||
|
||
// If uri is an object, it must be options. | ||
if(typeof uri === 'object') { | ||
options = uri; | ||
} else { | ||
// Parse uri. | ||
const url = URL.parse(uri); | ||
const { hostname, port, protocol } = url; | ||
const [ user, pass ] = (url.auth || '').split(':'); | ||
|
||
// Put uri parameters in options. | ||
options.user = user; | ||
options.pass = pass; | ||
options.host = hostname; | ||
options.port = port; | ||
options.ssl = protocol === 'https:'; | ||
} | ||
|
||
// Save options to this. | ||
this.user = options.user; | ||
this.pass = options.pass; | ||
this.host = options.host; | ||
this.port = options.port; | ||
this.ssl = options.ssl; | ||
this.token = options.token; | ||
|
||
// Load api methodGroups proxys. | ||
const methodGroups = [ "auth", "base", "console", "core", "db", "job", "module", "plugin", "session" ]; | ||
methodGroups.forEach((methodGroup) => { | ||
this[methodGroup] = new Proxy({}, { | ||
get: (target, methodName) => { | ||
methodName = decamelize(methodName, '_'); | ||
return (...args) => { | ||
return this._exec(methodGroup + '.' + methodName, ...args); | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Connects to the remote MsfRpc server. | ||
* This is not required if a token was specified in the constructor options. | ||
* @return {Promise} | ||
*/ | ||
connect() { | ||
return this._call("auth.login", this.user, this.pass).then((res) => { | ||
// Save token to this. | ||
this.token = res.token; | ||
}); | ||
} | ||
|
||
/** | ||
* Call an MsfRpc method. | ||
* Take a look at the following links for more information about abailable methods: | ||
* http://www.nothink.org/metasploit/documentation/RemoteAPI_4.1.pdf | ||
* https://help.rapid7.com/metasploit/Content/api/rpc/overview.html | ||
* https://help.rapid7.com/metasploit/Content/api/rpc/standard-reference.html | ||
* https://rapid7.github.io/metasploit-framework/api/Msf/RPC.html | ||
* @param {string} method - MsfRpc method. | ||
* @param {...[any]} args - MsfRpc method's arguments. | ||
* @return {Promise<object>} - MsfRpc call response. | ||
*/ | ||
_call(method, ...args) { | ||
// Encode method and arguments as msgpack buffer. | ||
const buffer = msgpack.encode([method, ...args]); | ||
|
||
return new Promise((resolve) => { | ||
// Send post request to the MsfRpc server. | ||
request({ | ||
method: 'POST', | ||
uri: `${this.ssl ? 'https' : 'http'}://${this.host}:${this.port}/api/1.0`, | ||
body: buffer, | ||
headers: { | ||
'content-type': 'binary/message-pack' | ||
}, | ||
// This translates to encode body as binary data. | ||
encoding: null | ||
}, (error, response, body) => { | ||
if(error) { | ||
throw error; | ||
} else { | ||
// Parse body. | ||
body = this._parseBody(body) | ||
|
||
// If server responded with an exception, build and throw error. | ||
if(body.error) { | ||
const errorLines = []; | ||
errorLines.push(`${body.error_message}`); | ||
errorLines.push(` Backtrace:`); | ||
body.error_backtrace.forEach((trace) => { | ||
errorLines.push(` ${trace}`); | ||
}); | ||
errorLines.push(''); | ||
throw new Error(errorLines.join('\n')); | ||
} else { | ||
// Else, resolve with parsed body. | ||
resolve(body); | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Call a MsfRpc method and include the access token. | ||
* @param {string} method - MsfRpc method. | ||
* @param {...[any]} args - MsfRpc method's arguments. | ||
* @return {Promise<object>} - MsfRpc call response. | ||
*/ | ||
_exec(method, ...args) { | ||
return this._call(method, this.token, ...args); | ||
} | ||
|
||
/** | ||
* Decodes and debufferizes response body. | ||
* @param {object} body - Response body. | ||
* @return {object} | ||
*/ | ||
_parseBody(body) { | ||
const decoded = msgpack.decode(body); | ||
const debufferized = this._debufferize(decoded); | ||
return debufferized; | ||
} | ||
|
||
/** | ||
* Debufferizes an object. | ||
* @description | ||
* When msgpack5 decodes a buffer, it returns an object. | ||
* All object values are buffers. | ||
* So this method recursively converts all buffes to strings. | ||
* @param {any} value - Value to debufferize. | ||
* @return {any} | ||
*/ | ||
_debufferize(value) { | ||
if(value instanceof Buffer) { | ||
return value.toString(); | ||
} else if(value instanceof Array) { | ||
const arr = []; | ||
value.forEach((val) => { | ||
arr.push(this._debufferize(val)); | ||
}); | ||
return arr; | ||
} else if(value instanceof Array) { | ||
const arr = []; | ||
value.forEach((val) => { | ||
arr.push(this._debufferize(val)); | ||
}); | ||
return arr; | ||
} else if(value instanceof Object) { | ||
const obj = {}; | ||
Object.keys(value).forEach((key) => { | ||
if(value.hasOwnProperty(key)) { | ||
obj[key] = this._debufferize(value[key]); | ||
} | ||
}); | ||
return obj; | ||
} else { | ||
return value; | ||
} | ||
} | ||
} |
Oops, something went wrong.