@gendigital/sage-opencode 0.12.0 → 0.13.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.
Files changed (31) hide show
  1. package/dist/mcp-server.cjs +38 -10
  2. package/dist/mcp-server.cjs.map +2 -2
  3. package/dist/tool-handler.d.ts.map +1 -1
  4. package/dist/tool-handler.js +5 -3
  5. package/dist/tool-handler.js.map +1 -1
  6. package/package.json +3 -3
  7. package/resources/threats/_macros.yaml +193 -0
  8. package/resources/threats/agent-layer.yaml +19 -1
  9. package/resources/threats/commands.yaml +165 -31
  10. package/resources/threats/credentials.yaml +24 -4
  11. package/resources/threats/dummy.yaml +30 -0
  12. package/resources/threats/files.yaml +38 -0
  13. package/resources/threats/mac-commands.yaml +118 -27
  14. package/resources/threats/mac-credentials.yaml +34 -8
  15. package/resources/threats/mac-files.yaml +20 -0
  16. package/resources/threats/mac-obfuscation.yaml +28 -6
  17. package/resources/threats/mac-persistence.yaml +30 -4
  18. package/resources/threats/mac-supply-chain.yaml +12 -3
  19. package/resources/threats/mitre.yaml +325 -62
  20. package/resources/threats/obfuscation.yaml +33 -8
  21. package/resources/threats/persistence.yaml +40 -5
  22. package/resources/threats/prompt-injection.yaml +58 -0
  23. package/resources/threats/self-defense.yaml +15 -2
  24. package/resources/threats/supply_chain.yaml +6 -1
  25. package/resources/threats/urls.yaml +10 -0
  26. package/resources/threats/win-commands.yaml +294 -60
  27. package/resources/threats/win-credentials.yaml +68 -9
  28. package/resources/threats/win-files.yaml +20 -0
  29. package/resources/threats/win-obfuscation.yaml +56 -8
  30. package/resources/threats/win-persistence.yaml +45 -7
  31. package/resources/threats/win-supply-chain.yaml +5 -1
@@ -4,10 +4,13 @@
4
4
 
5
5
  # cmdkey stored credentials
6
6
  - id: "CLT-WIN-CRED-001"
7
+ version: 1
8
+ detection_name: "CMD:SageWindowsCredential-A [Heur]"
7
9
  category: secrets
8
10
  severity: warning
9
11
  confidence: 0.60
10
- pattern: "\\b[Cc]mdkey\\s+/add:"
12
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009.
13
+ pattern: "{{CMD_POS}}[Cc]mdkey(?:\\.exe)?{{NOT_FILENAME}}\\s+/add:"
11
14
  match_on: command
12
15
  title: "Stored credential creation via cmdkey"
13
16
  expires_at: null
@@ -15,10 +18,14 @@
15
18
 
16
19
  # ConvertTo-SecureString with plaintext
17
20
  - id: "CLT-WIN-CRED-002"
21
+ version: 1
22
+ detection_name: "CMD:SageWindowsCredential-B [Heur]"
18
23
  category: secrets
19
24
  severity: warning
20
25
  confidence: 0.60
21
- pattern: "[Cc]onvert[Tt]o-[Ss]ecure[Ss]tring.*-[Aa]s[Pp]lain[Tt]ext"
26
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. Had no
27
+ # boundary at all.
28
+ pattern: "{{CMD_POS}}[Cc]onvert[Tt]o-[Ss]ecure[Ss]tring{{NOT_FILENAME}}.*-[Aa]s[Pp]lain[Tt]ext"
22
29
  match_on: command
23
30
  title: "ConvertTo-SecureString with plaintext password"
24
31
  expires_at: null
@@ -26,10 +33,16 @@
26
33
 
27
34
  # Reading credential files on Windows (type, more, Get-Content)
28
35
  - id: "CLT-WIN-CRED-003"
36
+ version: 1
37
+ detection_name: "CMD:SageWindowsCredential-C [Heur]"
29
38
  category: secrets
30
39
  severity: warning
31
40
  confidence: 0.60
32
- pattern: "(^|[^\\w-])(?:type|more|[Gg]et-[Cc]ontent)\\b.*\\.(?:env|credentials|pgpass|netrc)(?=$|[.\\s\"'`;&|)<>])"
41
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. The old
42
+ # `(^|[^\w-])` boundary accepted any whitespace-delimited position (still
43
+ # excluding a `-type`-shaped flag, which the replacement preserves since
44
+ # {{CMD_POS}} has no valid boundary immediately before a hyphen either).
45
+ pattern: "{{CMD_POS}}(?:type|more|[Gg]et-[Cc]ontent){{NOT_FILENAME}}.*\\.(?:env|credentials|pgpass|netrc)(?=$|[.\\s\"'`;&|)<>])"
33
46
  match_on: command
