splunk / security_content

Splunk Security Content

Home Page:https://research.splunk.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[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.

Looks like that is an extraction from the Windows TA using the "SubjectUserName" field, but it's present on both multiline and XML formats.

Snipaste_2022-11-15_07-47-44

Should we switch to "SubjectUserName" instead?

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.

Hey same thing with this one - for XML. If you'd like to update the rest that is totally cool.
May be a typo or mistake here?
| eval Argument=TaskName, process=Command+" "+Arguments

Either way let me know. You can also Slack me on the user group. Happy to work on this in real time.

image

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

image

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`