transacted_hollowing icon indicating copy to clipboard operation
transacted_hollowing copied to clipboard

Just a question

Open hawaii67 opened this issue 2 years ago • 10 comments

Hey there,

the payload or malicious PE file should be on the fileytem here. Mostly it will be already fished away by AV, especially if it is malicious or suspicious enough :-) In my case for testing purpose it is mimikatz being wiped away. I was just wondering how malware can benefit from those techniques like process ghosting or transacted hollowing.........

hawaii67 avatar Jan 27 '22 14:01 hawaii67

Hi! Of course it is just a PoC, and on purpose it wasn't implemented as a ready-made loader for malware :) In the real-life scenario you will not read the payload from the file, but have it hardcoded in the binary. I implemented the injection part, not the storage of the payload - to demonstrate the technique, but at the same time to prevent it from being used as a malware packer by script kiddies. ;)

hasherezade avatar Jan 27 '22 16:01 hasherezade

Thanks for your quick answer hasherezade. Sure it is a POC. I am just interested how malware is working with it. When in the real-life scenario the payload will not be read from the file - since when a PE file has a malware file backpacked so to say, why not just injecting the malicious part - why do I need techniques like transacted hollowing or process ghosting? Sorry for this maybe stupid question, I just want to understand.....

hawaii67 avatar Jan 27 '22 17:01 hawaii67

why not just injecting the malicious part

So, the techniques like transacted hollowing or process ghosting are exactly for the injection. you can have the payload stored in the loader - but in order to execute it, you have to load it first, and make it runnable. And there are various techniques dedicated to this part. Depending on the technique used, the loader may be less or more stealthy. Different loaders have also different steps, and may have different limitations. It is too long topic to elaborate here, but I will try to explain you briefly, Some examples:

  • manual loading (each step of the PE loading is implemented manually - including filling the Imports. works best for self-injection, or reflective injection). the new module needs to be added into an existing process. payload is mapped as MEM_PRIVATE
  • process hollowing (aka RunPE) - the most common technique of process impersonation. replaces a PE module in the newly created, suspended process. then takes advantage of Windows loader to fill the Imports of the payload. typically the payload is mapped as MEM_PRIVATE
  • transacted hollowing - like process hollowing, but the payload is first loaded as image from a transacted file. so, it is mapped as MEM_IMAGE into the target (that makes it look similar to legitimately loaded modules)
  • process ghosting - maps payload as MEM_IMAGE from the invisible (delete-pending) file. then creates the full process out of this image, manually mapping all the needed structures.
  • and there are even more...

So they all are made to achieve the goal of running the payload under the cover of a different process - they just do it in different ways, and the end result may give different artifacts in memory.

hasherezade avatar Jan 27 '22 19:01 hasherezade

Hey thank you for this awesome explanation. Very good insight you gave. My point is, for example for transacted hollowing, the malicious file must be on the HD in order to use the transacted feature for the file. And when the malware is touching the disk, AV can detect it.

hawaii67 avatar Jan 29 '22 08:01 hawaii67

In case of transacted hollowing, similarly to process doppelganging, the payload is dropped (temporarily) into a transacted file. but due to the transacted feature, this file is accessible only to the creator, and AV cannot scan it. more about it I described in the article about Process Doppelganging: https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/ - check also an original presentation of the authors of this technique (https://www.youtube.com/watch?v=Cch8dvp836w).

hasherezade avatar Jan 29 '22 12:01 hasherezade

Ah thank you again! Now I see. FIRST a not malicious file is transacted and THEN the malicious code is written to the transacted file. That was my understanding problem. Thanks a lot again!

hawaii67 avatar Jan 29 '22 12:01 hawaii67

ok, I hope your doubts are resolved now :)

hasherezade avatar Jan 30 '22 00:01 hasherezade

What about this one: https://github.com/hasherezade/transacted_hollowing/blob/a9eaed85627827d28d34d03d059bbdd4e88834c9/transacted_file.cpp#L40 Is it possible to not write the file to disk at all? This is also used in all other injection techniques you made i.e. process_doppelganging, process_overwriting and process_ghosting. In other projects you do NtSetInformationFile in order to force the file to be deleted on close but it's still not as ideal as it could've been if the binary was never written to disk. I'm not looking for a ready to use solution but rather just a hint or at least a yes or no if it's possible at all so that I can do some more research on my own. Thanks

Ou7law007 avatar Mar 15 '22 22:03 Ou7law007

@Ou7law007 - this particular line: https://github.com/hasherezade/transacted_hollowing/blob/a9eaed85627827d28d34d03d059bbdd4e88834c9/transacted_file.cpp#L40 is a part of the Transacted File Creation, which is a compulsory part of both Process Doppelgänging and transacted_hollowing. Check the writeup: https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/ The file is created inside the transaction, which means, until the transaction is commited, only the process that created it can see those changes. So the dropped file is never observed by other entities, since the transaction is rolled back. It is not a simple file dropping. As this technique is an essential part of the aforementioned techniques, it cannot be skipped.

Process Ghosting is similar - there we also drop the file to which other processes don't have access - but instead of using the transactions, we use delete-pending file. This is also a part of this technique, and a step that cannot be skipped.

Process Overwriting is very different in this - here you don't have to drop the payload at all, you can load it directly from a buffer in memory of the injector.

hasherezade avatar Mar 17 '22 08:03 hasherezade

The thing that was added just for the purpose of the demo, so that my loaders will not be misused as ready-made components by script-kiddies, is, for example, this:

https://github.com/hasherezade/process_overwriting/blob/49c3365ceb2de21efbd24c15fc86faf01dfb8a81/process_overwrite/main.cpp#L97

    // load the payload:
    BYTE* payloadBuf = peconv::load_pe_module(payloadPath, payloadSize, false, false);
    if (payloadBuf == NULL) {
        std::cerr << "Cannot read payload!" << std::endl;
        return -1;
    }
    /*
    // if the file is NOT dropped on the disk, you can load it directly from a memory buffer:
    BYTE* payloadBuf = peconv::load_pe_module(buffer, bufsize, payloadSize, false, false);
    */

In a real-life loader, the buffer used will not be from the dropped file, but rather a resource within a PE, or any other hardcoded buffer.

hasherezade avatar Mar 17 '22 08:03 hasherezade