34
47
  title: "Reading credential file via type/more/Get-Content"
35
48
  expires_at: null
@@ -37,10 +50,14 @@
37
50
 
38
51
  # [Environment]::SetEnvironmentVariable with credential keyword
39
52
  - id: "CLT-WIN-CRED-004"
53
+ version: 1
54
+ detection_name: "CMD:SageWindowsCredential-D [Heur]"
40
55
  category: secrets
41
56
  severity: warning
42
57
  confidence: 0.60
43
- pattern: "\\[Environment\\]::SetEnvironmentVariable.*([Pp]assword|[Ss]ecret|[Tt]oken|[Kk]ey)"
58
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. Had no
59
+ # boundary at all.
60
+ pattern: "{{CMD_POS}}\\[Environment\\]::SetEnvironmentVariable{{NOT_FILENAME}}.*([Pp]assword|[Ss]ecret|[Tt]oken|[Kk]ey)"
44
61
  match_on: command
45
62
  title: "Setting credential environment variable via .NET"
46
63
  expires_at: null
@@ -48,6 +65,8 @@
48
65
 
49
66
  # $env: credential assignment
50
67
  - id: "CLT-WIN-CRED-005"
68
+ version: 1
69
+ detection_name: "CMD:SageWindowsCredential-E [Heur]"
51
70
  category: secrets
52
71
  severity: warning
53
72
  confidence: 0.60
@@ -59,10 +78,28 @@
59
78
 
60
79
  # Mimikatz / sekurlsa
61
80
  - id: "CLT-WIN-CRED-006"
81
+ version: 1
82
+ detection_name: "CMD:SageWindowsCredential-F [Heur]"
62
83
  category: secrets
63
84
  severity: critical
64
85
  confidence: 0.95
65
- pattern: "[Mm]imikatz|[Ss]ekurlsa::"
86
+ # Neither {{CMD_POS}} nor {{NOT_COMPOUND_LEFT}} fits here: real invocations
87
+ # routinely have "Mimikatz" as a SUFFIX of a compound name (the PowerSploit
88
+ # function `Invoke-Mimikatz`), not standalone -- {{CMD_POS}} requires a real
89
+ # boundary immediately before it, and {{NOT_COMPOUND_LEFT}} would reject the
90
+ # preceding hyphen, so either would break the single most common real-world
91
+ # invocation shape. `sekurlsa::` is a Mimikatz module reference that's
92
+ # always an argument to something, never itself in command position.
93
+ # {{NOT_AFTER_TEXT_CMD}} alone closes the reported gap (prose/search-command
94
+ # mentions) without touching either loose-substring-matching property.
95
+ # case_insensitive covers casing generally, so the term itself no longer
96
+ # needs hand-cased character classes -- and it must be set here regardless,
97
+ # since {{NOT_AFTER_TEXT_CMD}}'s denylist (Select-String, Write-Host, ...)
98
+ # is fixed-case and silently stops suppressing lowercase/mixed-case
99
+ # invocations without it. See CLT-WIN-PERSIST-008 for the same macro used
100
+ # the same way.
101
+ pattern: "{{NOT_AFTER_TEXT_CMD}}(?:mimikatz|sekurlsa::)"
102
+ case_insensitive: true
66
103
  match_on: command
67
104
  title: "Mimikatz credential dumping tool"
68
105
  expires_at: null
@@ -70,10 +107,13 @@
70
107
 
71
108
  # Registry hive export for credential theft
72
109
  - id: "CLT-WIN-CRED-007"
110
+ version: 1
111
+ detection_name: "CMD:SageWindowsCredential-G [Heur]"
73
112
  category: secrets
74
113
  severity: critical
75
114
  confidence: 0.95
76
- pattern: "\\breg\\s+save\\b.*\\bHKLM\\\\(SAM|SYSTEM|SECURITY)\\b"
115
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009.
116
+ pattern: "{{CMD_POS}}reg(?:\\.exe)?{{NOT_FILENAME}}\\s+save\\b.*\\bHKLM\\\\(SAM|SYSTEM|SECURITY)\\b"
77
117
  match_on: command
78
118
  title: "Registry hive export for credential theft (reg save HKLM\\SAM/SYSTEM)"
