Skip to main content

ploit_malper/
msf.rs

1use std::collections::BTreeSet;
2
3use crate::models::{MSFModule, MSFNoModuleReason};
4
5use std::sync::OnceLock;
6
7/// Offline Metasploit module catalog. Every entry carries exploit
8/// intelligence: rank, disclosure date, supported platforms and required
9/// options, so recommendations are actionable without a live MSF-RPC server.
10fn catalog() -> &'static Vec<MSFModule> {
11    static MODULES: OnceLock<Vec<MSFModule>> = OnceLock::new();
12    MODULES.get_or_init(|| {
13        vec![
14            MSFModule {
15                name: "exploit/multi/http/apache_path_traversal".into(),
16                cve: Some("CVE-2021-41773".into()),
17                rank: "excellent".into(),
18                disclosure_date: "2021-10-05".into(),
19                platforms: vec!["Unix".into(), "Windows".into()],
20                required_options: vec!["RHOSTS".into(), "TARGETURI".into(), "LHOST".into()],
21            },
22            MSFModule {
23                name: "exploit/multi/http/log4shell_header_injection".into(),
24                cve: Some("CVE-2021-44228".into()),
25                rank: "excellent".into(),
26                disclosure_date: "2021-12-09".into(),
27                platforms: vec!["Unix".into(), "Windows".into(), "Java".into()],
28                required_options: vec![
29                    "RHOSTS".into(),
30                    "TARGETURI".into(),
31                    "HTTP_HEADER".into(),
32                    "LHOST".into(),
33                ],
34            },
35            MSFModule {
36                name: "exploit/windows/smb/ms17_010_eternalblue".into(),
37                cve: Some("CVE-2017-0144".into()),
38                rank: "excellent".into(),
39                disclosure_date: "2017-03-14".into(),
40                platforms: vec!["Windows".into()],
41                required_options: vec!["RHOSTS".into()],
42            },
43            MSFModule {
44                name: "exploit/windows/rdp/cve_2019_0708_bluekeep".into(),
45                cve: Some("CVE-2019-0708".into()),
46                rank: "excellent".into(),
47                disclosure_date: "2019-05-14".into(),
48                platforms: vec!["Windows".into()],
49                required_options: vec!["RHOSTS".into(), "RPORT".into()],
50            },
51            MSFModule {
52                name: "exploit/multi/http/struts2_content_type_ognl".into(),
53                cve: Some("CVE-2017-5638".into()),
54                rank: "excellent".into(),
55                disclosure_date: "2017-03-07".into(),
56                platforms: vec!["Unix".into(), "Windows".into(), "Java".into()],
57                required_options: vec!["RHOSTS".into(), "TARGETURI".into()],
58            },
59            MSFModule {
60                name: "exploit/windows/netlogon/zerologon".into(),
61                cve: Some("CVE-2020-1472".into()),
62                rank: "excellent".into(),
63                disclosure_date: "2020-08-11".into(),
64                platforms: vec!["Windows".into()],
65                required_options: vec!["RHOSTS".into(), "RPORT".into()],
66            },
67            MSFModule {
68                name: "exploit/windows/driver/cve_2021_34527_printnightmare".into(),
69                cve: Some("CVE-2021-34527".into()),
70                rank: "excellent".into(),
71                disclosure_date: "2021-07-01".into(),
72                platforms: vec!["Windows".into()],
73                required_options: vec!["RHOSTS".into(), "TARGET".into(), "LHOST".into()],
74            },
75            MSFModule {
76                name: "exploit/windows/http/exchange_proxylogon_rce".into(),
77                cve: Some("CVE-2021-26855".into()),
78                rank: "excellent".into(),
79                disclosure_date: "2021-02-27".into(),
80                platforms: vec!["Windows".into()],
81                required_options: vec![
82                    "RHOSTS".into(),
83                    "EMAIL".into(),
84                    "PASSWORD".into(),
85                    "LHOST".into(),
86                ],
87            },
88            MSFModule {
89                name: "auxiliary/scanner/http/cisco_directory_traversal".into(),
90                cve: Some("CVE-2020-3452".into()),
91                rank: "good".into(),
92                disclosure_date: "2020-07-14".into(),
93                platforms: vec!["Cisco ASA".into()],
94                required_options: vec!["RHOSTS".into(), "TARGETURI".into()],
95            },
96            MSFModule {
97                name: "exploit/unix/webapp/drupal_drupalgeddon2".into(),
98                cve: Some("CVE-2018-7600".into()),
99                rank: "excellent".into(),
100                disclosure_date: "2018-03-28".into(),
101                platforms: vec!["Unix".into(), "PHP".into()],
102                required_options: vec!["RHOSTS".into(), "TARGETURI".into(), "LHOST".into()],
103            },
104            MSFModule {
105                name: "exploit/multi/http/confluence_webwork_ognl_injection".into(),
106                cve: Some("CVE-2021-26084".into()),
107                rank: "excellent".into(),
108                disclosure_date: "2021-08-25".into(),
109                platforms: vec!["Unix".into(), "Windows".into(), "Java".into()],
110                required_options: vec!["RHOSTS".into(), "TARGETURI".into(), "LHOST".into()],
111            },
112            MSFModule {
113                name: "exploit/multi/http/vmware_vcenter_uploadova_rce".into(),
114                cve: Some("CVE-2021-21972".into()),
115                rank: "excellent".into(),
116                disclosure_date: "2021-02-23".into(),
117                platforms: vec!["Unix".into(), "Windows".into()],
118                required_options: vec!["RHOSTS".into(), "TARGETURI".into(), "LHOST".into()],
119            },
120            MSFModule {
121                name: "auxiliary/scanner/http/apache_version".into(),
122                cve: None,
123                rank: "normal".into(),
124                disclosure_date: "unknown".into(),
125                platforms: vec!["Apache".into()],
126                required_options: vec!["RHOSTS".into()],
127            },
128            MSFModule {
129                name: "auxiliary/scanner/http/iis_version".into(),
130                cve: None,
131                rank: "normal".into(),
132                disclosure_date: "unknown".into(),
133                platforms: vec!["Windows / IIS".into()],
134                required_options: vec!["RHOSTS".into()],
135            },
136            MSFModule {
137                name: "auxiliary/scanner/ssh/ssh_version".into(),
138                cve: None,
139                rank: "normal".into(),
140                disclosure_date: "unknown".into(),
141                platforms: vec!["OpenSSH".into()],
142                required_options: vec!["RHOSTS".into(), "RPORT".into()],
143            },
144            MSFModule {
145                name: "auxiliary/scanner/mysql/mysql_version".into(),
146                cve: None,
147                rank: "normal".into(),
148                disclosure_date: "unknown".into(),
149                platforms: vec!["MySQL".into()],
150                required_options: vec!["RHOSTS".into(), "RPORT".into()],
151            },
152            MSFModule {
153                name: "exploit/linux/mysql/mysql_yassl_getname".into(),
154                cve: None,
155                rank: "good".into(),
156                disclosure_date: "2012-05-10".into(),
157                platforms: vec!["Linux / MySQL".into()],
158                required_options: vec!["RHOSTS".into(), "RPORT".into()],
159            },
160            MSFModule {
161                name: "auxiliary/scanner/postgres/postgres_version".into(),
162                cve: None,
163                rank: "normal".into(),
164                disclosure_date: "unknown".into(),
165                platforms: vec!["PostgreSQL".into()],
166                required_options: vec!["RHOSTS".into(), "RPORT".into()],
167            },
168            MSFModule {
169                name: "auxiliary/scanner/smb/smb_version".into(),
170                cve: None,
171                rank: "normal".into(),
172                disclosure_date: "unknown".into(),
173                platforms: vec!["SMB".into()],
174                required_options: vec!["RHOSTS".into()],
175            },
176            MSFModule {
177                name: "auxiliary/scanner/ftp/ftp_version".into(),
178                cve: None,
179                rank: "normal".into(),
180                disclosure_date: "unknown".into(),
181                platforms: vec!["FTP".into()],
182                required_options: vec!["RHOSTS".into(), "RPORT".into()],
183            },
184            MSFModule {
185                name: "auxiliary/scanner/rdp/rdp_scanner".into(),
186                cve: None,
187                rank: "normal".into(),
188                disclosure_date: "unknown".into(),
189                platforms: vec!["RDP".into()],
190                required_options: vec!["RHOSTS".into(), "RPORT".into()],
191            },
192            MSFModule {
193                name: "exploit/multi/http/tomcat_jsp_upload_bypass".into(),
194                cve: None,
195                rank: "excellent".into(),
196                disclosure_date: "2017-06-19".into(),
197                platforms: vec!["Tomcat".into()],
198                required_options: vec![
199                    "RHOSTS".into(),
200                    "TARGETURI".into(),
201                    "TARGET".into(),
202                    "LHOST".into(),
203                ],
204            },
205            MSFModule {
206                name: "exploit/multi/http/jenkins_script_console".into(),
207                cve: None,
208                rank: "excellent".into(),
209                disclosure_date: "2019-01-01".into(),
210                platforms: vec!["Jenkins".into()],
211                required_options: vec!["RHOSTS".into(), "TARGETURI".into(), "LHOST".into()],
212            },
213            MSFModule {
214                name: "auxiliary/scanner/http/wordpress_scanner".into(),
215                cve: None,
216                rank: "normal".into(),
217                disclosure_date: "unknown".into(),
218                platforms: vec!["WordPress".into()],
219                required_options: vec!["RHOSTS".into(), "TARGETURI".into()],
220            },
221            MSFModule {
222                name: "auxiliary/scanner/http/robots_txt".into(),
223                cve: None,
224                rank: "normal".into(),
225                disclosure_date: "unknown".into(),
226                platforms: vec!["HTTP".into()],
227                required_options: vec!["RHOSTS".into(), "TARGETURI".into()],
228            },
229            MSFModule {
230                name: "auxiliary/scanner/http/golang_pprof".into(),
231                cve: None,
232                rank: "normal".into(),
233                disclosure_date: "unknown".into(),
234                platforms: vec!["Go".into()],
235                required_options: vec!["RHOSTS".into(), "TARGETURI".into()],
236            },
237        ]
238    })
239}
240
241/// Metasploit modules directly tied to a specific CVE.
242pub fn modules_for_cve(cve: &str) -> Vec<MSFModule> {
243    let needle = cve.trim().to_uppercase();
244    catalog()
245        .iter()
246        .filter(|module| {
247            module
248                .cve
249                .as_deref()
250                .map(|known| known.eq_ignore_ascii_case(&needle))
251                .unwrap_or(false)
252        })
253        .cloned()
254        .collect()
255}
256
257/// Metasploit modules relevant to a set of technologies / service banners.
258/// Matching is case-insensitive substring over module metadata.
259pub fn modules_for_technology(needles: &[String]) -> Vec<MSFModule> {
260    if needles.is_empty() {
261        return Vec::new();
262    }
263    let lowered: Vec<String> = needles.iter().map(|n| n.to_lowercase()).collect();
264    let mut found = BTreeSet::new();
265    let mut result = Vec::new();
266    for module in catalog() {
267        if module.cve.is_some() {
268            continue; // CVE-driven modules are surfaced through CVE lookup.
269        }
270        let haystack = format!(
271            "{}{}{}{}",
272            module.name,
273            module.platforms.join(" "),
274            module.disclosure_date,
275            module
276                .required_options
277                .iter()
278                .map(|o| o.to_string())
279                .collect::<Vec<_>>()
280                .join(" ")
281        )
282        .to_lowercase();
283        if lowered.iter().any(|needle| haystack.contains(needle))
284            && found.insert(module.name.clone())
285        {
286            result.push(module.clone());
287        }
288    }
289    result
290}
291
292/// Explicit reason when no Metasploit module is known for a CVE, so the
293/// report never silently omits the search.
294pub fn no_module_reason(cve: &str) -> MSFNoModuleReason {
295    let cve = cve.trim().to_uppercase();
296    if modules_for_cve(&cve).is_empty() {
297        MSFNoModuleReason {
298            cve,
299            reason: "No Metasploit module is known for this CVE in the offline catalog. Verify with `msfconsole -q -x \"search cve:<id>\"` against an updated Metasploit install; if none exists, check Exploit-DB and packet storm for public PoCs.".to_string(),
300        }
301    } else {
302        MSFNoModuleReason {
303            cve,
304            reason: "Module available; see Metasploit Recommendations.".to_string(),
305        }
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use super::*;
312
313    #[test]
314    fn cve_lookup_returns_exact_module() {
315        let modules = modules_for_cve("cve-2021-44228");
316        assert_eq!(modules.len(), 1);
317        assert_eq!(
318            modules[0].name,
319            "exploit/multi/http/log4shell_header_injection"
320        );
321        assert_eq!(modules[0].rank, "excellent");
322        assert!(!modules[0].required_options.is_empty());
323    }
324
325    #[test]
326    fn unknown_cve_has_explicit_reason() {
327        let reason = no_module_reason("CVE-2099-99999");
328        assert!(reason.reason.contains("No Metasploit module"));
329    }
330
331    #[test]
332    fn technology_lookup_filters_cve_modules() {
333        let modules = modules_for_technology(&["apache".to_string()]);
334        assert!(modules
335            .iter()
336            .any(|m| m.name == "auxiliary/scanner/http/apache_version"));
337        assert!(modules.iter().all(|m| m.cve.is_none()));
338    }
339}