metasploit_shim/
lib.rs

1#![allow(non_snake_case)]
2
3use std::error::Error;
4use std::io::{Write,Read};
5use std::collections::HashMap;
6pub use serde_json::Value;
7
8mod logging;
9pub use logging::*;
10
11mod report;
12pub use report::*;
13
14/// Function Pointer for the metasploit 'run' action callback
15type RunFn = fn(&MsfParamWrapper)->Result<Option<String>,Box<dyn Error>>;
16
17/// Function Pointer for the metasploit 'check' action callback
18type CheckFn = fn(&MsfParamWrapper)->Result<(),Box<dyn Error>>;
19
20#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug, Default)]
21#[serde(rename_all = "camelCase")] // since msf requires 'type', a reserved kw
22pub struct Reference {
23    pub Type: String, // a reserved keyword
24    pub Ref: String,  // a reserved keyword
25}
26
27#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug, Default)]
28#[serde(rename_all = "camelCase")] // since msf requires 'type', a reserved kw
29pub struct ModuleOption {
30    pub Type: String, // rust kw
31    pub description: String,
32    pub required: bool,
33    pub default: String,
34}
35
36#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug,Default)]
37#[serde(rename_all = "camelCase")] // since msf requires 'type', a reserved kw
38pub struct Target {
39    pub platform: String,
40    pub arch: String,
41}
42
43#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug,Default)]
44#[serde(rename_all = "camelCase")] // since msf requires 'type', a reserved kw
45pub struct Payload {
46    pub command_stager_flavor: String,
47}
48
49#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug, Default)]
50#[serde(rename_all = "camelCase")] // since msf requires 'type', a reserved kw
51pub struct Metadata {
52    pub name: String,
53    pub description: String,
54    pub authors: Vec<String>,
55    pub date: String,
56    pub rank: String,
57    pub targets: Vec<Target>,
58    pub payload: Payload,
59    pub Type: String,
60    pub privileged: bool,
61    pub options: HashMap<String,ModuleOption>,
62    pub license: String,
63    pub wfsdelay: usize,
64    pub references: Vec<Reference>,
65    pub capabilities: Vec<String>,
66    // not sure if this is fully supported by the MSF API
67    // so I will leave this out for now.
68    // pub capabilities: Vec<String>, 
69}
70
71#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug)]
72struct RunResponse {
73    jsonrpc: String,
74    id: String,
75    result: RunResult,
76}
77
78#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug)]
79#[serde(rename_all = "camelCase")] // since msf requires 'return', a rust kw
80struct RunResult {
81    Message: String,
82    Return: String, // rust kw
83}
84
85#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug)]
86pub struct MetadataResponse {
87    pub jsonrpc: String,
88    pub id: String,
89    pub result: Metadata,
90}
91
92#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug)]
93struct CheckError {
94    code: isize,
95    message: String,
96}
97
98#[derive(serde_derive::Deserialize,serde_derive::Serialize, Debug)]
99struct CheckErrorResponse {
100    jsonrpc: String,
101    id: String,
102    error: CheckError,
103}
104
105fn send_check_unsupported(
106    id: &str,
107) -> Result<(),Box<dyn Error>> {
108    let check_error_response = CheckErrorResponse {
109        jsonrpc: "2.0".to_string(),
110        id: id.to_string(),
111        error: CheckError {
112            code: -32601,
113            message: "Soft checks are not supported".to_string(),
114        }
115    };
116
117    let check_error_response_str= serde_json::to_string(&check_error_response)?;
118    rpc_send(&check_error_response_str);
119    Ok(())
120}
121
122pub fn send_metadata(
123    request: Request, 
124    metadata: Metadata
125) -> Result<(),Box<dyn Error>> {
126    let metadata_response = MetadataResponse {
127        jsonrpc: request.jsonrpc,
128        id: request.id,
129        result: metadata,
130    };
131    
132    let metadata_resp_string = serde_json::to_string(&metadata_response)?;
133    rpc_send(&metadata_resp_string);
134
135    Ok(())
136}
137
138fn rpc_send(string: &str){
139    print!("{}",string);
140    std::io::stdout().flush().ok().expect("couldn't flush stdout");
141}
142
143fn rpc_read(
144) -> Result<Request,Box<dyn Error>> {
145    let mut stdin_h = std::io::stdin();
146    let mut buf = [0u8; 10000];
147    let num = stdin_h.read(&mut buf)?;
148    // read data from stdin
149    let req_dec = std::str::from_utf8(&buf)?;
150    let mut data = req_dec.to_string();
151    data.truncate(num);
152    // deserialize into json
153    let request: Request= serde_json::from_str(&data)?;
154    Ok(request)
155}
156
157// sends the result after completing the module run
158fn send_complete(
159    id: &str,
160    result: Option<String>,
161)-> Result<(),Box<dyn Error>> {
162    let result_str = match result {
163        Some(v) => v,
164        None => "".to_string(),
165    };
166    let run_result = RunResult {
167        Message: "Module complete".to_string(),
168        Return: result_str,
169    };
170    let run_response = RunResponse {
171        jsonrpc: "2.0".to_string(),
172        id: id.to_string(),
173        result: run_result,
174    };
175    let run_response_string = serde_json::to_string(&run_response)?;
176    rpc_send(&run_response_string);
177    Ok(())
178}
179
180pub fn init(
181    metadata: Metadata,
182    run_fn: RunFn, 
183    check_fn: Option<CheckFn>,
184) -> Result<(),Box<dyn Error>> {
185    let request = rpc_read()?;
186
187    match &request.method.as_str() {
188        &"describe" => {
189            send_metadata(request,metadata)?;
190        }
191        &"run" => {
192            let msfparams: MsfParamWrapper = MsfParamWrapper::new(request.params);
193            let response = run_fn(&msfparams)?;
194            send_complete(&request.id, response)?;
195        }
196        &"soft_check" => {
197            match check_fn {
198                // will keep this commented out until I know for sure
199                // this is supported by MSF API
200                // Some(check) => check(&request.params)?,
201                // None => {
202                //     log_error("check unsupported");
203                //     send_check_unsupported(&request.id)?;
204                // }
205                _ => send_check_unsupported(&request.id)?,
206            }
207        }
208        _ => eprintln!("ERROR: unknown method received"),
209    }
210
211    Ok(())
212}