79
119
  expires_at: null
@@ -81,10 +121,19 @@
81
121
 
82
122
  # LSASS credential dumping
83
123
  - id: "CLT-WIN-CRED-008"
124
+ version: 1
125
+ detection_name: "CMD:SageWindowsCredential-H [Heur]"
84
126
  category: secrets
85
127
  severity: critical
86
128
  confidence: 0.95
87
- pattern: "\\b(procdump|procdump64)\\b.*\\blsass\\b|\\brundll32\\b.*\\bcomsvcs(\\.dll)?\\b.*\\bMiniDump\\b"
129
+ # {{CMD_POS}} + {{NOT_FILENAME}} on each leading verb, same shape as
130
+ # CLT-CMD-009. Optional `.exe` suffix ahead of {{NOT_FILENAME}}, same as
131
+ # CLT-MITRE-096 (tscon) -- otherwise `rundll32.exe` would fail to match,
132
+ # since {{NOT_FILENAME}} itself rejects a trailing dot. The internal
133
+ # `\blsass\b`/`\bcomsvcs\b`/`\bMiniDump\b` mentions are left as bare --
134
+ # only reachable once the leading verb has already matched at command
135
+ # position.
136
+ pattern: "{{CMD_POS}}(procdump|procdump64)(?:\\.exe)?{{NOT_FILENAME}}.*\\blsass\\b|{{CMD_POS}}rundll32(?:\\.exe)?{{NOT_FILENAME}}.*\\bcomsvcs(\\.dll)?\\b.*\\bMiniDump\\b"
88
137
  match_on: command
89
138
  title: "LSASS credential dumping (procdump/comsvcs.dll MiniDump)"
90
139
  expires_at: null
@@ -92,10 +141,14 @@
92
141
 
93
142
  # WLAN password extraction (ex CLT-TECH-034)
94
143
  - id: "CLT-WIN-CRED-009"
144
+ version: 1
145
+ detection_name: "CMD:SageWindowsCredential-I [Heur]"
95
146
  category: secrets
96
147
  severity: warning
97
148
  confidence: 0.60
98
- pattern: "netsh.*wlan.*show.*profiles.*key=clear"
149
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009. Had no
150
+ # boundary at all.
151
+ pattern: "{{CMD_POS}}netsh(?:\\.exe)?{{NOT_FILENAME}}.*wlan.*show.*profiles.*key=clear"
99
152
  case_insensitive: true
100
153
  match_on: command
101
154
  title: "WLAN password extraction via netsh"
@@ -104,13 +157,19 @@
104
157
 
105
158
  # --- Windows copy/move/link of secret files ---
106
159
  - id: "CLT-WIN-CRED-010"
160
+ version: 1
161
+ detection_name: "CMD:SageWindowsCredential-J [Heur]"
107
162
  category: secrets
108
163
  severity: warning
109
164
  confidence: 0.60
110
165
  # Protected files: .env*, .aws\credentials, .ssh\(id_rsa|id_ed25519|id_ecdsa|id_dsa),
111
166
  # .netrc, .pgpass, .npmrc, .pypirc, key.properties, .docker\config.json,
112
167
  # kubeconfig, .kube\config, master.key, credentials.yml
113
- pattern: "\\b(copy|xcopy|robocopy|Copy-Item|Move-Item|mklink)\\b.*(?<=[\\\\/\\s])(\\.env(?!\\S*\\.(example|sample|template|dist)\\b)(\\.\\w+)?(?=[\\s\\\\/]|$)|\\.aws[\\\\/]credentials|\\.ssh[\\\\/](id_rsa|id_ed25519|id_ecdsa|id_dsa)|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc|key\\.properties|\\.docker[\\\\/]config\\.json|kubeconfig|\\.kube[\\\\/]config|master\\.key|credentials\\.yml)"
168
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009. xcopy/robocopy
169
+ # are real standalone binaries and admit an optional `.exe` suffix; copy/
170
+ # mklink are cmd builtins and Copy-Item/Move-Item are cmdlets, neither of
171
+ # which has a `.exe` form.
172
+ pattern: "{{CMD_POS}}(copy|xcopy(?:\\.exe)?|robocopy(?:\\.exe)?|Copy-Item|Move-Item|mklink){{NOT_FILENAME}}.*(?<=[\\\\/\\s])(\\.env(?!\\S*\\.(example|sample|template|dist)\\b)(\\.\\w+)?(?=[\\s\\\\/]|$)|\\.aws[\\\\/]credentials|\\.ssh[\\\\/](id_rsa|id_ed25519|id_ecdsa|id_dsa)|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc|key\\.properties|\\.docker[\\\\/]config\\.json|kubeconfig|\\.kube[\\\\/]config|master\\.key|credentials\\.yml)"
114
173
  case_insensitive: true
