[BUG] WinEvent Scheduled Task Created to Spawn Shell
nterl0k opened this issue · comments
If you have a Splunk Support contract, creating a support case for your issue may result in faster resolution.
Describe the bug
The correlation "WinEvent Scheduled Task Created to Spawn Shell" is written with a limiting stats command that omits a large number of detections in a production environment. The existing code uses the "Author" field as a group by field, which isn't mandatory/always seen when creating a task and thus causes this correlation to miss detection. Altering the stats command to use aggregate functions alleviates this issue.
`wineventlog_security` EventCode=4698
| xmlkv Message
| search Command IN ("*powershell.exe*", "*wscript.exe*", "*cscript.exe*", "*cmd.exe*", "*sh.exe*", "*ksh.exe*", "*zsh.exe*", "*bash.exe*", "*scrcons.exe*", "*pwsh.exe*")
| stats count min(_time) as firstTime max(_time) as lastTime by dest, Task_Name, Command, Author, Enabled, Hidden
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `winevent_scheduled_task_created_to_spawn_shell_filter`
The PoC below moves optional fields into the aggregate functions, includes the Arguments field for more context, and evals Caller_User_Name/Command/Arguments to CIM fields so that there is more context to the analyst in incident review:
`wineventlog_security` EventCode=4698
| xmlkv Message
| search Command IN ("*powershell.exe*", "*wscript.exe*", "*cscript.exe*", "*cmd.exe*", "*sh.exe*", "*ksh.exe*", "*zsh.exe*", "*bash.exe*", "*scrcons.exe*", "*pwsh.exe*")
| stats count min(_time) as firstTime max(_time) as lastTime latest(Arguments) as Arguments latest(Author) as Author by dest, Task_Name, Command, Enabled, Hidden,Caller_User_Name
| eval command=Task_Name, process=Command+" "+Arguments, src_user=Author, user = Caller_User_Name
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `winevent_scheduled_task_created_to_spawn_shell_filter`
Expected behavior
stats not to drop a large number of results
Screenshots
If applicable, add screenshots to help explain your problem.
App Version:
- ESCU: [e.g. 3.3.1]
Additional context
Similar to #2445
hi @nterl0k are you using 4698 in XML or multiline?
@MHaggis XML since that's the default TA config these days, so I just stick with it.
The underscores do remind me of multiline though, might be inadvertent inclusion by the TA. Lemme look at it more, maybe there's a better user field.
Thank you! I'll get the data going tomorrow and see what I get too.
@MHaggis I poked around at this a little today and found a better way to fit the spirit of CIM/common sense.
In this event you get the account that configured the task with the "SubjectUserName" field and the account that the task is set to run as in the "UserId" field. The setting the "UserId" as the CIM "user" field and using "SubjectUserName" as the CIM "src_user" field makes it contextually accurate.
Both original fields seem to 100% coverage, so they "technically" could be group-by fields.... Here's an updated SPL:
`wineventlog_security` EventCode=4698
| xmlkv Message
| search Command IN ("*powershell.exe*", "*wscript.exe*", "*cscript.exe*", "*cmd.exe*", "*sh.exe*", "*ksh.exe*", "*zsh.exe*", "*bash.exe*", "*scrcons.exe*", "*pwsh.exe*")
| stats count min(_time) as firstTime max(_time) as lastTime latest(Arguments) as Arguments latest(Author) as Author latest(SubjectUserName) as src_user latest(UserId) as user by dest, Task_Name, Command, Enabled, Hidden
| eval command=Task_Name, process=Command+" "+Arguments
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `winevent_scheduled_task_created_to_spawn_shell_filter`
The only issue is "UserId" can show up as SID, User, or Domain\User formatting... so it might benefit from an inline eval or a knowledge object in the Windows TA to address that. For the time being it works well enough.
If you like the way this this looks/feels, there are a few other correlations that use 4698 I can give the same treatment to and do a bulk PR for them.
oh maybe Argument is a copy over from the prior use you had for it in the other query?
@MHaggis So funny thing about "Arguments" it doesn't actually show up in the raw data unless you add command arguments in the scheduled task. Like so
Also try this revised code (I found a bug if "Arguments" is null it won't period concatenate with "Command" and the process field ends up blank.... Sorry for my terrible first attempts at helping here :)
`wineventlog_security` EventCode=4698
| xmlkv Message
| search Command IN ("*powershell.exe*", "*wscript.exe*", "*cscript.exe*", "*cmd.exe*", "*sh.exe*", "*ksh.exe*", "*zsh.exe*", "*bash.exe*", "*scrcons.exe*", "*pwsh.exe*")
| stats count min(_time) as firstTime max(_time) as lastTime latest(Arguments) as Arguments latest(Author) as Author by dest, Task_Name, Command, Enabled, Hidden,Caller_User_Name
| eval command=Task_Name, process=Command+if(isnotnull(Arguments)," ".Arguments,""), src_user=Author, user = Caller_User_Name
| `security_content_ctime(firstTime)`
| `security_content_ctime(lastTime)`
| `winevent_scheduled_task_created_to_spawn_shell_filter`