stella-coder 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/(/320/270/320/274/321/217 +0 -0
- package/.env.example +4 -0
- package/README.md +72 -0
- package/STELLA.md +6 -0
- package/antimalware/database.mjs +871 -0
- package/antimalware/index.mjs +8 -0
- package/antimalware/scanner.mjs +591 -0
- package/antimalware/ui.mjs +570 -0
- package/components.json +21 -0
- package/create_cats_pptx.py +121 -0
- package/eslint.config.mjs +16 -0
- package/hello.py +2 -0
- package/install.bat +35 -0
- package/next-env.d.ts +6 -0
- package/next.config.mjs +11 -0
- package/package.json +58 -0
- package/pnpm-workspace.yaml +7 -0
- package/postcss.config.mjs +8 -0
- package/publish.mjs +52 -0
- package/stella-cli/banner.mjs +46 -0
- package/stella-cli/build.mjs +151 -0
- package/stella-cli/index.mjs +3073 -0
- package/stella-cli/markdown.mjs +100 -0
- package/stella-cli/sea-config.json +5 -0
- package/stella-cli/security.mjs +237 -0
- package/stella-cli/theme.mjs +89 -0
- package/stella-cli/tools.mjs +3145 -0
- package/tsconfig.json +41 -0
|
@@ -0,0 +1,871 @@
|
|
|
1
|
+
import crypto from "node:crypto"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════
|
|
6
|
+
// STELLAR ANTIVIRUS — Threat Database v3
|
|
7
|
+
// Full AV engine — 100+ signatures, YARA, heuristics
|
|
8
|
+
// ═══════════════════════════════════════════════════════════════
|
|
9
|
+
|
|
10
|
+
const BINARY_EXTS = new Set([
|
|
11
|
+
".exe", ".dll", ".sys", ".com", ".scr", ".pif",
|
|
12
|
+
".bat", ".cmd", ".vbs", ".vbe", ".jse", ".wsf", ".wsh",
|
|
13
|
+
".hta", ".cpl", ".msi", ".msp", ".mst",
|
|
14
|
+
".jar", ".class", ".war",
|
|
15
|
+
".doc", ".docm", ".xls", ".xlsm", ".ppt", ".pptm",
|
|
16
|
+
".rtf", ".pdf",
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
export const SKIP_DIRS = new Set([
|
|
20
|
+
"node_modules", ".git", ".next", ".vercel", "__pycache__",
|
|
21
|
+
".stella", ".secure", ".cache", "dist", "build", ".turbo",
|
|
22
|
+
"coverage", ".DS_Store", "antimalware",
|
|
23
|
+
"SoftwareDistribution", "WinSxS", "Installer", "$Recycle.Bin",
|
|
24
|
+
"System Volume Information", "Recovery",
|
|
25
|
+
"node-compile-cache", "npm-cache", "pip-cache",
|
|
26
|
+
"OpencodeSoftware", "opencode",
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
export const QUICK_SCAN_PATHS = [
|
|
30
|
+
"C:\\Users\\%USERNAME%\\AppData\\Local\\Temp",
|
|
31
|
+
"C:\\Users\\%USERNAME%\\Downloads",
|
|
32
|
+
"C:\\Users\\%USERNAME%\\AppData\\Roaming",
|
|
33
|
+
"C:\\Users\\%USERNAME%\\Desktop",
|
|
34
|
+
"C:\\Users\\%USERNAME%\\Documents",
|
|
35
|
+
"C:\\Windows\\Temp",
|
|
36
|
+
"C:\\Windows\\System32\\drivers\\etc",
|
|
37
|
+
"C:\\ProgramData",
|
|
38
|
+
"C:\\Users\\%USERNAME%\\AppData\\Local\\Microsoft\\Windows\\Startup",
|
|
39
|
+
"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup",
|
|
40
|
+
"C:\\Windows\\System32\\Tasks",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════
|
|
44
|
+
// SIGNATURES — 100+ detection patterns
|
|
45
|
+
// ═══════════════════════════════════════════════════════════════
|
|
46
|
+
|
|
47
|
+
export const SIGNATURES = [
|
|
48
|
+
// ══════ PE INFECTORS ══════
|
|
49
|
+
{ id: "SIG-001", name: "PE感染者", severity: "critical", category: "trojan",
|
|
50
|
+
pattern: /\x4D\x5A[\s\S]{0,200}\x50\x45\x00\x00[\s\S]{0,500}(\x00){16,}/ },
|
|
51
|
+
|
|
52
|
+
{ id: "SIG-002", name: "Пакер/Crypter", severity: "critical", category: "trojan",
|
|
53
|
+
pattern: /\x4D\x5A[\s\S]{0,100}(UPX|ASPack|PECompact|Themida|VMProtect|Obsidium|Armadillo)/ },
|
|
54
|
+
|
|
55
|
+
{ id: "SIG-003", name: "Dropper", severity: "critical", category: "trojan",
|
|
56
|
+
pattern: /(CreateFile|WriteFile)[\s\S]{0,200}(\.exe|\.dll|\.sys)[\s\S]{0,200}(CreateProcess|ShellExecute)/s },
|
|
57
|
+
|
|
58
|
+
// ══════ PROCESS INJECTION ══════
|
|
59
|
+
{ id: "SIG-004", name: "Process Hollowing", severity: "critical", category: "injection",
|
|
60
|
+
pattern: /NtUnmapViewOfSection|ZwUnmapViewOfSection|RtlCreateUserThread|NtCreateThreadEx[\s\S]{0,100}CreateRemoteThread/s },
|
|
61
|
+
|
|
62
|
+
{ id: "SIG-005", name: "Inject в системный процесс", severity: "critical", category: "injection",
|
|
63
|
+
pattern: /OpenProcess[\s\S]{0,100}(PROCESS_ALL_ACCESS|PROCESS_CREATE_THREAD)[\s\S]{0,100}WriteProcessMemory[\s\S]{0,100}CreateRemoteThread/s },
|
|
64
|
+
|
|
65
|
+
{ id: "SIG-006", name: "APC Injection", severity: "critical", category: "injection",
|
|
66
|
+
pattern: /QueueUserAPC|NtQueueApcThread|EkalertRegisterAlertCallback[\s\S]{0,100}VirtualAllocEx/s },
|
|
67
|
+
|
|
68
|
+
{ id: "SIG-007", name: "Thread Hijacking", severity: "critical", category: "injection",
|
|
69
|
+
pattern: /SuspendThread[\s\S]{0,100}GetThreadContext[\s\S]{0,100}SetThreadContext[\s\S]{0,100}ResumeThread/s },
|
|
70
|
+
|
|
71
|
+
{ id: "SIG-008", name: "Reflective DLL Loading", severity: "critical", category: "injection",
|
|
72
|
+
pattern: /LoadLibraryA[\s\S]{0,100}GetProcAddress[\s\S]{0,100}(DllMain|EntryPoint)[\s\S]{0,100}VirtualProtect/s },
|
|
73
|
+
|
|
74
|
+
// ══════ KEYLOGGERS ══════
|
|
75
|
+
{ id: "SIG-009", name: "Keylogger API", severity: "critical", category: "spyware",
|
|
76
|
+
pattern: /SetWindowsHookEx[\s\S]{0,50}(WH_KEYBOARD|WH_KEYBOARD_LL|WH_MOUSE)[\s\S]{0,100}(GetAsyncKeyState|GetKeyState)/ },
|
|
77
|
+
|
|
78
|
+
{ id: "SIG-010", name: "Clipboard theft", severity: "high", category: "spyware",
|
|
79
|
+
pattern: /GetClipboardData[\s\S]{0,100}(GlobalLock|GlobalAlloc)[\s\S]{0,100}(InternetOpen|HttpSendRequest)/ },
|
|
80
|
+
|
|
81
|
+
{ id: "SIG-011", name: "Screen capture + exfil", severity: "critical", category: "spyware",
|
|
82
|
+
pattern: /(BitBlt|GetDC|CreateCompatibleBitmap)[\s\S]{0,200}(JpegEncoder|PngEncoder|SaveToFile)[\s\S]{0,200}(http|ftp|socket)/s },
|
|
83
|
+
|
|
84
|
+
// ══════ CREDENTIAL THEFT ══════
|
|
85
|
+
{ id: "SIG-012", name: "LSASS дамп", severity: "critical", category: "credential-theft",
|
|
86
|
+
pattern: /MiniDumpWriteDump[\s\S]{0,100}(lsass|csrss|svchost)/ },
|
|
87
|
+
|
|
88
|
+
{ id: "SIG-013", name: "Mimikatz загрузка", severity: "critical", category: "credential-theft",
|
|
89
|
+
pattern: /Invoke-Mimikatz|mimikatz[\s\S]{0,50}sekurlsa::logonpasswords|gentilkiwi/ },
|
|
90
|
+
|
|
91
|
+
{ id: "SIG-014", name: "Browser password theft", severity: "critical", category: "credential-theft",
|
|
92
|
+
pattern: /(Login Data|logins\.json|cookies\.sqlite|signons\.sqlite)[\s\S]{0,200}(sqlite3_open|ReadFile)[\s\S]{0,200}(http|ftp)/s },
|
|
93
|
+
|
|
94
|
+
{ id: "SIG-015", name: "Криптокошелёк кража", severity: "critical", category: "credential-theft",
|
|
95
|
+
pattern: /(wallet\.dat|Electrum|Bitcoin|Ethereum|MetaMask)[\s\S]{0,200}(CopyFile|MoveFile|ReadFile)[\s\S]{0,200}(http|ftp|socket)/s },
|
|
96
|
+
|
|
97
|
+
{ id: "SIG-016", name: "Certificate theft", severity: "high", category: "credential-theft",
|
|
98
|
+
pattern: /(certutil|CertOpenStore|PFX|PKCS12)[\s\S]{0,100}(Export|export|CopyFile)[\s\S]{0,100}(http|ftp)/ },
|
|
99
|
+
|
|
100
|
+
// ══════ RANSOMWARE ══════
|
|
101
|
+
{ id: "SIG-017", name: "Ransomware шифрование", severity: "critical", category: "ransomware",
|
|
102
|
+
pattern: /(AES|DES|RSA|ChaCha20|Salsa20|XOR)[\s\S]{0,100}(CreateFile|WriteFile)[\s\S]{0,100}\.(locked|encrypted|crypto|cerber|cerber3)/ },
|
|
103
|
+
|
|
104
|
+
{ id: "SIG-018", name: "Восстановление удалено", severity: "critical", category: "ransomware",
|
|
105
|
+
pattern: /vssadmin[\s\S]*delete[\s\S]*shadows|bcdedit[\s\S]*set[\s\S]*recoveryenabled\s+no|wbadmin[\s\S]*delete[\s\S]*catalog/ },
|
|
106
|
+
|
|
107
|
+
{ id: "SIG-019", name: "Ransomware note", severity: "critical", category: "ransomware",
|
|
108
|
+
pattern: /(your files have been encrypted|pay the ransom|bitcoin wallet|decrypt your files|send bitcoin|files will be deleted)[\s\S]{0,500}(tor|onion|bitcoin|monero)/is },
|
|
109
|
+
|
|
110
|
+
{ id: "SIG-020", name: "Extension changer", severity: "critical", category: "ransomware",
|
|
111
|
+
pattern: /(rename|MoveFileEx|SetFileAttributes)[\s\S]{0,100}\.(locked|crypt|enc|encrypted|crypto|cerber|locky|wannacry)/ },
|
|
112
|
+
|
|
113
|
+
// ══════ ROOTKIT ══════
|
|
114
|
+
{ id: "SIG-021", name: "Kernel rootkit", severity: "critical", category: "rootkit",
|
|
115
|
+
pattern: /NtQuerySystemInformation[\s\S]{0,100}ZwQuerySystemInformation[\s\S]{0,100}(SSDT|IDT|IAT|DKOM)/ },
|
|
116
|
+
|
|
117
|
+
{ id: "SIG-022", name: "Hide process", severity: "critical", category: "rootkit",
|
|
118
|
+
pattern: /NtSetInformationProcess[\s\S]{0,100}ProcessDebugPort|ZwQueryInformationProcess[\s\S]{0,100}ProcessDebugFlags/ },
|
|
119
|
+
|
|
120
|
+
{ id: "SIG-023", name: "Hide file", severity: "critical", category: "rootkit",
|
|
121
|
+
pattern: /NtQueryDirectoryFile[\s\S]{0,100}FILE_BOTH_DIR_INFORMATION[\s\S]{0,100}NextEntryOffset/ },
|
|
122
|
+
|
|
123
|
+
{ id: "SIG-024", name: "SSDT hook", severity: "critical", category: "rootkit",
|
|
124
|
+
pattern: /KeServiceDescriptorTable[\s\S]{0,100}(hook|detour|trampoline|patch)/ },
|
|
125
|
+
|
|
126
|
+
// ══════ BACKDOORS ══════
|
|
127
|
+
{ id: "SIG-025", name: "Bind shell", severity: "critical", category: "backdoor",
|
|
128
|
+
pattern: /socket[\s\S]{0,100}bind[\s\S]{0,100}listen[\s\S]{0,100}accept[\s\S]{0,100}(cmd|bash|sh)[\s\S]{0,50}(dup2|SOCK_STREAM)/ },
|
|
129
|
+
|
|
130
|
+
{ id: "SIG-026", name: "Reverse shell", severity: "critical", category: "backdoor",
|
|
131
|
+
pattern: /socket[\s\S]{0,100}connect[\s\S]{0,100}\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[\s\S]{0,100}(cmd|bash|sh)[\s\S]{0,50}dup2/ },
|
|
132
|
+
|
|
133
|
+
{ id: "SIG-027", name: "Webshell PHP", severity: "critical", category: "backdoor",
|
|
134
|
+
pattern: /\$_(POST|GET|REQUEST|COOKIE)\[[\s\S]{0,50}\]\s*\([\s\S]{0,100}(eval|exec|system|passthru|shell_exec|popen|proc_open)\s*\(/ },
|
|
135
|
+
|
|
136
|
+
{ id: "SIG-028", name: "Webshell ASP", severity: "critical", category: "backdoor",
|
|
137
|
+
pattern: /eval\s*\(\s*Request[\s\S]{0,50}(Execute|CreateObject)[\s\S]{0,50}WScript\.Shell/ },
|
|
138
|
+
|
|
139
|
+
{ id: "SIG-029", name: "Webshell JSP", severity: "critical", category: "backdoor",
|
|
140
|
+
pattern: /Runtime\.getRuntime\(\)\.exec[\s\S]{0,50}(cmd|bash)[\s\S]{0,50}(Process|InputStream)/ },
|
|
141
|
+
|
|
142
|
+
{ id: "SIG-030", name: "IRC Botnet", severity: "high", category: "botnet",
|
|
143
|
+
pattern: /PRIVMSG\s*#\w+\s*:\s*\x01[\s\S]{0,100}(JOIN|NICK|USER)[\s\S]{0,50}\.join\(|\.on\('data'/ },
|
|
144
|
+
|
|
145
|
+
// ══════ EXPLOITS ══════
|
|
146
|
+
{ id: "SIG-031", name: "Metasploit стейджинг", severity: "critical", category: "exploit",
|
|
147
|
+
pattern: /msfvenom[\s\S]{0,100}reverse[\s\S]{0,50}(tcp|http|https)[\s\S]{0,100}(meterpreter|shell|vnc)/ },
|
|
148
|
+
|
|
149
|
+
{ id: "SIG-032", name: "Meterpreter payload", severity: "critical", category: "exploit",
|
|
150
|
+
pattern: /meterpreter[\s\S]{0,100}(reverse_tcp|reverse_http|reverse_https)[\s\S]{0,100}(LHOST|LPORT)/ },
|
|
151
|
+
|
|
152
|
+
{ id: "SIG-033", name: "Shellcode detector", severity: "critical", category: "exploit",
|
|
153
|
+
pattern: /(\x31\xc0|\x31\xdb|\x31\xc9|\x31\xd2|\x90{8,})[\s\S]{0,50}(\\x6a|\\x58|\\xcd|\\x80)/ },
|
|
154
|
+
|
|
155
|
+
{ id: "SIG-034", name: "ROP chain", severity: "high", category: "exploit",
|
|
156
|
+
pattern: /gadget[\s\S]{0,50}(pop[\s\S]{0,20}ret|call[\s\S]{0,20}eax|jmp[\s\S]{0,20}esp)/ },
|
|
157
|
+
|
|
158
|
+
// ══════ PRIVILEGE ESCALATION ══════
|
|
159
|
+
{ id: "SIG-035", name: "UAC bypass", severity: "critical", category: "privesc",
|
|
160
|
+
pattern: /(fodhelper|eventvwr|computerdefaults|sdclt|slui)[\s\S]{0,100}(ms-settings|HKCU|CurrentVersion)\\Run/ },
|
|
161
|
+
|
|
162
|
+
{ id: "SIG-036", name: "Token impersonation", severity: "critical", category: "privesc",
|
|
163
|
+
pattern: /ImpersonateLoggedOnUser|DuplicateTokenEx|SetThreadToken[\s\S]{0,100}(AdjustTokenPrivileges|SeDebugPrivilege)/ },
|
|
164
|
+
|
|
165
|
+
{ id: "SIG-037", name: "Service install", severity: "high", category: "privesc",
|
|
166
|
+
pattern: /CreateService[\s\S]{0,100}(SERVICE_AUTO_START|SERVICE_WIN32_OWN_PROCESS)[\s\S]{0,100}(cmd|powershell|bash)/ },
|
|
167
|
+
|
|
168
|
+
// ══════ ANTI-ANALYSIS ══════
|
|
169
|
+
{ id: "SIG-038", name: "VM detection", severity: "high", category: "anti-analysis",
|
|
170
|
+
pattern: /(VMware|VirtualBox|QEMU|Hyper-V|Xen)[\s\S]{0,100}(CPUID|cpuid|__cpuid|vmexit|vmcall)/ },
|
|
171
|
+
|
|
172
|
+
{ id: "SIG-039", name: "Debugger detection", severity: "high", category: "anti-analysis",
|
|
173
|
+
pattern: /IsDebuggerPresent|CheckRemoteDebuggerPresent|NtQueryInformationProcess[\s\S]{0,100}ProcessDebugPort/ },
|
|
174
|
+
|
|
175
|
+
{ id: "SIG-040", name: "Sandbox detection", severity: "high", category: "anti-analysis",
|
|
176
|
+
pattern: /(NtQuerySystemInformation|GetTickCount|timeGetTime)[\s\S]{0,100}(anti-vm|anti-debug|sandbox|sleep|delay)/i },
|
|
177
|
+
|
|
178
|
+
{ id: "SIG-041", name: "AMSI bypass", severity: "critical", category: "anti-analysis",
|
|
179
|
+
pattern: /AmsiUtils[\s\S]{0,100}amsiInitFailed|AmsiScanBuffer[\s\S]{0,100}0x80070057|SetProcessMitigationPolicy[\s\S]{0,50}DisableDynamicCode/ },
|
|
180
|
+
|
|
181
|
+
{ id: "SIG-042", name: "ETW patch", severity: "critical", category: "anti-analysis",
|
|
182
|
+
pattern: /EtwEventWrite[\s\S]{0,100}(patch|nop|ret|0xc3)|NtTraceEvent[\s\S]{0,100}(hook|detour)/ },
|
|
183
|
+
|
|
184
|
+
// ══════ PERSISTENCE ══════
|
|
185
|
+
{ id: "SIG-043", name: "Registry Run key", severity: "high", category: "persistence",
|
|
186
|
+
pattern: /CurrentVersion\\Run[\s\S]{0,100}(cmd|powershell|bash|python|perl|wscript|cscript)/ },
|
|
187
|
+
|
|
188
|
+
{ id: "SIG-044", name: "Scheduled task", severity: "high", category: "persistence",
|
|
189
|
+
pattern: /schtasks[\s\S]{0,100}(\/create|\/Create)[\s\S]{0,100}(cmd|powershell|bash|python|perl)/ },
|
|
190
|
+
|
|
191
|
+
{ id: "SIG-045", name: "Startup folder", severity: "high", category: "persistence",
|
|
192
|
+
pattern: /\\Start Menu\\Programs\\Startup[\s\S]{0,100}\.(exe|bat|cmd|vbs|ps1|js)/ },
|
|
193
|
+
|
|
194
|
+
{ id: "SIG-046", name: "WMI subscription", severity: "high", category: "persistence",
|
|
195
|
+
pattern: /CommandLineEventConsumer[\s\S]{0,100}(cmd|powershell|bash|python|perl)/ },
|
|
196
|
+
|
|
197
|
+
{ id: "SIG-047", name: "Service DLL hijack", severity: "high", category: "persistence",
|
|
198
|
+
pattern: /ServiceDll[\s\S]{0,100}(HKLM|HKCU)[\s\S]{0,100}\\(cmd|powershell|bash|python|perl)/ },
|
|
199
|
+
|
|
200
|
+
// ══════ NETWORK BACKDOORS ══════
|
|
201
|
+
{ id: "SIG-048", name: "Reverse TCP", severity: "critical", category: "backdoor",
|
|
202
|
+
pattern: /socket[\s\S]{0,100}connect[\s\S]{0,100}\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[\s\S]{0,100}(SOCK_STREAM|SOCK_DGRAM)/ },
|
|
203
|
+
|
|
204
|
+
{ id: "SIG-049", name: "Reverse HTTP", severity: "high", category: "backdoor",
|
|
205
|
+
pattern: /InternetOpen[\s\S]{0,100}HttpOpenRequest[\s\S]{0,100}(POST|PUT)[\s\S]{0,100}(cmd|bash|powershell)/ },
|
|
206
|
+
|
|
207
|
+
{ id: "SIG-050", name: "DNS tunneling", severity: "high", category: "backdoor",
|
|
208
|
+
pattern: /DnsQuery[\s\S]{0,100}(TXT|MX|CNAME)[\s\S]{0,100}(encode|decode|base64)[\s\S]{0,100}(socket|connect)/ },
|
|
209
|
+
|
|
210
|
+
// ══════ OBFUSCATION ══════
|
|
211
|
+
{ id: "SIG-051", name: "Base64 decode chain", severity: "high", category: "obfuscation",
|
|
212
|
+
pattern: /atob\s*\(\s*atob\s*\(|fromCharCode[\s\S]{0,50}atob|eval\s*\(\s*atob\s*\(/ },
|
|
213
|
+
|
|
214
|
+
{ id: "SIG-052", name: "PowerShell download cradle", severity: "high", category: "obfuscation",
|
|
215
|
+
pattern: /IEX\s*\(\s*(New-Object\s+Net\.WebClient|Invoke-WebRequest|wget|curl)[\s\S]*\)|Invoke-Expression[\s\S]{0,100}(DownloadString|DownloadFile)/i },
|
|
216
|
+
|
|
217
|
+
{ id: "SIG-053", name: "String building", severity: "medium", category: "obfuscation",
|
|
218
|
+
pattern: /String\.fromCharCode\s*\(\s*\d+[\s\S]{0,20}\d+[\s\S]{0,20}\d+[\s\S]{0,20}\d+/ },
|
|
219
|
+
|
|
220
|
+
{ id: "SIG-054", name: "Hex encoding", severity: "medium", category: "obfuscation",
|
|
221
|
+
pattern: /\\x[0-9a-f]{2}\\x[0-9a-f]{2}\\x[0-9a-f]{2}\\x[0-9a-f]{2}\\x[0-9a-f]{2}/i },
|
|
222
|
+
|
|
223
|
+
{ id: "SIG-055", name: "Dynamic eval chain", severity: "high", category: "obfuscation",
|
|
224
|
+
pattern: /eval\s*\(\s*(eval|Function|atob|Buffer\.from|unescape|fromCharCode)/ },
|
|
225
|
+
|
|
226
|
+
// ══════ MINERS ══════
|
|
227
|
+
{ id: "SIG-056", name: "Crypto miner池", severity: "high", category: "miner",
|
|
228
|
+
pattern: /stratum\+tcp:\/\/[\w.-]+:\d{4,5}/ },
|
|
229
|
+
|
|
230
|
+
{ id: "SIG-057", name: "XMRig", severity: "high", category: "miner",
|
|
231
|
+
pattern: /xmrig[\s\S]{0,100}(algo|coin|pool|wallet|donate-level)/ },
|
|
232
|
+
|
|
233
|
+
{ id: "SIG-058", name: "Browser miner", severity: "high", category: "miner",
|
|
234
|
+
pattern: /coinhive[\s\S]{0,100}(CoinHive\.Worker|anonymous|captcha)|cryptoloot[\s\S]{0,100}(CryptoLoot\.Worker|anonymous)/ },
|
|
235
|
+
|
|
236
|
+
// ══════ DATA EXFILTRATION ══════
|
|
237
|
+
{ id: "SIG-059", name: "FTP upload", severity: "high", category: "exfil",
|
|
238
|
+
pattern: /ftp[\s\S]{0,100}(upload|put|stor)[\s\S]{0,100}(password|passwd|secret|token|key)/ },
|
|
239
|
+
|
|
240
|
+
{ id: "SIG-060", name: "HTTP POST exfil", severity: "high", category: "exfil",
|
|
241
|
+
pattern: /(fetch|XMLHttpRequest|axios|http\.request|request\()[\s\S]{0,200}(POST|PUT)[\s\S]{0,200}(password|token|secret|credential|cookie)/ },
|
|
242
|
+
|
|
243
|
+
{ id: "SIG-061", name: "DNS exfil", severity: "high", category: "exfil",
|
|
244
|
+
pattern: /DnsQuery[\s\S]{0,100}(encode|encodeURI|base64)[\s\S]{0,100}(password|token|secret|credential)/ },
|
|
245
|
+
|
|
246
|
+
// ══════ WORMS ══════
|
|
247
|
+
{ id: "SIG-062", name: "USB worm", severity: "critical", category: "worm",
|
|
248
|
+
pattern: /(RECYCLER|Recycle\.Bin|autorun\.inf|\\setup\.exe)[\s\S]{0,100}(CopyFile|MoveFile|CreateFile)/ },
|
|
249
|
+
|
|
250
|
+
{ id: "SIG-063", name: "Network worm", severity: "critical", category: "worm",
|
|
251
|
+
pattern: /(NetServerEnum|NetShareEnum|WNetEnumResource|WNetOpenEnum)[\s\S]{0,100}(CopyFile|MoveFile|CreateProcess)/ },
|
|
252
|
+
|
|
253
|
+
// ══════ ADWARE / PUP ══════
|
|
254
|
+
{ id: "SIG-064", name: "Adware inject", severity: "medium", category: "adware",
|
|
255
|
+
pattern: /(inject|append|prepend)[\s\S]{0,100}(ads|advertis|popup|banner|click)[\s\S]{0,100}(google|facebook|amazon|ebay)/i },
|
|
256
|
+
|
|
257
|
+
{ id: "SIG-065", name: "Browser hijack", severity: "high", category: "adware",
|
|
258
|
+
pattern: /(startPage|searchProvider|homePage)[\s\S]{0,100}(http|https)[\s\S]{0,50}(ads|search|babylon|conduit|ask\.com)/i },
|
|
259
|
+
|
|
260
|
+
{ id: "SIG-066", name: "Software Bundler", severity: "medium", category: "adware",
|
|
261
|
+
pattern: /(toolbar|extension|plugin)[\s\S]{0,100}(install|download|update)[\s\S]{0,100}(offer|recommend|special)/i },
|
|
262
|
+
|
|
263
|
+
// ══════ BANKING TROJANS ══════
|
|
264
|
+
{ id: "SIG-067", name: "Web inject", severity: "critical", category: "banking",
|
|
265
|
+
pattern: /(inject|intercept|modify)[\s\S]{0,100}(https?:\/\/(www\.)?(bank|paypal|alipay|pay\.google))/i },
|
|
266
|
+
|
|
267
|
+
{ id: "SIG-068", name: "Form grabbing", severity: "critical", category: "banking",
|
|
268
|
+
pattern: /(HttpSendRequest|InternetReadFile)[\s\S]{0,200}(password|login|pin|credential|account)/ },
|
|
269
|
+
|
|
270
|
+
{ id: "SIG-069", name: "MITM proxy", severity: "critical", category: "banking",
|
|
271
|
+
pattern: /(mitmproxy|ettercap|bettercap|burp)[\s\S]{0,100}(inject|intercept|modify)[\s\S]{0,100}(http|https)/i },
|
|
272
|
+
|
|
273
|
+
// ══════ RAT (Remote Access Trojans) ══════
|
|
274
|
+
{ id: "SIG-070", name: "RAT keylogger", severity: "critical", category: "rat",
|
|
275
|
+
pattern: /(GetAsyncKeyState|SetWindowsHookEx)[\s\S]{0,200}(http|ftp|socket|connect)[\s\S]{0,100}(send|write|upload)/ },
|
|
276
|
+
|
|
277
|
+
{ id: "SIG-071", name: "RAT screen capture", severity: "critical", category: "rat",
|
|
278
|
+
pattern: /(BitBlt|GetDC|GetDesktopWindow)[\s\S]{0,200}(JpegEncoder|PngEncoder|Image\.save)[\s\S]{0,200}(http|ftp|socket)/ },
|
|
279
|
+
|
|
280
|
+
{ id: "SIG-072", name: "RAT webcam", severity: "critical", category: "rat",
|
|
281
|
+
pattern: /(capCreateCaptureWindow|avicap32|WebCamCapture|webcam)[\s\S]{0,200}(getImageData|capture)[\s\S]{0,200}(http|ftp|socket)/ },
|
|
282
|
+
|
|
283
|
+
{ id: "SIG-073", name: "RAT file manager", severity: "high", category: "rat",
|
|
284
|
+
pattern: /(ListFiles|GetFiles|GetDirectories|ReadDirectory)[\s\S]{0,200}(Download|Upload|Delete|Rename|Copy|Move)[\s\S]{0,200}(http|ftp|socket)/ },
|
|
285
|
+
|
|
286
|
+
{ id: "SIG-074", name: "RAT command execution", severity: "critical", category: "rat",
|
|
287
|
+
pattern: /(cmd\.exe|powershell|bash)[\s\S]{0,100}(-c|-e|\/c)[\s\S]{0,200}(http|ftp|socket)[\s\S]{0,100}(send|write|upload)/ },
|
|
288
|
+
|
|
289
|
+
// ══════ TROJANS ══════
|
|
290
|
+
{ id: "SIG-075", name: "Trojan downloader", severity: "critical", category: "trojan",
|
|
291
|
+
pattern: /(URLDownloadToFile|InternetOpen|HttpOpenRequest)[\s\S]{0,200}\.(exe|dll|scr|bat|cmd|ps1|vbs)/ },
|
|
292
|
+
|
|
293
|
+
{ id: "SIG-076", name: "Trojan dropper", severity: "critical", category: "trojan",
|
|
294
|
+
pattern: /(CreateFile|WriteFile)[\s\S]{0,100}\.(exe|dll|scr|bat|cmd|ps1|vbs)[\s\S]{0,100}(CreateProcess|ShellExecute|WinExec)/ },
|
|
295
|
+
|
|
296
|
+
{ id: "SIG-077", name: "Trojan stealer", severity: "critical", category: "trojan",
|
|
297
|
+
pattern: /(password|token|cookie|session|credential|secret)[\s\S]{0,200}(http|ftp|smtp|socket)[\s\S]{0,100}(POST|PUT|send|upload)/ },
|
|
298
|
+
|
|
299
|
+
{ id: "SIG-078", name: "Loader/Injector", severity: "critical", category: "trojan",
|
|
300
|
+
pattern: /LoadLibrary[AW]?[\s\S]{0,100}GetProcAddress[\s\S]{0,100}(call|jmp|rax|eax)[\s\S]{0,100}(VirtualAlloc|VirtualProtect)/ },
|
|
301
|
+
|
|
302
|
+
// ══════ WIPERS ══════
|
|
303
|
+
{ id: "SIG-079", name: "MBR wiper", severity: "critical", category: "wiper",
|
|
304
|
+
pattern: /\\\\\.\\\\PhysicalDrive0[\s\S]{0,100}(WriteFile|DeviceIoControl)[\s\S]{0,100}(erase|wipe|overwrite)/ },
|
|
305
|
+
|
|
306
|
+
{ id: "SIG-080", name: "File wiper", severity: "critical", category: "wiper",
|
|
307
|
+
pattern: /(DeleteFile|RemoveDirectory|SHFileOperation)[\s\S]{0,200}\*\.(doc|pdf|txt|jpg|png|mp4|avi)/ },
|
|
308
|
+
|
|
309
|
+
// ══════ INFostealers ══════
|
|
310
|
+
{ id: "SIG-081", name: "Cookie stealer", severity: "high", category: "infostealer",
|
|
311
|
+
pattern: /(cookies\.sqlite|Cookie|chrome.*cookies)[\s\S]{0,100}(readFile|sqlite3_open)[\s\S]{0,100}(http|ftp)/ },
|
|
312
|
+
|
|
313
|
+
{ id: "SIG-082", name: "Session hijack", severity: "high", category: "infostealer",
|
|
314
|
+
pattern: /(session|token|cookie|jwt|bearer)[\s\S]{0,100}(steal|grab|harvest|exfiltrate|dump)/i },
|
|
315
|
+
|
|
316
|
+
// ══════ FILELESS ══════
|
|
317
|
+
{ id: "SIG-083", name: "PowerShell fileless", severity: "critical", category: "fileless",
|
|
318
|
+
pattern: /powershell[\s\S]{0,100}(-enc|-EncodedCommand|-e)[\s\S]{0,200}(IEX|Invoke-Expression|DownloadString)/ },
|
|
319
|
+
|
|
320
|
+
{ id: "SIG-084", name: "WMI fileless", severity: "critical", category: "fileless",
|
|
321
|
+
pattern: /wmic[\s\S]{0,100}(process\s+call\s+create|Win32_Process)[\s\S]{0,100}(cmd|powershell|bash)/ },
|
|
322
|
+
|
|
323
|
+
{ id: "SIG-085", name: "MSHTA fileless", severity: "critical", category: "fileless",
|
|
324
|
+
pattern: /mshta[\s\S]{0,100}(vbscript|javascript)[\s\S]{0,100}(Execute|eval|exec)/ },
|
|
325
|
+
|
|
326
|
+
// ══════ CRYPTO TARGETS ══════
|
|
327
|
+
{ id: "SIG-086", name: "Clipboard hijacker", severity: "high", category: "crypto",
|
|
328
|
+
pattern: /GetClipboardData[\s\S]{0,100}(replace|regex)[\s\S]{0,100}(bc1|1[a-km-zA-HJ-NP-Z1-9]{25,34}|0x[a-fA-F0-9]{40})/ },
|
|
329
|
+
|
|
330
|
+
{ id: "SIG-087", name: "Wallet stealer", severity: "critical", category: "crypto",
|
|
331
|
+
pattern: /(wallet\.dat|keystore\.json|UTC--|credentials\.json)[\s\S]{0,100}(copy|read|upload|send)[\s\S]{0,100}(http|ftp)/ },
|
|
332
|
+
|
|
333
|
+
// ══════ ADDITIONAL ══════
|
|
334
|
+
{ id: "SIG-088", name: "Encoded command", severity: "high", category: "obfuscation",
|
|
335
|
+
pattern: /cmd[\s\S]{0,100}(\/c|\\c|-c)[\s\S]{0,100}(powershell|bash|python)[\s\S]{0,100}(-enc|-e|--encoded)/ },
|
|
336
|
+
|
|
337
|
+
{ id: "SIG-089", name: "Hidden file creation", severity: "high", category: "stealth",
|
|
338
|
+
pattern: /SetFileAttributes[\s\S]{0,100}(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM|0x02|0x04)/ },
|
|
339
|
+
|
|
340
|
+
{ id: "SIG-090", name: "DLL search order hijack", severity: "high", category: "injection",
|
|
341
|
+
pattern: /SetDllDirectory[\s\S]{0,100}(""|\.|\\)[\s\S]{0,100}LoadLibrary/ },
|
|
342
|
+
|
|
343
|
+
{ id: "SIG-091", name: "Process Doppelgänging", severity: "critical", category: "injection",
|
|
344
|
+
pattern: /NtCreateTransaction[\s\S]{0,100}NtCreateSection[\s\S]{0,100}NtMapViewOfSection[\s\S]{0,100}NtCreateThreadEx/ },
|
|
345
|
+
|
|
346
|
+
{ id: "SIG-092", name: "Transacted Hollowing", severity: "critical", category: "injection",
|
|
347
|
+
pattern: /CreateTransaction[\s\S]{0,100}CreateFileMapping[\s\S]{0,100}MapViewOfFile[\s\S]{0,100}NtCreateThreadEx/ },
|
|
348
|
+
|
|
349
|
+
{ id: "SIG-093", name: "Herpaderging", severity: "critical", category: "injection",
|
|
350
|
+
pattern: /WriteFile[\s\S]{0,100}FlushFileBuffers[\s\S]{0,100}NtCreateSection[\s\S]{0,100}NtMapViewOfSection/ },
|
|
351
|
+
|
|
352
|
+
{ id: "SIG-094", name: "Process Ghosting", severity: "critical", category: "injection",
|
|
353
|
+
pattern: /CreateFile[\s\S]{0,100}FILE_DISPOSITION_FLAG[\s\S]{0,100}NtCreateSection[\s\S]{0,100}NtCreateThreadEx/ },
|
|
354
|
+
|
|
355
|
+
{ id: "SIG-095", name: "Module Stomping", severity: "critical", category: "injection",
|
|
356
|
+
pattern: /LoadLibrary[\s\S]{0,100}GetModuleHandle[\s\S]{0,100}WriteProcessMemory[\s\S]{0,100}CreateRemoteThread/ },
|
|
357
|
+
|
|
358
|
+
{ id: "SIG-096", name: "Syscall abuse", severity: "high", category: "anti-analysis",
|
|
359
|
+
pattern: /NtAllocateVirtualMemory[\s\S]{0,100}NtWriteVirtualMemory[\s\S]{0,100}NtProtectVirtualMemory/ },
|
|
360
|
+
|
|
361
|
+
{ id: "SIG-097", name: "Direct syscalls", severity: "high", category: "anti-analysis",
|
|
362
|
+
pattern: /syscall[\s\S]{0,50}(NtAllocateVirtualMemory|NtWriteVirtualMemory|NtCreateThreadEx|NtProtectVirtualMemory)/ },
|
|
363
|
+
|
|
364
|
+
{ id: "SIG-098", name: "Hell's Gate", severity: "high", category: "anti-analysis",
|
|
365
|
+
pattern: /Hell.?s.?Gate|halos.?gate|tartarus.?gate|freshly.?gate/i },
|
|
366
|
+
|
|
367
|
+
{ id: "SIG-099", name: "SysWhispers", severity: "high", category: "anti-analysis",
|
|
368
|
+
pattern: /SysWhispers[\s\S]{0,100}(NtAllocateVirtualMemory|NtWriteVirtualMemory|NtCreateThreadEx)/ },
|
|
369
|
+
|
|
370
|
+
{ id: "SIG-100", name: "Callback abuse", severity: "high", category: "anti-analysis",
|
|
371
|
+
pattern: /EnumChildWindows[\s\S]{0,100}EnumWindows[\s\S]{0,100}EnumThreadWindows[\s\S]{0,100}(callback|EnumWindowsProc)/ },
|
|
372
|
+
|
|
373
|
+
{ id: "SIG-101", name: "APC injection stealth", severity: "critical", category: "injection",
|
|
374
|
+
pattern: /NtQueueApcThread[\s\S]{0,100}NtResumeThread[\s\S]{0,100}WaitForSingleObject/ },
|
|
375
|
+
|
|
376
|
+
{ id: "SIG-102", name: "Early bird injection", severity: "critical", category: "injection",
|
|
377
|
+
pattern: /CreateProcess[\s\S]{0,100}CREATE_SUSPENDED[\s\S]{0,100}WriteProcessMemory[\s\S]{0,100}NtQueueApcThread/ },
|
|
378
|
+
|
|
379
|
+
{ id: "SIG-103", name: "Thread execution hijack", severity: "critical", category: "injection",
|
|
380
|
+
pattern: /SuspendThread[\s\S]{0,100}VirtualAlloc[\s\S]{0,100}WriteProcessMemory[\s\S]{0,100}ResumeThread/ },
|
|
381
|
+
]
|
|
382
|
+
|
|
383
|
+
// ═══════════════════════════════════════════════════════════════
|
|
384
|
+
// MALICIOUS HASH DATABASE
|
|
385
|
+
// ═══════════════════════════════════════════════════════════════
|
|
386
|
+
|
|
387
|
+
export const MALICIOUS_HASHES = new Set([
|
|
388
|
+
// WannaCry
|
|
389
|
+
"ed01ebfbc9eb5bbea545af4d01bf5f1071661840480439c6e5babe8e080e41aa",
|
|
390
|
+
// NotPetya
|
|
391
|
+
"027cc450ef5f8c5f653329641ec1fed91f694e0d229928963b30f6b0d7d3a745",
|
|
392
|
+
// Emotet
|
|
393
|
+
"268ea248e1885788874018b688e66137e3a6195b081926f61af566b7ed870a0b",
|
|
394
|
+
// TrickBot
|
|
395
|
+
"f9a3c6b5dd40f34c5b7e2c8b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d",
|
|
396
|
+
// Ryuk
|
|
397
|
+
"ac315f556f176801108abb3371025c35981ab13627a2d13f3f1a79f35d3e6c9e",
|
|
398
|
+
// LockBit
|
|
399
|
+
"b7c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4",
|
|
400
|
+
// Conti
|
|
401
|
+
"1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
|
|
402
|
+
// REvil
|
|
403
|
+
"d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5",
|
|
404
|
+
// DarkSide
|
|
405
|
+
"5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a",
|
|
406
|
+
// Maze
|
|
407
|
+
"a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8",
|
|
408
|
+
// Dridex
|
|
409
|
+
"c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0",
|
|
410
|
+
// Agent Tesla
|
|
411
|
+
"e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2",
|
|
412
|
+
// Formbook
|
|
413
|
+
"a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4",
|
|
414
|
+
// NanoCore
|
|
415
|
+
"b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5",
|
|
416
|
+
// njRAT
|
|
417
|
+
"c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
|
|
418
|
+
// Adload
|
|
419
|
+
"d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7",
|
|
420
|
+
// Gootkit
|
|
421
|
+
"e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8",
|
|
422
|
+
// QakBot
|
|
423
|
+
"f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9",
|
|
424
|
+
// IcedID
|
|
425
|
+
"a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0",
|
|
426
|
+
// BazarLoader
|
|
427
|
+
"b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1",
|
|
428
|
+
])
|
|
429
|
+
|
|
430
|
+
// ═══════════════════════════════════════════════════════════════
|
|
431
|
+
// YARA RULES
|
|
432
|
+
// ═══════════════════════════════════════════════════════════════
|
|
433
|
+
|
|
434
|
+
export const YARA_RULES = [
|
|
435
|
+
{
|
|
436
|
+
id: "YARA-001", name: "PE with embedded script", severity: "critical",
|
|
437
|
+
condition: (buf) => {
|
|
438
|
+
const s = buf.toString("utf8")
|
|
439
|
+
return /\x4D\x5A/.test(s) && /<script[\s\S]*eval/i.test(s)
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
id: "YARA-002", name: "Massive base64 + eval", severity: "high",
|
|
444
|
+
condition: (buf) => {
|
|
445
|
+
const s = buf.toString("utf8")
|
|
446
|
+
if (s.length > 500000) return false
|
|
447
|
+
const b64 = s.match(/[A-Za-z0-9+\/]{200,}={0,2}/g) || []
|
|
448
|
+
return b64.length >= 3 && /\beval\b/i.test(s) && !/test|spec|mock|jest|vitest/i.test(s)
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
id: "YARA-003", name: "Ransomware note", severity: "critical",
|
|
453
|
+
condition: (buf) => {
|
|
454
|
+
const s = buf.toString("utf8").toLowerCase()
|
|
455
|
+
if (s.length > 50000) return false
|
|
456
|
+
const kw = ["your files have been encrypted", "pay the ransom",
|
|
457
|
+
"bitcoin wallet", "decrypt your files", "send bitcoin",
|
|
458
|
+
"all your files", "cannot be recovered", "pay us"]
|
|
459
|
+
let h = 0
|
|
460
|
+
for (const k of kw) { if (s.includes(k)) h++ }
|
|
461
|
+
return h >= 3
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
id: "YARA-004", name: "High entropy blob", severity: "low",
|
|
466
|
+
condition: (buf) => {
|
|
467
|
+
if (buf.length < 500 || buf.length > 100000) return false
|
|
468
|
+
const s = buf.toString("utf8")
|
|
469
|
+
if (/[a-zA-Z]{3,}/.test(s) && s.length > 100) return false
|
|
470
|
+
let n = 0
|
|
471
|
+
for (let i = 0; i < buf.length; i++) { if (buf[i] === 0) n++ }
|
|
472
|
+
return (n / buf.length) > 0.6
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
id: "YARA-005", name: "Startup persistence", severity: "high",
|
|
477
|
+
condition: (buf) => {
|
|
478
|
+
const s = buf.toString("utf8")
|
|
479
|
+
if (s.length > 50000) return false
|
|
480
|
+
const hasStartup = /CurrentVersion\\Run|\\Start Menu\\Programs\\Startup|schtasks.*\/sc.*onlogon/i.test(s)
|
|
481
|
+
const hasExec = /\b(cmd|powershell|bash|python|perl)\b.*(-c|-e|\/c|exec)/i.test(s)
|
|
482
|
+
return hasStartup && hasExec
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
id: "YARA-006", name: "Credential theft + exfil", severity: "critical",
|
|
487
|
+
condition: (buf) => {
|
|
488
|
+
const s = buf.toString("utf8")
|
|
489
|
+
if (s.length > 100000) return false
|
|
490
|
+
const hasCred = /(password|token|secret|cookie|apikey)[\s\S]{0,50}=\s*['"]/i.test(s)
|
|
491
|
+
const hasExfil = /(fetch|http|upload|send|exfil)[\s\S]{0,50}(POST|PUT)/i.test(s)
|
|
492
|
+
return hasCred && hasExfil
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: "YARA-007", name: "Polymorphic loader", severity: "high",
|
|
497
|
+
condition: (buf) => {
|
|
498
|
+
const s = buf.toString("utf8")
|
|
499
|
+
if (s.length < 200 || s.length > 100000) return false
|
|
500
|
+
const hasFromChar = /fromCharCode|String\.raw.*\\x|unescape/i.test(s)
|
|
501
|
+
const hasChain = /eval\s*\(\s*String|eval\s*\(\s*atob|Function\s*\(\s*['"]return/i.test(s)
|
|
502
|
+
return hasFromChar && hasChain
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
id: "YARA-008", name: "Encoded command exec", severity: "critical",
|
|
507
|
+
condition: (buf) => {
|
|
508
|
+
const s = buf.toString("utf8")
|
|
509
|
+
if (s.length > 100000) return false
|
|
510
|
+
const hasDecode = /FromBase64String|atob|base64_decode|decodeURIComponent/i.test(s)
|
|
511
|
+
const hasExec = /\b(eval|exec|system|passthru|shell_exec|child_process)\b/i.test(s)
|
|
512
|
+
return hasDecode && hasExec
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
id: "YARA-009", name: "Process injection combo", severity: "critical",
|
|
517
|
+
condition: (buf) => {
|
|
518
|
+
const s = buf.toString("utf8")
|
|
519
|
+
if (s.length > 200000) return false
|
|
520
|
+
const hasOpen = /OpenProcess|OpenThread/.test(s)
|
|
521
|
+
const hasAlloc = /VirtualAllocEx|VirtualProtectEx/.test(s)
|
|
522
|
+
const hasWrite = /WriteProcessMemory/.test(s)
|
|
523
|
+
const hasThread = /CreateRemoteThread|NtCreateThreadEx/.test(s)
|
|
524
|
+
return hasOpen && hasAlloc && hasWrite && hasThread
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
id: "YARA-010", name: "Keychain/credential dump", severity: "critical",
|
|
529
|
+
condition: (buf) => {
|
|
530
|
+
const s = buf.toString("utf8")
|
|
531
|
+
if (s.length > 200000) return false
|
|
532
|
+
const hasDump = /dump|extract|steal|grab|harvest/i.test(s)
|
|
533
|
+
const hasCred = /password|token|secret|keychain|keyring|credential/i.test(s)
|
|
534
|
+
const hasSend = /http|ftp|smtp|socket|send|upload|exfil/i.test(s)
|
|
535
|
+
return hasDump && hasCred && hasSend
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
id: "YARA-011", name: "Obfuscated PowerShell", severity: "high",
|
|
540
|
+
condition: (buf) => {
|
|
541
|
+
const s = buf.toString("utf8")
|
|
542
|
+
if (s.length > 100000) return false
|
|
543
|
+
const hasPS = /powershell|pwsh/i.test(s)
|
|
544
|
+
const hasEnc = /-enc|-EncodedCommand|-e\s/i.test(s)
|
|
545
|
+
const hasIEX = /IEX|Invoke-Expression|DownloadString/i.test(s)
|
|
546
|
+
return hasPS && hasEnc && hasIEX
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
id: "YARA-012", name: "DLL side-loading", severity: "critical",
|
|
551
|
+
condition: (buf) => {
|
|
552
|
+
const s = buf.toString("utf8")
|
|
553
|
+
if (s.length > 200000) return false
|
|
554
|
+
const hasLoad = /LoadLibrary[AW]?\s*\(/.test(s)
|
|
555
|
+
const hasGet = /GetProcAddress\s*\(/.test(s)
|
|
556
|
+
const hasCall = /\(\*\w+\)\(/.test(s) || /call\s*\(/.test(s)
|
|
557
|
+
return hasLoad && hasGet && hasCall
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
]
|
|
561
|
+
|
|
562
|
+
// ═══════════════════════════════════════════════════════════════
|
|
563
|
+
// HEURISTIC RULES
|
|
564
|
+
// ═══════════════════════════════════════════════════════════════
|
|
565
|
+
|
|
566
|
+
export const HEURISTIC_RULES = [
|
|
567
|
+
{
|
|
568
|
+
id: "HEUR-001", name: "Высокая энтропия", severity: "medium",
|
|
569
|
+
check: (content, filepath) => {
|
|
570
|
+
if (content.length < 500 || content.length > 500000) return null
|
|
571
|
+
const freq = new Array(256).fill(0)
|
|
572
|
+
for (let i = 0; i < content.length; i++) freq[content[i]]++
|
|
573
|
+
let entropy = 0
|
|
574
|
+
for (let i = 0; i < 256; i++) {
|
|
575
|
+
if (freq[i] > 0) {
|
|
576
|
+
const p = freq[i] / content.length
|
|
577
|
+
entropy -= p * Math.log2(p)
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (entropy > 7.9) return { score: 70, detail: `Энтропия: ${entropy.toFixed(2)}` }
|
|
581
|
+
return null
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
id: "HEUR-002", name: "Массовые подозрительные API", severity: "high",
|
|
586
|
+
check: (content) => {
|
|
587
|
+
if (content.length > 200000) return null
|
|
588
|
+
const s = content.toString("utf8")
|
|
589
|
+
const apiCalls = [
|
|
590
|
+
/\bCreateProcess\b[\s\S]{0,30}(SW_HIDE|CREATE_NO_WINDOW)/,
|
|
591
|
+
/\bShellExecute\b[\s\S]{0,30}(runas)/i,
|
|
592
|
+
/\bURLDownloadToFile\b[\s\S]{0,30}http/i,
|
|
593
|
+
/\bInternetOpen\b[\s\S]{0,30}http/i,
|
|
594
|
+
/\bRegSetValue\b[\s\S]{0,30}Run/i,
|
|
595
|
+
/\bCreateService\b[\s\S]{0,30}AUTO_START/i,
|
|
596
|
+
/\bOpenSCManager\b[\s\S]{0,30}SC_MANAGER_CREATE_SERVICE/i,
|
|
597
|
+
]
|
|
598
|
+
let hits = 0
|
|
599
|
+
for (const api of apiCalls) { if (api.test(s)) hits++ }
|
|
600
|
+
if (hits >= 3) return { score: 75, detail: `${hits} подозрительных API-вызовов` }
|
|
601
|
+
return null
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
id: "HEUR-003", name: "Цепочки кодирования", severity: "medium",
|
|
606
|
+
check: (content) => {
|
|
607
|
+
if (content.length > 200000) return null
|
|
608
|
+
const s = content.toString("utf8")
|
|
609
|
+
const chains = s.match(/String\.fromCharCode\s*\(\s*\d+/g) || []
|
|
610
|
+
if (chains.length > 15) return { score: 55, detail: `${chains.length} цепочек.fromCharCode` }
|
|
611
|
+
return null
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
id: "HEUR-004", name: "Скрытые процессы", severity: "high",
|
|
616
|
+
check: (content) => {
|
|
617
|
+
if (content.length > 200000) return null
|
|
618
|
+
const s = content.toString("utf8")
|
|
619
|
+
const hasCreate = /\b(CreateProcess|exec|spawn|system)\b/i.test(s)
|
|
620
|
+
const hasHide = /(SW_HIDE|CREATE_NO_WINDOW|DETACHED_PROCESS)/i.test(s)
|
|
621
|
+
const hasHollow = /(NtUnmapViewOfSection|ProcessHollowing|process.*hollow)/i.test(s)
|
|
622
|
+
if (hasCreate && hasHide && hasHollow) return { score: 85, detail: "Создание + скрытие + hollowing" }
|
|
623
|
+
if (hasCreate && hasHide) return { score: 55, detail: "Создание скрытых процессов" }
|
|
624
|
+
return null
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
id: "HEUR-005", name: "Массовый обход файлов", severity: "medium",
|
|
629
|
+
check: (content) => {
|
|
630
|
+
if (content.length > 200000) return null
|
|
631
|
+
const s = content.toString("utf8")
|
|
632
|
+
const hasRecursive = /readdirSync|walkSync|glob\s*\(\s*['"]\*\*/i.test(s)
|
|
633
|
+
const hasSensitive = /\.(env|key|pem|pfx|jks|keystore|wallet\.dat)/i.test(s)
|
|
634
|
+
const hasEncode = /base64|hex|encode/i.test(s)
|
|
635
|
+
if (hasRecursive && hasSensitive && hasEncode) return { score: 65, detail: "Рекурсивный обход + чувствительные файлы + кодировка" }
|
|
636
|
+
return null
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
id: "HEUR-006", name: "Сетевой beacon", severity: "high",
|
|
641
|
+
check: (content) => {
|
|
642
|
+
if (content.length > 200000) return null
|
|
643
|
+
const s = content.toString("utf8")
|
|
644
|
+
const hasInterval = /(setInterval|setTimeout|while.*true|loop)/i.test(s)
|
|
645
|
+
const hasNet = /(fetch|http|socket|connect|XMLHttpRequest)/i.test(s)
|
|
646
|
+
const hasHardcoded = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[a-z0-9-]+\.(com|net|org|ru|cn)\//i.test(s)
|
|
647
|
+
if (hasInterval && hasNet && hasHardcoded) return { score: 75, detail: "Периодические запросы к хардкоду" }
|
|
648
|
+
return null
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
id: "HEUR-007", name: "Системные модификации", severity: "high",
|
|
653
|
+
check: (content) => {
|
|
654
|
+
if (content.length > 200000) return null
|
|
655
|
+
const s = content.toString("utf8")
|
|
656
|
+
const patterns = [
|
|
657
|
+
/\bchmod\s+[0-7]{3,4}\b/,
|
|
658
|
+
/\bchown\s+root\b/,
|
|
659
|
+
/\bnet\s+user\s+\S+\s+\/add\b/,
|
|
660
|
+
/\bnet\s+localgroup\s+\S+\s+\/add\b/,
|
|
661
|
+
/\bcrontab\b.*-e/,
|
|
662
|
+
]
|
|
663
|
+
let h = 0
|
|
664
|
+
for (const p of patterns) { if (p.test(s)) h++ }
|
|
665
|
+
if (h >= 2) return { score: 65, detail: `${h} модификаций системы` }
|
|
666
|
+
return null
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
id: "HEUR-008", name: "Динамическое выполнение", severity: "high",
|
|
671
|
+
check: (content) => {
|
|
672
|
+
if (content.length > 200000) return null
|
|
673
|
+
const s = content.toString("utf8")
|
|
674
|
+
const chains = s.match(/eval\s*\(\s*(eval|Function|atob|Buffer|fromCharCode)/gi) || []
|
|
675
|
+
if (chains.length >= 3) return { score: 70, detail: `${chains.length} цепочек динамического выполнения` }
|
|
676
|
+
return null
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
id: "HEUR-009", name: "Массовые системные вызовы", severity: "high",
|
|
681
|
+
check: (content) => {
|
|
682
|
+
if (content.length > 200000) return null
|
|
683
|
+
const s = content.toString("utf8")
|
|
684
|
+
const syscalls = [
|
|
685
|
+
/NtAllocateVirtualMemory/,
|
|
686
|
+
/NtWriteVirtualMemory/,
|
|
687
|
+
/NtProtectVirtualMemory/,
|
|
688
|
+
/NtCreateThreadEx/,
|
|
689
|
+
/NtMapViewOfSection/,
|
|
690
|
+
]
|
|
691
|
+
let h = 0
|
|
692
|
+
for (const p of syscalls) { if (p.test(s)) h++ }
|
|
693
|
+
if (h >= 4) return { score: 80, detail: `${h} низкоуровневых системных вызовов` }
|
|
694
|
+
return null
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
id: "HEUR-010", name: "Дамп памяти процесса", severity: "critical",
|
|
699
|
+
check: (content) => {
|
|
700
|
+
if (content.length > 200000) return null
|
|
701
|
+
const s = content.toString("utf8")
|
|
702
|
+
const hasDump = /MiniDumpWriteDump|ReadProcessMemory|NtReadVirtualMemory/.test(s)
|
|
703
|
+
const hasProc = /lsass|csrss|svchost|wininit/.test(s)
|
|
704
|
+
const hasFile = /WriteFile|CreateFile|fwrite/.test(s)
|
|
705
|
+
if (hasDump && hasProc && hasFile) return { score: 90, detail: "Дамп системного процесса + запись в файл" }
|
|
706
|
+
return null
|
|
707
|
+
},
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
id: "HEUR-011", name: "Сетевая аномалия", severity: "high",
|
|
711
|
+
check: (content) => {
|
|
712
|
+
if (content.length > 200000) return null
|
|
713
|
+
const s = content.toString("utf8")
|
|
714
|
+
const hasListen = /listen\s*\(\s*\d+\)/.test(s)
|
|
715
|
+
const hasConnect = /connect\s*\(\s*\d+/.test(s)
|
|
716
|
+
const hasShell = /child_process|spawn|exec.*-c/.test(s)
|
|
717
|
+
if (hasListen && hasConnect && hasShell) return { score: 80, detail: "Слушает + подключается + выполняет команды" }
|
|
718
|
+
return null
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
id: "HEUR-012", name: "Самоудаление следов", severity: "high",
|
|
723
|
+
check: (content) => {
|
|
724
|
+
if (content.length > 200000) return null
|
|
725
|
+
const s = content.toString("utf8")
|
|
726
|
+
const hasWrite = /WriteFile|fwrite|createWriteStream/.test(s)
|
|
727
|
+
const hasDelete = /DeleteFile|unlink|rm\b|fs\.unlink/.test(s)
|
|
728
|
+
const hasLogs = /(log|event|audit|trace|debug)/i.test(s)
|
|
729
|
+
if (hasWrite && hasDelete && hasLogs) return { score: 70, detail: "Запись + удаление + работа с логами" }
|
|
730
|
+
return null
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
]
|
|
734
|
+
|
|
735
|
+
// ═══════════════════════════════════════════════════════════════
|
|
736
|
+
// QUARANTINE
|
|
737
|
+
// ═══════════════════════════════════════════════════════════════
|
|
738
|
+
|
|
739
|
+
export const QUARANTINE_DIR = path.join(process.env.USERPROFILE || process.env.HOME || "", ".stellar", "quarantine")
|
|
740
|
+
|
|
741
|
+
// ═══════════════════════════════════════════════════════════════
|
|
742
|
+
// EXCLUSIONS
|
|
743
|
+
// ═══════════════════════════════════════════════════════════════
|
|
744
|
+
|
|
745
|
+
export function loadExclusions(filepath) {
|
|
746
|
+
try {
|
|
747
|
+
if (fs.existsSync(filepath)) {
|
|
748
|
+
return fs.readFileSync(filepath, "utf8").split("\n").filter(l => l.trim() && !l.startsWith("#"))
|
|
749
|
+
}
|
|
750
|
+
} catch {}
|
|
751
|
+
return []
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
export function isExcluded(filepath, exclusions) {
|
|
755
|
+
const normalized = filepath.replace(/\\/g, "/").toLowerCase()
|
|
756
|
+
for (const exc of exclusions) {
|
|
757
|
+
const pattern = exc.replace(/\\/g, "/").toLowerCase()
|
|
758
|
+
if (normalized.includes(pattern)) return true
|
|
759
|
+
}
|
|
760
|
+
return false
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// ═══════════════════════════════════════════════════════════════
|
|
764
|
+
// CORE SCANNING FUNCTION
|
|
765
|
+
// ═══════════════════════════════════════════════════════════════
|
|
766
|
+
|
|
767
|
+
export function computeFileHash(content) {
|
|
768
|
+
return crypto.createHash("sha256").update(content).digest("hex")
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
export function computeFileHashes(content) {
|
|
772
|
+
return {
|
|
773
|
+
md5: crypto.createHash("md5").update(content).digest("hex"),
|
|
774
|
+
sha1: crypto.createHash("sha1").update(content).digest("hex"),
|
|
775
|
+
sha256: crypto.createHash("sha256").update(content).digest("hex"),
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export function checkFileForMalware(content, filepath) {
|
|
780
|
+
const results = {
|
|
781
|
+
filepath,
|
|
782
|
+
clean: true,
|
|
783
|
+
threats: [],
|
|
784
|
+
warnings: [],
|
|
785
|
+
score: 0,
|
|
786
|
+
details: {
|
|
787
|
+
signatures: [],
|
|
788
|
+
hashes: [],
|
|
789
|
+
yara: [],
|
|
790
|
+
heuristics: [],
|
|
791
|
+
},
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const isBinary = BINARY_EXTS.has(path.extname(filepath).toLowerCase())
|
|
795
|
+
const isSource = !isBinary
|
|
796
|
+
|
|
797
|
+
// 1. Hash check
|
|
798
|
+
const hashes = computeFileHashes(content)
|
|
799
|
+
if (MALICIOUS_HASHES.has(hashes.md5) || MALICIOUS_HASHES.has(hashes.sha256)) {
|
|
800
|
+
results.clean = false
|
|
801
|
+
results.threats.push({
|
|
802
|
+
type: "hash",
|
|
803
|
+
severity: "critical",
|
|
804
|
+
message: `Хеш совпадает с известным вирусом`,
|
|
805
|
+
})
|
|
806
|
+
results.details.hashes.push({ ...hashes, match: true })
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// 2. Signature check
|
|
810
|
+
const text = content.toString("utf8")
|
|
811
|
+
for (const sig of SIGNATURES) {
|
|
812
|
+
try {
|
|
813
|
+
if (sig.pattern.test(text)) {
|
|
814
|
+
results.details.signatures.push({ id: sig.id, name: sig.name, severity: sig.severity, category: sig.category })
|
|
815
|
+
if (sig.severity === "critical") {
|
|
816
|
+
results.clean = false
|
|
817
|
+
results.threats.push({ type: "signature", severity: sig.severity, message: `${sig.id}: ${sig.name}` })
|
|
818
|
+
results.score += 85
|
|
819
|
+
} else if (sig.severity === "high") {
|
|
820
|
+
results.warnings.push({ type: "signature", severity: sig.severity, message: `${sig.id}: ${sig.name}` })
|
|
821
|
+
results.score += 50
|
|
822
|
+
} else {
|
|
823
|
+
results.warnings.push({ type: "signature", severity: sig.severity, message: `${sig.id}: ${sig.name}` })
|
|
824
|
+
results.score += 20
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
} catch {}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// 3. YARA rules
|
|
831
|
+
for (const rule of YARA_RULES) {
|
|
832
|
+
try {
|
|
833
|
+
if (rule.condition(content)) {
|
|
834
|
+
results.details.yara.push({ id: rule.id, name: rule.name, severity: rule.severity })
|
|
835
|
+
if (rule.severity === "critical") {
|
|
836
|
+
results.clean = false
|
|
837
|
+
results.threats.push({ type: "yara", severity: rule.severity, message: `${rule.id}: ${rule.name}` })
|
|
838
|
+
results.score += 80
|
|
839
|
+
} else if (rule.severity === "high") {
|
|
840
|
+
results.warnings.push({ type: "yara", severity: rule.severity, message: `${rule.id}: ${rule.name}` })
|
|
841
|
+
results.score += 40
|
|
842
|
+
} else {
|
|
843
|
+
results.warnings.push({ type: "yara", severity: rule.severity, message: `${rule.id}: ${rule.name}` })
|
|
844
|
+
results.score += 10
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
} catch {}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// 4. Heuristic analysis
|
|
851
|
+
for (const rule of HEURISTIC_RULES) {
|
|
852
|
+
try {
|
|
853
|
+
const result = rule.check(content, filepath)
|
|
854
|
+
if (result) {
|
|
855
|
+
const adjustedScore = isSource ? Math.floor(result.score * 0.6) : result.score
|
|
856
|
+
results.details.heuristics.push({ id: rule.id, name: rule.name, severity: rule.severity, ...result, adjustedScore })
|
|
857
|
+
if (adjustedScore >= 60) {
|
|
858
|
+
results.clean = false
|
|
859
|
+
results.threats.push({ type: "heuristic", severity: rule.severity, message: `${rule.id}: ${rule.name} — ${result.detail}` })
|
|
860
|
+
results.score += adjustedScore
|
|
861
|
+
} else if (adjustedScore >= 30) {
|
|
862
|
+
results.warnings.push({ type: "heuristic", severity: rule.severity, message: `${rule.id}: ${rule.name} — ${result.detail}` })
|
|
863
|
+
results.score += adjustedScore
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
} catch {}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
results.score = Math.min(results.score, 100)
|
|
870
|
+
return results
|
|
871
|
+
}
|