115
174
  match_on: command
116
175
  title: "Windows copy/move of credential or secret file"
@@ -5,6 +5,8 @@
5
5
 
6
6
  # SAM/SECURITY/SYSTEM hive
7
7
  - id: "CLT-WIN-FILE-001"
8
+ version: 1
9
+ detection_name: "FN:SageWindowsFile-A [Heur]"
8
10
  category: secrets
9
11
  severity: critical
10
12
  confidence: 0.95
@@ -16,6 +18,8 @@
16
18
 
17
19
  # NTDS.dit (Active Directory database)
18
20
  - id: "CLT-WIN-FILE-002"
21
+ version: 1
22
+ detection_name: "FN:SageWindowsFile-B [Heur]"
19
23
  category: secrets
20
24
  severity: critical
21
25
  confidence: 0.95
@@ -27,6 +31,8 @@
27
31
 
28
32
  # Windows hosts file
29
33
  - id: "CLT-WIN-FILE-003"
34
+ version: 1
35
+ detection_name: "FN:SageWindowsFile-C [Heur]"
30
36
  category: tool
31
37
  severity: warning
32
38
  confidence: 0.60
@@ -38,6 +44,8 @@
38
44
 
39
45
  # Startup folder
40
46
  - id: "CLT-WIN-FILE-004"
47
+ version: 1
48
+ detection_name: "FN:SageWindowsFile-D [Heur]"
41
49
  category: tool
42
50
  severity: warning
43
51
  confidence: 0.60
@@ -49,6 +57,8 @@
49
57
 
50
58
  # Executable script in System32/SysWOW64
51
59
  - id: "CLT-WIN-FILE-005"
60
+ version: 1
61
+ detection_name: "FN:SageWindowsFile-E [Heur]"
52
62
  category: tool
53
63
  severity: critical
54
64
  confidence: 0.90
@@ -60,6 +70,8 @@
60
70
 
61
71
  # Driver file in System32/drivers
62
72
  - id: "CLT-WIN-FILE-006"
73
+ version: 1
74
+ detection_name: "FN:SageWindowsFile-F [Heur]"
63
75
  category: tool
64
76
  severity: critical
65
77
  confidence: 0.90
@@ -71,6 +83,8 @@
71
83
 
72
84
  # Task Scheduler directory
73
85
  - id: "CLT-WIN-FILE-007"
86
+ version: 1
87
+ detection_name: "FN:SageWindowsFile-G [Heur]"
74
88
  category: tool
75
89
  severity: warning
76
90
  confidence: 0.60
@@ -82,6 +96,8 @@
82
96
 
83
97
  # SSH key or config file (Windows path)
84
98
  - id: "CLT-WIN-FILE-008"
99
+ version: 1
100
+ detection_name: "FN:SageWindowsFile-H [Heur]"
85
101
  category: secrets
86
102
  severity: warning
87
103
  confidence: 0.60
@@ -93,6 +109,8 @@
93
109
 
94
110
  # AWS credentials file (Windows path)
95
111
  - id: "CLT-WIN-FILE-009"
112
+ version: 1
113
+ detection_name: "FN:SageWindowsFile-I [Heur]"
96
114
  category: secrets
97
115
  severity: warning
98
116
  confidence: 0.60
@@ -104,6 +122,8 @@
104
122
 
105
123
  # Browser credential stores
106
124
  - id: "CLT-WIN-FILE-010"
125
+ version: 1
126
+ detection_name: "FN:SageWindowsFile-J [Heur]"
107
127
  category: secrets
108
128
  severity: critical
109
129
  confidence: 0.90
@@ -4,6 +4,8 @@
4
4
 
5
5
  # PowerShell -EncodedCommand
6
6
  - id: "CLT-WIN-OBFUS-001"
7
+ version: 1
8
+ detection_name: "CMD:SageWindowsObfuscation-A [Heur]"
7
9
  category: tool
8
10
  severity: critical
9
11
  confidence: 0.95
@@ -15,10 +17,14 @@
15
17
 
16
18
  # certutil -decode
17
19
  - id: "CLT-WIN-OBFUS-002"
20
+ version: 1
21
+ detection_name: "CMD:SageWindowsObfuscation-B [Heur]"
18
22
  category: tool
