Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create injection_writememory.py #401

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

kevross33
Copy link
Contributor

@kevross33 kevross33 commented Feb 27, 2024

Sigs for detecting WriteProcessMemory to a remote process.

Example from APT29 EnvyScout/ROOTSAW dropped GraphicalNeutrino (https://go.recordedfuture.com/hubfs/reports/cta-2023-0127.pdf)

image

Sigs for detecting WriteProcessMemory to a remote process.
@kevoreilly
Copy link
Collaborator

Thanks - I think there is some overlap here with one of the few api sigs in the main repo:

modules/signatures/CAPE.py

class CAPE_Injection(Signature):
    name = "injection_inter_process"
    description = "Behavioural detection: Injection (inter-process)"
    severity = 3
    categories = ["injection"]
    authors = ["kevoreilly"]
    minimum = "1.3"
    evented = True
    ttps = ["T1055"]  # MITRE v6,7,8
    mbcs = ["OB0006", "E1055"]

    def __init__(self, *args, **kwargs):
        Signature.__init__(self, *args, **kwargs)
        self.lastprocess = None
        self.process_handles = None
        self.write_handles = None
        self.injection_detected = False

    filter_categories = set(["process"])

    def on_call(self, call, process):
        if process is not self.lastprocess:
            if self.process_handles:
                for handle in self.process_handles:
                    if handle in self.write_handles:
                        self.injection_detected = True
            self.process_handles = set()
            self.write_handles = set()
            self.lastprocess = process

        if call["api"] in ("CreateProcessInternalW", "OpenProcess", "NtOpenProcess"):
            phandle = self.get_argument(call, "ProcessHandle")
            self.process_handles.add(phandle)
        elif call["api"] in ("NtWriteVirtualMemory", "NtWow64WriteVirtualMemory64", "WriteProcessMemory", "NtMapViewOfSection"):
            whandle = self.get_argument(call, "ProcessHandle")
            self.write_handles.add(whandle)

    def on_complete(self):
        if self.injection_detected:
            return True
        elif self.process_handles:
            for handle in self.process_handles:
                if handle in self.write_handles:
                    return True

I haven't checked to look whether the above is detected by this signature and if not why not.

@kevross33
Copy link
Contributor Author

It doesn't (21a0b617431850a9ea2698515c277cbd95de4e59c493d0d8f194f3808eb16354 Instructions.iso). While most injection techniques are covered I sometimes am finding they don't fire on these behaviours potentially because of how it is being done instead of the typical chain. That is why I have done this (and others in testing) breaking down anomalies like these. For example in this case writing to the memory of the other process and then others resuming the thread in the other process.

@doomedraven
Copy link
Collaborator

so maybe we want to merge them as they are related but not the same? thoughts?

@kevoreilly
Copy link
Collaborator

Yes of course we should merge what we haven't got and clean up what we have to maximise coverage.

Historically there was an additional use for the signatures in 'CAPE.py' as they were used as triggers for package selection... back a long time ago. Now we don't need a special set of signatures to trigger packages so I think the best way is probably to remove CAPE.py completely and ensure that Kevin's sigs here cover everything we need. If not we can add to them as needs be.

Let me test these and the CAPE.py sigs against Kevin's samples as well as my own 'injection' test set and I will try to consolidate them all. I don't mind doing that after this is merged.

@doomedraven
Copy link
Collaborator

doomedraven commented Mar 7, 2024 via email

@kevoreilly
Copy link
Collaborator

@kevross33 any reason why these signatures do not include the api NtWriteVirtualMemory? Incidentally this function and the two you have included are the three for which injected data is captured by the monitor.

@kevross33
Copy link
Contributor Author

kevross33 commented Mar 11, 2024 via email

@kevoreilly
Copy link
Collaborator

I will add this api and make sure the net is sound 👌

@kevoreilly
Copy link
Collaborator

There is a slight complication here in that the API calls shown in your initial screenshot are Windows internal calls from within the CreateProcess API. This function is normally hooked but in the case of rundll32 this API happens to be redirected by 'Application Compatibility' or the Microsoft Shim Engine.

2024-04-10 15:04:40,409 [root] DEBUG: 5192: Monitor initialised: 32-bit capemon loaded in process 5192 at 0x726f0000, thread 4868, image base 0x650000, stack from 0x634000-0x640000
2024-04-10 15:04:40,409 [root] DEBUG: 5192: Commandline: "C:\Windows\system32\rundll32.exe" "C:\21a0b617431850a9ea269851\BUGSPLAT.DLL",#1
2024-04-10 15:04:40,424 [root] DEBUG: 5192: hook_api: Warning - CoCreateInstance export address 0x773156BD differs from GetProcAddress -> 0x76B988E0 (combase.dll::0xe88e0)
2024-04-10 15:04:40,424 [root] DEBUG: 5192: hook_api: Warning - CoCreateInstanceEx export address 0x773156FC differs from GetProcAddress -> 0x76BD3020 (combase.dll::0x123020)
2024-04-10 15:04:40,424 [root] DEBUG: 5192: hook_api: Warning - CoGetClassObject export address 0x77315C8C differs from GetProcAddress -> 0x76BCD870 (combase.dll::0x11d870)
2024-04-10 15:04:40,424 [root] DEBUG: 5192: hook_api: Warning - UpdateProcThreadAttribute export address 0x75D1FD46 differs from GetProcAddress -> 0x7713D580 (KERNELBASE.dll::0xfd580)
2024-04-10 15:04:40,424 [root] DEBUG: 5192: hook_api: Warning - CreateProcessA export address 0x75CB2D90 differs from GetProcAddress -> 0x729A18A0 (AcLayers.DLL::0x218a0)
2024-04-10 15:04:40,440 [root] DEBUG: 5192: hook_api: Warning - CreateProcessW export address 0x75C988E0 differs from GetProcAddress -> 0x729A1AE0 (AcLayers.DLL::0x21ae0)
2024-04-10 15:04:40,440 [root] DEBUG: 5192: hook_api: Warning - WinExec export address 0x75CDCF20 differs from GetProcAddress -> 0x729A1DA0 (AcLayers.DLL::0x21da0)
2024-04-10 15:04:40,440 [root] DEBUG: 5192: hook_api: Warning - CLSIDFromProgID export address 0x77314EF6 differs from GetProcAddress -> 0x76B44FD0 (combase.dll::0x94fd0)

I have previously experimented with ignoring these redirections in hooks but this caused detonation issues. I am currently researching whether a certain subset of these might be ignored, such as those for APIs from kernel32 like this one. I will hopefully reach a conclusion soon.

Not that this means the signature is problematic - but it's certainly worth noting the signal used here as an example is a false positive and this is not malware injecting into anything but Windows internal mechanics.

@doomedraven
Copy link
Collaborator

what is the state of this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants