rapid7 / metasploit-framework

Metasploit Framework
https://www.metasploit.com/
Other
34.13k stars 13.97k forks source link

Make Meterpreter Reflective DLL Injection More Stealthy In Memory #16493

Closed tekwizz123 closed 2 years ago

tekwizz123 commented 2 years ago

Currently it is fairly easy to detect Meterpreter Reflective DLL injection in memory due to the fact that it leaves behind large allocated RWX memory regions even after Meterpreter exits and the DLL also exports an obviously named function ReflectiveLoader(). Both of these are good indicators for malware analysts to match on. Furthermore the allocated memory segments contain the full EXE header, something that isn't strictly needed but gives a good fingerprint for detecting the Meterpreter payload. This is all mentioned at https://www.elastic.co/blog/hunting-memory.

In an effort to improve the security of public tools and to also improve Metasploit itself, it would be a good idea to consider if we can recode the ReflectiveLoader code to also remove allocated RWX sections as soon as they are no longer needed. It would also be a good idea to see if we can randomize the name of the exported function at generation time instead of leaving it as the static ReflectiveLoader string.

The second recommendation is probably going to be harder to do than the first given that we presently store the code separately from the module, therefore unless we have a way to dynamically recompile the payload (something we don't have the capability to do at present), this may prove to be an issue and may require further work.

The former issue should be possible to solve by looking at where we allocate memory segments and then making sure we call the appropriate Windows functions to free them.

timwr commented 2 years ago

https://bruteratel.com/research/feature-update/2021/06/01/PE-Reflection-Long-Live-The-King/ I'll have a go at applying the correct memory protections from the ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics field.

timwr commented 2 years ago

https://github.com/rapid7/ReflectiveDLLInjection/pull/12

ghost commented 2 years ago

Hi,@tekwizz123 You mentioned this in your comment

'''The second recommendation is probably going to be harder to do than the first given that we presently store the code separately from the module, therefore unless we have a way to dynamically recompile the payload (something we don't have the capability to do at present), this may prove to be an issue and may require further work.'''

However,dynamically recompile may not be difficult. In my experience,i often use https://github.com/scrt/avcleaner to rebuild meterpreter or part of meterpreter.

And i get a quite pretty result to evade Av/Edr.

ghost commented 2 years ago

Also,i have read https://www.anquanke.com/post/id/211563 to realize its work

timwr commented 2 years ago

Couldn't we also just do a gsub! on the obviously named string?

ghost commented 2 years ago

@timwr Yes,i think its the most efficiency way. However,the source of meterpreter is large. It must be time-consuming

ghost commented 2 years ago

Oh,@timwr,i misunderstood your words! Yes,we can change the "flagged words" dynamically. Nevertheless,it is just a time problem before getting detected again(For example,the cloud-based protection in windows defender,which is good at detecting suspicious action,no matter how we obfuscate flagged words) . Thus,i think not only should we change the flagged words,we also need to change meterpreter's suspicious actions(I am considered inserting junk code to meterpreter dynamically and compile it when generating payloads or stage sending) Unfortunetely,i just have python version junk code generator,i am finding a way to embed it to msf(a hard work) Besides,i have no good idea to exert a feature into msf to compile obfuscated-meterpreter every time.

smcintyre-r7 commented 2 years ago

It would also be a good idea to see if we can randomize the name of the exported function at generation time instead of leaving it as the static ReflectiveLoader string.

Can you provide more context on this? Since https://github.com/rapid7/ReflectiveDLLInjection/pull/9 was landed, the RDI can use ordinals, and I thought Meterpreter builds had all been updated to use the ordinal instead of the name. Maybe RDLL exploits before or even after that PR were landed might still be using the name.

gwillcox-r7 commented 2 years ago

It would also be a good idea to see if we can randomize the name of the exported function at generation time instead of leaving it as the static ReflectiveLoader string.

Can you provide more context on this? Since rapid7/ReflectiveDLLInjection#9 was landed, the RDI can use ordinals, and I thought Meterpreter builds had all been updated to use the ordinal instead of the name. Maybe RDLL exploits before or even after that PR were landed might still be using the name.

Hmm so this was taken purely from the blog which was written in 2019, before that PR was landed. I raised this issue more as a double check, I haven't taken a look deeper into the specifics so its very possible this may have been addressed by the PR you mentioned.