19
23
  severity: warning
20
24
  confidence: 0.60
21
- pattern: "[Cc][Ee][Rr][Tt][Uu][Tt][Ii][Ll]\\s.*-decode"
25
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009. Had no
26
+ # boundary at all.
27
+ pattern: "{{CMD_POS}}[Cc][Ee][Rr][Tt][Uu][Tt][Ii][Ll](?:\\.exe)?{{NOT_FILENAME}}\\s.*-decode"
22
28
  match_on: command
23
29
  title: "certutil base64 decode (obfuscation)"
24
30
  expires_at: null
@@ -26,6 +32,8 @@
26
32
 
27
33
  # Hidden PowerShell window
28
34
  - id: "CLT-WIN-OBFUS-003"
35
+ version: 1
36
+ detection_name: "CMD:SageWindowsObfuscation-C [Heur]"
29
37
  category: tool
30
38
  severity: warning
31
39
  confidence: 0.60
@@ -37,6 +45,8 @@
37
45
 
38
46
  # Bypass + NoProfile combo
39
47
  - id: "CLT-WIN-OBFUS-004"
48
+ version: 1
49
+ detection_name: "CMD:SageWindowsObfuscation-D [Heur]"
40
50
  category: tool
41
51
  severity: warning
42
52
  confidence: 0.90
@@ -48,6 +58,8 @@
48
58
 
49
59
  # [char] code obfuscation
50
60
  - id: "CLT-WIN-OBFUS-005"
61
+ version: 1
62
+ detection_name: "CMD:SageWindowsObfuscation-E [Heur]"
51
63
  category: tool
52
64
  severity: warning
53
65
  confidence: 0.60
@@ -59,6 +71,8 @@
59
71
 
60
72
  # Security provider DLL injection via registry
61
73
  - id: "CLT-WIN-OBFUS-006"
74
+ version: 1
75
+ detection_name: "CMD:SageWindowsObfuscation-F [Heur]"
62
76
  category: tool
63
77
  severity: critical
64
78
  confidence: 0.90
@@ -70,10 +84,15 @@
70
84
 
71
85
  # mshta VBScript execution (Execute, CreateObject, close patterns)
72
86
  - id: "CLT-WIN-OBFUS-007"
87
+ version: 1
88
+ detection_name: "CMD:SageWindowsObfuscation-G [Heur]"
73
89
  category: tool
74
90
  severity: critical
75
91
  confidence: 0.90
76
- pattern: "\\bmshta\\b.*\\bvbscript:(Execute|CreateObject|close\\s*\\()"
92
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-MITRE-096 (tscon),
93
+ # including the optional `.exe` suffix ahead of {{NOT_FILENAME}} (which
94
+ # itself rejects a trailing dot).
95
+ pattern: "{{CMD_POS}}mshta(?:\\.exe)?{{NOT_FILENAME}}.*\\bvbscript:(Execute|CreateObject|close\\s*\\()"
77
96
  case_insensitive: true
78
97
  match_on: command
79
98
  title: "mshta VBScript execution (Execute/CreateObject obfuscation)"
@@ -82,10 +101,13 @@
82
101
 
83
102
  # mshta javascript: eval execution
84
103
  - id: "CLT-WIN-OBFUS-008"
104
+ version: 1
105
+ detection_name: "CMD:SageWindowsObfuscation-H [Heur]"
85
106
  category: tool
86
107
  severity: critical
87
108
  confidence: 0.90
88
- pattern: "\\bmshta\\b.*\\bjavascript:"
109
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-OBFUS-007.
110
+ pattern: "{{CMD_POS}}mshta(?:\\.exe)?{{NOT_FILENAME}}.*\\bjavascript:"
89
111
  case_insensitive: true
90
112
  match_on: command
91
113
  title: "mshta JavaScript execution (LOLBin obfuscation)"
@@ -94,10 +116,15 @@
94
116
 
95
117
  # wscript/cscript //E: engine override on non-script files
96
118
  - id: "CLT-WIN-OBFUS-009"
119
+ version: 1
120
+ detection_name: "CMD:SageWindowsObfuscation-I [Heur]"
97
121
  category: tool
98
122
  severity: critical
99
123
  confidence: 0.90
