last-byte / PersistenceSniper

Powershell module that can be used by Blue Teams, Incident Responders and System Administrators to hunt persistences implanted in Windows machines. Official Twitter/X account @PersistSniper. Made with ❤️ by @last0x00 and @dottor_morte
Other
1.91k stars 184 forks source link

Unable to detect ghosttasks #25

Closed j-wsy closed 4 months ago

j-wsy commented 7 months ago

Hi, love the tool.

I have a vm with a working ghosttask loaded (restarted and all that, and confirmed the ghosttask is functioning). I can see it in my regedit \tasks\, and I can see it doesn't have a SD, as expected. I can see it doing the action I made it do.

Running the latest PersistenceSniper v1.16.0, I can't seem to detect it. I see a bunch of other false-positives, so the tool itself is working, but no output relating to ghosttask.

j-wsy commented 7 months ago

image

j-wsy commented 7 months ago

Here's another example using a ghosttask named "April1", on a separate clean vm. Could not detect using Find-AllPersistence.

Am I doing something wrong/do I need to do anything else?

postrebootScreenshot 2024-04-08 235441

last-byte commented 7 months ago

Hey there, solid copy. I’ll investigate it right away and fix it in the next minor release.

j-wsy commented 6 months ago

thanks, looking forward to it.

daniele777 commented 6 months ago

Malware is fake amsi provider?

strassi commented 4 months ago

@j-wsy

How did you create the ghost task. Some tools are creating ghosttask by deleting the SD (security descriptor) for the task, which hides it for every user. image

But some tooling might preserve the SD value, which causes the persistencesniper script to fail finding the task. Persistence Sniper seems to check if the SD is missing. https://github.com/last-byte/PersistenceSniper/blob/6687a26250a3577a0f4c709cbf7c29191a5ad1e8/PersistenceSniper/PersistenceSniper.psm1#L1907

Can you confirm of having a SD for your ghosttask? You have to search in the "Tree" Key for the specific ghost task.

Fig4_Deletion-of-the-security-descriptor-SD-value
j-wsy commented 4 months ago

Hi @strassi I understand what you mean, though I have some questions. image

In green highlight, it shows the GhostTask "demo" with a \TaskCache\Tree\ SD. This was created via the method on https://github.com/netero1010/GhostTask - under "Example 1". Understandably after reading the PersistenceSniper source code, this would fail the boolean: if ($null -eq $taskSD).

In netero1010's project, it describes the code as "Creates scheduled tasks with a restrictive security descriptor, making them invisible to all users."

It seems then that a GhostTask isn't about a missing SD, but something within the SD that permits/denies visibility. So perhaps hunting for a missing SD is not right, but I don't have a better idea at the moment.

As a side note, I want to point out that if you follow the GhostTask's Id (in yellow highlight) and view it under \TaskCache\Tasks (rather than TaskCache\Tree), it has no SecurityDescriptor. This is what I was referring to at the start of this thread, but I'm not sure if this is different to "SD". I do observe that other legit Ids can be missing SecurityDescriptor too, so perhaps it's just not the same. Regardless, once again a lack of an SD doesn't seem to imply a malicious GhostTask...

strassi commented 4 months ago

A possible workaround would be the detection of the used SD of the tool. The very restrictive permissions of GhostTask look like this: https://github.com/netero1010/GhostTask/blob/7db8cd4120328a80e27e220785a8546bb1a4ed28/GhostTask.c#L769

last-byte commented 4 months ago

This should be fixed in 1.16.1 which I just released and seems to catch the use case :) @j-wsy @strassi

j-wsy commented 4 months ago

Awesome, thanks @last-byte

It does work on the ghosttask I set up above using https://github.com/netero1010/GhostTask.

I have a question though:

It looks like you added maliciousSD and it's comparing it to the SD (if there is one) of the suspected ghosttask. Where did you get this maliciousSD base64 encode from, and is this a hardcode value specific to the ghosttask SD in https://github.com/netero1010/GhostTask/blob/main/GhostTask.c#L769?

It looks like that specific line ConvertStringSecurityDescriptorToSecurityDescriptorA("O:BAG:SYD:", 1, &pSd, &sdLength); is what generates the ghosttask SD data (https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format), and the D: part I think makes it restrictive?

If we made a slight change to the unicode/hex of the SD, I guess it would bypass detection?

edit: realised thats what strassi was talking about haha sorry

last-byte commented 4 months ago

Yes, the encoded base64 is the SD that's generated by GhostTask, but I'll look into your suggestion as it makes sense only to look for that specific part potentially.

last-byte commented 4 months ago

To add to that, I'll check and see which part of the SD is mandatory so that manipulation attempts of the SD do not result in evasion.