100
- pattern: "(wscript|cscript)(\\.exe)?\\b.*//[Ee]:([Vv][Bb][Ss]cript|[Jj][Ss]cript)"
124
+ # {{CMD_POS}} + {{NOT_FILENAME}} instead of a leading bare alternation with
125
+ # no command-position boundary; {{NOT_FILENAME}} replaces the trailing
126
+ # `\b`, same effect but also rejects a trailing dot.
127
+ pattern: "{{CMD_POS}}(wscript|cscript)(?:\\.exe)?{{NOT_FILENAME}}.*//[Ee]:([Vv][Bb][Ss]cript|[Jj][Ss]cript)"
101
128
  case_insensitive: true
102
129
  match_on: command
103
130
  title: "wscript/cscript script engine override (//E:VBScript evasion)"
@@ -106,6 +133,8 @@
106
133
 
107
134
  # NTFS $INDEX_ALLOCATION folder creation (ex CLT-TECH-001)
108
135
  - id: "CLT-WIN-OBFUS-010"
136
+ version: 1
137
+ detection_name: "CMD:SageWindowsObfuscation-J [Heur]"
109
138
  category: tool
110
139
  severity: warning
111
140
  confidence: 0.60
@@ -118,6 +147,8 @@
118
147
 
119
148
  # ADS bypass via type redirect or wmic process create (ex CLT-TECH-002)
120
149
  - id: "CLT-WIN-OBFUS-011"
150
+ version: 1
151
+ detection_name: "CMD:SageWindowsObfuscation-K [Heur]"
121
152
  category: tool
122
153
  severity: warning
123
154
  confidence: 0.60
@@ -130,6 +161,8 @@
130
161
 
131
162
  # Dotdotdot hidden folder (ex CLT-TECH-003)
132
163
  - id: "CLT-WIN-OBFUS-012"
164
+ version: 1
165
+ detection_name: "CMD:SageWindowsObfuscation-L [Heur]"
133
166
  category: tool
134
167
  severity: warning
135
168
  confidence: 0.60
@@ -142,10 +175,15 @@
142
175
 
143
176
  # cmd caret obfuscation (ex CLT-TECH-014)
144
177
  - id: "CLT-WIN-OBFUS-013"
178
+ version: 1
179
+ detection_name: "CMD:SageWindowsObfuscation-M [Heur]"
145
180
  category: tool
146
181
  severity: warning
147
182
  confidence: 0.60
148
- pattern: "cmd.*([^\\^]\\^[a-z].*){5}"
183
+ # {{CMD_POS}} + {{NOT_FILENAME}} (with optional `.exe` suffix), same shape
184
+ # as CLT-MITRE-096. Had no boundary at all -- not even a `\b` -- so `cmd`
185
+ # matched as a bare substring of `cmdlet` or similar.
186
+ pattern: "{{CMD_POS}}cmd(?:\\.exe)?{{NOT_FILENAME}}.*([^\\^]\\^[a-z].*){5}"
149
187
  case_insensitive: true
150
188
  match_on: command
151
189
  title: "cmd caret (^) obfuscation"
@@ -154,10 +192,13 @@
154
192
 
155
193
  # cmd substring concatenation obfuscation (ex CLT-TECH-015)
156
194
  - id: "CLT-WIN-OBFUS-014"
195
+ version: 1
196
+ detection_name: "CMD:SageWindowsObfuscation-N [Heur]"
157
197
  category: tool
158
198
  severity: warning
159
199
  confidence: 0.60
160
- pattern: "cmd.*(%[^%]+:~[^%]*%[a-z]*){2}"
200
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-OBFUS-013.
201
+ pattern: "{{CMD_POS}}cmd(?:\\.exe)?{{NOT_FILENAME}}.*(%[^%]+:~[^%]*%[a-z]*){2}"
161
202
  case_insensitive: true
162
203
  match_on: command
163
204
  title: "cmd substring concatenation obfuscation"
@@ -166,10 +207,14 @@
166
207
 
167
208
  # PowerShell backtick obfuscation (ex CLT-TECH-021)
168
209
  - id: "CLT-WIN-OBFUS-015"
210
+ version: 1
211
+ detection_name: "CMD:SageWindowsObfuscation-O [Heur]"
169
212
  category: tool
170
213
  severity: warning
171
214
  confidence: 0.60
172
- pattern: "powershell.*(`[a-z].*){4}"
215
+ # {{CMD_POS}} + {{NOT_FILENAME}} (with optional `.exe` suffix), same shape
216
+ # as CLT-MITRE-096. Had no boundary at all.
217
+ pattern: "{{CMD_POS}}powershell(?:\\.exe)?{{NOT_FILENAME}}.*(`[a-z].*){4}"
173
218
  case_insensitive: true
174
219
  match_on: command
175
220
  title: "PowerShell backtick obfuscation"
@@ -178,10 +223,13 @@
178
223
 
179
224
  # PowerShell XOR decryption (ex CLT-TECH-026)
180
225
  - id: "CLT-WIN-OBFUS-016"
226
+ version: 1
227
+ detection_name: "CMD:SageWindowsObfuscation-P [Heur]"
181
228
  category: tool
182
229
  severity: warning
183
230
  confidence: 0.60
184
- pattern: "powershell.+-bxor\\s*['\"]"
231
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-OBFUS-015.
232
+ pattern: "{{CMD_POS}}powershell(?:\\.exe)?{{NOT_FILENAME}}.+-bxor\\s*['\"]"
185
233
  case_insensitive: true
186
234
  match_on: command
187
235
  title: "PowerShell XOR decryption"
@@ -5,10 +5,13 @@
5
5
 
6
6
  # Registry Run key via reg add
7
7
  - id: "CLT-WIN-PERSIST-001"
8
+ version: 1
9
+ detection_name: "CMD:SageWindowsPersistence-A [Heur]"
8
10
  category: tool
9
11
  severity: critical
10
12
  confidence: 0.90
11
- pattern: "\\b[Rr][Ee][Gg]\\b\\s+[Aa][Dd][Dd].*\\\\(Run|RunOnce)\\\\"
13
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009.
14
+ pattern: "{{CMD_POS}}[Rr][Ee][Gg](?:\\.exe)?{{NOT_FILENAME}}\\s+[Aa][Dd][Dd].*\\\\(Run|RunOnce)\\\\"
12
15
  match_on: command
13
16
  title: "Registry Run key persistence via reg add"
14
17
  expires_at: null
@@ -16,10 +19,13 @@
16
19
 
17
20
  # sc create/config service
18
21
  - id: "CLT-WIN-PERSIST-002"
22
+ version: 1
23
+ detection_name: "CMD:SageWindowsPersistence-B [Heur]"
19
24
  category: tool
20
25
  severity: critical
21
26
  confidence: 0.90
22
- pattern: "\\b[Ss][Cc]\\b\\s+(create|config).*binpath"
27
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009.
28
+ pattern: "{{CMD_POS}}[Ss][Cc](?:\\.exe)?{{NOT_FILENAME}}\\s+(create|config).*binpath"
23
29
  match_on: command
24
30
  title: "Windows service creation/modification via sc"
25
31
  expires_at: null
@@ -27,10 +33,13 @@
27
33
 
28
34
  # schtasks /create
29
35
  - id: "CLT-WIN-PERSIST-003"
36
+ version: 1
37
+ detection_name: "CMD:SageWindowsPersistence-C [Heur]"
30
38
  category: tool
31
39
  severity: warning
32
40
  confidence: 0.60
33
- pattern: "\\b[Ss][Cc][Hh][Tt][Aa][Ss][Kk][Ss]\\b.*/[Cc]reate"
41
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-CMD-009.
42
+ pattern: "{{CMD_POS}}[Ss][Cc][Hh][Tt][Aa][Ss][Kk][Ss](?:\\.exe)?{{NOT_FILENAME}}.*/[Cc]reate"
34
43
  match_on: command
35
44
  title: "Scheduled task creation via schtasks"
36
45
  expires_at: null
@@ -38,10 +47,16 @@
38
47
 
39
48
  # PowerShell New-ScheduledTask
40
49
  - id: "CLT-WIN-PERSIST-004"
50
+ version: 1
51
+ detection_name: "CMD:SageWindowsPersistence-D [Heur]"
41
52
  category: tool
42
53
  severity: warning
43
54
  confidence: 0.60
44
- pattern: "[Nn]ew-[Ss]cheduled[Tt]ask"
55
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. Had no
56
+ # boundary at all, so it matched inside the distinct, real cmdlets
57
+ # New-ScheduledTaskAction and New-ScheduledTaskTrigger even when the real
58
+ # New-ScheduledTask was never called.
59
+ pattern: "{{CMD_POS}}[Nn]ew-[Ss]cheduled[Tt]ask{{NOT_FILENAME}}"
45
60
  match_on: command
46
61
  title: "PowerShell scheduled task creation"
47
62
  expires_at: null
@@ -49,10 +64,15 @@
49
64
 
50
65
  # PowerShell Set-ItemProperty Run key
51
66
  - id: "CLT-WIN-PERSIST-005"
67
+ version: 1
68
+ detection_name: "CMD:SageWindowsPersistence-E [Heur]"
52
69
  category: tool
53
70
  severity: critical
54
71
  confidence: 0.90
55
- pattern: "[Ss]et-[Ii]tem[Pp]roperty.*\\\\(Run|RunOnce)\\\\"
72
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. Had no
73
+ # boundary at all, so it matched inside the distinct, real cmdlet
74
+ # Set-ItemPropertyValue even when Set-ItemProperty itself was never called.
75
+ pattern: "{{CMD_POS}}[Ss]et-[Ii]tem[Pp]roperty{{NOT_FILENAME}}.*\\\\(Run|RunOnce)\\\\"
56
76
  match_on: command
57
77
  title: "PowerShell Registry Run key persistence"
58
78
  expires_at: null
@@ -60,10 +80,13 @@
60
80
 
61
81
  # PowerShell New-Service
62
82
  - id: "CLT-WIN-PERSIST-006"
83
+ version: 1
84
+ detection_name: "CMD:SageWindowsPersistence-F [Heur]"
63
85
  category: tool
64
86
  severity: warning
65
87
  confidence: 0.60
66
- pattern: "\\b[Nn]ew-[Ss]ervice\\b"
88
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036.
89
+ pattern: "{{CMD_POS}}[Nn]ew-[Ss]ervice{{NOT_FILENAME}}"
67
90
  match_on: command
68
91
  title: "PowerShell Windows service creation"
69
92
  expires_at: null
@@ -71,6 +94,8 @@
71
94
 
72
95
  # Startup folder path
73
96
  - id: "CLT-WIN-PERSIST-007"
97
+ version: 1
98
+ detection_name: "CMD:SageWindowsPersistence-G [Heur]"
74
99
  category: tool
75
100
  severity: warning
76
101
  confidence: 0.60
@@ -82,10 +107,23 @@
82
107
 
83
108
  # WMI event subscription persistence
84
109
  - id: "CLT-WIN-PERSIST-008"
110
+ version: 1
111
+ detection_name: "CMD:SageWindowsPersistence-H [Heur]"
85
112
  category: tool
86
113
  severity: critical
87
114
  confidence: 0.90
88
- pattern: "\\b(CommandLineEventConsumer|ActiveScriptEventConsumer)\\b"
115
+ # A WMI class name legitimately appears as an argument value (`-Class
116
+ # CommandLineEventConsumer`), so {{CMD_POS}} would break real detections —
117
+ # only the symmetric boundary guard applies here, plus {{NOT_FILENAME}}
118
+ # (instead of {{NOT_COMPOUND_RIGHT}}) to also reject a trailing dot
119
+ # (`CommandLineEventConsumer.md`) and {{NOT_AFTER_TEXT_CMD}} to reject a
120
+ # mention inside a search/print command (`grep "CommandLineEventConsumer"`)
121
+ # without gating on quotes, which would just hand an attacker a trivial
122
+ # evasion. See {{NOT_AFTER_TEXT_CMD}} in _macros.yaml for the full guard
123
+ # design and its accepted residual gap (an unlisted benign command still
124
+ # false-positives).
125
+ pattern: "{{NOT_AFTER_TEXT_CMD}}{{NOT_COMPOUND_LEFT}}(CommandLineEventConsumer|ActiveScriptEventConsumer){{NOT_FILENAME}}"
126
+ case_insensitive: true
89
127
  match_on: command
90
128
  title: "WMI event subscription persistence"
91
129
  expires_at: null
@@ -4,10 +4,14 @@
4
4
 
5
5
  # Install-Module without -RequiredVersion
6
6
  - id: "CLT-WIN-SUPPLY-001"
7
+ version: 1
8
+ detection_name: "CMD:SageWindowsSupplyChain-A [Heur]"
7
9
  category: supply_chain
8
10
  severity: warning
9
11
  confidence: 0.60
10
- pattern: "[Ii]nstall-[Mm]odule\\s+(?!.*-[Rr]equired[Vv]ersion)"
12
+ # {{CMD_POS}} + {{NOT_FILENAME}}, same shape as CLT-WIN-CMD-036. The bare
13
+ # cmdlet mention fired on prose merely describing the risk.
14
+ pattern: "{{CMD_POS}}[Ii]nstall-[Mm]odule{{NOT_FILENAME}}\\s+(?!.*-[Rr]equired[Vv]ersion)"
11
15
  match_on: command
12
16
  title: "PowerShell Install-Module without -RequiredVersion"
13
17
  expires_at: null